Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6734bae4ea | ||
|
|
a574ff0879 | ||
|
|
35a721b4c0 | ||
|
|
796162b09c | ||
|
|
2eb91c0e81 | ||
|
|
1a35b4ce2d | ||
|
|
3c3d881125 |
No files matched your search
@@ -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
@@ -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())
|
||||
@@ -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)
|
||||
@@ -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())
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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)),
|
||||
|
||||
@@ -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(®)?;
|
||||
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(®istry),
|
||||
)
|
||||
.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(®istry)
|
||||
.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(®istry)).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(°raded), 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(®istry)).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());
|
||||
}
|
||||
@@ -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(®));
|
||||
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
|
||||
+5943
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5928
File diff suppressed because it is too large.
Load diff
+5929
File diff suppressed because it is too large.
Load diff
@@ -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"}
|
||||
@@ -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"])
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
Finished `release` profile [optimized] target(s) in 0.10s
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
canonical seed fixture rebuilt at /tmp/rune_cb_truth_home
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
OK: 33 cases byte-identical against live oracle rune.capability_broker
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
1
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,2 @@
|
||||
parity: 468/468 checks OK (frozen=33 fuzz=421 live=14)
|
||||
LIVE PARITY 100% on the gap-closing functions
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -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)
|
||||
Reference in new issue
Block a user