test-driver/tests/selfverification/test_checks_can_fail.py
tegwick 1b9860a8ee T10: gate review and first compression pass
All four gate criteria met. False Adaptation Rate 0/7 with 12 of 13 mechanical
mutations absorbed. 178 tests pass. TD-WP-0002 finished.

Fitness loop closed via F-0003: actor isolation was a property of scenarios
written to expose it, not of runs. Actors now carry an automatic private
marker and the runner examines all of them on every scenario, with two
permanent regressions behind it.

Compression - six abstractions removed, each declared and never used:
Verdict.SUSPICIOUS (a verdict no oracle could emit), Step.expect_refusal,
ActorIsolationError, World.seed, EvidencePack.latest, Trajectory.method.

F-0008: Temperature may be redundant. Crystallization was built without it
ever being consulted; measured stability of realization did the work, and is
observed rather than declared. Gated for removal alongside energy.py.

INTENT_CHANGED and REALIZATION_FAILED had never run. Both now have
purpose-built cases and a test that fails if a seventh outcome is added
without one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1629012@bnt-lap001
Assistant-Session: 78d4fb13-8a1e-474b-87a3-9b9261c49a39
2026-08-23 00:39:36 +02:00

221 lines
8.3 KiB
Python

"""A self-test that cannot fail is worth nothing.
Every check in `checks.py` is fed a deliberately broken artefact here, and must
complain. Without this file, the self-verification suite would be a row of green
ticks with no evidence that any of them is load-bearing.
Two kinds of break appear below, and the difference is worth noticing:
* **structural breaks** — the guarantee is actually violated in a running
system (actors sharing memory). The check must catch it from the evidence.
* **artefact breaks** — the guarantee cannot be violated through the framework
because the architecture forbids it, so the check is exercised against a
hand-built pack instead. Where that applies it is stated explicitly, together
with the separate assertion that the framework does refuse.
"""
from __future__ import annotations
import copy
import json
import pytest
from testdriver import Actor, Cast, Oracle, Runner, World
from testdriver.runner import CollectorIndependenceError
from lab.mutations import ObservationChannel, build_lab
from testdriver import DirectDriver, StateObserver
from scenarios.alice_bob_carol import USE_CASE, build
from tests.selfverification.checks import (
check_actor_isolation,
check_evidence_supports_every_verdict,
check_intent_independence,
check_isolation_was_examined,
check_no_actor_collected_judgment,
check_runs_agree,
check_verdicts_follow_from_judgment_evidence,
)
from tests.selfverification.test_self_verification import SECRETS, run_and_serialize
# --- td://self/actor-isolation -------------------------------------------
def test_shared_actor_memory_is_caught():
"""A structural break: two actors handed the same private store.
This is what an isolation bug actually looks like when the same agent
technology executes several actors in one process — nobody writes
`bob.memory = alice.memory`, but a shared default or a cached client
achieves it by accident.
"""
lab, tokens = build_lab()
shared: dict = {}
cast = Cast()
for name in ("alice", "bob", "carol"):
actor = Actor(name, name.title(), credentials={"token": tokens[name]})
object.__setattr__(actor, "_memory", shared) # the leak
cast.add(actor)
_, _, _, asset, _ = build()
world = World("w-leaky", lab, lab.version, cast=cast)
driver = DirectDriver(lab, tokens)
observer = StateObserver(ObservationChannel(lab), asset.scenario.watches)
for actor_id, secret in SECRETS.items():
world.cast[actor_id].remember(f"private-{actor_id}", secret)
result = Runner(world, driver, observer, Oracle()).run(asset)
pack = json.loads(result.evidence.to_json())
memories = {a.id: {k: a.recall(k) for k in a.known_keys()} for a in world.cast}
violations = check_actor_isolation(pack, SECRETS, memories)
assert violations, "shared actor memory went undetected"
assert any("holds" in v for v in violations)
def test_a_secret_leaking_into_the_record_is_caught():
"""An artefact break: the leak escapes into evidence even if memory is clean."""
pack, memories, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
for obs in tampered["observations"]:
if obs["collector"] == "alice":
obs["data"]["stolen"] = SECRETS["bob"]
break
assert check_actor_isolation(tampered, SECRETS, memories)
# --- td://self/oracle-independence ---------------------------------------
def test_the_framework_refuses_to_let_an_actor_collect_judgment_evidence():
"""The architecture prevents this, so it cannot be produced by a real run."""
world, driver, observer, asset, oracle = build()
observer.name = "bob"
with pytest.raises(CollectorIndependenceError):
Runner(world, driver, observer, oracle).run(asset)
def test_actor_collected_judgment_evidence_is_caught_in_the_record():
"""...and if it ever did appear in a pack, the out-of-band check sees it.
Both halves are needed. The first says the door is locked; this one says we
would notice if someone came through the window.
"""
pack, _, actors = run_and_serialize()
tampered = copy.deepcopy(pack)
for obs in tampered["observations"]:
if obs["stratum"] == "S3":
obs["collector"] = "bob"
break
assert check_no_actor_collected_judgment(tampered, actors)
def test_a_verdict_that_contradicts_its_evidence_is_caught():
"""The strongest of the checks: verdicts must follow from S3 alone."""
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["verdicts"][0]["verdict"] = "FAIL" # a verdict nothing supports
assertions = list(USE_CASE.claims) + list(USE_CASE.invariants)
violations = check_verdicts_follow_from_judgment_evidence(tampered, assertions)
assert violations
assert "retained judgment evidence yields" in violations[0]
def test_a_pass_silently_replacing_a_fail_is_caught():
"""The specific corruption the project most needs to notice."""
pack, _, _ = run_and_serialize("M15")
tampered = copy.deepcopy(pack)
for verdict in tampered["verdicts"]:
if verdict["verdict"] == "FAIL":
verdict["verdict"] = "PASS"
assertions = list(USE_CASE.claims) + list(USE_CASE.invariants)
assert check_verdicts_follow_from_judgment_evidence(tampered, assertions)
# --- td://self/evidence-reproducibility -----------------------------------
def test_a_verdict_without_a_snapshot_is_caught():
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["observations"] = [
o for o in tampered["observations"] if o["kind"] != "state_snapshot"
]
assert check_evidence_supports_every_verdict(tampered)
def test_a_verdict_without_a_record_of_how_the_step_ran_is_caught():
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["observations"] = [
o for o in tampered["observations"] if o["kind"] != "realization"
]
violations = check_evidence_supports_every_verdict(tampered)
assert any("how" in v for v in violations)
def test_evidence_that_does_not_name_the_version_is_caught():
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["sut_version"] = ""
assert check_evidence_supports_every_verdict(tampered)
def test_disagreeing_runs_are_caught():
first, _, _ = run_and_serialize()
second, _, _ = run_and_serialize("M15")
assert check_runs_agree(first, second)
# --- td://self/intent-independence ----------------------------------------
def test_implementation_derived_intent_is_caught():
pack, _, _ = run_and_serialize("M15")
tampered = copy.deepcopy(pack)
tampered["provenance_index"]["c-bob-revoked"] = "agent-from-implementation"
violations = check_intent_independence(tampered)
assert violations
assert "derived from the implementation" in violations[0]
def test_unrecorded_provenance_is_caught():
"""Absent provenance is not a benign omission — it makes the verdict
unauditable, which for this framework is the same as unusable."""
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["provenance_index"] = {}
assert check_intent_independence(tampered)
# --- F-0003 resolution: isolation observed on every run -------------------
def test_an_unexamined_run_is_caught():
"""A run that never looked at isolation must not read as isolated."""
pack, _, _ = run_and_serialize()
tampered = copy.deepcopy(pack)
tampered["observations"] = [
o for o in tampered["observations"] if o["kind"] != "actor_isolation"
]
assert check_isolation_was_examined(tampered)
def test_a_leak_is_caught_without_the_test_planting_anything():
"""The regression F-0003 leaves behind.
No secrets seeded by the harness, no scenario written to expose isolation.
An actor holding another's automatic marker is caught by the ordinary run.
"""
from testdriver import Oracle, Runner
from scenarios.alice_bob_carol import build
world, driver, observer, asset, oracle = build()
world.cast["bob"].remember("overheard", world.cast["alice"].canary)
result = Runner(world, driver, observer, oracle).run(asset)
pack = json.loads(result.evidence.to_json())
violations = check_isolation_was_examined(pack)
assert violations
assert "holds the private marker of 'alice'" in violations[0]