From ca24748dfce75b97f37f3a48dc9102ac67301bc5 Mon Sep 17 00:00:00 2001 From: yuqei Date: Thu, 8 Oct 2026 23:08:08 +0800 Subject: [PATCH] test(infra): bind historical evidence to its original snapshot Keep historical RC03 hashes independent of later source changes while verifying every current manifest item against its committed blob. --- .../test_release_candidate_manifest_tools.py | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/yuqei-infra/tests/test_release_candidate_manifest_tools.py b/yuqei-infra/tests/test_release_candidate_manifest_tools.py index 5e91eb27..58142092 100644 --- a/yuqei-infra/tests/test_release_candidate_manifest_tools.py +++ b/yuqei-infra/tests/test_release_candidate_manifest_tools.py @@ -42,9 +42,9 @@ def _git(repo: Path, *args: str) -> str: return completed.stdout.strip() -def _git_blob(repo: Path, path: str) -> bytes: +def _git_blob(repo: Path, path: str, revision: str = "HEAD") -> bytes: completed = subprocess.run( - ["git", "-C", str(repo), "cat-file", "blob", f"HEAD:{path}"], + ["git", "-C", str(repo), "cat-file", "blob", f"{revision}:{path}"], check=True, capture_output=True, ) @@ -411,53 +411,6 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p "**/*.sqlite3", } <= dockerignore_rules - current_index = json.loads( - ( - REPO_ROOT - / "docs/qa/multiscene-closeout-20260910/rc03-current-candidate-evidence-index-v3.json" - ).read_text(encoding="utf-8") - ) - assert current_index["validation"]["self_contained"] is True - assert current_index["validation"]["predecessor_required_for_interpretation"] is False - assert current_index["validation"]["listed_file_count"] == 54 - assert current_index["validation"]["accepted_current_evidence_count"] == 50 - assert current_index["validation"]["excluded_invalid_lineage_count"] == 4 - assert all(item["normative_for_v3"] is False for item in current_index["lineage"]) - indexed_paths = [item["path"] for item in current_index["files"]] - assert len(indexed_paths) == len(set(indexed_paths)) == 54 - for item in current_index["files"]: - evidence = REPO_ROOT / item["path"] - category, _, _ = ownership.classify_path(item["path"], size=item["size_bytes"]) - if category == "generated_evidence_retain_exclude": - # Raw and invalid-lineage QA outputs are intentionally retained outside - # the immutable source candidate. When they remain in a development - # workspace, still verify that the compact index recorded their bytes - # correctly; a clean release checkout must not require them to exist. - if not evidence.exists(): - continue - evidence_bytes = evidence.read_bytes() - else: - assert category in {"release_source_include", "release_test_include"} - assert evidence.is_file() - # Verify the immutable Git bytes instead of checkout bytes: Windows may - # materialize text files with CRLF. The RC-03 index was created from - # worktree bytes, so accept only an exact LF/CRLF rendering of the same - # immutable blob; the candidate manifest/archive bind the raw blob. - evidence_bytes = _git_blob(REPO_ROOT, item["path"]) - variants = _text_eol_variants(evidence_bytes) - assert any( - len(candidate) == item["size_bytes"] - and hashlib.sha256(candidate).hexdigest() == item["sha256"] - for candidate in variants - ) - if item["path"].endswith(".json"): - json.loads(evidence_bytes) - continue - assert len(evidence_bytes) == item["size_bytes"] - assert hashlib.sha256(evidence_bytes).hexdigest() == item["sha256"] - if item["path"].endswith(".json"): - json.loads(evidence_bytes) - repo, commit = _candidate_repo(tmp_path) output = tmp_path / "manifest.json" @@ -474,6 +427,10 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p assert first["summaries"]["migrations"][0]["heads"] == ["contract-head"] assert first["summaries"]["migrations"][1]["heads"] == ["ai-head"] recorded_paths = {item["path"] for item in first["files"]["items"]} + for item in first["files"]["items"]: + content = _git_blob(repo, item["path"], commit) + assert item["size"] == len(content) + assert item["sha256"] == hashlib.sha256(content).hexdigest() assert set(manifest.RELEASE_CONTROL_PATHS) <= recorded_paths configuration_paths = {item["path"] for item in first["summaries"]["configuration"]} assert set(manifest.RELEASE_CONTROL_PATHS) <= configuration_paths @@ -490,6 +447,49 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p assert "No image was built or assigned a digest" in first["claims_not_made"][0] +def test_historical_rc03_index_matches_original_committed_snapshot() -> None: + if _git(REPO_ROOT, "rev-parse", "--is-shallow-repository") == "true": + pytest.skip("historical RC03 byte verification requires complete Git history") + index_path = "docs/qa/multiscene-closeout-20260910/rc03-current-candidate-evidence-index-v3.json" + index_commit = _git(REPO_ROOT, "log", "-1", "--diff-filter=A", "--format=%H", "--", index_path) + assert index_commit + historical_index = json.loads((REPO_ROOT / index_path).read_text(encoding="utf-8")) + assert historical_index == json.loads(_git_blob(REPO_ROOT, index_path, index_commit)) + assert historical_index["release_claim"] is False + assert historical_index["validation"]["self_contained"] is True + assert historical_index["validation"]["predecessor_required_for_interpretation"] is False + assert historical_index["validation"]["listed_file_count"] == 54 + assert historical_index["validation"]["accepted_current_evidence_count"] == 50 + assert historical_index["validation"]["excluded_invalid_lineage_count"] == 4 + assert all(item["normative_for_v3"] is False for item in historical_index["lineage"]) + indexed_paths = [item["path"] for item in historical_index["files"]] + assert len(indexed_paths) == len(set(indexed_paths)) == 54 + for item in historical_index["files"]: + evidence = REPO_ROOT / item["path"] + category, _, _ = ownership.classify_path(item["path"], size=item["size_bytes"]) + if category == "generated_evidence_retain_exclude": + if not evidence.exists(): + continue + evidence_bytes = evidence.read_bytes() + else: + assert category in {"release_source_include", "release_test_include"} + evidence_bytes = _git_blob(REPO_ROOT, item["path"], index_commit) + # The historical index recorded worktree bytes; bind its own source snapshot, not today's HEAD. + variants = _text_eol_variants(evidence_bytes) + assert any( + len(candidate) == item["size_bytes"] + and hashlib.sha256(candidate).hexdigest() == item["sha256"] + for candidate in variants + ) + if item["path"].endswith(".json"): + json.loads(evidence_bytes) + continue + assert len(evidence_bytes) == item["size_bytes"] + assert hashlib.sha256(evidence_bytes).hexdigest() == item["sha256"] + if item["path"].endswith(".json"): + json.loads(evidence_bytes) + + def test_manifest_refuses_ambiguous_dirty_missing_and_secret_candidates(tmp_path: Path) -> None: repo, commit = _candidate_repo(tmp_path) external_output = tmp_path / "manifest.json"