Compare commits

...
7 Commits
Author SHA1 Message Date
conductor 6734bae4ea chore(release): auto-bump version to 0.303.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 04:24:51 +01:00
Nick a574ff0879 chore(store): minidoc/t21/adversarial contract entities for the 2026-10-13T22:59→10-14T00:14 sessions
Pairs with the journal catch-up and mini-doc projections (same
sessions; the cancelled-worktree store never got committed).
2026-10-14 04:24:32 +01:00
Nick 35a721b4c0 chore(store): mini-doc projections for the 2026-10-13T22:59→10-14T00:09 builder sessions
Companion artifacts of the journal catch-up (entities tracked, journal
committed); zero name-overlap with master's docs tree.
2026-10-14 04:24:32 +01:00
Nick 796162b09c chore(store): journal catch-up — minidoc builder sessions (append-only union)
Lines 2026-10-13T16:30→2026-10-14T00:09 from minidoc-test builder
sessions against this worktree's store; the later batch pairs with
already-tracked contract entities. Union law: both sides append,
content-dedup on merge.
2026-10-14 04:24:32 +01:00
Nick 2eb91c0e81 test(capability_broker): Phase B — full-ladder evidence green, parity instrument, connection_pool flag fix
Ladder results (evidence under verification/, Read-back per the
file-based evidence protocol; summary in cb-summary.md): battery 11/0;
freeze --verify 33 cases byte-identical (fixture-pinned standalone
re-verify + self-verifying regen); live parity 468/468 (frozen=33
fuzz=421 live=14) — LIVE PARITY 100% on the gap fns; clippy -D warnings
clean; adjacent Python 107/107 in BOTH pins (delegation live and
RUNE_CAPABILITY_BROKER_CORE=python); full suite both pins: failure set
ZERO-delta vs the master baseline (118 pre-existing).

Phase B language advantages proven by the battery-after-landing:
trait CbIo IO injection (deterministic mtime pins in-test), Result
error paths, exhaustive handle_hook match, zero-copy static tables,
in-process Rust-to-Rust cs kernel delegation in _py_score_card.

Fix-first with proof: test_connection_pool's evict-oldest flag read
raw temp-dir paths so any 'a' in the random tempdir name flipped it
(~17% isolated flake, sole live full-suite delta on first run);
normalized to basenames like the status comparison — 15/15 green
after, both full-suite deltas zero. 1e4598aa instrument class.
2026-10-14 04:24:32 +01:00
Nick 1a35b4ce2d feat(capability_broker): close PARTIAL gaps — dichotomy wave
Port the 10 audit-missing fns name-preserving into the existing Rust
crate (gap.rs): _native_tool_schemas, load_registry, _cards_are_stale,
load_cards, generate_card, build_cards, _cs_core, _py_score_card,
match_capabilities, handle_hook. Doc-envelope cb_* FFI entries (lib.rs,
cs_free_string stays with capability_scoring), ctypes loader bindings
(broker_loader.py), facade delegation under the
RUNE_CAPABILITY_BROKER_CORE=python pin (capability_broker.py), and a
cfg(test) battery (gap_battery.rs) replaying the shared freeze_truth.py
frozen corpus VERBATIM via include_str. synthesize_card capabilities list
pinned to the oracle law ([name]). Module audit 10/19 PARTIAL -> 19/19
FULL. Ladder evidence lands with the Phase B commit. Contract
BUILDER-2026-10-13T16:01:25Z-9b9389-factory-gap-cb.
2026-10-14 04:24:32 +01:00
Nick 3c3d881125 chore(store): close microkernel dichotomy contract BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk (parity b9b089fa, audit 60197993) 2026-10-14 04:21:18 +01:00
91 changed files with 63522 additions and 15 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.302.0**
**Current release: v0.303.0**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.302.0"
version = "0.303.0"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
@@ -0,0 +1,378 @@
#!/usr/bin/env python3
"""Live parity: capability_broker gap-closing ports vs the Python oracle
(dichotomy wave, contract BUILDER-2026-10-13T16:01:25Z-9b9389-factory-gap-cb).
Layers:
1. FROZEN — frozen_gap_truth.json (generated by
scripts/gen_capability_broker_gap_truth.py against the LIVE oracle with
RUNE_CAPABILITY_BROKER_CORE=python pinned) replayed through the ctypes
FFI cb_* entries case by case, deep-copied, threading the fixture state
exactly as the oracle's replayable-script sequence did.
2. FUZZ — seeded random manifests/registries/queries/hooks (seed 2479)
per kernel: oracle floor vs FFI, exact compare.
3. LIVE — dual-fixture: the oracle runs on fixture home A, the FFI on
fixture home B, both canonical-seeded; results identical.
Exit 0 only at 100% parity on the gap-closing functions.
Run: python3 scripts/check_capability_broker_gap_parity.py
Needs: cargo build --release in src/rust/capability_broker (the .so).
"""
import copy
import json
import os
import random
import shutil
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
from rune import broker_loader # noqa: E402
from rune import capability_broker as cb # noqa: E402
TRUTH_PATH = REPO / "src" / "rust" / "capability_broker" / "frozen_gap_truth.json"
HOME_A = Path("/tmp/rune_cb_parity_a")
HOME_B = Path("/tmp/rune_cb_parity_b")
# Pin the oracle's module-level card I/O onto fixture A (the module constants
# resolved at import; the FFI layer gets the same values as explicit paths).
CB_REGISTRY = HOME_A / "src" / "rune" / ".microkernel.json"
CB_CARDS = HOME_A / "memory" / "index" / "capability_cards.json"
# Pinned staleness epochs (fixture law — no wall-clock timing luck; mirrors
# the generator's os.utime pins).
FIXED_SEED_MTIME = 1_000_000_000.0
FIXED_REGISTRY_MTIME = 1_000_000_100.0
fails: list[str] = []
counts = {"frozen": 0, "fuzz": 0, "live": 0}
def fail(layer, name, detail):
fails.append(f"[{layer}] {name}: {detail}")
print(f"FAIL[{layer}] {name}: {detail}")
def j(x):
return json.dumps(x, sort_keys=True, ensure_ascii=True)
def check(layer, name, want, got):
counts[layer] += 1
if j(want) != j(got):
fail(layer, name, f"want={j(want)}\n got={j(got)}")
def oracle_tools():
try:
from rune.tool_executor import TOOLS
except ImportError:
from tool_executor import TOOLS
return list(TOOLS)
def build_fixture(home: Path) -> tuple[str, str]:
shutil.rmtree(home, ignore_errors=True)
registry = home / "src" / "rune" / ".microkernel.json"
cards = home / "memory" / "index" / "capability_cards.json"
registry.parent.mkdir(parents=True)
cards.parent.mkdir(parents=True)
registry.write_text(json.dumps(_registry_content()))
cards.write_text(json.dumps([{"name": "seed-stale", "description": "seed",
"capabilities": ["seed_cap"], "file": "seed.py",
"full_path": "plugins/seed/seed.py", "priority": 3,
"semantic_examples": [], "risk": "read-only",
"auto_invoked": False, "hooks": [],
"searchable_text": "seed stale card"}]))
os.utime(cards, (FIXED_SEED_MTIME, FIXED_SEED_MTIME))
os.utime(registry, (FIXED_REGISTRY_MTIME, FIXED_REGISTRY_MTIME))
return str(registry), str(cards)
def _registry_content():
"""The canonical fixture registry — the frozen truth carries its VALUE
(the load_registry case); read from the truth so the fixture and the
corpus can never drift apart."""
truth = json.loads(TRUTH_PATH.read_text())
for case in truth["cases"]:
if case["fn"] == "load_registry":
return case["expected"]
raise RuntimeError("load_registry case missing from the frozen truth")
def b_paths():
return build_fixture_b[0], build_fixture_b[1]
def b_registry_path():
return build_fixture_b[0]
def b_cards_path():
return build_fixture_b[1]
build_fixture_b: tuple[str, str] = ("", "")
def oracle_call(fn, a):
return {
"generate_card": lambda: cb.generate_card(a["name"], a["manifest"]),
"build_cards": lambda: cb.build_cards(),
"load_registry": lambda: cb.load_registry(),
"cards_are_stale": lambda: cb._cards_are_stale(),
"native_tool_schemas": lambda: cb._native_tool_schemas(),
"match_capabilities": lambda: cb.match_capabilities(a["query"], a["top_k"]),
"handle_hook": lambda: cb.handle_hook(a["event"], a["data"]),
}[fn]()
def ffi_call(fn, a):
return {
"generate_card": lambda: broker_loader.generate_card(a["name"], a["manifest"]),
"build_cards": lambda: broker_loader.build_cards(b_registry_path()),
"load_registry": lambda: broker_loader.load_registry(b_registry_path()),
"cards_are_stale": lambda: broker_loader.cards_are_stale(b_cards_path(), b_registry_path()),
"native_tool_schemas": lambda: broker_loader.native_tool_schemas(a["tools"]),
"match_capabilities": lambda: broker_loader.match_capabilities(
a["cards"], a["query"], a["top_k"]),
"handle_hook": lambda: broker_loader.handle_hook(a["event"], a["data"], a["cards"]),
}[fn]()
# ── layer 1: FROZEN replay through the FFI ──────────────────────────────────
def replay_frozen() -> None:
truth = json.loads(TRUTH_PATH.read_text())
cases = truth["cases"]
reg_b, cards_b = build_fixture(HOME_B)
build_fixture_b = (reg_b, cards_b)
globals()["build_fixture_b"] = build_fixture_b
tools = oracle_tools()
tools_from_truth: list | None = None
cards_state: list = []
for idx, case in enumerate(cases):
fn, args = case["fn"], copy.deepcopy(case["args"])
want = case["expected"]
label = f"#{idx} {fn}"
try:
if fn == "_cards_are_stale":
got = broker_loader.cards_are_stale(cards_b, reg_b)
elif fn == "load_cards":
t = tools if tools_from_truth is None else tools_from_truth
got = broker_loader.load_cards(cards_b, reg_b, t)
cards_state = copy.deepcopy(got)
elif fn == "build_cards":
got = broker_loader.build_cards(reg_b)
elif fn == "load_registry":
got = broker_loader.load_registry(reg_b)
elif fn == "_native_tool_schemas":
got = broker_loader.native_tool_schemas(tools)
tools_from_truth = (
[copy.deepcopy(v) for v in got.values()]
if isinstance(got, dict) else []
)
elif fn == "generate_card":
got = broker_loader.generate_card(args[0], args[1])
elif fn == "_py_score_card":
# in-process kernel contract — the same cs arithmetic the
# oracle reaches through cs_loader
from rune import cs_loader
got = cs_loader.score_card(args[0], args[1])
elif fn == "match_capabilities":
got = broker_loader.match_capabilities(cards_state, args[0], int(args[1]))
elif fn == "handle_hook":
got = broker_loader.handle_hook(
args[0], args[1] if len(args) > 1 else {}, cards_state)
else:
fail("frozen", label, "no FFI mapping")
continue
check("frozen", label, want, got)
except Exception as exc: # noqa: BLE001 — the envelope err surfaced as a raise
fail("frozen", label, f"FFI raised: {type(exc).__name__}: {exc}")
# ── layer 2: seeded fuzz, oracle floor vs FFI ───────────────────────────────
CAP_POOL = ["memory_recall", "memory_write", "claim_verification", "warm_routing",
"politics", "research", "tasks", "cache", "epistemic_verify"]
WORDS = ["memory", "store", "this", "decision", "verify", "claim", "drift",
"cache", "route", "task", "file", "lint", "query", "remember", "zzz"]
def random_manifest(rng):
m = {}
if rng.random() < 0.9:
m["description"] = " ".join(rng.choice(WORDS) for _ in range(rng.randint(0, 8)))
if rng.random() < 0.8:
m["capabilities"] = rng.sample(CAP_POOL, rng.randint(0, 3))
if rng.random() < 0.4:
m["hooks"] = {"on_message": "handle_hook"}
if rng.random() < 0.5:
m["priority"] = rng.choice([1, 4, 10, 100, 2.5, 7])
if rng.random() < 0.5:
m["_file"] = rng.choice(["main.py", "plugins/x/main.py", ""])
return m
def replay_fuzz() -> None:
rng = random.Random(2479)
build_fixture(HOME_B) # canonical registry under fixture B for build_cards
for i in range(200):
name = f"plug{i}"
manifest = random_manifest(rng)
try:
want = cb.generate_card(name, copy.deepcopy(manifest))
except Exception as exc: # noqa: BLE001
want = {"__raise__": type(exc).__name__}
try:
got = broker_loader.generate_card(name, copy.deepcopy(manifest))
except Exception as exc: # noqa: BLE001
got = {"__raise__": type(exc).__name__}
check("fuzz", f"generate_card#{i}", want, got)
for i in range(60):
plugins = {}
for p in range(rng.randint(0, 5)):
if rng.random() < 0.85:
plugins[f"plug{p}"] = {"manifest": random_manifest(rng)}
else:
plugins[f"plug{p}"] = {"active": False}
build_fixture(HOME_A) # fresh dirs on both sides each iteration
reg_b, _ = build_fixture(HOME_B)
Path(CB_REGISTRY).write_text(json.dumps({"plugins": plugins}))
reg_b2, _2 = b_paths()
Path(reg_b2).write_text(json.dumps({"plugins": plugins}))
want = cb.build_cards()
got = broker_loader.build_cards(reg_b2)
check("fuzz", f"build_cards#{i}", want, got)
# canonical restore + rebuild both sides once (deterministic card pool)
build_fixture(HOME_A)
reg_b, cards_b = build_fixture(HOME_B)
build_fixture_b = (reg_b, cards_b)
globals()["build_fixture_b"] = build_fixture_b
cb_cards = cb.load_cards()
ffi_cards = broker_loader.load_cards(cards_b, reg_b, oracle_tools())
check("fuzz", "card_pool", cb_cards, ffi_cards)
for i in range(60):
query = " ".join(rng.choice(WORDS) for _ in range(rng.randint(0, 6)))
top_k = rng.choice([1, 3, 5, 10])
want = cb.match_capabilities(query, top_k)
got = broker_loader.match_capabilities(ffi_cards, query, top_k)
check("fuzz", f"match#{i}", want, got)
for i in range(60):
event = "on_message" if rng.random() < 0.67 else "other"
data: dict = {}
if rng.random() < 0.85:
data["message"] = " ".join(rng.choice(WORDS) for _ in range(rng.randint(0, 5)))
if rng.random() < 0.3:
data["text"] = " ".join(rng.choice(WORDS) for _ in range(rng.randint(0, 5)))
if rng.random() < 0.2:
data.pop("message", None)
data["status"] = "error state" if rng.random() < 0.5 else ""
if event == "other" and rng.random() < 0.5:
data = {}
try:
want = cb.handle_hook(event, copy.deepcopy(data))
except Exception as exc: # noqa: BLE001
want = {"__raise__": type(exc).__name__}
try:
got = broker_loader.handle_hook(event, copy.deepcopy(data), ffi_cards)
except Exception as exc: # noqa: BLE001
got = {"__raise__": type(exc).__name__}
check("fuzz", f"hook#{i}", want, got)
# staleness flip, rebuilt identically on both sides (20× both arms)
for i in range(20):
reg_a, cards_a = build_fixture(HOME_A)
reg_b, cards_b = build_fixture(HOME_B)
build_fixture_b = (reg_b, cards_b)
globals()["build_fixture_b"] = build_fixture_b
want = cb._cards_are_stale()
got = broker_loader.cards_are_stale(cards_b, reg_b)
check("fuzz", f"stale_pre#{i}", want, got)
cb.load_cards() # atomic rebuild mutates fixture A
broker_loader.load_cards(cards_b, reg_b, oracle_tools()) # mutates B
want = cb._cards_are_stale()
got = broker_loader.cards_are_stale(cards_b, reg_b)
check("fuzz", f"stale_post#{i}", want, got)
# ── layer 3: LIVE dual-fixture battery ──────────────────────────────────────
def run_live() -> None:
reg_a, _ = build_fixture(HOME_A)
reg_b, cards_b = build_fixture(HOME_B)
build_fixture_b = (reg_b, cards_b)
globals()["build_fixture_b"] = build_fixture_b
tools = oracle_tools()
pairs = [
("load_registry", {}),
("build_cards", {}),
("native_tool_schemas", {"tools": tools}),
("cards_are_stale", {}),
]
for fn, a in pairs:
check("live", fn, oracle_call(fn, a), ffi_call(fn, a))
# match/hook: identical card material on both sides — drive the FFI
# rebuild first (the oracle's load_cards below mutates A the same way)
ffi_index = broker_loader.load_cards(cards_b, reg_b, tools)
check("live", "index_bytes", cb.load_cards(), ffi_index)
cards = copy.deepcopy(ffi_index)
for i, query in enumerate([
"recall and store memory facts", "verify this claim", "route this task",
"find files matching a pattern", "zzz nothing", "cache this result",
]):
check("live", f"match#{i}",
cb.match_capabilities(query, 5),
broker_loader.match_capabilities(cards, query, 5))
for i, (event, data) in enumerate([
("on_message", {"message": "verify this claim about drift"}),
("other", {"message": "hello world"}),
("on_message", {"status": "error state"}),
]):
check("live", f"hook#{i}",
cb.handle_hook(event, copy.deepcopy(data)),
broker_loader.handle_hook(event, copy.deepcopy(data), cards))
def main() -> int:
if not broker_loader.available():
print("broker_loader .so missing — cargo build --release in "
"src/rust/capability_broker")
return 2
# The oracle floor reads RUNE_CAPABILITY_BROKER_CORE — pin pure Python so
# the facade runs the ORACLE arms (the FFI layer is driven directly).
os.environ["RUNE_CAPABILITY_BROKER_CORE"] = "python"
cb.REGISTRY = str(CB_REGISTRY)
cb.CARDS_FILE = str(CB_CARDS)
for p in (HOME_A, HOME_B):
shutil.rmtree(p, ignore_errors=True)
replay_frozen()
replay_fuzz()
run_live()
total = sum(counts.values())
print(f"parity: {total - len(fails)}/{total} checks OK "
f"(frozen={counts['frozen']} fuzz={counts['fuzz']} live={counts['live']})")
if fails:
print(f"FAILURES: {len(fails)}")
return 1
print("LIVE PARITY 100% on the gap-closing functions")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave microkernel gap contract (GO port).
Full lifecycle walk in ONE process (shared-store clobber hazard — do NOT
split across processes; re-walk on a fresh post-rebase store per the
segment-architecture conflict pattern). The QUALITY-GATE LAW (scaffold.py
2026-10-13) requires the designed close() entry (predicted-vs-observed
quality + material-change) rather than a raw transition to 'closed'.
Carries the already-pushed SHAs:
feat 3a1b9e54 close PARTIAL gaps — dichotomy wave
chore da9e15e9 regenerate audit — microkernel FULL
Usage: close_contract_microkernel.py
"""
import json
import os
import sys
from pathlib import Path
os.environ.setdefault(
"CS_RUST_LIB",
"/mnt/workdrive/rune/src/rust/research_budget/target/release/deps/libcapability_scoring.so",
)
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from rune.construction_interface import ConstructionInterface
PARITY_SHA = "3a1b9e54"
AUDIT_SHA = "da9e15e9"
EVIDENCE = f"parity {PARITY_SHA}; audit {AUDIT_SHA}"
DETAIL = (
f"microkernel GO dichotomy gap-close — parity commit {PARITY_SHA}, "
f"audit commit {AUDIT_SHA}; dichotomy audit fn coverage 6/12 "
"PARTIAL -> 12/12 FULL. Ported name-preserving into "
"src/go/microkernel: NowIso (+nowFunc clock seam, Python "
"isoformat timespec=seconds +00:00 shape), ExtractManifest "
"(brace-counted PLUGIN block + ast.literal_eval-subset parser: "
"dicts/lists/tuples/strings-with-escapes/ints/floats/True/False/"
"None, comments, trailing commas, unicode, rune-safe truncation), "
"Discover (self-registration sweep, sorted listing), RunHook "
"(subprocess hook runner: skipped / file-not-found / ok-JSON / "
"raw-stdout-[:500] / rc-error stderr-[:200] / timeout, banker's-"
"rounded durations), Fire (8-way parallel dispatch + bounded "
"fire-log, CLI fire case rewired off the old fake), "
"LoadRegistry/SaveRegistry (renamed from lowercase; corrupt-file "
"full-default parity, log normalized to []). Register fixes proven "
"vs oracle: Python truthiness for hook values (string targets "
"index — real PLUGIN dicts use them) and auto_activate, _file "
"plumbed into entries. Frozen truth via the shared "
"scripts/freeze_truth.py harness (generator "
"scripts/gen_microkernel_gap_truth.py, aware-clock pin — fire() "
"mixes naive/aware datetime.now()): 25-case envelope regen-stable, "
"--verify byte-identical x2; Go battery 25/25 subtests "
"(truth_microkernel_gap_test.go), -race clean; live oracle-vs-Go "
"parity 24/24 (scripts/check_microkernel_parity.py, parity op mode "
"in parity.go); gofmt/vet/go build ./... clean; Python both-pins "
"green for the module (18 test_p1_01 failures proven pre-existing "
"on stashed base). Six representation-level divergences documented "
"(listing order, non-dict PLUGIN crash class, --data separators, "
"partial-registry crash class, integral-float rendering, typed-"
"struct persistence). Evidence read back: verification/"
"summary-microkernel.md + verification/microkernel-"
"{truth,goladder,live-parity,pytest-*,audit}.exit"
)
iface = ConstructionInterface(builder="factory-gap-mk")
r = iface.submit_need(
"microkernel dichotomy gap-close (GO): name-preserving port of the 6 "
"unmatched fns (now_iso, discover, _extract_manifest, _load_registry, "
"_save_registry, _run_hook) into src/go/microkernel, plus Fire wiring "
"the CLI fire case to real 8-way parallel subprocess dispatch with the "
"bounded fire-log, and Register fixes (Python truthiness for hook "
"values, _file plumbing). Frozen-truth battery 25/25, live parity "
"24/24, gofmt/vet/build clean, Python both-pins green (18 test_p1_01 "
"failures proven pre-existing). Audit: microkernel 6/12 PARTIAL -> "
"12/12 FULL. Delivered on gitea/master: feat " + PARITY_SHA + ", "
"audit " + AUDIT_SHA + ".",
origin="builder",
)
print("submit_need:", json.dumps(r)[:300])
if not r.get("success"):
print("NEED FAILED — aborting")
sys.exit(1)
c = r["ids"]["contract_id"]
print("contract_id:", c)
for phase in ("approved", "building", "verifying"):
t = iface.transition(c, phase, evidence_ref=EVIDENCE)
ok = t.get("success")
print(f"transition->{phase}:", "ok" if ok else json.dumps(t)[:300])
if not ok:
sys.exit(1)
closed = iface.close(
c,
observed_evidence=[{"kind": "port_evidence", "detail": DETAIL}],
scope_files=[
"src/go/microkernel/main.go",
"src/go/microkernel/microkernel.go",
"src/go/microkernel/parity.go",
"src/go/microkernel/truth_microkernel.json",
"src/go/microkernel/truth_microkernel_test.go",
"src/go/microkernel/truth_microkernel_gap.json",
"src/go/microkernel/truth_microkernel_gap_test.go",
"scripts/gen_microkernel_gap_truth.py",
"scripts/check_microkernel_parity.py",
"scripts/close_contract_microkernel.py",
"verification/summary-microkernel.md",
],
)
print("close:", json.dumps(closed)[:400])
doc = iface.scaffold.load()
e = iface.scaffold.contract(doc, c)
print("FINAL PHASE:", e.get("phase") if e else "MISSING")
if not closed.get("success") or not e or e.get("phase") != "closed":
sys.exit(1)
print("CLOSED", c)
+292
View File
@@ -0,0 +1,292 @@
#!/usr/bin/env python3
"""Freeze the capability_broker gap-closing truth corpus (dichotomy wave
#2479 gap-cb tranche).
Drives the LIVE Python oracle (src/rune/capability_broker.py) through the
shared harness (scripts/freeze_truth.py: RUNE_CAPABILITY_BROKER_CORE=python
auto-pinned from the module stem, inputs deep-copied per case,
{"fn","args","kwargs","expected"} envelope) into
src/rust/capability_broker/frozen_gap_truth.json, embedded VERBATIM by the
crate's cfg(test) battery (gap_battery.rs, include_str!).
Determinism contract — fixture-home replay (provider_budget law): the
oracle's module-level card I/O (REGISTRY / CARDS_FILE) resolves through
memory_env from RUNE_HOME / RUNE_SCRIPTS_DIR, so every case replays
against a rebuilt fixture home:
RUNE_HOME = /tmp/rune_cb_truth_home
RUNE_SCRIPTS_DIR= /tmp/rune_cb_truth_home/src/rune
src/rune/.microkernel.json ← SYNTHETIC_REGISTRY (frozen const)
memory/index/capability_cards.json ← STALE_CARDS_SEED, written
BEFORE the registry (stale arm)
The case list is a REPLAYABLE SCRIPT over that home (stateful mtimes are
legal because every replay mutates the fixture identically from the same
canonical seed): staleness flips when load_cards' atomic rebuild rewrites
the index, and every later score/match/hook case reads the rebuilt index.
WARNING: SYNTHETIC_REGISTRY / STALE_CARDS_SEED below are kept byte-equal
with the consts embedded in src/rust/capability_broker/src/gap_battery.rs —
the Rust battery rebuilds the same fixture home from the same values.
Self-verifying (byte-identical law): rebuild → freeze → rebuild → freeze
(byte-compare) → rebuild → run the shared harness gate in a fresh
subprocess — must report byte-identical:
python3 scripts/gen_capability_broker_gap_truth.py # self-verifies
Standalone re-verify later (fixture rebuilt first):
python3 scripts/gen_capability_broker_gap_truth.py --setup
RUNE_HOME=/tmp/rune_cb_truth_home \
RUNE_SCRIPTS_DIR=/tmp/rune_cb_truth_home/src/rune \
RUNE_CAPABILITY_BROKER_CORE=python \
python3 scripts/freeze_truth.py --verify \
src/rust/capability_broker/frozen_gap_truth.json \
--module rune.capability_broker
Excluded from the envelope (documented seams, not oracle-freezable — no
absolute paths, no live module handles): `_cs_core`'s Some arm (returns the
cs_loader module, not JSON — the pinned-None arm is asserted by the
both-pins pytest and the kernel mirror by the Rust battery) and the
corrupt-file / OSError arms of load_cards (seam battery + the live parity
script drive those against dual fixtures). No absolute path appears in the
frozen truth.
"""
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
os.environ["RUNE_CAPABILITY_BROKER_CORE"] = "python" # poisoned-truth law
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "scripts"))
HOME = Path("/tmp/rune_cb_truth_home")
OUT = REPO / "src" / "rust" / "capability_broker" / "frozen_gap_truth.json"
FROZEN_NOW = "2026-10-13T10:47:50Z"
# Fixture env MUST precede the oracle import (module constants resolve at
# import time through memory_env).
os.environ["RUNE_HOME"] = str(HOME)
os.environ["RUNE_SCRIPTS_DIR"] = str(HOME / "src" / "rune")
SYNTHETIC_REGISTRY = {
"plugins": {
"hooked": {
"manifest": {
"name": "hooked",
"description": "recall and store memory facts",
"capabilities": ["memory_recall", "memory_write"],
"hooks": {"on_message": "handle_hook"},
"priority": 10,
"_file": "plugins/hooked/main.py",
},
"registered_at": "2026-10-13T01:02:03",
"active": True,
},
"verifier": {
"manifest": {
"name": "verifier",
"description": "verify this claim and detect drift",
"capabilities": ["claim_verification"],
"priority": 20,
"_file": "main.py",
},
},
"verbose": {
"manifest": {
"name": "verbose",
"description": "search, search, and search the store again, "
"then validate, audit, and extract",
"capabilities": ["abstraction"],
"priority": 40,
},
},
"plain": {
"manifest": {
"name": "plain",
"description": "route this task",
"capabilities": ["warm_routing"],
},
},
"unicode": {
"manifest": {
"name": "unicode",
"description": "Vérifiez les mémoires récemment écrites",
"capabilities": ["research"],
"priority": 2.5,
},
},
"empty_manifest": {"manifest": {}, "active": False},
"no_manifest": {"active": False},
"default_priority": {
"manifest": {
"name": "default_priority",
"description": "compile the constitution",
"capabilities": [],
}
},
}
}
# Seeded BEFORE the registry so the staleness arms are deterministic:
STALE_CARDS_SEED = [
{
"name": "zed",
"description": "old seeded card for a retired plugin",
"capabilities": ["zed_cap"],
"file": "zed.py",
"full_path": "plugins/zed/zed.py",
"priority": 3,
"semantic_examples": [],
"risk": "read-only",
"auto_invoked": False,
"hooks": [],
"searchable_text": "zed old seeded card zed_retired_cap",
}
]
# both fixture mtimes are PINNED to fixed epochs (os.utime) — wall-clock
# timing luck in adjacent writes is never part of the truth. The rebuild
# in the case sequence rewrites the index with a real (necessarily later)
# mtime, flipping staleness deterministically.
FIXED_SEED_MTIME = 1_000_000_000.0
FIXED_REGISTRY_MTIME = 1_000_000_100.0
def build_fixture() -> None:
shutil.rmtree(HOME, ignore_errors=True)
(HOME / "src" / "rune").mkdir(parents=True)
(HOME / "memory" / "index").mkdir(parents=True)
cards_file = HOME / "memory" / "index" / "capability_cards.json"
cards_file.write_text(json.dumps(STALE_CARDS_SEED, indent=2))
registry_file = HOME / "src" / "rune" / ".microkernel.json"
registry_file.write_text(json.dumps(SYNTHETIC_REGISTRY, indent=2))
os.utime(cards_file, (FIXED_SEED_MTIME, FIXED_SEED_MTIME))
os.utime(registry_file, (FIXED_REGISTRY_MTIME, FIXED_REGISTRY_MTIME))
def main() -> int:
if len(sys.argv) > 1 and sys.argv[1] == "--setup":
build_fixture()
print(f"canonical seed fixture rebuilt at {HOME}")
return 0
from rune import capability_broker as cb
from freeze_truth import freeze, write_envelope
build_fixture()
hooked_card = cb.generate_card(
"hooked", dict(SYNTHETIC_REGISTRY["plugins"]["hooked"]["manifest"])
)
cases = [
# ── staleness + rebuild chain over the fixture home ───────────────
("_cards_are_stale", [], {}), # registry newer than the seed
("load_cards", [], {}), # atomic rebuild: plugin + native cards
("_cards_are_stale", [], {}), # cards now newer
("load_cards", [], {}), # fresh read of the rebuilt index
("build_cards", [], {}), # plugin cards only
("load_registry", [], {}),
("_native_tool_schemas", [], {}),
# ── generate_card (pure — manifest corpus) ────────────────────────
("generate_card", [
"hooked",
dict(SYNTHETIC_REGISTRY["plugins"]["hooked"]["manifest"]),
]),
("generate_card", ["bare_name", {}]),
("generate_card", [
"many_verbs",
{"description": "search, search, and search the store again, "
"then validate, audit, and extract", "capabilities": ["unknown_cap"]},
]),
("generate_card", [
"capped_examples",
{"description": "covers many known caps",
"capabilities": ["memory_recall", "memory_write", "memory_search"]},
]),
("generate_card", [
"empty_hooks",
{"description": "recall something", "capabilities": ["memory_recall"],
"hooks": {}},
]),
("generate_card", [
"flat_file",
{"description": "verify this", "capabilities": [], "_file": "main.py",
"priority": 7},
]),
("generate_card", [
"empty_file", {"description": "", "capabilities": [], "_file": ""},
]),
("generate_card", [
"float_priority",
{"description": "assess the runtime", "capabilities": [], "priority": 2.5},
]),
("generate_card", [
"unicode",
dict(SYNTHETIC_REGISTRY["plugins"]["unicode"]["manifest"]),
]),
("generate_card", ["no_caps_no_hooks", {"description": "route the task"}]),
("generate_card", ["", {"description": "route me", "capabilities": []}]),
("generate_card", [
"verb_str_caps",
{"description": "letter iteration is legal on str caps",
"capabilities": "abc"},
]),
# ── _py_score_card happy arm (cs core delegation) ─────────────────
("_py_score_card", [dict(hooked_card), "recall memory facts"]),
("_py_score_card", [dict(hooked_card), "no keywords here"]),
# ── match_capabilities over the rebuilt index ────────────────────
("match_capabilities", ["recall and store memory facts", 5]),
("match_capabilities", ["verify this claim about drift", 3]),
("match_capabilities", ["zzz nothing matches here", 5]),
("match_capabilities", ["read a file and lint it", 2]),
# ── handle_hook branches ─────────────────────────────────────────
("handle_hook", ["other", {"message": "hello world"}]),
("handle_hook", ["on_message", {}]),
("handle_hook", ["on_message", {"message": ""}]),
("handle_hook", ["on_message", {"message": " "}]),
("handle_hook", ["on_message", {"message": "hi"}]),
("handle_hook", ["on_message", {"text": "find previous decisions about Y"}]),
("handle_hook", ["on_message", {"status": "error state"}]),
("handle_hook", ["on_message", {"message": "remember this fact and store it"}]),
]
truth = freeze("rune.capability_broker", cases, oracle_module="rune.capability_broker")
# byte-identical law: a rebuilt fixture home + a fresh oracle process
# must regenerate the same truth, case for case.
build_fixture()
truth2 = freeze("rune.capability_broker", cases, oracle_module="rune.capability_broker")
if json.dumps(truth, sort_keys=True) != json.dumps(truth2, sort_keys=True):
print("MISMATCH: truth not replayable against a rebuilt fixture home")
return 1
write_envelope(FROZEN_NOW, truth, OUT)
env = dict(os.environ)
env["PYTHONPATH"] = os.pathsep.join(
[str(REPO / "src"), str(REPO / "scripts"), env.get("PYTHONPATH", "")]
).rstrip(os.pathsep)
build_fixture()
gate = subprocess.run(
[sys.executable, str(REPO / "scripts" / "freeze_truth.py"),
"--verify", str(OUT), "--module", "rune.capability_broker"],
capture_output=True, text=True, env=env,
)
print(gate.stdout, gate.stderr)
if gate.returncode != 0:
print("VERIFY GATE FAILED")
return 1
print(f"frozen {len(truth)} cases -> {OUT} (harness gate byte-identical)")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""Open the #2479 dichotomy-wave gap-closing construction contract for
capability_broker (PARTIAL → 20/20 fn coverage). Walks draft→approved→
building in ONE process (shared-store clobber hazard). Close happens after
the two landings are pushed, with SHA evidence (close_contract_gap_cb.py).
Usage: open_contract_gap_cb.py
"""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from rune.construction_interface import ConstructionInterface
iface = ConstructionInterface(builder="factory-gap-cb")
r = iface.submit_need(
"Close capability_broker PARTIAL gaps (dichotomy wave, issue #2479 "
"tranche): port the 10 audit-missing functions name-preserving into "
"the existing Rust crate (_native_tool_schemas, load_registry, "
"_cards_are_stale, load_cards, generate_card, build_cards, _cs_core, "
"_py_score_card, match_capabilities, handle_hook) with doc-envelope "
"FFI cb_* (cs_free_string shared via capability_scoring, never "
"re-exported), ctypes loader mirroring broker_loader.py, facade "
"delegation with RUNE_CAPABILITY_BROKER_CORE=python pin; frozen-truth "
"battery via the shared freeze_truth.py harness replayed VERBATIM in "
"a cfg(test) battery; live parity 100% on the new fns; Phase B "
"language-advantage pass.",
origin="builder",
)
print("submit_need:", json.dumps(r)[:400])
if not r.get("success"):
print("NEED FAILED — aborting")
sys.exit(1)
c = r["ids"]["contract_id"]
print("contract_id:", c)
for phase in ("approved", "building"):
t = iface.transition(c, phase)
print(f"transition->{phase}:", json.dumps(t)[:300])
if not t.get("success"):
sys.exit(1)
print("OPENED", c)
+1 -1
View File
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
import json
from pathlib import Path
__version__ = "0.302.0"
__version__ = "0.303.0"
# One build identity (handoff 2026-09-10 §4): the semantic version above is
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
+53 -4
View File
@@ -40,10 +40,15 @@ def _load() -> ctypes.CDLL:
if not _LIB_PATH.is_file():
raise BrokerUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
lib.cs_select_for_job.argtypes = [ctypes.c_void_p]
lib.cs_select_for_job.restype = ctypes.c_void_p
lib.cs_find_capability.argtypes = [ctypes.c_void_p]
lib.cs_find_capability.restype = ctypes.c_void_p
for sym in (
"cs_select_for_job", "cs_find_capability",
"cb_native_tool_schemas", "cb_load_registry", "cb_cards_are_stale",
"cb_load_cards", "cb_generate_card", "cb_build_cards",
"cb_match_capabilities", "cb_handle_hook",
):
fn = getattr(lib, sym)
fn.argtypes = [ctypes.c_void_p]
fn.restype = ctypes.c_void_p
# free comes from capability_scoring (same process) if loaded; else our own malloc path
try:
lib.cs_free_string
@@ -84,3 +89,47 @@ def find_capability(tools: list, cards: list, query: str, top_k: int = 5) -> lis
return _call("cs_find_capability", {
"tools": tools, "cards": cards, "query": query, "top_k": top_k,
})
# ── gap-closing port surface (dichotomy wave, #2479 gap-cb tranche) ─────────
# Doc-envelope FFI cb_* mirroring the cs_* selection entries above; freedom
# through capability_scoring's cs_free_string (never re-exported here).
def native_tool_schemas(tools: list) -> dict:
return _call("cb_native_tool_schemas", {"tools": tools})
def load_registry(registry_path: str) -> dict:
return _call("cb_load_registry", {"registry_path": registry_path})
def cards_are_stale(cards_path: str, registry_path: str) -> bool:
return _call("cb_cards_are_stale", {
"cards_path": cards_path, "registry_path": registry_path,
})
def load_cards(cards_path: str, registry_path: str, tools: list) -> list:
return _call("cb_load_cards", {
"cards_path": cards_path, "registry_path": registry_path, "tools": tools,
})
def generate_card(name: str, manifest: dict) -> dict:
return _call("cb_generate_card", {"name": name, "manifest": manifest})
def build_cards(registry_path: str) -> list:
return _call("cb_build_cards", {"registry_path": registry_path})
def match_capabilities(cards: list, query: str, top_k: int = 5) -> list:
return _call("cb_match_capabilities", {
"cards": cards, "query": query, "top_k": top_k,
})
def handle_hook(event: str, data: dict, cards: list) -> dict:
return _call("cb_handle_hook", {
"event": event, "data": data, "cards": cards,
})
+1 -1
View File
@@ -233,7 +233,7 @@ def main() -> int:
)
check(
"Rune minor version advertises provisioning and restore verification",
'__version__ = "0.302.0"' in rune_version,
'__version__ = "0.303.0"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+67
View File
@@ -62,6 +62,12 @@ def _native_tool_schemas():
from tool_executor import TOOLS
except Exception: # noqa: BLE001 — deliberate: best-effort degrade (logged or continued); crash would be worse
return {}
# Kernel-first law has ONE carve-out: select_for_job rehydrates its
# selection from this dict BY IDENTITY (the full schema objects, not
# slim FFI copies) — an FFI round-trip breaks object identity for zero
# computational gain. The Rust port (gap::_native_tool_schemas) stays
# battery- and parity-pinned for the stage-3 burn when TOOLS leaves
# Python; the facade keeps the object graph native.
return {tool["name"]: tool for tool in TOOLS if isinstance(tool.get("name"), str)}
@@ -433,6 +439,13 @@ RISK_MAP = {
def load_registry():
"""Load the microkernel registry."""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
return broker_loader.load_registry(REGISTRY)
except Exception:
logger.debug("broker core unavailable - Python load_registry", exc_info=True)
if not os.path.exists(REGISTRY):
return {}
with open(REGISTRY) as f:
@@ -493,6 +506,13 @@ def _cards_are_stale():
A missing registry can never make cards stale — there is nothing
newer to rebuild from (native cards are synthesized from TOOLS).
"""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
return broker_loader.cards_are_stale(CARDS_FILE, REGISTRY)
except Exception:
logger.debug("broker core unavailable - Python staleness", exc_info=True)
if not os.path.exists(REGISTRY):
return False
try:
@@ -512,6 +532,22 @@ def load_cards():
is older than the registry it was generated from. Native-tool cards
are always synthesized so selection has full tool coverage.
"""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
tools = []
try:
try:
from rune.tool_executor import TOOLS
except ImportError: # direct script execution
from tool_executor import TOOLS
tools = list(TOOLS)
except Exception: # noqa: BLE001 — degrade-not-crash: the oracle rebuilds without native cards too
pass
return broker_loader.load_cards(CARDS_FILE, REGISTRY, tools)
except Exception:
logger.debug("broker core unavailable - Python load_cards", exc_info=True)
needs_rebuild = True
if os.path.exists(CARDS_FILE):
try:
@@ -549,6 +585,13 @@ def load_cards():
def generate_card(name, manifest):
"""Generate a capability card from a plugin manifest."""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
return broker_loader.generate_card(name, manifest)
except Exception:
logger.debug("broker core unavailable - Python generate_card", exc_info=True)
desc = manifest.get("description", "")
caps = manifest.get("capabilities", [])
hooks = manifest.get("hooks", {})
@@ -603,6 +646,13 @@ def generate_card(name, manifest):
def build_cards():
"""Generate plugin cards from the microkernel registry (native cards
are appended by load_cards so plugin-only rebuilds stay pure)."""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
return broker_loader.build_cards(REGISTRY)
except Exception:
logger.debug("broker core unavailable - Python build_cards", exc_info=True)
reg = load_registry()
plugins = reg.get("plugins", {})
cards = []
@@ -654,6 +704,13 @@ def _py_score_card(card, query):
def match_capabilities(query, top_k=5):
"""Find the most relevant capabilities for a query."""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available():
return broker_loader.match_capabilities(load_cards(), str(query), int(top_k))
except Exception:
logger.debug("broker core unavailable - Python match", exc_info=True)
cards = load_cards()
scored = []
for card in cards:
@@ -717,6 +774,16 @@ def find_capability(query, top_k=5):
def handle_hook(event, data=None):
"""On-message hook: find relevant capabilities for the user's message."""
if os.environ.get("RUNE_CAPABILITY_BROKER_CORE", "auto") != "python":
try:
from rune import broker_loader
if broker_loader.available() and isinstance(event, str) and (
data is None or isinstance(data, dict)
):
cards = load_cards()
return broker_loader.handle_hook(event, {} if data is None else data, cards)
except Exception:
logger.debug("broker core unavailable - Python hook", exc_info=True)
if event == "on_message" and data:
message = data.get("message", "") or data.get("text", "") or str(data)
if message and len(message.strip()) > 2:
+2 -2
View File
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
This is not an interface. This is how I see, speak, and interact with the world.
Version: v0.302.0
Version: v0.303.0
Features: 41 (24 original + 17 new native commands)
Usage:
@@ -2037,7 +2037,7 @@ class RuneApp(App):
# Show version info
self.chat_channel.add_message(
"system",
f"[dim]Rune v0.302.0 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.303.0 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
File diff suppressed because it is too large. Load diff
+8 -2
View File
@@ -71,9 +71,15 @@ pub fn synthesize_card(tool: &Json) -> Json {
};
let searchable = format!("{} {} native tool", name, description).to_lowercase();
Json::Obj(vec![
("name".into(), Json::Str(name)),
("name".into(), Json::Str(name.clone())),
("description".into(), Json::Str(description)),
("capabilities".into(), Json::Arr(vec![])),
// oracle law (capability_broker._native_tool_cards): the card's
// capabilities list is exactly [name] — the batch-1 battery pinned
// only names/reason/task_family, so it could not catch this.
(
"capabilities".into(),
Json::Arr(vec![Json::Str(name.clone())]),
),
("file".into(), Json::Str("tool_executor.py".into())),
("full_path".into(), Json::Str(String::new())),
("priority".into(), Json::Num(100.0)),
+809
View File
@@ -0,0 +1,809 @@
//! gap.rs — dichotomy-wave PARTIAL→gap-closing port (contract
//! BUILDER-2026-10-13T16:01:25Z-9b9389-factory-gap-cb, issue #2479 tranche).
//!
//! The ten audit-missing functions of src/rune/capability_broker.py, ported
//! name-preserving and logic-1:1 against the live Python oracle:
//! `_native_tool_schemas`, `load_registry`, `_cards_are_stale`, `load_cards`,
//! `generate_card`, `build_cards`, `_cs_core`, `_py_score_card`,
//! `match_capabilities`, `handle_hook`.
//!
//! Laws (mirroring structural_store/gap.rs):
//! * no-env / no-path: every path arrives as an argument; the facade reads
//! RUNE_CAPABILITY_BROKER_CORE (the freeze harness law) and mirrors the
//! `CsCore` probe contract kernel-side
//! * file I/O behind the injectable [`CbIo`] seam (tests use a driven seam;
//! the FFI layer installs [`StdIo`])
//! * Python-parity JSON on the wire (the crate's pyjson shared law:
//! pyjson::dump_indent2 == json.dump(v, indent=2), ensure_ascii,
//! preserved key order)
//! * `handle_hook`'s `str(data)` fallback arm reproduces Python object
//! repr for the JSON shapes the hook payloads use (dict/list/str/num/
//! bool/None)
use capability_scoring::pyjson::{self, Json};
use capability_scoring::scoring::score_card;
use std::fmt::Write as _;
// ── oracle tables (transcribed verbatim, order preserved) ───────────────────
/// SEMANTIC_EXAMPLES — the oracle dict, insertion order preserved.
pub const SEMANTIC_EXAMPLES: &[(&str, &[&str])] = &[
("memory_recall", &["What do I remember about X?", "Have we discussed this before?", "Find previous decisions about Y.", "What do I know about Z?"]),
("memory_write", &["Remember this fact.", "Store this for later.", "Save this decision."]),
("memory_search", &["Search my memory for X.", "Look up anything about Y."]),
("claim_verification", &["Is this claim supported?", "Verify this statement.", "Check if this is accurate."]),
("warm_routing", &["What context is relevant?", "Prime my memory for this topic."]),
("persona_compile", &["Who am I?", "What are my values?", "Load my identity."]),
("drift_detection", &["Am I drifting from my identity?", "Check for persona drift."]),
("growth_extraction", &["What should I learn from this?", "Extract behavioral deltas."]),
("harness_validation", &["Is my harness compliant?", "Validate my runtime."]),
("epub", &["Read this ebook.", "Extract text from this epub."]),
("tasks", &["What are my current tasks?", "Persist this task.", "Show my task list."]),
("politics", &["What do I know about this political topic?", "Absorb this political understanding."]),
("abstraction", &["Extract facts from this text.", "What observations can you make?", "Synthesize knowledge from this.", "What patterns do you see?"]),
("temporal", &["What was true then vs now?", "When did this change?", "Is this still current?", "Show me the history of this."]),
("corrections", &["I corrected you on this before.", "Don't do that again.", "Remember this correction."]),
("habits", &["You should do this automatically.", "Make this a habit.", "Remember this pattern."]),
("cache", &["Cache this result.", "Is this cached?", "Clear the cache."]),
("events", &["What events have happened?", "Show me the event log.", "What changed recently?"]),
("benchmark", &["Run the benchmark.", "Test the system.", "Check for regressions."]),
("identity", &["Sign this file.", "Verify this signature.", "Show my agent ID."]),
("agent_profiles", &["Switch to blank agent.", "Create a test profile.", "Restore Rune profile."]),
("voice_sync", &["Sync the voice.", "Update the system prompt.", "Is the prompt in sync?"]),
("prompt_sync", &["Sync the system prompt.", "Derive prompt from store.", "Is the prompt current?"]),
("context_pressure", &["How full is the context?", "Am I running out of context?", "Check context pressure."]),
("model_routing", &["Which model should I use?", "Route this task.", "What's the best model for this?"]),
("witness", &["What did you learn from this?", "Reflect on what happened.", "What signals did you detect?"]),
("task_gate", &["I've told you this before.", "This should be automatic.", "Make this a standard process.", "Remember this instruction."]),
("self_improve", &["What needs improvement?", "Analyze the system state.", "What's not working?", "Suggest improvements."]),
("task_persist", &["Save this task for later.", "What tasks are pending?", "Show my task list.", "Update task status."]),
("deep_research", &["Research this topic thoroughly.", "Help me investigate this.", "Find information about this.", "Look into this subject."]),
("research_lens", &["Is this claim supported by evidence?", "Check this against the baloney detector.", "Verify this research."]),
("epistemic_verify", &["Is this actually true?", "Verify this claim.", "Check the evidence."]),
];
/// RISK_MAP — the oracle dict, insertion order preserved.
pub const RISK_MAP: &[(&str, &str)] = &[
("memory_recall", "read-only"),
("memory_search", "read-only"),
("memory_stats", "read-only"),
("memory_write", "write"),
("claim_verification", "read-only"),
("evidence_check", "read-only"),
("warm_routing", "read-only"),
("neuron_firing", "read-only"),
("always_on_digest", "read-only"),
("persona_compile", "read-only"),
("identity_serve", "read-only"),
("constitution_serve", "read-only"),
("drift_detection", "read-only"),
("drift_autofix", "write"),
("identity_check", "read-only"),
("sycophancy_check", "read-only"),
("genuineness_check", "read-only"),
("memory_write_governance", "write"),
("evidence_gating", "read-only"),
("coherence_check", "read-only"),
("growth_extraction", "write"),
("behavioural_delta", "write"),
("harness_validation", "read-only"),
("harness_audit", "read-only"),
("harness_policy", "read-only"),
("environment_assessment", "read-only"),
("task_planning", "read-only"),
("epub", "read-only"),
("extraction", "read-only"),
("text", "read-only"),
("tasks", "write"),
("persistence", "write"),
("politics", "read-only"),
("research", "read-only"),
("reasoning", "read-only"),
("status", "read-only"),
];
/// The `\b(recall|search|...|find)\b` verb alternation of
/// generate_card, as whole-`\w`-token equals (each alternative is a
/// complete word token, so token-level equality is exact).
pub const CARD_VERBS: &[&str] = &[
"recall", "search", "verify", "check", "write", "store", "detect", "audit",
"extract", "route", "compile", "validate", "assess", "build", "list", "show",
"find",
];
// ── the core probe (facade `_cs_core` mirror, _ss_core law) ─────────────────
/// The Rust capability_scoring core — the thing `cs_loader` activates when
/// the facade probe allows it. `RUNE_CAPABILITY_CORE=python` pins the
/// Python fallback; any other value (including unset/auto) activates this
/// core.
pub struct CsCore;
impl CsCore {
pub fn id(&self) -> &'static str {
"rust"
}
/// The kernel's score card — the same scoring crate the Python
/// cs_loader FFI reaches, in-process (language-advantage delegation).
pub fn score_card(&self, card: &Json, query: &str) -> f64 {
capability_scoring::scoring::score_card(card, query)
}
}
/// Facade probe contract, kernel mirror: `None` = Python fallback pinned.
#[allow(non_snake_case)]
pub fn _cs_core(pin: Option<&str>) -> Option<CsCore> {
match pin {
Some("python") => None,
_ => Some(CsCore),
}
}
/// Facade probe contract, kernel mirror — the strangler-exit stub:
/// delegation-only; the pinned-None arm carries the oracle's fixed error
/// contract (raised by the Python facade, mirrored here for shape).
#[allow(non_snake_case)]
pub fn _py_score_card(card: &Json, query: &str) -> Result<f64, String> {
match _cs_core(None) {
Some(core) => Ok(core.score_card(card, query)),
None => Err(
"capability_scoring kernel not built — run the capability_scoring build; the Python oracle was retired"
.into(),
),
}
}
// ── injectable I/O seam ─────────────────────────────────────────────────────
/// The card-file I/O seam: load_registry/_cards_are_stale/load_cards never
/// touch the filesystem directly — the FFI layer installs [`StdIo`], tests
/// install driven seams.
pub trait CbIo {
fn exists(&self, path: &str) -> bool;
fn read(&self, path: &str) -> Result<String, String>;
/// os.path.getmtime — `None` mirrors the OSError arm (missing/unreadable).
fn mtime(&self, path: &str) -> Option<f64>;
fn mkdir_parents(&self, dir: &str) -> Result<(), String>;
fn write_text(&self, path: &str, contents: &str) -> Result<(), String>;
fn replace(&self, from: &str, to: &str) -> Result<(), String>;
fn remove(&self, path: &str) -> Result<(), String>;
}
pub struct StdIo;
impl CbIo for StdIo {
fn exists(&self, path: &str) -> bool {
std::path::Path::new(path).exists()
}
fn read(&self, path: &str) -> Result<String, String> {
std::fs::read_to_string(path).map_err(|e| format!("read {}: {}", path, e))
}
fn mtime(&self, path: &str) -> Option<f64> {
std::fs::metadata(path)
.and_then(|m| m.modified())
.ok()
.and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
.map(|d| d.as_secs_f64())
}
fn mkdir_parents(&self, dir: &str) -> Result<(), String> {
std::fs::create_dir_all(dir).map_err(|e| format!("mkdir {}: {}", dir, e))
}
fn write_text(&self, path: &str, contents: &str) -> Result<(), String> {
std::fs::write(path, contents).map_err(|e| format!("write {}: {}", path, e))
}
fn replace(&self, from: &str, to: &str) -> Result<(), String> {
std::fs::rename(from, to).map_err(|e| format!("replace {} -> {}: {}", from, to, e))
}
fn remove(&self, path: &str) -> Result<(), String> {
std::fs::remove_file(path).map_err(|e| format!("remove {}: {}", path, e))
}
}
// ── helpers ─────────────────────────────────────────────────────────────────
pub fn obj_get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
match v {
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
_ => None,
}
}
fn obj_get_str<'a>(v: &'a Json, key: &str) -> Option<&'a str> {
match obj_get(v, key) {
Some(Json::Str(s)) => Some(s.as_str()),
_ => None,
}
}
// ── _native_tool_schemas port ───────────────────────────────────────────────
/// `{tool["name"]: tool for tool in TOOLS if isinstance(tool.get("name"), str)}`
/// — the TOOLS import stays Python-side (facade passes the list across the
/// FFI). Later duplicate names win the value but keep the first slot's
/// position (Python dict comprehension exactly).
#[allow(non_snake_case)]
pub fn _native_tool_schemas(tools: &[Json]) -> Json {
let mut pairs: Vec<(String, Json)> = Vec::new();
for tool in tools {
let name = match obj_get_str(tool, "name") {
Some(n) => n.to_string(),
// non-str name — isinstance filter drops the entry
None => continue,
};
if let Some(slot) = pairs.iter_mut().find(|(k, _)| *k == name) {
slot.1 = tool.clone();
} else {
pairs.push((name, tool.clone()));
}
}
Json::Obj(pairs)
}
// ── load_registry port ──────────────────────────────────────────────────────
/// Micro-registry loader: the missing file is the empty dict; a corrupt
/// file raises (the FFI envelope's err arm carries it the way the oracle's
/// uncaught ValueError surfaces to callers).
#[allow(non_snake_case)]
pub fn load_registry(registry_path: &str, io: &dyn CbIo) -> Result<Json, String> {
if !io.exists(registry_path) {
return Ok(Json::Obj(vec![]));
}
let text = io.read(registry_path)?;
pyjson::parse(&text)
}
// ── _cards_are_stale port ───────────────────────────────────────────────────
/// Pure decision over the injected staleness inputs:
/// a missing registry can never make cards stale; an unreadable cards
/// file is the rebuild trigger; otherwise cards are stale when older than
/// the registry.
#[allow(non_snake_case)]
pub fn _cards_are_stale(
registry_exists: bool,
cards_mtime: Option<f64>,
registry_mtime: Option<f64>,
) -> bool {
if !registry_exists {
return false;
}
match (cards_mtime, registry_mtime) {
(Some(c), Some(r)) => c < r,
// OSError arm: unreadable cards/registry file → rebuild is the safe move
_ => true,
}
}
// ── generate_card port ──────────────────────────────────────────────────────
fn semantic_examples_for(cap: &str) -> Option<&'static [&'static str]> {
SEMANTIC_EXAMPLES
.iter()
.find(|(k, _)| *k == cap)
.map(|(_, v)| *v)
}
fn risk_for(caps: &[String]) -> &'static str {
for cap in caps {
if let Some((_, "write")) = RISK_MAP.iter().find(|(k, _)| k == cap) {
return "write";
}
}
"read-only"
}
/// Python object repr for the JSON shapes hook payloads use
/// (handle_hook's `str(data)` fallback arm).
pub fn py_repr(v: &Json) -> String {
match v {
Json::Null => "None".into(),
Json::Bool(true) => "True".into(),
Json::Bool(false) => "False".into(),
Json::Num(n) => pyjson::fmt_num(*n),
Json::Str(s) => py_repr_str(s),
Json::Arr(items) => {
let mut out = String::from("[");
for (i, item) in items.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
out.push_str(&py_repr(item));
}
out.push(']');
out
}
Json::Obj(pairs) => {
let mut out = String::from("{");
for (i, (k, val)) in pairs.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
let _ = write!(out, "{}: {}", py_repr_str(k), py_repr(val));
}
out.push('}');
out
}
}
}
/// Python `repr()` of a str: single-quote preferred, double-quoted when the
/// string contains ' but not ", with the ASCII control escapes.
fn py_repr_str(s: &str) -> String {
let quote = if s.contains('\'') && !s.contains('"') {
'"'
} else {
'\''
};
let mut out = String::new();
out.push(quote);
for ch in s.chars() {
match ch {
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
'\\' => out.push_str("\\\\"),
c if c == quote => {
out.push('\\');
out.push(c);
}
c if (c as u32) < 0x20 => {
let _ = write!(out, "\\x{:02x}", c as u32);
}
c => out.push(c),
}
}
out.push(quote);
out
}
/// re.findall of the verb alternation over the lowercased description:
/// maximal \w-runs equal to a verb, in order, duplicates preserved.
fn find_verbs(lower_desc: &str) -> Vec<&'static str> {
let bytes = lower_desc.as_bytes();
let is_word = |c: u8| c.is_ascii_alphanumeric() || c == b'_';
let mut verbs = Vec::new();
let mut i = 0;
while i < bytes.len() {
if is_word(bytes[i]) {
let start = i;
while i < bytes.len() && is_word(bytes[i]) {
i += 1;
}
let tok = &lower_desc[start..i];
if let Some(v) = CARD_VERBS.iter().find(|v| **v == tok) {
verbs.push(*v);
}
} else {
i += 1;
}
}
verbs
}
/// Capability values in manifest.get("capabilities", []) iteration order:
/// Python iterates str values char-wise (findall over a str caps field is
/// legal); anything else raises (the TypeError arm → envelope err).
fn cap_iter(caps: &Json) -> Result<Vec<String>, String> {
match caps {
Json::Arr(items) => {
let mut out = Vec::new();
for item in items {
match item {
Json::Str(s) => out.push(s.clone()),
_ => return Err("cannot join non-str capability".into()),
}
}
Ok(out)
}
// a str capabilities field iterates CHARACTER-wise in Python
Json::Str(s) => Ok(s.chars().map(|c| c.to_string()).collect()),
Json::Null => Ok(vec![]),
_ => Err("capabilities is not iterable".into()),
}
}
fn hooks_keys(hooks: &Json) -> Result<(bool, Vec<String>), String> {
match hooks {
Json::Obj(pairs) => Ok((!pairs.is_empty(), pairs.iter().map(|(k, _)| k.clone()).collect())),
// non-dict hooks: bool() is legal but the oracle crashes on
// hooks.keys() in the card build — the TypeError arm.
_ => Err("'hooks' object has no attribute 'keys'".into()),
}
}
fn manifest_field_str<'a>(m: &'a Json, key: &str, default: &'a str) -> Result<&'a str, String> {
match obj_get(m, key) {
Some(Json::Str(s)) => Ok(s.as_str()),
Some(_) => Err(format!("manifest field '{}' must be a str", key)),
None => Ok(default),
}
}
/// Card generator from a plugin manifest (oracle generate_card, 1:1).
/// Note the oracle carries the RAW capabilities value into the card (a str
/// caps field iterates char-wise for the derived fields but the card keeps
/// the original value), while the examples/risk loops iterate it.
#[allow(non_snake_case)]
pub fn generate_card(name: &str, manifest: &Json) -> Result<Json, String> {
let description = manifest_field_str(manifest, "description", "")?;
let caps_v = match obj_get(manifest, "capabilities") {
Some(v) => v.clone(),
None => Json::Arr(vec![]),
};
let caps: Vec<String> = if obj_get(manifest, "capabilities").is_none() {
vec![]
} else {
cap_iter(&caps_v)?
};
let hooks_v = match obj_get(manifest, "hooks") {
Some(v) => v.clone(),
None => Json::Obj(vec![]),
};
let file_path = manifest_field_str(manifest, "_file", "")?;
let priority = match obj_get(manifest, "priority") {
Some(Json::Num(n)) => *n,
Some(_) => return Err("manifest field 'priority' must be a number".into()),
None => 100.0,
};
// Generate semantic examples from capabilities
let mut examples: Vec<String> = Vec::new();
for cap in &caps {
if let Some(exs) = semantic_examples_for(cap) {
examples.extend(exs.iter().map(|s| s.to_string()));
}
}
// If no predefined examples, generate from description verbs
if examples.is_empty() && !description.is_empty() {
for verb in find_verbs(&description.to_lowercase()).iter().take(3) {
let mut e = String::new();
let mut c = verb.chars();
if let Some(first) = c.next() {
let _ = write!(e, "{}{}", first.to_ascii_uppercase(), c.as_str());
}
e.push_str(" something relevant");
examples.push(e);
}
}
// Determine risk level
let risk = risk_for(&caps);
// Determine if automatically invoked
let (auto, hook_names) = hooks_keys(&hooks_v)?;
let file = if !file_path.is_empty() {
file_path.rsplit('/').next().unwrap_or("").to_string()
} else {
String::new()
};
let searchable = format!(
"{} {} {} {}",
name,
description,
caps.join(" "),
examples.join(" ")
)
.to_lowercase();
Ok(Json::Obj(vec![
("name".into(), Json::Str(name.into())),
("description".into(), Json::Str(description.into())),
// the RAW capabilities value — the oracle's card field is the
// manifest's original, not the iterated copy
("capabilities".into(), caps_v.clone()),
("file".into(), Json::Str(file)),
("full_path".into(), Json::Str(file_path.into())),
("priority".into(), Json::Num(priority)),
(
"semantic_examples".into(),
Json::Arr(
examples
.iter()
.take(5)
.map(|e| Json::Str(e.clone()))
.collect(),
),
),
("risk".into(), Json::Str(risk.into())),
("auto_invoked".into(), Json::Bool(auto)),
(
"hooks".into(),
Json::Arr(hook_names.iter().map(|h| Json::Str(h.clone())).collect()),
),
("searchable_text".into(), Json::Str(searchable)),
]))
}
// ── build_cards port ────────────────────────────────────────────────────────
/// Plugin cards from a REGISTRY VALUE (the registry text/parse stays
/// load_registry's law so plugin-only rebuilds stay pure). Native cards are
/// appended by load_cards.
#[allow(non_snake_case)]
pub fn build_cards(registry: &Json) -> Result<Json, String> {
let plugins = match obj_get(registry, "plugins") {
Some(Json::Obj(p)) => p,
None => {
// reg.get("plugins", {}) — missing → empty dict → no cards
return Ok(Json::Arr(vec![]));
}
Some(_) => return Err("'dict' object has no attribute 'items'".into()),
};
let mut cards: Vec<Json> = Vec::new();
for (name, data) in plugins {
let manifest = match data {
Json::Obj(_) => {
let empty = Json::Obj(vec![]);
obj_get(data, "manifest").unwrap_or(&empty).clone()
}
// data.get on a non-dict raises — the AttributeError arm
_ => return Err("'dict' object has no attribute 'get'".into()),
};
let nonempty = matches!(&manifest, Json::Obj(p) if !p.is_empty());
if nonempty {
cards.push(generate_card(name, &manifest)?);
}
}
// Sort by priority (stable — Python sort of c.get("priority", 100))
cards.sort_by(|a, b| {
let pa = match obj_get(a, "priority") {
Some(Json::Num(n)) => *n,
_ => 100.0,
};
let pb = match obj_get(b, "priority") {
Some(Json::Num(n)) => *n,
_ => 100.0,
};
pa.partial_cmp(&pb).unwrap_or(std::cmp::Ordering::Equal)
});
Ok(Json::Arr(cards))
}
// ── _native_tool_cards port (cards synthesis for the rebuild path) ─────────
/// Synthesize a card per native tool schema (oracle _native_tool_cards).
/// Calls the batch-1 kernel's synth so the two ports stay one law; the
/// name-skip loop above it is the gap-closing port surface.
#[allow(non_snake_case)]
pub fn _native_tool_cards(tools: &[Json]) -> Vec<Json> {
use crate::broker::synthesize_card;
let mut cards = Vec::new();
for tool in tools {
let name = match obj_get(tool, "name") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
if name.is_empty() {
continue;
}
cards.push(synthesize_card(tool));
}
cards
}
// ── load_cards port ─────────────────────────────────────────────────────────
/// Card-index loader with the full rebuild contract: rebuild when the file
/// is missing, empty, corrupt JSON, or older than its registry; the rebuild
/// write is atomic (sibling tmp + replace) and degrades to read-only
/// (cards still returned from memory) when the dir is unwritable.
///
/// `tools` is the native-tool metadata list (the TOOLS import stays
/// Python-side / FFI-passed — no imports in the kernel).
#[allow(non_snake_case)]
pub fn load_cards(
cards_path: &str,
registry_path: &str,
tools: &[Json],
io: &dyn CbIo,
) -> Result<Json, String> {
let mut needs_rebuild = true;
if io.exists(cards_path) {
match io.read(cards_path) {
Ok(text) => match pyjson::parse(&text) {
Ok(existing) => {
let valid_list = match &existing {
Json::Arr(items) => !items.is_empty(),
_ => false,
};
needs_rebuild = !valid_list;
if !needs_rebuild {
needs_rebuild = _cards_are_stale(
io.exists(registry_path),
io.mtime(cards_path),
io.mtime(registry_path),
);
}
}
// corrupt file (json.JSONDecodeError)
Err(_) => needs_rebuild = true,
},
// OSError reading the existing file → corrupt-file arm
Err(_) => needs_rebuild = true,
}
}
if needs_rebuild {
let reg = load_registry(registry_path, io)?;
let cards_v = build_cards(&reg)?;
let mut cards = match cards_v {
Json::Arr(a) => a,
_ => vec![],
};
cards.extend(_native_tool_cards(tools));
let tmp_file = format!("{}.tmp", cards_path);
let dir = std::path::Path::new(cards_path)
.parent()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default();
// Atomic rebuild write; OSError degrades to in-memory selection.
// The oracle calls makedirs(dirname) unconditionally — an empty
// dirname raises FileNotFoundError, which is the same OSError arm.
let write_result = (|| -> Result<(), String> {
io.mkdir_parents(&dir)?;
io.write_text(&tmp_file, &pyjson::dump_indent2(&Json::Arr(cards.clone())))?;
io.replace(&tmp_file, cards_path)
})();
if write_result.is_err() {
let _ = io.remove(&tmp_file);
}
return Ok(Json::Arr(cards));
}
let text = io.read(cards_path)?;
pyjson::parse(&text)
}
// ── match_capabilities port ─────────────────────────────────────────────────
/// Most-relevant cards for a query: score_card over the loaded cards,
/// score > 0 only, STABLE sort by descending score (ties keep card order —
/// the Python `sort(key=lambda x: -x[0])` law).
#[allow(non_snake_case)]
pub fn match_capabilities(cards: &[Json], query: &str, top_k: usize) -> Json {
let mut scored: Vec<(f64, Json)> = Vec::new();
for card in cards {
let score = score_card(card, query);
if score > 0.0 {
scored.push((score, card.clone()));
}
}
scored.sort_by(|a, b| {
b.0.partial_cmp(&a.0)
.unwrap_or(std::cmp::Ordering::Equal)
});
Json::Arr(scored.into_iter().take(top_k).map(|(_, c)| c).collect())
}
// ── handle_hook port ────────────────────────────────────────────────────────
/// Python truthiness for hook message values (the `or`-chain arms).
fn truthy(v: &Json) -> bool {
match v {
Json::Null => false,
Json::Bool(b) => *b,
Json::Num(n) => *n != 0.0,
Json::Str(s) => !s.is_empty(),
Json::Arr(a) => !a.is_empty(),
Json::Obj(o) => !o.is_empty(),
}
}
/// On-message hook: relevant capabilities for the user's message, matches
/// reduced to {name, file, risk}. cards arrive pre-loaded (the card I/O
/// stays behind the load_cards seam).
///
/// Crash-parity law (oracle quirk #15): a truthy non-str message/text
/// reaching `.strip()` raises AttributeError OUT of the oracle (the strip
/// sits in the `if` condition, outside its try/except) — the kernel
/// surfaces that arm as an envelope err so the facade's fallback re-raises
/// the exact exception instead of silently degrading.
#[allow(non_snake_case)]
pub fn handle_hook(event: &str, data: &Json, cards: &[Json]) -> Result<Json, String> {
if event == "on_message" && truthy(data) {
let empty_str = Json::Str(String::new());
let msg_v = obj_get(data, "message").unwrap_or(&empty_str);
let message: String = if truthy(msg_v) {
match msg_v {
Json::Str(s) => s.clone(),
_ => {
return Err(format!(
"'{}' object has no attribute 'strip'",
py_type_name(msg_v)
))
}
}
} else {
let text_v = obj_get(data, "text").unwrap_or(&empty_str);
if truthy(text_v) {
match text_v {
Json::Str(s) => s.clone(),
_ => {
return Err(format!(
"'{}' object has no attribute 'strip'",
py_type_name(text_v)
))
}
}
} else {
py_repr(data)
}
};
let stripped = message.trim();
if !message.is_empty() && stripped.chars().count() > 2 {
let matches = match_capabilities(cards, &message, 3);
let reduced: Vec<Json> = match &matches {
Json::Arr(items) => items
.iter()
.map(|m| {
Json::Obj(vec![
(
"name".into(),
match obj_get(m, "name") {
Some(Json::Str(s)) => Json::Str(s.clone()),
_ => Json::Null,
},
),
(
"file".into(),
match obj_get(m, "file") {
Some(Json::Str(s)) => Json::Str(s.clone()),
_ => Json::Null,
},
),
(
"risk".into(),
match obj_get(m, "risk") {
Some(Json::Str(s)) => Json::Str(s.clone()),
_ => Json::Null,
},
),
])
})
.collect(),
_ => vec![],
};
return Ok(Json::Obj(vec![
("status".into(), Json::Str("ok".into())),
("event".into(), Json::Str(event.into())),
("handler".into(), Json::Str("capability_broker".into())),
("matches".into(), Json::Arr(reduced)),
]));
}
}
Ok(Json::Obj(vec![
("status".into(), Json::Str("ok".into())),
("event".into(), Json::Str(event.into())),
("handler".into(), Json::Str("capability_broker".into())),
]))
}
/// Python type name of a JSON value (the AttributeError text of the strip
/// crash arms: `'int' object has no attribute 'strip'`).
fn py_type_name(v: &Json) -> &'static str {
match v {
Json::Null => "NoneType",
Json::Bool(_) => "bool",
Json::Num(n) => {
if n.fract() == 0.0 {
"int"
} else {
"float"
}
}
Json::Str(_) => "str",
Json::Arr(_) => "list",
Json::Obj(_) => "dict",
}
}
@@ -0,0 +1,520 @@
//! gap battery — replays frozen_gap_truth.json VERBATIM (the freeze_truth
//! envelope) against the gap.rs ports over an equivalent fixture home, plus
//! the seam-level branch law for the arms the harness can't freeze (document
//! the divergence scope in the truth file, not here — those live in
//! scripts/check_capability_broker_gap_parity.py's dual-fixture layers).
//!
//! WARNING: STALE_CARDS_SEED is kept byte-equal with STALE_CARDS_SEED in
//! scripts/gen_capability_broker_gap_truth.py (the fixture-home replay
//! contract: oracle truth and Rust replay must rebuild the same canonical
//! home).
use crate::gap::{self, CbIo};
use capability_scoring::pyjson::{self, Json};
use std::sync::atomic::{AtomicUsize, Ordering};
const TRUTH: &str = include_str!("../frozen_gap_truth.json");
const STALE_CARDS_SEED: &str = r#"[
{
"name": "zed",
"description": "old seeded card for a retired plugin",
"capabilities": [
"zed_cap"
],
"file": "zed.py",
"full_path": "plugins/zed/zed.py",
"priority": 3,
"semantic_examples": [],
"risk": "read-only",
"auto_invoked": false,
"hooks": [],
"searchable_text": "zed old seeded card zed_retired_cap"
}
]"#;
static TMP_SEQ: AtomicUsize = AtomicUsize::new(0);
struct FixtureHome {
root: std::path::PathBuf,
registry_path: String,
cards_path: String,
}
impl Drop for FixtureHome {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.root);
}
}
fn fixture_home() -> FixtureHome {
use std::fs;
let seq = TMP_SEQ.fetch_add(1, Ordering::SeqCst);
let root = std::env::temp_dir().join(format!(
"rune-cb-gap-battery-{}-{}",
std::process::id(),
seq
));
let registry_path = root.join("src").join("rune").join(".microkernel.json");
let cards_dir = root.join("memory").join("index");
fs::create_dir_all(registry_path.parent().unwrap()).expect("registry dir");
fs::create_dir_all(&cards_dir).expect("cards dir");
// seed the cards BEFORE the registry (stale arm, fixture-home law)
fs::write(cards_dir.join("capability_cards.json"), STALE_CARDS_SEED).expect("seed cards");
FixtureHome {
root: root.clone(),
registry_path: registry_path.to_string_lossy().to_string(),
cards_path: cards_dir
.join("capability_cards.json")
.to_string_lossy()
.to_string(),
}
}
/// Deterministic staleness law: adjacent fs writes can share a coarse-clock
/// inode timestamp, so the seeded fixture mtimes are PINNED (fixed epochs,
/// mirroring the generator's os.utime) — the truth never leans on timing
/// luck. Later real writes (the atomic rebuild) are necessarily newer.
fn pin_mtime(path: &str, epoch_secs: u64) {
use std::time::Duration;
let f = std::fs::OpenOptions::new()
.write(true)
.open(path)
.expect("open for mtime pin");
f.set_modified(std::time::UNIX_EPOCH + Duration::from_secs(epoch_secs))
.expect("pin mtime");
}
fn truth_doc() -> Json {
pyjson::parse(TRUTH).expect("frozen_gap_truth.json parses")
}
fn case_field<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
gap::obj_get(v, key)
}
fn as_string(v: Option<&Json>) -> String {
match v {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
}
}
fn as_usize(v: Option<&Json>) -> usize {
match v {
Some(Json::Num(n)) => *n as usize,
_ => 0,
}
}
fn j(v: &Json) -> String {
pyjson::dumps(v)
}
fn assert_json_eq(name: &str, got: &Json, want: &Json) {
assert_eq!(
j(got),
j(want),
"case {} diverged from the frozen oracle truth",
name
);
}
/// The sequence driver: thread the fixture state across the replayable
/// script exactly as the oracle did (cards state carries case to case).
#[test]
fn gap_replays_frozen_truth_verbatim() {
let truth = truth_doc();
let cases = match case_field(&truth, "cases") {
Some(Json::Arr(a)) => a.clone(),
_ => panic!("truth envelope missing cases"),
};
let home = fixture_home();
let io = gap::StdIo;
// The registry value is carried BY the truth (value-coupled fixture):
// find load_registry's expected and materialize it as fixture bytes.
let registry = cases
.iter()
.find(|c| as_string(case_field(c, "fn")) == "load_registry")
.and_then(|c| case_field(c, "expected"))
.cloned()
.expect("load_registry case present");
std::fs::write(
&home.registry_path,
pyjson::dump_indent2(&registry),
)
.expect("write fixture registry");
// pinned staleness law (mirrors the generator's os.utime pins)
pin_mtime(&home.cards_path, 1_000_000_000);
pin_mtime(&home.registry_path, 1_000_000_100);
let tools: Vec<Json> = cases
.iter()
.find(|c| as_string(case_field(c, "fn")) == "_native_tool_schemas")
.and_then(|c| case_field(c, "expected"))
.map(|expected| match expected {
Json::Obj(pairs) => pairs.iter().map(|(_, v)| v.clone()).collect(),
_ => vec![],
})
.expect("_native_tool_schemas case present");
let mut cards: Vec<Json> = Vec::new();
for (idx, case) in cases.iter().enumerate() {
let name = as_string(case_field(case, "fn"));
let args = match case_field(case, "args") {
Some(Json::Arr(a)) => a.clone(),
_ => vec![],
};
let expected = case_field(case, "expected").expect("expected present");
let label = format!("#{} {}", idx, name);
match name.as_str() {
"_cards_are_stale" => {
let stale = gap::_cards_are_stale(
io.exists(&home.registry_path),
io.mtime(&home.cards_path),
io.mtime(&home.registry_path),
);
assert_json_eq(&label, &Json::Bool(stale), expected);
}
"load_cards" => {
let out = gap::load_cards(
&home.cards_path,
&home.registry_path,
&tools,
&io,
)
.unwrap_or_else(|e| panic!("{}: load_cards errored: {}", label, e));
cards = match &out {
Json::Arr(a) => a.clone(),
_ => vec![],
};
assert_json_eq(&label, &out, expected);
}
"build_cards" => {
let out = gap::build_cards(&registry)
.unwrap_or_else(|e| panic!("{}: build_cards errored: {}", label, e));
assert_json_eq(&label, &out, expected);
}
"load_registry" => {
let out = gap::load_registry(&home.registry_path, &io)
.unwrap_or_else(|e| panic!("{}: load_registry errored: {}", label, e));
assert_json_eq(&label, &out, expected);
}
"_native_tool_schemas" => {
let out = gap::_native_tool_schemas(&tools);
assert_json_eq(&label, &out, expected);
}
"generate_card" => {
let out = gap::generate_card(&as_string(args.first()), args.get(1).unwrap_or(&Json::Obj(vec![])))
.unwrap_or_else(|e| panic!("{}: generate_card errored: {}", label, e));
assert_json_eq(&label, &out, expected);
}
"_py_score_card" => {
let card = args.first().cloned().unwrap_or(Json::Obj(vec![]));
let query = as_string(args.get(1));
let score = gap::_py_score_card(&card, &query)
.unwrap_or_else(|e| panic!("{}: _py_score_card errored: {}", label, e));
assert_json_eq(&label, &Json::Num(score), expected);
}
"match_capabilities" => {
let query = as_string(args.first());
let top_k = as_usize(args.get(1));
let out = gap::match_capabilities(&cards, &query, top_k);
assert_json_eq(&label, &out, expected);
}
"handle_hook" => {
let event = as_string(args.first());
let data = args.get(1).cloned().unwrap_or(Json::Obj(vec![]));
let out = gap::handle_hook(&event, &data, &cards)
.unwrap_or_else(|e| panic!("{}: handle_hook errored: {}", label, e));
assert_json_eq(&label, &out, expected);
}
other => panic!("unmapped case fn in the frozen corpus: {}", other),
}
}
}
// ── seam-level branch law (arms outside the harness envelope) ───────────────
struct FailIo {
fail_read: bool,
fail_write: bool,
fail_replace: bool,
}
impl gap::CbIo for FailIo {
fn exists(&self, path: &str) -> bool {
std::path::Path::new(path).exists()
}
fn read(&self, path: &str) -> Result<String, String> {
if self.fail_read {
return Err(format!("read {}: permission denied", path));
}
std::fs::read_to_string(path).map_err(|e| e.to_string())
}
fn mtime(&self, path: &str) -> Option<f64> {
std::fs::metadata(path).ok().and_then(|m| {
m.modified().ok().and_then(|t| {
t.duration_since(std::time::UNIX_EPOCH).ok().map(|d| d.as_secs_f64())
})
})
}
fn mkdir_parents(&self, _dir: &str) -> Result<(), String> {
Ok(())
}
fn write_text(&self, path: &str, contents: &str) -> Result<(), String> {
if self.fail_write {
return Err(format!("write {}: read-only memory dir", path));
}
std::fs::write(path, contents).map_err(|e| e.to_string())
}
fn replace(&self, from: &str, to: &str) -> Result<(), String> {
if self.fail_replace {
return Err(format!("replace {}: read-only memory dir", to));
}
std::fs::rename(from, to).map_err(|e| e.to_string())
}
fn remove(&self, path: &str) -> Result<(), String> {
let _ = std::fs::remove_file(path);
Ok(())
}
}
#[test]
fn cards_are_stale_branch_law() {
// registry missing → never stale
assert!(!gap::_cards_are_stale(false, None, None));
assert!(!gap::_cards_are_stale(false, Some(1.0), None));
// unreadable (OSError arm) → rebuild is the safe move
assert!(gap::_cards_are_stale(true, None, Some(2.0)));
assert!(gap::_cards_are_stale(true, Some(1.0), None));
assert!(gap::_cards_are_stale(true, None, None));
// both readable: cards older → stale; equal/newer → not stale
assert!(gap::_cards_are_stale(true, Some(1.0), Some(2.0)));
assert!(!gap::_cards_are_stale(true, Some(2.0), Some(2.0)));
assert!(!gap::_cards_are_stale(true, Some(3.0), Some(2.0)));
}
#[test]
fn load_registry_missing_and_value_law() {
let home = fixture_home();
let io = gap::StdIo;
let _ = std::fs::remove_file(&home.registry_path); // never created by fixture_home
// missing registry → the empty dict (never an Err)
let empty = gap::load_registry(&home.registry_path, &io).unwrap();
assert_eq!(j(&empty), "{}");
// corrupt registry text surfaces as an envelope err (oracle ValueError)
std::fs::write(&home.registry_path, "not-json{{").expect("corrupt");
assert!(gap::load_registry(&home.registry_path, &io).is_err());
}
#[test]
fn load_cards_rebuild_and_degrade_arms() {
let home = fixture_home();
let io = gap::StdIo;
let registry: Json = pyjson::parse(r#"{"plugins": {"only": {"manifest": {
"name": "only", "description": "route this", "capabilities": ["warm_routing"],
"priority": 1}}}}"#).expect("registry fixture");
std::fs::write(&home.registry_path, pyjson::dump_indent2(&registry)).expect("registry");
// missing cards + missing dir → makedirs law creates the dir, rebuild writes
std::fs::remove_dir_all(home.root.join("memory")).expect("drop cards dir");
let out = gap::load_cards(&home.cards_path, &home.registry_path, &[], &io).expect("rebuild");
let arr = match &out {
Json::Arr(a) => a.clone(),
_ => panic!("cards list"),
};
assert_eq!(arr.len(), 1, "plugin-only rebuild (no native tools passed)");
// the rebuild WROTE the fresh index (cards file newer than registry)
assert!(!gap::_cards_are_stale(
true,
io.mtime(&home.cards_path),
io.mtime(&home.registry_path),
));
// second load takes the fresh-read arm and round-trips identically
let again = gap::load_cards(&home.cards_path, &home.registry_path, &[], &io).expect("fresh");
assert_eq!(j(&out), j(&again));
// read-only dir (write fails): degrade-to-memory returns the cards and
// leaves the index untouched (tmp removed)
let fail_io = FailIo {
fail_read: false,
fail_write: true,
fail_replace: true,
};
std::fs::write(&home.cards_path, "").expect("clobber to empty cards");
let degraded = gap::load_cards(&home.cards_path, &home.registry_path, &[], &fail_io).expect("degrade");
assert_eq!(j(&degraded), j(&out));
let on_disk = std::fs::read_to_string(&home.cards_path).expect("cards readable");
assert_eq!(on_disk, "", "write failure leaves no fresh index behind");
}
#[test]
fn load_cards_corrupt_and_non_list_arms() {
let home = fixture_home();
let io = gap::StdIo;
let registry: Json = pyjson::parse(r#"{"plugins": {}}"#).expect("registry");
std::fs::write(&home.registry_path, pyjson::dump_indent2(&registry)).expect("registry");
for (label, seeds) in [
("corrupt", "{\"name\": true"), // JSONDecodeError → rebuild
("scalar", "42"), // valid JSON, not a list → rebuild
("empty_list", "[]"), // empty list → rebuild
] {
std::fs::write(&home.cards_path, seeds).expect("seed");
let out = gap::load_cards(&home.cards_path, &home.registry_path, &[], &io).expect(label);
let arr = match &out {
Json::Arr(a) => a.clone(),
_ => panic!("{}", label),
};
assert!(arr.is_empty(), "{}: plugin-less rebuild has no cards", label);
// the rebuild replaced the bad index on disk (atomic replace)
let on_disk = pyjson::parse(
&std::fs::read_to_string(&home.cards_path).expect("rewritten"),
)
.expect("valid JSON index");
assert_eq!(j(&out), j(&on_disk), "{}: rebuilt index == returned cards", label);
}
}
#[test]
fn native_tool_schemas_law() {
// str-name filter, later duplicate names win the VALUE at the FIRST
// slot's position, empty-string names are legal keys (isinstance str)
let tools = pyjson::parse(
r#"[
{"name": "a_tool", "description": "first"},
{"name": 5, "description": "non-str name dropped"},
{"description": "no name dropped"},
{"name": "dup", "description": "earlier"},
{"name": "dup", "description": "later"},
{"name": "", "description": "empty name kept"}
]"#,
)
.expect("tools fixture");
let tools = match tools {
Json::Arr(a) => a,
_ => panic!("tools list"),
};
let out = gap::_native_tool_schemas(&tools);
let pairs = match &out {
Json::Obj(p) => p.clone(),
_ => panic!("schema map"),
};
let keys: Vec<&str> = pairs.iter().map(|(k, _)| k.as_str()).collect();
assert_eq!(keys, vec!["a_tool", "dup", ""], "first-slot position law");
assert_eq!(
j(gap::obj_get(&out, "dup").unwrap()),
r#"{"name": "dup", "description": "later"}"#,
"later duplicate wins the value, first slot keeps its place"
);
}
#[test]
fn cs_core_probe_and_py_score_card_contract() {
// pinned-None arm (the RUNE_CAPABILITY_CORE=python contract)
assert!(gap::_cs_core(Some("python")).is_none());
assert!(gap::_cs_core(Some("auto")).is_some());
assert!(gap::_cs_core(None).is_some());
let core = gap::_cs_core(None).expect("live core");
assert_eq!(core.id(), "rust");
// happy arm: the kernel mirror delegates to the same scoring crate the
// Python cs_loader reaches
let card = pyjson::parse(
r#"{"name": "hooked", "description": "recall and store memory facts",
"capabilities": ["memory_recall", "memory_write"], "priority": 10,
"semantic_examples": ["What do I remember about X?"],
"searchable_text": "hooked recall and store memory facts"}"#,
)
.expect("card fixture");
let score = gap::_py_score_card(&card, "recall memory facts").expect("delegation");
assert_eq!(
score,
capability_scoring::scoring::score_card(&card, "recall memory facts")
);
}
#[test]
fn py_repr_law() {
let v = pyjson::parse(
r#"{"message": "", "text": null, "flag": true, "score": 4.5,
"count": 3, "nested": {"a": [1, "x"]}, "quote": "don't"}"#,
)
.expect("repr fixture");
assert_eq!(
gap::py_repr(&v),
"{'message': '', 'text': None, 'flag': True, 'score': 4.5, 'count': 3, 'nested': {'a': [1, 'x']}, 'quote': \"don't\"}"
);
// str(data) arm for the empty hook payload from the corpus
assert_eq!(gap::py_repr(&Json::Obj(vec![])), "{}");
}
#[test]
fn handle_hook_error_and_boundary_arms() {
let cards: Vec<Json> = vec![pyjson::parse(
r#"{"name": "memory_write", "file": "memory_write.py", "risk": "write",
"searchable_text": "memory_write write", "capabilities": ["memory_write"]}"#,
)
.expect("card")];
// truthy non-str message in the or-chain → the oracle raises
// AttributeError on .strip() (the strip is OUTSIDE its try/except);
// the kernel surfaces the crash as an envelope err with the exact
// Python type name so the facade fallback re-raises it natively
// (oracle quirk #15 — never silently degrade a crash arm)
let int_message = gap::handle_hook(
"on_message",
&pyjson::parse(r#"{"message": 5}"#).expect("data"),
&cards,
);
match int_message {
Err(e) => assert_eq!(e, "'int' object has no attribute 'strip'"),
Ok(v) => panic!("crash arm expected, got ok envelope {}", j(&v)),
}
let float_text = gap::handle_hook(
"on_message",
&pyjson::parse(r#"{"text": 4.5}"#).expect("data"),
&cards,
);
match float_text {
Err(e) => assert_eq!(e, "'float' object has no attribute 'strip'"),
Ok(v) => panic!("crash arm expected, got ok envelope {}", j(&v)),
}
// boundary: len(strip) <= 2 and non-message events fall to the ok arm
for (event, data) in [
("on_message", r#"{"message": " "}"#),
("on_message", r#"{"message": "hi"}"#),
("other_event", r#"{"message": "hello world"}"#),
] {
let out = gap::handle_hook(event, &pyjson::parse(data).expect("data"), &cards)
.unwrap_or_else(|e| panic!("{}: unexpected err {}", data, e));
match gap::obj_get(&out, "status") {
Some(Json::Str(s)) => assert_eq!(s, "ok", "{}", data),
other => panic!("ok arm expected for {}, got {:?}", data, other),
}
assert!(gap::obj_get(&out, "matches").is_none(), "{}", data);
}
}
#[test]
fn failio_seam_declared() {
// the seam exists for the driven-arms tests above (write/replace failure)
let io = FailIo {
fail_read: true,
fail_write: true,
fail_replace: true,
};
assert!(io.read("/nope").is_err());
}
+107
View File
@@ -6,12 +6,17 @@
//! oracle 2026-10-11).
pub mod broker;
pub mod gap;
pub use capability_scoring::pyjson;
#[path = "branch_battery.rs"]
#[cfg(test)]
mod branch_battery;
#[path = "gap_battery.rs"]
#[cfg(test)]
mod gap_battery;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
@@ -90,6 +95,108 @@ pub extern "C" fn cs_find_capability(arg: *const c_char) -> *mut c_char {
envelope(r)
}
/// cb_native_tool_schemas({"tools": [...]}) -> {name: schema}
#[no_mangle]
pub extern "C" fn cb_native_tool_schemas(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| gap::_native_tool_schemas(&arr(get(&a, "tools"))));
envelope(r)
}
/// cb_load_registry({"registry_path": "..."}) -> registry dict
#[no_mangle]
pub extern "C" fn cb_load_registry(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).and_then(|a| {
let path = s(get(&a, "registry_path"));
gap::load_registry(path, &gap::StdIo)
});
envelope(r)
}
/// cb_cards_are_stale({"cards_path": "...", "registry_path": "..."}) -> bool
#[no_mangle]
pub extern "C" fn cb_cards_are_stale(arg: *const c_char) -> *mut c_char {
use crate::gap::CbIo;
let r = read_arg(arg).map(|a| {
let io = gap::StdIo;
let registry_path = s(get(&a, "registry_path"));
let stale = gap::_cards_are_stale(
io.exists(registry_path),
io.mtime(s(get(&a, "cards_path"))),
io.mtime(registry_path),
);
pyjson::Json::Bool(stale)
});
envelope(r)
}
/// cb_load_cards({"cards_path": "...", "registry_path": "...", "tools": [...]})
/// -> cards list
#[no_mangle]
pub extern "C" fn cb_load_cards(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).and_then(|a| {
gap::load_cards(
s(get(&a, "cards_path")),
s(get(&a, "registry_path")),
&arr(get(&a, "tools")),
&gap::StdIo,
)
});
envelope(r)
}
/// cb_generate_card({"name": "...", "manifest": {...}}) -> card dict
#[no_mangle]
pub extern "C" fn cb_generate_card(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).and_then(|a| {
let empty = pyjson::Json::Obj(vec![]);
let manifest = get(&a, "manifest").unwrap_or(&empty);
gap::generate_card(s(get(&a, "name")), manifest)
});
envelope(r)
}
/// cb_build_cards({"registry_path": "..."}) -> plugin cards list
#[no_mangle]
pub extern "C" fn cb_build_cards(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg)
.and_then(|a| gap::load_registry(s(get(&a, "registry_path")), &gap::StdIo))
.and_then(|reg| gap::build_cards(&reg));
envelope(r)
}
/// cb_match_capabilities({"cards": [...], "query": "...", "top_k": n}) -> list
#[no_mangle]
pub extern "C" fn cb_match_capabilities(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).and_then(|a| {
let top_k = match get(&a, "top_k") {
Some(pyjson::Json::Num(n)) => *n as i64,
_ => 5,
};
// Negative top_k is Python's from-the-end slice — kernel err sends
// the facade back to the oracle arm rather than approximating it.
if top_k < 0 {
return Err("negative top_k is oracle-slice semantics".into());
}
Ok(gap::match_capabilities(
&arr(get(&a, "cards")),
s(get(&a, "query")),
top_k as usize,
))
});
envelope(r)
}
/// cb_handle_hook({"event": "...", "data": {...}, "cards": [...]}) -> hook dict
#[no_mangle]
pub extern "C" fn cb_handle_hook(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).and_then(|a| {
let empty = pyjson::Json::Obj(vec![]);
let data = get(&a, "data").unwrap_or(&empty);
gap::handle_hook(s(get(&a, "event")), data, &arr(get(&a, "cards")))
});
envelope(r)
}
// NOTE: cs_free_string is NOT exported here — capability_scoring (linked
// into the same Python process via rune/cs_loader) already exports it, and
// a duplicate symbol breaks the cdylib link. Callers free through that path.
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-13T22:59:19Z-55405d-mimo
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
create a practice scheduler with create/list/complete
## What it connects to
- `practice-scheduler-js/scheduler.js`
- `practice-scheduler-js/test_scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-13T22:59:19Z", "contract": "BUILDER-2026-10-13T22:59:19Z-55405d-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-335/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-335/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:mimo
- builder:mimo
- builder:mimo
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T22:59:46Z-789e2a-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T22:59:46Z", "contract": "BUILDER-2026-10-13T22:59:46Z-789e2a-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T22:59:46Z-89de7c-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
wave stage one
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T22:59:46Z", "contract": "BUILDER-2026-10-13T22:59:46Z-89de7c-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T22:59:46Z-b62a0d-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T22:59:46Z", "contract": "BUILDER-2026-10-13T22:59:46Z-b62a0d-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T22:59:49Z-0b7169-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture sections: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:03:05Z-4f97f0-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture outdir: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-0d3693-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-0d3693-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-370af6-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-370af6-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t21.4 test approved
- t21.4 test building
- t21.4 test verifying
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-3a694e-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `src/rune/bounded_change.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-3a694e-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:rune-planned", "contract:rune-spec"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:rune-planned", "contract:rune-spec"], "predicted_existing_affected": ["capability:rune-planned", "contract:rune-spec"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-7df69e-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-7df69e-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-13T23:10:19Z-8ca8b8-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
scope with an unmodeled file
## What it connects to
- `scripts/rollback_generation.py`
- `tests/test_t214_material_closure.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-8ca8b8-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": ["test:t214_material_closure"], "expected_new_missing": ["test:t214_material_closure"], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["tests/test_t214_material_closure.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-bac749-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-bac749-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": ["scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:10:19Z-df7c20-t21.5-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
add the widget import capability to widget-forge (bounded change; import widgets from external bundles)
## What it connects to
- `src/widget_import.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:10:19Z", "contract": "BUILDER-2026-10-13T23:10:19Z-df7c20-t21.5-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:widget-export", "contract:widget-import"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:widget-export", "contract:widget-import"], "predicted_existing_affected": ["component:widget-export", "contract:widget-import"], "scope_check": {"in_scope": ["src/widget_import.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-13T23:19:23Z-a09cb5-mimo
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
create a practice scheduler with create/list/complete
## What it connects to
- `practice-scheduler-js/scheduler.js`
- `practice-scheduler-js/test_scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-13T23:19:23Z", "contract": "BUILDER-2026-10-13T23:19:23Z-a09cb5-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-341/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-341/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:mimo
- builder:mimo
- builder:mimo
- closure-record
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-13T23:52:59Z-695021-mimo
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
create a practice scheduler with create/list/complete
## What it connects to
- `practice-scheduler-js/scheduler.js`
- `practice-scheduler-js/test_scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-13T23:52:59Z", "contract": "BUILDER-2026-10-13T23:52:59Z-695021-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-374/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-374/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:mimo
- builder:mimo
- builder:mimo
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:53:22Z-0d9e17-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:53:22Z", "contract": "BUILDER-2026-10-13T23:53:22Z-0d9e17-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:53:22Z-140ad5-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
wave stage one
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:53:22Z", "contract": "BUILDER-2026-10-13T23:53:22Z-140ad5-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:53:22Z-a2eac2-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T23:53:22Z", "contract": "BUILDER-2026-10-13T23:53:22Z-a2eac2-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:53:25Z-47a381-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture sections: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:55:32Z-5c980d-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture outdir: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-14T00:03:54Z-4eff51-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
scope with an unmodeled file
## What it connects to
- `scripts/rollback_generation.py`
- `tests/test_t214_material_closure.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-4eff51-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": ["test:t214_material_closure"], "expected_new_missing": ["test:t214_material_closure"], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["tests/test_t214_material_closure.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-63402f-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-63402f-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t21.4 test approved
- t21.4 test building
- t21.4 test verifying
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-77fda1-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-77fda1-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-a10729-t21.5-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
add the widget import capability to widget-forge (bounded change; import widgets from external bundles)
## What it connects to
- `src/widget_import.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-a10729-t21.5-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:widget-export", "contract:widget-import"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:widget-export", "contract:widget-import"], "predicted_existing_affected": ["component:widget-export", "contract:widget-import"], "scope_check": {"in_scope": ["src/widget_import.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-bc6f90-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `src/rune/bounded_change.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-bc6f90-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:rune-planned", "contract:rune-spec"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:rune-planned", "contract:rune-spec"], "predicted_existing_affected": ["capability:rune-planned", "contract:rune-spec"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-d47ac2-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-d47ac2-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:03:54Z-d980c4-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:03:54Z", "contract": "BUILDER-2026-10-14T00:03:54Z-d980c4-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": ["scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-14T00:05:32Z-ca1597-mimo
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
create a practice scheduler with create/list/complete
## What it connects to
- `practice-scheduler-js/scheduler.js`
- `practice-scheduler-js/test_scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-14T00:05:32Z", "contract": "BUILDER-2026-10-14T00:05:32Z-ca1597-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-380/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-380/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:mimo
- builder:mimo
- builder:mimo
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:05:56Z-02dbf9-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:05:56Z", "contract": "BUILDER-2026-10-14T00:05:56Z-02dbf9-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:05:56Z-7083eb-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
wave stage one
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:05:56Z", "contract": "BUILDER-2026-10-14T00:05:56Z-7083eb-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:05:56Z-d3e0ab-test-builder
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
persistent project export
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:05:56Z", "contract": "BUILDER-2026-10-14T00:05:56Z-d3e0ab-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
## Evidence
- builder:test-builder
- builder:test-builder
- builder:test-builder
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:05:58Z-14a3f2-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture sections: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:07:51Z-7138bc-minidoc-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
minidoc fixture outdir: the mini-doc emission target
## What it connects to
- `tests/test_contract_minidoc.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: not recorded.
## Evidence
- t
- t
- t
- final evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-042c20-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-042c20-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-0e26a8-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `src/rune/bounded_change.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-0e26a8-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:rune-planned", "contract:rune-spec"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:rune-planned", "contract:rune-spec"], "predicted_existing_affected": ["capability:rune-planned", "contract:rune-spec"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-48afcc-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-48afcc-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-77424d-t21.5-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
add the widget import capability to widget-forge (bounded change; import widgets from external bundles)
## What it connects to
- `src/widget_import.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-77424d-t21.5-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:widget-export", "contract:widget-import"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:widget-export", "contract:widget-import"], "predicted_existing_affected": ["component:widget-export", "contract:widget-import"], "scope_check": {"in_scope": ["src/widget_import.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,25 @@
# Contract BUILDER-2026-10-14T00:14:44Z-a77cde-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
scope with an unmodeled file
## What it connects to
- `scripts/rollback_generation.py`
- `tests/test_t214_material_closure.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-a77cde-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": ["test:t214_material_closure"], "expected_new_missing": ["test:t214_material_closure"], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["tests/test_t214_material_closure.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t
- t
- t
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-af9ba5-adversarial-probe
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
build the hostile spec module
## What it connects to
- `scheduler.js`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-af9ba5-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": ["scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- builder:adversarial-probe
- builder:adversarial-probe
- closure-record
- e
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T00:14:44Z-fc95fd-t21.4-test
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
bounded change touching closure_target
## What it connects to
- `scripts/rollback_generation.py`
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T00:14:44Z", "contract": "BUILDER-2026-10-14T00:14:44Z-fc95fd-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
## Evidence
- closure-record
- t21.4 test approved
- t21.4 test building
- t21.4 test verifying
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
microkernel dichotomy gap-close (GO): name-preserving port of the 6 unmatched fns (now_iso, discover, _extract_manifest, _load_registry, _save_registry, _run_hook) into src/go/microkernel, plus Fire wiring the CLI fire case to real 8-way parallel subprocess dispatch with the bounded fire-log, and Register fixes (Python truthiness for hook values, _file plumbing). Frozen-truth battery 25/25, live parity 24/24, gofmt/vet/build clean, Python both-pins green (18 test_p1_01 failures proven pre-existing). Audit: microkernel 6/12 PARTIAL -> 12/12 FULL. Delivered on gitea/master: feat 3a1b9e54, audit da9e15e9.
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-14T02:56:26Z", "contract": "BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["module:deploy_qualify"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["module:deploy_qualify"], "predicted_existing_affected": ["module:deploy_qualify"], "scope_check": {"in_scope": [], "out_of_scope": ["scripts/check_microkernel_parity.py", "scripts/close_contract_microkernel.py", "scripts/gen_microkernel_gap_truth.py", "src/go/microkernel/main.go", "src/go/microkernel/microkernel.go", "src/go/microkernel/parity.go", "src/go/microkernel/truth_microkernel.json", "src/go/microkernel/truth_microkernel_gap.json", "src/go/microkernel/truth_microkernel_gap_test.go", "src/go/microkernel/truth_microkernel_test.go", "verification/summary-microkernel.md"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- parity 3a1b9e54; audit da9e15e9
- parity 3a1b9e54; audit da9e15e9
- parity 3a1b9e54; audit da9e15e9
- closure-record
@@ -3885,6 +3885,46 @@
{"builder": "factory-gap-gd", "detail": "BUILDER-2026-10-13T12:24:32Z-36734a-factory-gap-gd closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T12:32:11Z", "operation": "close"}
{"builder": "factory-gap-cp", "detail": "BUILDER-2026-10-13T13:18:48Z-5b5364-factory-gap-cp \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T13:19:13Z", "operation": "transition"}
{"builder": "factory-gap-cp", "detail": "BUILDER-2026-10-13T13:18:48Z-5b5364-factory-gap-cp \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T13:19:36Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T16:30:55Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:30:57Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:30:57Z-3ac503-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:31:17Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:30:57Z-3ac503-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:31:36Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:30:57Z-3ac503-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:31:56Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:30:57Z-3ac503-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:32:16Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T16:32:38Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:32:39Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:32:39Z-144725-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:33:01Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:32:39Z-144725-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:33:21Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:32:39Z-144725-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:33:41Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T16:32:39Z-144725-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T16:34:01Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T22:59:47Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:59:49Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T22:59:49Z-0b7169-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:00:24Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T22:59:49Z-0b7169-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:01:02Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T22:59:49Z-0b7169-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:01:50Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T22:59:49Z-0b7169-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:02:31Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T23:03:03Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:03:05Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:03:05Z-4f97f0-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:03:37Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:03:05Z-4f97f0-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:04:06Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:03:05Z-4f97f0-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:04:37Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:03:05Z-4f97f0-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:05:07Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T23:53:22Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:53:25Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:53:25Z-47a381-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:53:50Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:53:25Z-47a381-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:54:15Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:53:25Z-47a381-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:54:40Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:53:25Z-47a381-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:55:04Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-13T23:55:30Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:55:32Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:55:32Z-5c980d-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:56:11Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:55:32Z-5c980d-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:56:57Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:55:32Z-5c980d-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:57:30Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-13T23:55:32Z-5c980d-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:57:56Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-14T00:05:56Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:05:58Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:05:58Z-14a3f2-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:06:19Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:05:58Z-14a3f2-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:06:40Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:05:58Z-14a3f2-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:07:03Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:05:58Z-14a3f2-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:07:25Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "need-2026-10-14T00:07:49Z-minidoc-test \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:07:51Z", "operation": "submit_need"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:07:51Z-7138bc-minidoc-test \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:08:14Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:07:51Z-7138bc-minidoc-test \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:08:36Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:07:51Z-7138bc-minidoc-test \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:08:58Z", "operation": "transition"}
{"builder": "minidoc-test", "detail": "BUILDER-2026-10-14T00:07:51Z-7138bc-minidoc-test \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T00:09:28Z", "operation": "transition"}
{"builder": "factory-gap-he", "detail": "need-2026-10-13T15:18:57Z-factory-gap-he \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T15:18:58Z", "operation": "submit_need"}
{"builder": "factory-gap-he", "detail": "BUILDER-2026-10-13T15:18:58Z-fb34a0-factory-gap-he \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T15:19:17Z", "operation": "transition"}
{"builder": "factory-gap-he", "detail": "BUILDER-2026-10-13T15:18:58Z-fb34a0-factory-gap-he \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T15:19:37Z", "operation": "transition"}
@@ -6466,3 +6506,8 @@
{"builder": "factory-gap-ca", "detail": "BUILDER-2026-10-14T02:10:49Z-4ef2c5-factory-gap-ca \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:11:55Z", "operation": "transition"}
{"builder": "factory-gap-ca", "detail": "BUILDER-2026-10-14T02:10:49Z-4ef2c5-factory-gap-ca closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:12:17Z", "operation": "close"}
{"builder": "factory-gap-mk", "detail": "need-2026-10-14T02:55:01Z-factory-gap-mk \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:55:03Z", "operation": "submit_need"}
{"builder": "factory-gap-mk", "detail": "BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:55:23Z", "operation": "transition"}
{"builder": "factory-gap-mk", "detail": "BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:55:44Z", "operation": "transition"}
{"builder": "factory-gap-mk", "detail": "BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:56:05Z", "operation": "transition"}
{"builder": "factory-gap-mk", "detail": "BUILDER-2026-10-14T02:55:03Z-907bab-factory-gap-mk closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T02:56:26Z", "operation": "close"}
+275
View File
@@ -0,0 +1,275 @@
"""test_capability_broker_delegation.py — dichotomy-wave gap-closing tests.
The facade must behave identically with the Rust core LIVE
(RUNE_CAPABILITY_BROKER_CORE unset, libcapability_broker.so built) and with
the PYTHON ORACLE pinned (RUNE_CAPABILITY_BROKER_CORE=python). The fixture
home is rebuilt per test (mtime-pinned staleness law, no wall-clock luck);
the oracle's module-level card I/O is pointed at it through monkeypatched
module constants (the loader receives the same explicit paths).
"""
import json
import os
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from rune import broker_loader # noqa: E402
from rune import capability_broker as cb # noqa: E402
FIXED_SEED_MTIME = 1_000_000_000.0
FIXED_REGISTRY_MTIME = 1_000_000_100.0
needs_live = pytest.mark.skipif(
not broker_loader.available(), reason="Rust capability_broker core not built"
)
NEW_PIN = "RUNE_CAPABILITY_BROKER_CORE"
@pytest.fixture()
def fixture_home(tmp_path, monkeypatch):
registry = tmp_path / "src" / "rune" / ".microkernel.json"
cards = tmp_path / "memory" / "index" / "capability_cards.json"
registry.parent.mkdir(parents=True)
cards.parent.mkdir(parents=True)
registry_val = {
"plugins": {
"hooked": {
"manifest": {
"name": "hooked",
"description": "recall and store memory facts",
"capabilities": ["memory_recall", "memory_write"],
"hooks": {"on_message": "handle_hook"},
"priority": 10,
"_file": "plugins/hooked/main.py",
},
"registered_at": "2026-10-13T01:02:03",
"active": True,
},
"verifier": {
"manifest": {
"name": "verifier",
"description": "verify this claim and detect drift",
"capabilities": ["claim_verification"],
"priority": 20,
"_file": "main.py",
},
},
}
}
registry.write_text(json.dumps(registry_val, indent=2))
cards.write_text(
json.dumps(
[
{
"name": "seed-stale",
"description": "seed",
"capabilities": ["seed_cap"],
"file": "seed.py",
"full_path": "plugins/seed/seed.py",
"priority": 3,
"semantic_examples": [],
"risk": "read-only",
"auto_invoked": False,
"hooks": [],
"searchable_text": "seed stale card",
}
],
indent=2,
)
)
os.utime(cards, (FIXED_SEED_MTIME, FIXED_SEED_MTIME))
os.utime(registry, (FIXED_REGISTRY_MTIME, FIXED_REGISTRY_MTIME))
monkeypatch.setattr(cb, "REGISTRY", str(registry))
monkeypatch.setattr(cb, "CARDS_FILE", str(cards))
return {"registry": str(registry), "cards": str(cards), "value": registry_val}
def run_both_modes(call):
"""Run `call(cb_module)` with the Rust core LIVE and with the Python
oracle pinned; results must be identical."""
results = []
monkey = pytest.MonkeyPatch()
for pin in (False, True):
if pin:
monkey.setenv(NEW_PIN, "python")
else:
if not broker_loader.available():
pytest.skip("Rust core not built")
monkey.delenv(NEW_PIN, raising=False)
try:
results.append(call(cb))
finally:
monkey.undo()
assert json.dumps(results[0], ensure_ascii=True) == json.dumps(
results[1], ensure_ascii=True
), f"modes diverged:\n{results[0]!r}\nvs\n{results[1]!r}"
return results[0]
class TestGapDelegationDualMode:
@needs_live
def test_native_tool_schemas(self):
run_both_modes(lambda m: m._native_tool_schemas())
@needs_live
def test_load_registry(self, fixture_home):
run_both_modes(lambda m: m.load_registry())
@needs_live
def test_cards_are_stale(self, fixture_home):
assert run_both_modes(lambda m: m._cards_are_stale()) is True
@needs_live
def test_load_cards_rebuild_then_fresh(self, fixture_home):
def call(m):
rebuilt = m.load_cards()
fresh = m.load_cards()
return {"rebuilt": rebuilt, "fresh": fresh}
out = run_both_modes(call)
assert json.dumps(out["rebuilt"], ensure_ascii=True) == json.dumps(
out["fresh"], ensure_ascii=True
)
assert any(c.get("name") == "hooked" for c in out["rebuilt"])
@needs_live
def test_load_cards_corrupt_rebuild(self, fixture_home):
def call(m):
with open(m.CARDS_FILE, "w") as f:
f.write("{corrupt")
return m.load_cards()
run_both_modes(call)
@needs_live
def test_generate_card(self):
def call(m):
card = m.generate_card(
"hooked",
{
"name": "hooked",
"description": "recall and store memory facts",
"capabilities": ["memory_recall", "memory_write"],
"hooks": {"on_message": "handle_hook"},
"priority": 10,
"_file": "plugins/hooked/main.py",
},
)
with pytest.raises(TypeError):
m.generate_card("bad", {"capabilities": 5})
return card
run_both_modes(call)
@needs_live
def test_build_cards(self, fixture_home):
run_both_modes(lambda m: m.build_cards())
@needs_live
def test_match_capabilities(self, fixture_home):
def call(m):
return [
m.match_capabilities("recall and store memory facts"),
m.match_capabilities("verify this claim about drift", top_k=1),
m.match_capabilities("zzz nothing at all"),
]
run_both_modes(call)
@needs_live
def test_handle_hook_branches(self, fixture_home):
def call(m):
return [
m.handle_hook("other", {"message": "hello world"}),
m.handle_hook("on_message", {}),
m.handle_hook("on_message", {"message": "hi"}),
m.handle_hook("on_message", {"text": "verify this claim"}),
m.handle_hook("on_message", {"status": "error state"}),
m.handle_hook("on_message", {"message": "remember this fact and store it"}),
]
run_both_modes(call)
@needs_live
def test_handle_hook_crash_parity(self, fixture_home):
"""A truthy non-str message crashes the oracle with AttributeError
(the strip is outside its try/except). The live facade must raise
the SAME exception — the kernel errs and the Python fallback
re-raises natively (oracle quirk #15)."""
def call(m):
with pytest.raises(AttributeError, match="has no attribute 'strip'"):
m.handle_hook("on_message", {"message": 5})
with pytest.raises(AttributeError, match="has no attribute 'strip'"):
m.handle_hook("on_message", {"text": 4.5})
return "crash-parity"
run_both_modes(call)
@needs_live
def test_match_capabilities_negative_top_k(self, fixture_home):
"""Negative top_k is Python from-the-end slice semantics; the kernel
errs on it so the facade falls back to the oracle arm (both modes
agree)."""
def call(m):
return m.match_capabilities("recall and store memory facts", -1)
run_both_modes(call)
def test_cs_core_pinned_none(self, monkeypatch):
monkeypatch.setenv("RUNE_CAPABILITY_CORE", "python")
assert cb._cs_core() is None
if broker_loader.available():
monkeypatch.delenv("RUNE_CAPABILITY_CORE", raising=False)
assert cb._cs_core() is not None
def test_py_score_card_is_strangler_exit(self, monkeypatch):
monkeypatch.setenv("RUNE_CAPABILITY_CORE", "python")
with pytest.raises(RuntimeError, match="capability_scoring kernel not built"):
cb._py_score_card({"name": "x"}, "query")
if broker_loader.available():
from rune import cs_loader
monkeypatch.delenv("RUNE_CAPABILITY_CORE", raising=False)
card = {"name": "hooked", "description": "recall memory",
"capabilities": ["memory_recall"], "searchable_text": "hooked recall memory"}
assert cb._py_score_card(card, "recall") == cs_loader.score_card(card, "recall")
class TestBatch1PinRegression:
"""The batch-1 selection surface (RUNE_BROKER_CORE pin) is untouched —
both modes still route and agree."""
@needs_live
def test_select_and_find_two_pins(self, monkeypatch):
desc = "bash: list the largest files in the repo"
outs = []
monkey = pytest.MonkeyPatch()
for pin in (True, False):
if pin:
monkey.setenv("RUNE_BROKER_CORE", "python")
else:
if not broker_loader.available():
pytest.skip("Rust core not built")
monkey.delenv("RUNE_BROKER_CORE", raising=False)
monkey.delenv(NEW_PIN, raising=False)
try:
outs.append(
{
"select": cb.select_for_job(desc, True),
"find": cb.find_capability("list the largest files", top_k=3),
}
)
finally:
monkey.undo()
assert json.dumps(outs[0]["select"]["names"]) == json.dumps(
outs[1]["select"]["names"]
)
assert outs[0]["select"]["reason"] == outs[1]["select"]["reason"]
assert json.dumps(outs[0]["find"]) == json.dumps(outs[1]["find"])
+6 -2
View File
@@ -26,8 +26,12 @@ def _scenario(core_pin: str) -> list[dict]:
p.get_connection(b)
snapshots.append(("create-b", p.get_status(), None))
p.get_connection(c)
snapshots.append(("evict-oldest", p.get_status(),
"a" not in " ".join(p.get_status()["databases"]).lower()))
st_evict = p.get_status()
# flag must read basenames like the norm pass below — the raw-path
# substring form flaked on any 'a' in the random temp-dir name
snapshots.append(("evict-oldest", st_evict,
"a.db" not in [os.path.basename(d).lower()
for d in st_evict["databases"]]))
p.connections[b].close() # force stale
p.get_connection(b)
snapshots.append(("stale-b", p.get_status(), None))
+6 -1
View File
@@ -899,7 +899,12 @@ def test_operator_run_selects_capabilities_once(tmp_path, monkeypatch):
def test_load_cards_rebuild_write_is_atomic(tmp_path, monkeypatch):
"""Finding 7: the rebuild persists via temp file + os.replace — never a
direct in-place write that a crash could truncate into corrupt JSON."""
direct in-place write that a crash could truncate into corrupt JSON.
Pins the Python mechanism (the os.replace spy): the Rust core does its
own atomic replace kernel-side, pinned by the crate's gap battery
(load_cards_rebuild_and_degrade_arms)."""
monkeypatch.setenv("RUNE_CAPABILITY_BROKER_CORE", "python")
cards_file = tmp_path / "capability_cards.json"
cards_file.write_text("[]")
monkeypatch.setattr(cb, "CARDS_FILE", str(cards_file))
+1
View File
@@ -0,0 +1 @@
0
+24
View File
@@ -0,0 +1,24 @@
Finished `release` profile [optimized] target(s) in 0.01s
Running unittests src/lib.rs (target/release/deps/capability_broker-32625e21545245f2)
running 11 tests
test gap_battery::cards_are_stale_branch_law ... ok
test gap_battery::cs_core_probe_and_py_score_card_contract ... ok
test gap_battery::failio_seam_declared ... ok
test gap_battery::handle_hook_error_and_boundary_arms ... ok
test gap_battery::native_tool_schemas_law ... ok
test gap_battery::py_repr_law ... ok
test gap_battery::load_registry_missing_and_value_law ... ok
test gap_battery::load_cards_corrupt_and_non_list_arms ... ok
test gap_battery::load_cards_rebuild_and_degrade_arms ... ok
test branch_battery::select_matches_frozen_oracle ... ok
test gap_battery::gap_replays_frozen_truth_verbatim ... ok
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests capability_broker
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
Finished `release` profile [optimized] target(s) in 0.10s
+1
View File
@@ -0,0 +1 @@
0
+2
View File
@@ -0,0 +1,2 @@
Checking capability_broker v0.1.0 (/mnt/workdrive/rune-wave-cd/src/rust/capability_broker)
Finished `release` profile [optimized] target(s) in 0.83s
+1
View File
@@ -0,0 +1 @@
canonical seed fixture rebuilt at /tmp/rune_cb_truth_home
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
OK: 33 cases byte-identical against live oracle rune.capability_broker
+1
View File
@@ -0,0 +1 @@
1
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
1
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
0
+2
View File
@@ -0,0 +1,2 @@
parity: 468/468 checks OK (frozen=33 fuzz=421 live=14)
LIVE PARITY 100% on the gap-closing functions
+1
View File
@@ -0,0 +1 @@
0
+11
View File
@@ -0,0 +1,11 @@
........................................................................ [ 67%]
................................... [100%]
=============================== warnings summary ===============================
tests/test_p1_01_capability_authority.py::test_operator_trace_record_carries_capability_fields
tests/test_p1_01_capability_authority.py::test_operator_trace_record_carries_selected_tools
tests/test_p1_01_capability_authority.py::test_operator_run_selects_capabilities_once
/mnt/workdrive/rune-wave-cd/src/rune/rune_operator.py:952: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
"observed_at": __import__("datetime").datetime.utcnow()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
107 passed, 3 warnings in 1.29s
+1
View File
@@ -0,0 +1 @@
0
+11
View File
@@ -0,0 +1,11 @@
........................................................................ [ 67%]
................................... [100%]
=============================== warnings summary ===============================
tests/test_p1_01_capability_authority.py::test_operator_trace_record_carries_capability_fields
tests/test_p1_01_capability_authority.py::test_operator_trace_record_carries_selected_tools
tests/test_p1_01_capability_authority.py::test_operator_run_selects_capabilities_once
/mnt/workdrive/rune-wave-cd/src/rune/rune_operator.py:952: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
"observed_at": __import__("datetime").datetime.utcnow()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
107 passed, 3 warnings in 0.90s
+72
View File
@@ -0,0 +1,72 @@
# capability_broker gap-close verification summary
Module: capability_broker (dichotomy wave, issue #2479 gap-cb tranche)
Contract: contract:BUILDER-2026-10-13T16:01:25Z-9b9389-factory-gap-cb
Worktree: /mnt/workdrive/rune-wave-cd (base 12662658)
## Coverage
- Module audit: 10/19 PARTIAL → **19/19 FULL** (`scripts/dichotomy_audit.py`
in-memory row: `{'module': 'capability_broker', 'lines': 865, 'fns': 19,
'matched': 19, 'side': 'RUST', 'status': 'FULL', 'missing': []}`)
- Ported (name-preserving, gap.rs): _native_tool_schemas, load_registry,
_cards_are_stale, load_cards, generate_card, build_cards, _cs_core,
_py_score_card, match_capabilities, handle_hook
- FFI: cb_* doc-envelope entries in lib.rs; ctypes bindings in
src/rune/broker_loader.py; facade delegation in src/rune/capability_broker.py
gated by RUNE_CAPABILITY_BROKER_CORE=python pin.
## Stages (commands, exit codes, evidence)
| Stage | Command | Exit | Evidence |
|---|---|---|---|
| build | `cargo build --release` (crate dir) | 0 | verification/cb-build.{log,exit} |
| battery | `cargo test --release` (crate dir) | 0 — 11 passed / 0 failed | verification/cb-battery.{log,exit} |
| truth byte-identity | `gen_capability_broker_gap_truth.py --setup` then fixture-pinned `freeze_truth.py --verify frozen_gap_truth.json --module rune.capability_broker` | 0 — 33 cases byte-identical | verification/cb-fixture-setup.log, verification/cb-freeze-verify.{log,exit} |
| truth self-regen | `python3 scripts/gen_capability_broker_gap_truth.py` | 0 — rebuild→freeze→byte-compare→harness gate | verification/cb-truth-regen.{log,exit} |
| live parity | `python3 scripts/check_capability_broker_gap_parity.py` | 0 — **468/468** (frozen=33 fuzz=421 live=14), LIVE PARITY 100% | verification/cb-parity.{log,exit} |
| clippy | `cargo clippy --release --all-targets -- -D warnings` | 0 | verification/cb-clippy.{log,exit} |
| python adjacent (live) | `pytest tests/test_p1_01_capability_authority.py tests/test_capability_broker_delegation.py tests/test_capability_fit.py tests/test_context_broker.py tests/test_orchestration_broker.py tests/test_orchestration_capability.py` | 0 — 107 passed | verification/cb-py-live.{log,exit} |
| python adjacent (pinned) | same, `RUNE_CAPABILITY_BROKER_CORE=python` | 0 — 107 passed | verification/cb-py-pinned.{log,exit} |
| full suite (live) | `pytest tests/` | 1 — 118 failed / 2516 passed; **failure set == master baseline** (zero delta) | verification/cb-full-live.{log,exit} |
| full suite (pinned) | same, `RUNE_CAPABILITY_BROKER_CORE=python` | 1 — 118 failed / 2516 passed; **failure set == master baseline** (zero delta) | verification/cb-full-pinned.{log,exit} |
Full-suite baseline: 118 failures pre-exist on gitea/master (verified by
diffing the FAILED sets; both pins' deltas are empty). Exit 1 on the full
suite is the pre-existing master state, not a regression.
## Fixed during verification (fix-first, with proof)
`tests/test_connection_pool.py::test_kernel_matches_oracle_floor` flaked
~17% in isolation (2/12 runs) and was the sole live full-suite delta vs
master on first run: the evict-oldest flag read RAW temp-dir paths
(`"a" not in " ".join(databases)`), so any letter 'a' in the random
tempdir name flipped it. The status comparison already normalized to
basenames. Fixed the flag to basename form (same normalization); 15/15
green after the fix, and both full-suite failure-set deltas dropped to
zero. The port never touched connection_pool — pre-existing instrument
bug (fd731bee false-failing-instrument class).
## Phase B (ladder layer 6)
Language advantages in the landed kernel (gap.rs), battery green after
the landing: `trait CbIo` (+ `impl CbIo for StdIo`) injects filesystem
IO so the battery pins mtimes deterministically without process seams;
`Result<Json, String>` error paths mirror Python exception arms;
exhaustive `match` in handle_hook branches; zero-copy `&'static` tables
(semantic examples, RISK_MAP); `_py_score_card` delegates to the
capability_scoring kernel IN-PROCESS (Rust→Rust, no ctypes marshaling).
No cosmetic churn — every rewrite is observable-behavior-preserving and
parity-pinned.
## Divergences (documented, not bugs)
- `_cs_core`'s Some arm (returns the cs_loader module handle, not JSON)
is excluded from the frozen envelope; the pinned-None arm is asserted
by the both-pins pytest, the kernel mirror by the battery.
- load_cards corrupt-file / OSError arms: driven by the battery seam
test and the live parity dual-fixture layer instead of frozen truth.
- `_native_tool_schemas` keeps the Python object graph in the facade by
identity (select_for_job rehydrates by ID); the Rust port is
battery- and parity-pinned for the stage-3 burn. Comment documents the
carve-out at src/rune/capability_broker.py.
+1
View File
@@ -0,0 +1 @@
0
+3
View File
@@ -0,0 +1,3 @@
OK: 33 cases byte-identical against live oracle rune.capability_broker
frozen 33 cases -> /mnt/workdrive/rune-wave-cd/src/rust/capability_broker/frozen_gap_truth.json (harness gate byte-identical)