8000 Fix v0.13 qualification release assets by DaoyuanLi2816 · Pull Request #116 · DaoyuanLi2816/mini-verl · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/miniverl/qualification.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,27 @@ def _roles_and_gpu_are_exact(self) -> GPUQualification:
raise ValueError(
"v0.12 full qualification evidence is missing: " + ", ".join(details)
)
try:
requires_v013 = (int(version_parts[0]), int(version_parts[1])) >= (0, 13)
except (IndexError, ValueError):
requires_v013 = False
if requires_v013:
v013_checks = {
"v013_pinned_verl_v09_ppo_compiler",
"v013_independent_actor_critic_updates",
"v013_exact_actor_critic_resume",
"v013_trained_reward_model",
"v013_exact_wheel_ppo_runtime",
}
missing_v013_checks = sorted(v013_checks - set(self.checks.executed))
missing_v013_artifacts = sorted(
{"full_v013_ppo_result"} - {artifact.name for artifact in self.artifacts}
)
if missing_v013_checks or missing_v013_artifacts:
details = missing_v013_checks + missing_v013_artifacts
raise ValueError(
"v0.13 full qualification evidence is missing: " + ", ".join(details)
)
return self


Expand Down
18 changes: 10 additions & 8 deletions src/miniverl/release_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
V012_ARCHIVE_EVIDENCE = {
"full_v012_rl_result": ("v012_rl", "v012/rl-qualification.json"),
}
V013_ARCHIVE_EVIDENCE = {
"full_v013_ppo_result": ("v013_ppo", "v013/ppo-qualification.json"),
}
_SPECIAL_EVIDENCE = {"candidate-manifest.json"}
QUALIFICATION_SUM_FILES = (
"candidate-manifest.json",
Expand Down Expand Up @@ -138,6 +141,7 @@ def _validate_archive_mapping() -> None:
**ARCHIVE_EVIDENCE,
**V011_ARCHIVE_EVIDENCE,
**V012_ARCHIVE_EVIDENCE,
**V013_ARCHIVE_EVIDENCE,
}.items():
if (
not original_name
Expand All @@ -161,17 +165,15 @@ def _archive_evidence_for_version(version: str) -> dict[str, tuple[str, str]]:
mapping = dict(ARCHIVE_EVIDENCE)
version_parts = version.split(".", 2)
try:
is_v011 = (int(version_parts[0]), int(version_parts[1])) >= (0, 11)
release_series = (int(version_parts[0]), int(version_parts[1]))
except (IndexError, ValueError):
is_v011 = False
if is_v011:
return mapping
if release_series >= (0, 11):
mapping.update(V011_ARCHIVE_EVIDENCE)
try:
is_v012 = (int(version_parts[0]), int(version_parts[1])) >= (0, 12)
except (IndexError, ValueError):
is_v012 = False
if is_v012:
if release_series >= (0, 12):
mapping.update(V012_ARCHIVE_EVIDENCE)
if release_series >= (0, 13):
mapping.update(V013_ARCHIVE_EVIDENCE)
return mapping


Expand Down
62 changes: 60 additions & 2 deletions tests/unit/test_release_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,17 @@ def _fixture(tmp_path: Path, *, version: str = "0.11.0.dev0") -> tuple[Path, Pat
b'{"kind":"vllm-runtime"}\n',
),
}
if version.startswith("0.12."):
version_key = tuple(int(part) for part in version.split(".")[:2])
if version_key >= (0, 12):
evidence["full_v012_rl_result"] = (
"full/v012-rl.json",
b'{"kind":"v012-rl"}\n',
)
if version_key >= (0, 13):
evidence["full_v013_ppo_result"] = (
"full/v013-ppo.json",
b'{"kind":"v013-ppo"}\n',
)
artifacts = []
for name, (relative, content) in evidence.items():
path = qualification / relative
Expand Down Expand Up @@ -199,14 +205,24 @@ def _fixture(tmp_path: Path, *, version: str = "0.11.0.dev0") -> tuple[Path, Pat
"other_hardware_measured": False,
},
}
if version.startswith("0.12."):
if version_key >= (0, 12):
payload["checks"]["executed"].extend(
[
"v012_pinned_verl_v09_compiler",
"v012_grpo_nonconstant_reward_update",
"v012_exact_wheel_rl_runtime",
]
)
if version_key >= (0, 13):
payload["checks"]["executed"].extend(
[
"v013_pinned_verl_v09_ppo_compiler",
"v013_independent_actor_critic_updates",
"v013_exact_actor_critic_resume",
"v013_trained_reward_model",
"v013_exact_wheel_ppo_runtime",
]
)
qualification_path = qualification / "qualification.json"
qualification_path.write_text(json.dumps(payload), encoding="utf-8")
verification = tmp_path / "verification.json"
Expand Down Expand Up @@ -282,13 +298,15 @@ def test_release_evidence_mapping_is_versioned_for_historical_records() -> None:
historical = _archive_evidence_for_version("0.10.1")
current = _archive_evidence_for_version("0.11.0")
v012 = _archive_evidence_for_version("0.12.0")
v013 = _archive_evidence_for_version("0.13.0")
assert "full_v011_profiles_result" not in historical
assert set(current) - set(historical) == {
"full_v011_profiles_result",
"full_hf_cached_runtime_result",
"full_vllm_runtime_result",
}
assert set(v012) - set(current) == {"full_v012_rl_result"}
assert set(v013) - set(v012) == {"full_v013_ppo_result"}


def test_v012_release_archive_includes_rl_qualification(tmp_path: Path) -> None:
Expand All @@ -301,6 +319,46 @@ def test_v012_release_archive_includes_rl_qualification(tmp_path: Path) -> None:
assert check_release_assets(output) == []


def test_v013_release_archive_includes_ppo_qualification(tmp_path: Path) -> None:
from miniverl.release_assets import check_release_assets

output = _build(tmp_path, version="0.13.0")
manifest = json.loads((output / "qualification-evidence-manifest.json").read_text())

assert "v013_ppo" in {member["semantic_role"] for member in manifest["members"]}
assert check_release_assets(output) == []


@pytest.mark.parametrize(
("remove_artifact", "remove_check", "match"),
[
("full_v013_ppo_result", None, "v0.13 full qualification evidence is missing"),
(None, "v013_exact_actor_critic_resume", "v0.13 full qualification evidence is missing"),
],
)
def test_v013_qualification_requires_ppo_evidence_and_checks(
tmp_path: Path,
remove_artifact: str | None,
remove_check: str | None,
match: str,
) -> None:
from pydantic import ValidationError

from miniverl.qualification import GPUQualification

_, _, qualification, _ = _fixture(tmp_path, version="0.13.0")
payload = json.loads((qualification / "qualification.json").read_text())
if remove_artifact is not None:
payload["artifacts"] = [
artifact for artifact in payload["artifacts"] if artifact["name"] != remove_artifact
]
if remove_check is not None:
payload["checks"]["executed"].remove(remove_check)

with pytest.raises(ValidationError, match=match):
GPUQualification.model_validate(payload)


def test_archive_and_manifest_are_reproducible_and_explicit(tmp_path: Path) -> None:
first = _build(tmp_path / "first")
second = _build(tmp_path / "second")
Expand Down
0