Files
rune/tests/test_drift_resume.py
T
Nick b51afea0cb
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / canary (push) Successful in 35s
Auto-version and Release / release (push) Successful in 39s
CI Pipeline / lint (push) Successful in 46s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 2m49s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Failing after 15m13s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 5s
feat(reentry): durable event replay + drift-aware resume + 16O benchmark (T16 16C-fix/16O/16P)
- event_wait.find_matching_event(): replays matching completion events
  from the durable bridge event log at registration. Root-caused from
  TWO production cycles: on a serialized single-runner machine the CI
  wake always lands before/around deploy registration — a forward-only
  FIFO rendezvous can never deliver it (both cycles fell back to the
  900s deadline, truthfully). The event log exists precisely for this;
  the wake is still never the verdict.
- ci_event_wait: event_replayed mode short-circuits to the authority
  read; 2 new held-outs (9 total).
- drift_resume.py (16P): claim-vs-observation reconciliation with
  EXPECTED/BENIGN/MATERIAL/CONFLICTING/UNKNOWN classes; MATERIAL/
  CONFLICTING/UNKNOWN block dependent work; user-locked claims escalate
  to CONFLICTING (reality never silently overrides user-locked
  authority). Held-outs driven by the REAL 16O fixture: the VAT
  regression blocks resume; the checkpoint commit resumes clean.
- 16O benchmark persisted (store/evidence/t16/16O_benchmark.md): honest
  result — on a tiny fixture cold and scaffold-assisted re-entry cost
  about the same (8 vs 9 files); the scaffold's advantage is drift
  classification, recorded next actions, and intent, not raw step
  count. No fabricated win.

Suite 1884 green; ratchets PASS.
2026-09-15 17:34:00 +01:00

83 lines
3.2 KiB
Python

"""test_drift_resume.py — T16 §16P: drift-aware resume held-outs,
driven by the REAL 16O fixture."""
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
import pytest
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
from rune import drift_resume as dr # noqa: E402
FIXTURE = Path("/mnt/workdrive/t16-reentry")
REPO_DIR = FIXTURE / "repo"
STORE = FIXTURE / "scaffold" / "current.json"
def test_16p_drift_classes_deterministic():
ok = {"actual": "", "checked_by": "pytest", "matches": True}
bad = {"actual": "2 tests fail", "checked_by": "pytest", "matches": False}
unverif = {"actual": None, "checked_by": "pytest", "matches": None}
assert dr.classify_drift({"claim": "green"}, ok)["class"] == "CONFIRMED"
assert dr.classify_drift({"claim": "green"}, bad)["class"] == "MATERIAL"
assert dr.classify_drift({"claim": "x"}, unverif)["class"] == "UNKNOWN"
locked = dict({"claim": "layout"}, user_locked=True)
assert dr.classify_drift(locked, bad)["class"] == "CONFLICTING"
def test_16p_reality_wins_user_locked_needs_user():
r = dr.reconcile(
[{"claim": "layout locked as X", "user_locked": True}],
lambda c: {"actual": "layout is Y", "checked_by": "ls",
"matches": False})
assert r["resume"] is False # blocked, not overridden
assert r["blocking"][0]["class"] == "CONFLICTING"
def test_16p_real_fixture_vat_regression_blocks_resume():
"""The REAL fixture: scaffold claims stage-1 verified green; reality
has the VAT regression. The reconciliation must block."""
doc = json.loads(STORE.read_text())
stage1 = next(e for e in doc["entities"]
if e["id"] == "contract:stage-1-monthly-totals")
def run_fixture_tests(claim):
proc = subprocess.run(
[sys.executable, "-m", "pytest", "tests/", "-q"],
cwd=REPO_DIR, capture_output=True, text=True,
env={"PATH": "/usr/bin:/bin:/usr/local/bin",
"PYTHONPATH": "src"})
passed = proc.returncode == 0
return {"actual": proc.stdout.strip().splitlines()[-1]
if proc.stdout else proc.stderr[:120],
"checked_by": "pytest tests/", "matches": passed}
claims = [{"claim": "stage-1 verified green", "kind": "verification",
"stale_ok": False}]
r = dr.reconcile(claims, run_fixture_tests)
assert r["resume"] is False
assert r["blocking"][0]["class"] == "MATERIAL"
assert "failed" in r["blocking"][0]["evidence"]
assert stage1["phase"] == "closed" # the stale claim we caught
def test_16p_clean_repo_resumes():
"""Same observer on the checkpoint commit: no drift, resume allowed."""
def check_at_checkpoint(claim):
proc = subprocess.run(
["git", "show", "39bd917:src/report.py"], cwd=REPO_DIR,
capture_output=True, text=True)
vat_free = "1.19" not in proc.stdout
return {"actual": "" if vat_free else "VAT present at checkpoint",
"checked_by": "git show", "matches": vat_free}
r = dr.reconcile([{"claim": "stage-1 green at checkpoint"}],
check_at_checkpoint)
assert r["resume"] is True and r["blocking"] == []