Files
rune/tests/test_v19_iteration.py
T
Nick 3fb28e2461 feat(t19): testing mode + self-hosted /testing command + T19 layer model (19L-19U)
- testing_mode.py (19L/M/N/O/P): TestingSession (coordination-only,
  pausable — durable truth stays in the Behaviour Ledger); dynamic
  queue (fix-for-B-reopens-A via structural closure, 19S-9 proven);
  Observation→closure gate (closure requires retest AND user
  confirmation — automated green alone recorded as NOT closed);
  forge projection through the T18 boundary (failure never rewrites
  truth, 19S-14 proven); cross-project aggregate.
- 19R LIVE_PROOF: /testing command implemented through the full
  system — self-scaffold lookup → capability-ledger packet (bound
  exactly ONE file) → qualified INWARD basis → predictive impact →
  preview → contract 19r-testing-command → event-bridged verification
  → descriptive impact (prediction matched, delta persisted) →
  selective invalidation + obligations → ledgers updated → closed.
- 19T benchmark (honest): cold agent found the answer in 6 tool calls
  (4 files) — on this well-organized repo raw speed ≈ equal; the
  scaffold advantage is correctness/continuity (validation state,
  obligations, invalidation), recorded without inflation.
- 19U: V1 definition gains the T19 layer model + both governing
  objectives verbatim; implementation audit gains T19 classifications.
- type ratchet: forge.py gitea_auth import made resolvable via
  pyrightconfig extraPaths (the +1 warning FIXED, not re-baselined).

Suite 2002 green; ratchets PASS; Henxels rc=0.
2026-09-16 01:24:29 +01:00

150 lines
7.2 KiB
Python

"""test_v19_iteration.py — T19 §19E/19H/19K + remaining 19S cases:
surgical context packets, predictive/descriptive impact, obligations,
moved-source identity, fresh-builder resilience."""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
from rune import behaviour_ledger as bl # noqa: E402
from rune import capability_ledger as cl # noqa: E402
from rune import iteration as it # noqa: E402
from rune import structural_model as sm # noqa: E402
@pytest.fixture()
def world(tmp_path):
model = sm.StructuralModel(tmp_path / "store", "demo")
model.add("domain", "d", parent="project:demo")
model.add("subsystem", "s", parent="domain:d")
model.add("component", "bridge", parent="subsystem:s",
ext={"source": "src/bridge.py"})
model.add("component", "consumer", parent="subsystem:s",
ext={"source": "src/consumer.py"})
model.add("interface", "events", parent="subsystem:s")
model.add("state_store", "queue", parent="project:demo")
model.add("test_suite", "tests", parent="project:demo")
model.add("deployment_surface", "prod", parent="project:demo")
model.relate("component:bridge", "provides", "interface:events")
model.relate("component:consumer", "consumes", "interface:events")
model.relate("component:bridge", "owns", "state_store:queue")
model.relate("component:bridge", "verified_by", "test_suite:tests")
model.relate("component:bridge", "deployed_by", "deployment_surface:prod")
model.save()
ledger = cl.CapabilityLedger(tmp_path / "store")
ledger.define(capability_id="bridge-core", name="Event bridge",
purpose="accepts and completes events",
owning_project="demo", component="component:bridge",
source_locations=["src/bridge.py"],
invariants=["no event dropped silently"],
behaviour_specs=["behaviour:VAL-1"])
ledger.save()
beh = bl.BehaviourLedger(tmp_path / "store")
beh.define(behaviour_id="VAL-1", owning_project="demo",
intended_behaviour="events complete exactly once",
owner_component="component:bridge",
dependencies=["component:bridge", "state_store:queue"])
beh.record_auto_verification("VAL-1", passed=True)
beh.record_real_world("VAL-1", passed=True, detail="confirmed")
beh.save()
return model, ledger, beh
# ── 19E: surgical context packet ─────────────────────────────────────────
def test_19e_context_packet_bounded_and_complete(world):
model, ledger, _ = world
pkt = it.context_packet(model, ledger, "component:bridge",
intent="harden event completion")
assert pkt["target"] == "component:bridge"
assert pkt["owning_domain"] == "domain:d"
assert pkt["local"]["capability_id"] == "capability:bridge-core"
assert "src/bridge.py" in pkt["local_files"]
assert "component:consumer" in pkt["connected"]["consumers"]
assert "state_store:queue" in pkt["connected"]["state_owned"]
assert "test_suite:tests" in pkt["connected"]["verification"]
# bounded: no whole-graph dump
assert "entities" not in str(pkt["connected"])
def test_19e_unknown_target_is_explicit(world):
model, ledger, _ = world
assert it.context_packet(model, ledger, "component:ghost").get("error")
# ── 19H: predictive vs descriptive impact ────────────────────────────────
def test_19h_predicted_vs_descriptive_delta(world, tmp_path):
model, ledger, _ = world
pred = it.predictive_impact(model, "component:bridge")
assert "component:bridge" in pred["mutation_scope"]
# reality: only bridge changed (consumer untouched despite interface)
desc = it.descriptive_impact(model, "component:bridge",
observed_changed=["component:bridge"],
generation="gen-9")
assert desc["unexpected"] == []
assert "component:consumer" in desc["unaffected_as_predicted"]
p = it.record_impact_delta(tmp_path / "store", desc)
lines = p.read_text().strip().splitlines()
import json
assert json.loads(lines[-1])["generation"] == "gen-9"
def test_19h_prediction_miss_recorded(world, tmp_path):
model, ledger, _ = world
# a change to something OUTSIDE the predicted closure (consumer's own
# internals) is a genuine prediction miss — recorded honestly
desc = it.descriptive_impact(model, "component:bridge",
observed_changed=["component:bridge",
"component:ghost-module"])
assert desc["unexpected"] == ["component:ghost-module"]
assert "component:consumer" not in desc["unexpected"] # was predicted
# ── 19K: machine-derived obligations ─────────────────────────────────────
def test_19k_obligations_from_structural_truth(world):
model, ledger, beh = world
obs = it.post_change_obligations(
model, "component:bridge", behaviours=beh,
changed_entities={"component:bridge"})
kinds = {o["kind"] for o in obs}
assert "inspect_consumer" in kinds # consumer via interface
assert "verify_interface" in kinds # provided interface
assert "check_state_compatibility" in kinds # owns state_store:queue
assert "verify_deployment" in kinds # deployed_by surface
assert "retest" in kinds # VAL-1 depends on bridge
# every obligation carries its structural WHY
for o in obs:
assert o["why"]
# ── 19S-6: moved source, stable identity ─────────────────────────────────
def test_19s6_move_preserves_identity(world, tmp_path):
model, ledger, _ = world
ledger.move("bridge-core", ["src/events/bridge.py"])
pkt = ledger.context_packet("bridge-core")
assert pkt["capability_id"] == "capability:bridge-core" # unchanged
assert pkt["source_locations"] == ["src/events/bridge.py"]
assert any(h["event"] == "moved" for h in ledger.doc["history"])
# ── 19S-13: fresh builder via packet only ─────────────────────────────────
def test_19s13_fresh_builder_rehydrates_from_packet(world):
"""Simulated compaction: a fresh process knows NOTHING except the
packet. It must identify the target, its obligations, and the
retest queue without repository rediscovery."""
model, ledger, beh = world
pkt = it.context_packet(model, ledger, "component:bridge",
intent="change completion semantics")
# fresh builder derives, from the packet alone:
assert pkt["local"]["purpose"] # what this is
assert pkt["local"]["invariants"] # what must hold
assert "component:consumer" in pkt["connected"]["consumers"] # who cares
obs = it.post_change_obligations(model, "component:bridge",
behaviours=beh)
assert any(o["kind"] == "retest" for o in obs) # what to re-verify