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
@@ -151,6 +151,8 @@ class Measurements(unittest.TestCase):
|
||||
(path / "samples_s2.json").write_text(
|
||||
json.dumps(dict(case=c, sample_file="samples_s2.npz"))
|
||||
)
|
||||
(path / f"re{c['re_d']}_s2.json").write_text(json.dumps(
|
||||
dict(case=c, run_status="COMPLETE", source_recheck="UNCHANGED")))
|
||||
np.savez(
|
||||
path / "samples_s2.npz",
|
||||
t_reference=t,
|
||||
@@ -163,6 +165,7 @@ class Measurements(unittest.TestCase):
|
||||
velocity_error=np.zeros(n),
|
||||
)
|
||||
result = analyze(path)
|
||||
self.assertEqual(result["receipt_gate"], "COMPLETE_SOURCE_UNCHANGED")
|
||||
self.assertEqual(len(result["windows"]), 32)
|
||||
np.testing.assert_allclose(
|
||||
result["windows"][0]["normalized_cv_residual"], 0, atol=1e-14
|
||||
@@ -178,5 +181,36 @@ class Measurements(unittest.TestCase):
|
||||
np.testing.assert_allclose(integrate(t, y), [112, 8], atol=1e-15)
|
||||
|
||||
|
||||
def test_receipt_gate_refuses_incomplete_invalid_and_unmarked_legacy(self):
|
||||
import json
|
||||
from analyze_jet_cv_continuation import receipt_gate
|
||||
|
||||
c = case(2, steps=3200)
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp)
|
||||
receipt = path / f"re{c['re_d']}_s2.json"
|
||||
with self.assertRaisesRegex(ValueError, "No sibling run receipt"):
|
||||
receipt_gate(path, c)
|
||||
for fields, message in (
|
||||
(dict(run_status="INCOMPLETE"), "INCOMPLETE"),
|
||||
(dict(run_status="INVALID_SOURCE_CHANGED", source_recheck="CHANGED"), "INVALID"),
|
||||
(dict(run_status="COMPLETE", source_recheck="RECHECK_FAILED"), "RECHECK_FAILED"),
|
||||
(dict(run_status="COMPLETE"), "source_recheck=None"),
|
||||
(dict(), "Legacy run receipt"),
|
||||
):
|
||||
receipt.write_text(json.dumps(dict(case=c, **fields)))
|
||||
with self.assertRaisesRegex(ValueError, message):
|
||||
receipt_gate(path, c)
|
||||
receipt.write_text(json.dumps(dict(case=dict(c, scale=1), run_status="COMPLETE",
|
||||
source_recheck="UNCHANGED")))
|
||||
with self.assertRaisesRegex(ValueError, "different case"):
|
||||
receipt_gate(path, c)
|
||||
receipt.write_text(json.dumps(dict(case=c)))
|
||||
self.assertEqual(receipt_gate(path, c, legacy=True), "LEGACY_NO_FINAL_SOURCE_RECHECK")
|
||||
receipt.write_text(json.dumps(dict(case=c, run_status="INCOMPLETE")))
|
||||
with self.assertRaisesRegex(ValueError, "INCOMPLETE"):
|
||||
receipt_gate(path, c, legacy=True) # legacy opt-in never admits new statuses
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user