Hunt for the -n auto fast-lane polluters flagged in docs/testing-lanes.md
("Follow-up: xdist by default"). Three root causes, all shared-repo-path
writers with no per-test isolation, following the #782 monkeypatch idiom:
1. tests/test_workbench_replay.py::test_replay_leaves_no_trace hardcoded
`Path("engine_state")` (the real shared dir) instead of reading
`engine_state._DEFAULT_DIR`, which the root-conftest autouse fixture
already redirects per-test. It was a victim, not a polluter: any
concurrent worker writing the real dir made this snapshot-diff flake.
Fixed by reading `engine_state._DEFAULT_DIR` dynamically.
2. evals/gsm8k_math/train_sample/v1/runner.py hardcoded its report.json
output to the committed repo path with no override. Two test files
(test_rat1_end_to_end_admission.py, test_wave_a_multiplicative_
aggregation_injector.py; 4 tests total) spawn it as a subprocess and
read the same file back — a write race under -n auto, and a confirmed
downstream victim (test_gsm8k_sealed_attempt_scout.py::
test_report_json_mtime_unchanged_by_scout_import asserts the file's
mtime is stable). Added an optional CORE_GSM8K_TRAIN_SAMPLE_REPORT_PATH
env override (default unchanged) and pointed the 4 call sites at
tmp_path.
3. core/cli.py's `_DEMO_RESULTS_DIR` (evals/forward_semantic_control/
results/) is written, glob-scanned, and index.json-rebuilt by ~11 tests
across tests/test_cli_demo.py's TestDemoSubcommand and TestDemoPreambles
classes. Added an autouse fixture monkeypatching `cli._DEMO_RESULTS_DIR`
to a per-test tmp dir. This also unmasked a latent order-dependent
coupling: test_demo_list_results_indexes_reports and
test_demo_list_results_json_well_formed never wrote their own report,
relying on a sibling test's leftover file in the shared dir (silently
correct only because pytest ran the file in declaration order). Made
both self-contained.
No assertion weakening, no test deletion, no global autouse fixture masking
real bugs. All three fixes preserve the real (non-test) default behavior
byte-for-byte when unpatched/env-unset.
Verification: 8x targeted -n 8 loop over the 7 affected files (before and
after) did not force-reproduce the underlying race live (narrow timing
window, small-scale run) — confirmation is source-level (hardcoded shared
paths bypassing the established isolation idiom) plus the prior documented
flake for test_replay_leaves_no_trace in docs/testing-lanes.md. Full
fast-lane -n auto run recorded in the PR description.
220 lines
8.3 KiB
Python
220 lines
8.3 KiB
Python
"""Sealed single-turn replay — GET /replay/{turn_id} (Wave R3).
|
|
|
|
Proof obligations from docs/analysis/replay-moment-backend-scoping-2026-06-12.md:
|
|
each test here must MEANINGFULLY FAIL under the violation it is written to
|
|
catch (CLAUDE.md schema-defined proof obligations rule).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import fields, replace
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
import engine_state
|
|
from chat.runtime import ChatRuntime
|
|
from workbench import api as workbench_api
|
|
from workbench.api import WorkbenchApi, _run_sealed_chat_turn, _with_turn_cost_and_id
|
|
from workbench.journal import TurnJournal, TurnJournalEntry
|
|
from workbench.replay import CRITICAL_FIELDS, INFORMATIONAL_FIELDS, replay_turn
|
|
|
|
|
|
def _snapshot(root: Path) -> dict[str, bytes]:
|
|
snap: dict[str, bytes] = {}
|
|
if not root.exists():
|
|
return snap
|
|
for path in sorted(root.rglob("*")):
|
|
if path.is_file() and "__pycache__" not in path.relative_to(root).parts:
|
|
snap[path.relative_to(root).as_posix()] = path.read_bytes()
|
|
return snap
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def recorded() -> tuple[TurnJournalEntry, object]:
|
|
"""One sealed-origin turn, journaled — the genesis-true positive control.
|
|
|
|
Module-scoped: the sealed runtime turn is the expensive part; every test
|
|
derives tampered copies from this single recorded entry.
|
|
"""
|
|
result = _run_sealed_chat_turn("What is truth?")
|
|
result = _with_turn_cost_and_id(result, 7, 1)
|
|
entry = TurnJournalEntry.from_chat_turn(result, turn_id=1)
|
|
return entry, result
|
|
|
|
|
|
def _api_with_entry(tmp_path: Path, entry: TurnJournalEntry) -> WorkbenchApi:
|
|
journal = TurnJournal(journal_dir=tmp_path / "workbench_data")
|
|
journal.append(entry)
|
|
return WorkbenchApi(journal=journal)
|
|
|
|
|
|
def test_field_classification_is_exhaustive() -> None:
|
|
"""A future journal field must force an explicit severity decision."""
|
|
names = {spec.name for spec in fields(TurnJournalEntry)}
|
|
assert CRITICAL_FIELDS | INFORMATIONAL_FIELDS == names
|
|
assert not CRITICAL_FIELDS & INFORMATIONAL_FIELDS
|
|
|
|
|
|
def test_sealed_origin_turn_replays_equivalent(tmp_path, recorded) -> None:
|
|
"""Positive control: genesis-origin entry replays bit-equivalent."""
|
|
entry, _ = recorded
|
|
api = _api_with_entry(tmp_path, entry)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
assert response.status == 200
|
|
data = response.payload["data"]
|
|
assert data["equivalent"] is True
|
|
assert data["comparison_basis"] == "sealed_fresh_runtime_single_turn"
|
|
assert data["origin_state"] == "unrecorded"
|
|
assert data["original_trace_hash"] == entry.trace_hash
|
|
assert data["replay_trace_hash"] == entry.trace_hash
|
|
assert all(d["severity"] == "informational" for d in data["divergences"])
|
|
|
|
|
|
def test_tampered_prompt_breaks_equivalence(tmp_path, recorded) -> None:
|
|
"""Obligation 1: mutating the recorded prompt flips equivalent to false."""
|
|
entry, _ = recorded
|
|
tampered = replace(entry, prompt="What is beauty?")
|
|
api = _api_with_entry(tmp_path, tampered)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
assert response.status == 200
|
|
data = response.payload["data"]
|
|
assert data["equivalent"] is False
|
|
critical_paths = {d["path"] for d in data["divergences"] if d["severity"] == "critical"}
|
|
assert critical_paths # the different prompt produced a different envelope
|
|
|
|
|
|
def test_tampered_surface_diverges_at_exactly_that_leaf(tmp_path, recorded) -> None:
|
|
"""Obligation 2: comparison reads the RECORDED entry, leaf-precise."""
|
|
entry, _ = recorded
|
|
tampered = replace(entry, surface=entry.surface + " [tampered]")
|
|
api = _api_with_entry(tmp_path, tampered)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
data = response.payload["data"]
|
|
assert data["equivalent"] is False
|
|
critical = [d for d in data["divergences"] if d["severity"] == "critical"]
|
|
assert [d["path"] for d in critical] == ["surface"]
|
|
assert critical[0]["original"] == entry.surface + " [tampered]"
|
|
assert critical[0]["replay"] == entry.surface
|
|
|
|
|
|
def test_no_comparison_without_real_execution(tmp_path, recorded, monkeypatch) -> None:
|
|
"""Obligation 3: a digest-to-itself shortcut cannot pass.
|
|
|
|
If the runtime cannot execute, the endpoint must surface a typed error
|
|
and never a fabricated comparison — equivalent: true is unreachable
|
|
without a real re-execution.
|
|
"""
|
|
entry, _ = recorded
|
|
api = _api_with_entry(tmp_path, entry)
|
|
|
|
def broken(prompt: str):
|
|
raise RuntimeError("runtime unavailable in test")
|
|
|
|
monkeypatch.setattr(workbench_api, "_run_sealed_chat_turn", broken)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
assert response.status == 500
|
|
assert response.payload["error"]["code"] == "runtime_unavailable"
|
|
assert "data" not in response.payload or not response.payload.get("data")
|
|
|
|
|
|
def test_hashless_legacy_turn_is_not_replayable(tmp_path, recorded, monkeypatch) -> None:
|
|
"""A legacy row without a canonical trace hash is audit residue, not replay proof."""
|
|
entry, _ = recorded
|
|
legacy = replace(entry, trace_hash=None, trace_integrity=None)
|
|
api = _api_with_entry(tmp_path, legacy)
|
|
executed = False
|
|
|
|
def execute(_prompt: str):
|
|
nonlocal executed
|
|
executed = True
|
|
raise AssertionError("legacy rows must fail before execution")
|
|
|
|
monkeypatch.setattr(workbench_api, "_run_sealed_chat_turn", execute)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
assert response.status == 501
|
|
assert response.payload["error"]["code"] == "evidence_unavailable"
|
|
assert "canonical pipeline trace hash" in response.payload["error"]["message"]
|
|
assert executed is False
|
|
|
|
|
|
def test_replay_leaves_no_trace(tmp_path, recorded) -> None:
|
|
"""Obligation 4: GET /replay writes nothing — journal and engine state.
|
|
|
|
``engine_state._DEFAULT_DIR`` is read fresh (not a module-level constant)
|
|
because the root-conftest ``_isolate_engine_state_default`` autouse
|
|
fixture repoints it at a per-test tmp dir; a hardcoded ``Path("engine_state")``
|
|
would instead snapshot the real shared repo dir and false-fail under
|
|
``-n auto`` whenever an unrelated concurrent worker wrote to it.
|
|
"""
|
|
entry, _ = recorded
|
|
journal = TurnJournal(journal_dir=tmp_path / "workbench_data")
|
|
journal.append(entry)
|
|
api = WorkbenchApi(journal=journal)
|
|
journal_before = _snapshot(tmp_path / "workbench_data")
|
|
engine_state_before = _snapshot(Path(engine_state._DEFAULT_DIR))
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
assert response.status == 200
|
|
assert _snapshot(tmp_path / "workbench_data") == journal_before
|
|
assert _snapshot(Path(engine_state._DEFAULT_DIR)) == engine_state_before
|
|
|
|
|
|
def test_wall_clock_divergence_does_not_break_equivalence(tmp_path, recorded) -> None:
|
|
"""Obligation 5: timestamp/cost/digest differ freely; equivalence holds."""
|
|
entry, _ = recorded
|
|
aged = replace(
|
|
entry,
|
|
timestamp="1970-01-01T00:00:00+00:00",
|
|
turn_cost_ms=999_999,
|
|
journal_digest="sha256:not-a-real-digest",
|
|
)
|
|
api = _api_with_entry(tmp_path, aged)
|
|
|
|
response = api.handle("GET", "/replay/1", b"")
|
|
|
|
data = response.payload["data"]
|
|
assert data["equivalent"] is True
|
|
informational_paths = {d["path"] for d in data["divergences"]}
|
|
assert "timestamp" in informational_paths
|
|
assert "turn_cost_ms" in informational_paths
|
|
|
|
|
|
def test_unknown_and_malformed_turn_ids_refuse_404(tmp_path, recorded) -> None:
|
|
entry, _ = recorded
|
|
api = _api_with_entry(tmp_path, entry)
|
|
|
|
for raw in ("999", "not-a-number", ""):
|
|
response = api.handle("GET", f"/replay/{raw}", b"")
|
|
assert response.status == 404
|
|
assert response.payload["error"]["code"] == "not_found"
|
|
|
|
|
|
def test_sealed_runtime_construction_is_sealed() -> None:
|
|
"""The replay executor's runtime has no engine-state store at all."""
|
|
runtime = ChatRuntime(no_load_state=True)
|
|
assert runtime._engine_state_store is None
|
|
# checkpoint_engine_state must be a no-op, not an error.
|
|
runtime.checkpoint_engine_state()
|
|
|
|
|
|
def test_replay_turn_propagates_executor_failure(recorded) -> None:
|
|
"""replay_turn itself never swallows execution failure into a result."""
|
|
entry, _ = recorded
|
|
|
|
def broken(prompt: str):
|
|
raise RuntimeError("boom")
|
|
|
|
with pytest.raises(RuntimeError, match="boom"):
|
|
replay_turn(entry, execute=broken)
|