test: gate V1 side files and V3 legacy receipts; early output rejection
- analyze_jet_cv_continuation: samples are analyzed only if the sibling re*_s*.json receipt is the same case with run_status COMPLETE and source_recheck UNCHANGED; receipts without run_status (pre-recheck runners) are refused unless --legacy-receipts, and labelled LEGACY_NO_FINAL_SOURCE_RECHECK. Results carry receipt_gate. - V3: receipts are schema 2 and need source_recheck UNCHANGED; a missing recheck is accepted only for frozen-mode schema 1 receipts whose run_case.py hash is one of the pre-recheck runners (9805383,2cf9853, db3d098; hashes checked against git history in a test). - V1/V3 refuse --output inside the checkout before source checks or CUDA (shared source_provenance.reject_output_inside). - A failing recheck is recorded as RECHECK_FAILED (still invalid); the in-run V1 receipt write is tmp+replace. Negative host tests for each gate. No threshold, solver or evidence edits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
df0f586331
commit
36ffc8b1b2
9 files changed
+185
-33
No files matched your search
@@ -73,6 +73,27 @@ def valid_builds(record, n, depth):
|
||||
return True
|
||||
|
||||
|
||||
# run_case.py (sha256) of the runners before the final source recheck (git: 9805383,
|
||||
# 2cf9853 = the a135252 qualification runner, db3d098); they wrote schema 1 receipts.
|
||||
LEGACY_RUN_CASE_SHA256 = {
|
||||
"9805383": "fbceab8c1aaaf357195a4fb9e6a699a195326e480e274692a277ce3df54ee6d9",
|
||||
"2cf9853": "0789d2e1ffa581078bd11e6251b660b2c268363171fda0c6b26ac41205f1de3a",
|
||||
"db3d098": "618c14ba94584aa9c0b714e0e2064a746d2b882973a13424f09dd7e54c68f7f1",
|
||||
}
|
||||
|
||||
|
||||
def rechecked(r, current):
|
||||
"""Schema 2 receipts need source_recheck UNCHANGED; a missing recheck is accepted only
|
||||
for frozen-mode schema 1 receipts written by a verified legacy runner."""
|
||||
if "invalid" in r:
|
||||
return False
|
||||
if r.get("schema") == 2:
|
||||
return r.get("source_recheck") == "UNCHANGED"
|
||||
harness = r.get("source", {}).get("harness_sha256") or {}
|
||||
return (not current and r.get("schema") == 1 and "source_recheck" not in r
|
||||
and harness.get("run_case.py") in LEGACY_RUN_CASE_SHA256.values())
|
||||
|
||||
|
||||
def assess(records, expected_revision=None, current=False):
|
||||
"""current=True assesses current-checkout receipts (run_case --current-checkout) with
|
||||
the same gates; it never accepts them as the frozen a135252 qualification, and the
|
||||
@@ -144,10 +165,7 @@ def assess(records, expected_revision=None, current=False):
|
||||
checks[label + " reference"] = (r.get("numerical_revision") == NUMERICAL_REVISION
|
||||
and "source_mode" not in r
|
||||
and r.get("reference_harness") == REFERENCE_HARNESS)
|
||||
# Final source recheck (run_case); receipts from before it existed carry no field
|
||||
# and are accepted only in the frozen mode.
|
||||
recheck = r.get("source_recheck") if current else r.get("source_recheck", "UNCHANGED")
|
||||
checks[label + " source_recheck"] = recheck == "UNCHANGED" and "invalid" not in r
|
||||
checks[label + " source_recheck"] = rechecked(r, current)
|
||||
checks[label + " numerics"] = r.get("numerics") == NUMERICS and r.get("initialization") == INITIALIZATION
|
||||
runtime = r.get("runtime_source", {})
|
||||
package = Path(runtime.get("checkout", "")) / "src/CelerisLab"
|
||||
|
||||
@@ -182,6 +182,8 @@ def main():
|
||||
p.error("--run-gpu and exactly one explicit CUDA_VISIBLE_DEVICES are required")
|
||||
repo = args.repo.resolve()
|
||||
sys.path[:0] = [str(repo / "src"), str(repo)]
|
||||
from tests.validation.source_provenance import reject_output_inside
|
||||
reject_output_inside(args.output, repo)
|
||||
source = verify_source(repo, args.expected_revision, current=args.current_checkout)
|
||||
runtime = runtime_source(repo)
|
||||
if args.dry_run:
|
||||
@@ -201,7 +203,7 @@ def main():
|
||||
masks = [k == ACTIVE for k in h.kinds]
|
||||
main_steps, early_steps = sample_steps(args.n, args.early_pressure)
|
||||
report = dict(
|
||||
schema=1,
|
||||
schema=2, # 2: final source recheck (source_recheck) is recorded
|
||||
source=source,
|
||||
numerical_revision=None if args.current_checkout else NUMERICAL_REVISION,
|
||||
**({"source_mode": "current_checkout"} if args.current_checkout else {}),
|
||||
|
||||
@@ -18,7 +18,7 @@ import numpy as np
|
||||
|
||||
import run_case
|
||||
from assess_projected_pairs import (BUILD_SOURCES, CASES, NUMERICS, NUMERICAL_REVISION,
|
||||
SOURCE_SHA256, assess)
|
||||
LEGACY_RUN_CASE_SHA256, SOURCE_SHA256, assess)
|
||||
from oracle import LIMITS, TIMES, U, rectangles
|
||||
|
||||
REPO = Path(__file__).resolve().parents[3]
|
||||
@@ -31,7 +31,7 @@ RUNTIME = dict(device=dict(name="host mock", pci_bus_id="mock", capability=[7, 0
|
||||
|
||||
def source():
|
||||
return dict(revision=MOCK_REVISION, dirty=False, source_tree_sha256=SOURCE_SHA256,
|
||||
harness_sha256={"run_case.py": "a" * 64},
|
||||
harness_sha256={"run_case.py": LEGACY_RUN_CASE_SHA256["2cf9853"]},
|
||||
build_capture_sha256=run_case.BUILD_CAPTURE_SHA256)
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ def records(early=False):
|
||||
h = build_hierarchy(cfg, refinements)
|
||||
main_steps, early_steps = run_case.sample_steps(n, early)
|
||||
out.append(dict(
|
||||
re_L=re, n=n, depth=depth, explosion=scheme, U=U, mach=float(U*np.sqrt(3)),
|
||||
schema=1, re_L=re, n=n, depth=depth, explosion=scheme, U=U, mach=float(U*np.sqrt(3)),
|
||||
viscosity=cfg.viscosity, tau_by_level=[0.5+3*c.viscosity for c in h.configs],
|
||||
refinements=refinements, numerics=NUMERICS.copy(), initialization=run_case.INITIALIZATION,
|
||||
source=source(), numerical_revision=NUMERICAL_REVISION,
|
||||
@@ -322,7 +322,7 @@ class ProjectedPairsTests(unittest.TestCase):
|
||||
source_mode="current_checkout",
|
||||
source_capture=run_case.CURRENT_CAPTURE)
|
||||
r["numerical_revision"], r["source_mode"] = None, "current_checkout"
|
||||
r["source_recheck"] = "UNCHANGED"
|
||||
r["schema"], r["source_recheck"] = 2, "UNCHANGED"
|
||||
ok = assess(current, MOCK_REVISION, current=True)
|
||||
self.assertTrue(ok["checks"]["clean_current_checkout_source"])
|
||||
self.assertTrue(all(v for k, v in ok["checks"].items() if k.endswith(" reference")))
|
||||
@@ -335,22 +335,61 @@ class ProjectedPairsTests(unittest.TestCase):
|
||||
self.assertTrue(assess(frozen, MOCK_REVISION)["checks"]["clean_a135252_numerical_source"])
|
||||
|
||||
def test_assessor_requires_unchanged_final_source(self):
|
||||
frozen = records()
|
||||
frozen = records() # schema 1 receipts from the verified legacy runner 2cf9853
|
||||
label = lambda r: f"{r['n']}/{r['depth']}/{r['explosion']} source_recheck"
|
||||
self.assertTrue(all(assess(frozen, MOCK_REVISION)["checks"][label(r)] for r in frozen))
|
||||
for mutate in (dict(source_recheck="CHANGED"), dict(invalid="SOURCE_CHANGED_DURING_RUN")):
|
||||
bad = deepcopy(frozen)
|
||||
bad[0].update(mutate)
|
||||
out = assess(bad, MOCK_REVISION)
|
||||
self.assertFalse(out["checks"][label(bad[0])])
|
||||
self.assertFalse(out["passed"])
|
||||
new = deepcopy(frozen)
|
||||
for r in new:
|
||||
r.update(schema=2, source_recheck="UNCHANGED")
|
||||
self.assertTrue(all(assess(new, MOCK_REVISION)["checks"][label(r)] for r in new))
|
||||
unknown_runner = dict(frozen[0]["source"], harness_sha256={"run_case.py": "a" * 64})
|
||||
for case, mutate in (
|
||||
("schema 1, unverified runner", dict(source=unknown_runner)),
|
||||
("schema 2 without recheck", dict(schema=2)),
|
||||
("schema 2 changed", dict(schema=2, source_recheck="CHANGED")),
|
||||
("schema 2 recheck failed", dict(schema=2, source_recheck="RECHECK_FAILED")),
|
||||
("schema 1 with a recheck field", dict(source_recheck="UNCHANGED")),
|
||||
("unknown schema", dict(schema=3, source_recheck="UNCHANGED")),
|
||||
("no schema", dict(schema=None)),
|
||||
("invalid", dict(schema=2, source_recheck="UNCHANGED",
|
||||
invalid="SOURCE_CHANGED_DURING_RUN")),
|
||||
):
|
||||
with self.subTest(case):
|
||||
bad = deepcopy(frozen)
|
||||
bad[0].update(mutate)
|
||||
out = assess(bad, MOCK_REVISION)
|
||||
self.assertFalse(out["checks"][label(bad[0])])
|
||||
self.assertFalse(out["passed"])
|
||||
current = deepcopy(frozen)
|
||||
for r in current:
|
||||
r["source"] = dict(r["source"], source_mode="current_checkout")
|
||||
r["numerical_revision"], r["source_mode"] = None, "current_checkout"
|
||||
# Current-checkout receipts are new: a missing recheck is not accepted.
|
||||
# Legacy acceptance is frozen-mode only.
|
||||
self.assertFalse(assess(current, MOCK_REVISION, current=True)["checks"][label(current[0])])
|
||||
|
||||
def test_legacy_runner_hashes_are_the_recorded_commits(self):
|
||||
sys.path.insert(0, str(REPO))
|
||||
from tests.validation.source_provenance import (HistoryUnavailable, historical_sha256,
|
||||
history_unavailable)
|
||||
try:
|
||||
for commit, digest in LEGACY_RUN_CASE_SHA256.items():
|
||||
path = "tests/validation/taylor_green/run_case.py"
|
||||
self.assertEqual(historical_sha256(REPO, commit, [path])[path], digest)
|
||||
except HistoryUnavailable as error:
|
||||
history_unavailable(self, error)
|
||||
current = hashlib.sha256((REPO / "tests/validation/taylor_green/run_case.py").read_bytes())
|
||||
self.assertNotIn(current.hexdigest(), LEGACY_RUN_CASE_SHA256.values())
|
||||
|
||||
def test_output_inside_checkout_is_refused_before_source_check(self):
|
||||
argv = ["run_case.py", "--repo", str(REPO), "--re", "100", "--n", "128", "--depth", "1",
|
||||
"--output", str(REPO / "tg-out.json"), "--expected-revision", MOCK_REVISION,
|
||||
"--dry-run"]
|
||||
with patch.object(sys, "argv", argv), \
|
||||
patch.object(run_case, "verify_source", side_effect=AssertionError("work started")):
|
||||
with self.assertRaisesRegex(SystemExit, "outside the source checkout"):
|
||||
run_case.main()
|
||||
self.assertFalse((REPO / "tg-out.json").exists())
|
||||
|
||||
def test_explicit_opt_in_selector_and_dry_run_without_cuda(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
output = Path(tmp) / "case.json"
|
||||
@@ -483,13 +522,15 @@ class ProjectedPairsTests(unittest.TestCase):
|
||||
[call(REPO, MOCK_REVISION, current=False)] * (2 if rechecked else 1))
|
||||
if fail in ("changed", "recheck_error"):
|
||||
# Full trajectory, but invalid: never a complete-looking receipt.
|
||||
self.assertEqual(receipt["source_recheck"], "CHANGED")
|
||||
self.assertEqual(receipt["source_recheck"],
|
||||
"CHANGED" if fail == "changed" else "RECHECK_FAILED")
|
||||
self.assertEqual(receipt["invalid"], "SOURCE_CHANGED_DURING_RUN")
|
||||
self.assertFalse(receipt["completed"])
|
||||
self.assertNotIn("screening_pass", receipt)
|
||||
self.assertEqual(receipt["source_after"] is None, fail == "recheck_error")
|
||||
continue
|
||||
self.assertEqual(receipt.get("source_recheck"), None if fail else "UNCHANGED")
|
||||
self.assertEqual(receipt["schema"], 2)
|
||||
self.assertEqual(selectors, ["projected_linear" if early else "constant"] if depth == 2 else [])
|
||||
self.assertEqual(receipt["source"], source())
|
||||
self.assertEqual(receipt["runtime_identity"], RUNTIME)
|
||||
|
||||
Reference in new issue
Block a user