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
- 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.
83 lines
3.2 KiB
Python
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"] == []
|