test: final source recheck for V1 jet CV and V3 Taylor-Green runs

Both runners now re-derive the recorded source identity after the run
(source_provenance.final_source_check) and only then mark the receipt
complete. A changed source, or a recheck that fails, rewrites the receipt
as invalid and raises:
- V1: in-run receipts carry run_status=INCOMPLETE; finish_receipt sets
  COMPLETE or INVALID_SOURCE_CHANGED (+ source_recheck/source_after).
- V3: completed stays False, invalid=SOURCE_CHANGED_DURING_RUN, no
  screening_pass; the assessor requires source_recheck UNCHANGED (frozen
  mode still accepts receipts from before the field existed).
Interrupted runs keep INCOMPLETE / completed=False. Host tests cover
unchanged, changed and failed rechecks and incomplete runs. No threshold
or solver change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-20 18:44:23 +00:00
1 parent 8cae58cdf1
commit df0f586331
7 files changed
+159 -15

No files matched your search

@@ -144,6 +144,10 @@ 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 + " numerics"] = r.get("numerics") == NUMERICS and r.get("initialization") == INITIALIZATION
runtime = r.get("runtime_source", {})
package = Path(runtime.get("checkout", "")) / "src/CelerisLab"
+11
View File
@@ -319,6 +319,17 @@ def main():
),
flush=True,
)
from tests.validation.source_provenance import final_source_check
recheck = final_source_check(
dict(source=source, runtime_source=runtime),
lambda: dict(source=verify_source(repo, args.expected_revision,
current=args.current_checkout),
runtime_source=runtime_source(repo)))
report.update(recheck)
if recheck["source_recheck"] != "UNCHANGED":
report.update(invalid="SOURCE_CHANGED_DURING_RUN") # completed stays False
save()
raise RuntimeError("Source changed during the run; receipt marked invalid")
report.update(
completed=True,
seconds=time.monotonic() - started,
@@ -12,7 +12,7 @@ import sys
import tempfile
from types import SimpleNamespace
import unittest
from unittest.mock import patch
from unittest.mock import call, patch
import numpy as np
@@ -322,6 +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"
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")))
@@ -333,6 +334,23 @@ class ProjectedPairsTests(unittest.TestCase):
self.assertFalse(assess(current, None, current=True)["checks"]["clean_current_checkout_source"])
self.assertTrue(assess(frozen, MOCK_REVISION)["checks"]["clean_a135252_numerical_source"])
def test_assessor_requires_unchanged_final_source(self):
frozen = records()
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"])
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.
self.assertFalse(assess(current, MOCK_REVISION, current=True)["checks"][label(current[0])])
def test_explicit_opt_in_selector_and_dry_run_without_cuda(self):
with tempfile.TemporaryDirectory() as tmp:
output = Path(tmp) / "case.json"
@@ -393,7 +411,8 @@ class ProjectedPairsTests(unittest.TestCase):
# Replace the GPU context and steppers before import. No CUDA module or flow is used.
for early, depth, fail in ((False, 1, None), (False, 2, None), (True, 2, None),
(True, 2, "resource"), (True, 2, "nonfinite"),
(True, 2, "probe_nonfinite")):
(True, 2, "probe_nonfinite"),
(False, 2, "changed"), (False, 1, "recheck_error")):
calls, selectors = [], []
class FakeRun:
@@ -448,13 +467,29 @@ class ProjectedPairsTests(unittest.TestCase):
patch.object(run_case, "runtime_identity", return_value=deepcopy(RUNTIME)), \
patch.object(run_case, "build_capture", return_value=nullcontext()), \
patch.object(run_case, "metrics", side_effect=metric), redirect_stdout(io.StringIO()):
if fail:
if fail in ("changed", "recheck_error"):
verify.side_effect = [source(), dict(source(), source_tree_sha256="d" * 64)
if fail == "changed" else RuntimeError("Wrong numerical source fingerprint")]
with self.assertRaisesRegex(RuntimeError, "Source changed during the run"):
run_case.main()
elif fail:
with self.assertRaises(MemoryError if fail == "resource" else FloatingPointError):
run_case.main()
else:
self.assertEqual(run_case.main(), 0)
receipt = json.loads(output.read_text())
verify.assert_called_once_with(REPO, MOCK_REVISION, current=False)
rechecked = fail in (None, "changed", "recheck_error")
self.assertEqual(verify.call_args_list,
[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["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(selectors, ["projected_linear" if early else "constant"] if depth == 2 else [])
self.assertEqual(receipt["source"], source())
self.assertEqual(receipt["runtime_identity"], RUNTIME)