- 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.
150 lines
7.2 KiB
Python
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
|