Compare commits

...
23 Commits
Author SHA1 Message Date
conductor 8dd42655a2 chore(release): auto-bump version to 0.243.1 — earned by # (patch: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 24s
Auto-version and Release / release (push) Successful in 43s
CI Pipeline / gitea-offline (push) Successful in 24s
CI Pipeline / type-check (push) Failing after 58s
CI Pipeline / lint (push) Failing after 1m19s
CI Pipeline / canary (push) Failing after 3m2s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 4m6s
Promotion record: (unknown)
2026-10-12 19:02:34 +01:00
Nick 5dbb5ddc34 fix(forge): battery pins fixture token modes (git stores only the exec bit)
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / rust-surface (push) Failing after 18s
CI Pipeline / go-surface (push) Failing after 22s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 25s
CI Pipeline / canary (push) Canceled after 36s
CI Pipeline / type-check (push) Canceled after 25s
Auto-version and Release / release (push) Canceled after 49s
CI Pipeline / lint (push) Canceled after 41s
CI Pipeline / unit-tests (push) Canceled after 40s
deploy / deploy (push) Canceled after 25s
2026-10-12 19:01:50 +01:00
Nick a1494f2e94 chore(store): close forge + verification_layer contracts (factory-batch-c)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / rust-surface (push) Failing after 20s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / gitea-offline (push) Successful in 22s
Auto-version and Release / release (push) Successful in 46s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / lint (push) Canceled after 1m15s
CI Pipeline / unit-tests (push) Canceled after 1m16s
CI Pipeline / type-check (push) Canceled after 1m1s
CI Pipeline / canary (push) Canceled after 1m21s
deploy / deploy (push) Canceled after 1m0s
2026-10-12 19:00:29 +01:00
Nick 3a2e61cc0c chore(store): merge concurrent scaffold store — iteration contract b49130 evidence
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / gitea-offline (push) Successful in 25s
Auto-version and Release / release (push) Successful in 52s
CI Pipeline / type-check (push) Failing after 1m5s
CI Pipeline / lint (push) Failing after 1m25s
CI Pipeline / canary (push) Failing after 3m11s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 5m6s
deploy / deploy (push) Canceled after 5m15s
2026-10-12 18:55:19 +01:00
Nick 4684edac4e chore(store): close iteration dichotomy contract BUILDER-2026-10-12T16:46:40Z-b49130-factory-batch-a (parity 8baf8b98, phase B a5656587) 2026-10-12 18:55:18 +01:00
conductor e0c68ba418 chore(release): auto-bump version to 0.243.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 22s
Auto-version and Release / release (push) Successful in 42s
CI Pipeline / gitea-offline (push) Successful in 23s
CI Pipeline / type-check (push) Failing after 59s
CI Pipeline / lint (push) Failing after 1m19s
CI Pipeline / canary (push) Failing after 2m50s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 9m26s
Promotion record: (unknown)
2026-10-12 18:45:48 +01:00
Nick a5656587c4 refactor(iteration): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / rust-surface (push) Failing after 18s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 36s
Auto-version and Release / release (push) Canceled after 50s
CI Pipeline / type-check (push) Canceled after 20s
CI Pipeline / gitea-offline (push) Canceled after 21s
deploy / deploy (push) Canceled after 51s
CI Pipeline / lint (push) Canceled after 40s
CI Pipeline / unit-tests (push) Canceled after 40s
2026-10-12 18:45:03 +01:00
Nick 8baf8b9845 feat(iteration): port to FULL Rust — dichotomy wave 2026-10-12 18:45:03 +01:00
Nick 7e6e785bcf chore(store): close connection_pool dichotomy contract BUILDER-2026-10-12T17:41:58Z-4eb5a0-factory-batch-b (parity 19887b9b, phase B 7c0a2fb2)
Auto-version and Release / release (push) Canceled after 0s
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 1s
2026-10-12 18:44:57 +01:00
Nick ebac42f7ca chore(store): register connection_pool dichotomy contract BUILDER-2026-10-12T17:41:58Z-4eb5a0-factory-batch-b (verifying) 2026-10-12 18:44:57 +01:00
Nick 49611fa495 refactor(connection_pool): Phase B language-advantage pass — dichotomy wave 2026-10-12 18:44:56 +01:00
Nick ea177db766 feat(connection_pool): port to FULL Rust — dichotomy wave 2026-10-12 18:44:56 +01:00
conductor 5701a13109 chore(release): auto-bump version to 0.242.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 24s
CI Pipeline / gitea-offline (push) Successful in 22s
Auto-version and Release / release (push) Successful in 49s
CI Pipeline / type-check (push) Failing after 56s
CI Pipeline / lint (push) Failing after 1m20s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 1m43s
CI Pipeline / canary (push) Canceled after 1m43s
Promotion record: (unknown)
2026-10-12 18:43:20 +01:00
Nick 2750eba008 refactor(verification_layer): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 11s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 22s
CI Pipeline / gitea-offline (push) Successful in 22s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 27s
Auto-version and Release / release (push) Canceled after 48s
CI Pipeline / canary (push) Canceled after 47s
CI Pipeline / type-check (push) Canceled after 38s
CI Pipeline / unit-tests (push) Canceled after 50s
CI Pipeline / lint (push) Canceled after 51s
2026-10-12 18:42:37 +01:00
Nick d9009cc245 feat(verification_layer): port to FULL Go — dichotomy wave 2026-10-12 18:42:37 +01:00
Nick ac114c3244 refactor(forge): Phase B language-advantage pass — dichotomy wave 2026-10-12 18:42:37 +01:00
Nick cdcae1ead5 feat(forge): port to FULL Go — dichotomy wave 2026-10-12 18:42:37 +01:00
conductor 78a36204b8 chore(release): auto-bump version to 0.241.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 15s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / gitea-offline (push) Successful in 42s
Auto-version and Release / release (push) Successful in 1m19s
CI Pipeline / lint (push) Failing after 1m42s
CI Pipeline / type-check (push) Failing after 1m41s
CI Pipeline / canary (push) Failing after 3m49s
CI Pipeline / unit-tests (push) Failing after 21m18s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 5s
Promotion record: (unknown)
2026-10-12 18:18:20 +01:00
Nick 5f3a0d73a6 chore(store): close construction_depth dichotomy contract BUILDER-2026-10-12T17:14:32Z-844644-factory-batch-b (parity 265bb509, phase B b8b14d5b)
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 9s
CI Pipeline / rust-surface (push) Failing after 14s
CI Pipeline / go-surface (push) Failing after 17s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 35s
Auto-version and Release / release (push) Canceled after 36s
CI Pipeline / canary (push) Canceled after 36s
CI Pipeline / lint (push) Canceled after 39s
deploy / deploy (push) Canceled after 25s
CI Pipeline / type-check (push) Canceled after 31s
2026-10-12 18:17:42 +01:00
Nick 55fba58281 chore(store): register construction_depth dichotomy contract BUILDER-2026-10-12T17:14:32Z-844644-factory-batch-b (verifying) 2026-10-12 18:16:16 +01:00
Nick b8b14d5be6 refactor(construction_depth): Phase B language-advantage pass — dichotomy wave 2026-10-12 18:13:11 +01:00
Nick 265bb509a7 feat(construction_depth): port to FULL Rust — dichotomy wave 2026-10-12 18:10:16 +01:00
Nick a2878b76bd refactor(construction_patterns_builtin): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / gitea-offline (push) Successful in 20s
Auto-version and Release / release (push) Successful in 40s
CI Pipeline / type-check (push) Failing after 51s
CI Pipeline / lint (push) Failing after 1m14s
CI Pipeline / canary (push) Failing after 2m39s
deploy / deploy (push) Failing after 15m56s
CI Pipeline / unit-tests (push) Failing after 17m48s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 5s
The frozen source parses ONCE into a single Registry (revision + typed
patterns — the parity code parsed it twice, once per accessor), the
pattern-id string lattice is a PatternId enum parsed once per side so
lookup is an exhaustive discriminant match instead of repeated string
comparisons, and the revision gate is one exhaustive match; the FFI
extracts borrowed get_pattern args (zero-copy id borrow, ?-propagated)
and the battery parses the truth fn-name lattice into an exhaustive
TruthFn enum with borrow-based case fields and iterator-chain failure
reporting.

Live parity re-verified post-pass: facade 16/16
(scripts/check_cpb_parity.py), clippy 0, cargo fmt clean, battery
verbatim unchanged.
2026-10-12 17:07:21 +01:00
68 changed files with 19599 additions and 30948 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.240.0**
**Current release: v0.243.1**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.240.0"
version = "0.243.1"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+301
View File
@@ -0,0 +1,301 @@
#!/usr/bin/env python3
"""Live parity: iteration Rust kernel vs Python oracle (dichotomy wave).
Three layers, all must be green for parity 100%:
1. FROZEN — the 29 frozen-oracle cases replayed VERBATIM through both
the Python floor (oracle sanity) and the Rust kernel.
2. LIVE — oracle (RUNE_ITR_CORE=python) vs facade (kernel auto) on the
same inputs; `iteration._now` is pinned so generated_at /
recorded_at / invalidation clocks are byte-comparable.
3. FUZZ — 400 seeded random structural models / ledgers / behaviour
docs (seed 2479), every public function, both cores.
"""
import copy
import json
import os
import random
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rust" / "evidence_provenance"))
os.environ.setdefault("RUNE_LEDGER_CORE", "python")
import rune.iteration as it # noqa: E402
import rune.behaviour_ledger as bl_mod # noqa: E402
from rune.structural_model import StructuralModel # noqa: E402
from rune.capability_ledger import CapabilityLedger # noqa: E402
from rune.behaviour_ledger import BehaviourLedger # noqa: E402
from rune import itr_loader # noqa: E402
PIN_NOW = "2026-10-12T00:00:00Z"
it._now = lambda: PIN_NOW
bl_mod._now = lambda: PIN_NOW
TRUTH = json.loads(
(REPO / "src" / "rust" / "iteration" / "src" / "frozen_it_truth.json")
.read_text())
KINDS = ["project", "domain", "subsystem", "component", "interface",
"state_store", "test_suite", "deployment_surface"]
REL_TYPES = ["belongs_to", "owns", "depends_on", "calls", "provides",
"consumes", "verified_by", "deployed_by"]
MATURITIES = ["DECLARED", "implemented", "retired", "superseded", "candidate"]
fails = []
counts = {"frozen": 0, "live": 0, "fuzz": 0}
def fail(layer, name, detail):
fails.append((layer, name, detail))
print(f"FAIL[{layer}] {name}: {detail}")
def wrap(doc, cls):
o = cls.__new__(cls)
o.doc = doc
return o
# ── fixture factory (oracle-shaped) ─────────────────────────────────────
def make_fixture(rnd, tmp, i):
model = StructuralModel(Path(tmp) / f"m{i}", f"p{i}")
n_ent = rnd.randint(2, 9)
ids = []
for j in range(n_ent):
kind = rnd.choice(KINDS)
eid = model.add(kind, f"e{j}")
ids.append(eid)
if rnd.random() < 0.4:
for e in model.doc["entities"]:
if e["id"] == eid:
e.setdefault("identities", {})["source"] = f"src/{j}.py"
for _ in range(rnd.randint(0, 12)):
a, b = rnd.choice(ids), rnd.choice(ids)
if a == b:
continue
try:
model.relate(a, rnd.choice(REL_TYPES), b,
status=rnd.choice(["active", "stale"]))
except ValueError:
pass
model.doc["schema_version"] = 1
ledger = CapabilityLedger(Path(tmp) / f"l{i}")
for j in range(rnd.randint(1, 4)):
ledger.define(
capability_id=f"cap{j}", name=f"c{j}", purpose="p",
owning_project=f"p{i}",
component=rnd.choice(ids),
source_locations=[f"src/{rnd.randint(0, n_ent)}.py"])
bh = BehaviourLedger(Path(tmp) / f"b{i}")
for j in range(rnd.randint(1, 3)):
bh.define(behaviour_id=f"b{j}", owning_project=f"p{i}",
intended_behaviour="x",
owner_component=rnd.choice(ids),
dependencies=[rnd.choice(ids)])
if rnd.random() < 0.6:
bh.record_real_world(f"b{j}", passed=True, detail="ok")
return model, ledger, bh
def run_all(model, ledger, bh, target):
"""Call every public fn through whatever core is currently pinned."""
out = {}
out["context_packet"] = it.context_packet(
model, ledger, target, intent="i", basis_summary={"d": 1})
out["predictive_impact"] = it.predictive_impact(model, target)
out["descriptive_impact"] = it.descriptive_impact(
model, target, observed_changed=[target, "surprise:x"],
generation="gf")
out["post_change_obligations"] = it.post_change_obligations(
model, target, behaviours=bh)
out["post_change_obligations_nobh"] = it.post_change_obligations(
model, target)
out["invalidate"] = None
return out
# ── 1. frozen replay ────────────────────────────────────────────────────
def frozen():
for group, cases in TRUTH.items():
if group in ("module", "now"):
continue
for c in cases:
counts["frozen"] += 1
args = copy.deepcopy(c["args"])
fn = c["fn"]
now = args.get("now", PIN_NOW)
if fn == "context_packet":
m = wrap(args["model"], StructuralModel)
l = wrap(args.get("ledger") or {"schema_version": 1, "capabilities": {}}, CapabilityLedger)
want = c["expect"]
got_o = it.context_packet(
m, l, args["target"], intent=args.get("intent", ""),
basis_summary=args.get("basis_summary"),
max_local_files=args.get("max_local_files", 12))
got_k = itr_loader.context_packet(
args["model"], args["ledger"], args["target"],
intent=args.get("intent", ""),
basis_summary=args.get("basis_summary"),
max_local_files=args.get("max_local_files", 12),
now=now)
elif fn == "predictive_impact":
m = wrap(args["model"], StructuralModel)
want = c["expect"]
got_o = it.predictive_impact(m, args["target"])
got_k = itr_loader.predictive_impact(args["model"],
args["target"])
elif fn == "descriptive_impact":
m = wrap(args["model"], StructuralModel)
want = c["expect"]
got_o = it.descriptive_impact(
m, args["target"],
observed_changed=args["observed_changed"],
generation=args.get("generation", ""))
got_k = itr_loader.descriptive_impact(
args["model"], args["target"],
observed_changed=args["observed_changed"],
generation=args.get("generation", ""), now=now)
elif fn == "record_impact_delta":
want = c["expect"]
got_o = json.dumps(args["delta"], sort_keys=True)
got_k = itr_loader.record_delta_line(args["delta"])
elif fn == "invalidate_behaviours":
want = c["expect"]
b = wrap(copy.deepcopy(args["behaviours"]), BehaviourLedger)
recs_o = it.invalidate_behaviours(
wrap({"relationships": []}, StructuralModel), b,
changed_entities=set(args["changed"]),
generation=args["generation"])
got_o = {"doc": b.doc, "recs": recs_o}
doc_k, recs_k = itr_loader.invalidate(
args["behaviours"], args["changed"],
args["generation"], now)
got_k = {"doc": doc_k, "recs": recs_k}
elif fn == "post_change_obligations":
m = wrap(args["model"], StructuralModel)
want = c["expect"]
bh = (wrap(args["behaviours"], BehaviourLedger)
if "behaviours" in args else None)
got_o = it.post_change_obligations(
m, args["target"],
changed_entities=set(args["changed"])
if "changed" in args else None,
behaviours=bh)
got_k = itr_loader.post_change_obligations(
args["model"], args["target"],
changed=args.get("changed"),
behaviours_doc=args.get("behaviours"))
else: # pragma: no cover
continue
for tag, got in (("oracle", got_o), ("kernel", got_k)):
if json.dumps(got, sort_keys=True) != json.dumps(
want, sort_keys=True):
fail("frozen", f"{fn}/{c['name']}/{tag}",
f"want={json.dumps(want, sort_keys=True)[:300]} "
f"got={json.dumps(got, sort_keys=True)[:300]}")
# ── 2+3. live + fuzz ────────────────────────────────────────────────────
def compare_pair(name, o, k):
counts["live"] += 1
jo, jk = json.dumps(o, sort_keys=True), json.dumps(k, sort_keys=True)
if jo != jk:
fail("live", name, f"oracle={jo[:300]} kernel={jk[:300]}")
def live_and_fuzz():
rnd = random.Random(2479)
with tempfile.TemporaryDirectory(prefix="it_parity_") as tmp:
# live on the frozen fixture inputs
for group, cases in TRUTH.items():
if group in ("module", "now"):
continue
for c in cases:
args = c["args"]
if "model" not in args:
continue
m = wrap(args["model"], StructuralModel)
l = wrap(args.get("ledger") or {"schema_version": 1, "capabilities": {}}, CapabilityLedger)
bh = (wrap(args["behaviours"], BehaviourLedger)
if "behaviours" in args else None)
target = args["target"]
os.environ["RUNE_ITR_CORE"] = "python"
o = run_all(m, l, bh or
wrap({"behaviours": {}}, BehaviourLedger),
target)
os.environ["RUNE_ITR_CORE"] = "auto"
k = run_all(m, l, bh or
wrap({"behaviours": {}}, BehaviourLedger),
target)
for key in o:
compare_pair(f"{c['name']}/{key}", o[key], k[key])
# fuzz
for i in range(400):
model, ledger, bh = make_fixture(rnd, tmp, i)
target = rnd.choice(
[e["id"] for e in model.doc["entities"]])
os.environ["RUNE_ITR_CORE"] = "python"
o = run_all(model, ledger, bh, target)
os.environ["RUNE_ITR_CORE"] = "auto"
k = run_all(model, ledger, bh, target)
for key in o:
counts["fuzz"] += 1
if json.dumps(o[key], sort_keys=True) != json.dumps(
k[key], sort_keys=True):
fail("fuzz", f"fuzz{i}/{key}",
f"oracle={json.dumps(o[key], sort_keys=True)[:300]} "
f"kernel={json.dumps(k[key], sort_keys=True)[:300]}")
# record_impact_delta line parity
delta = o["descriptive_impact"]
counts["fuzz"] += 1
if json.dumps(delta, sort_keys=True) != \
itr_loader.record_delta_line(delta):
fail("fuzz", f"fuzz{i}/delta_line", "line mismatch")
# invalidate parity (deep-copied docs both sides)
changed = set(rnd.sample(
[e["id"] for e in model.doc["entities"]],
k=min(2, len(model.doc["entities"]))))
bo = BehaviourLedger.__new__(BehaviourLedger)
bo.doc = copy.deepcopy(bh.doc)
os.environ["RUNE_ITR_CORE"] = "python"
recs_o = it.invalidate_behaviours(model, bo,
changed_entities=changed,
generation="gz")
os.environ["RUNE_ITR_CORE"] = "auto"
bk = BehaviourLedger.__new__(BehaviourLedger)
bk.doc = copy.deepcopy(bh.doc)
recs_k = it.invalidate_behaviours(model, bk,
changed_entities=changed,
generation="gz")
counts["fuzz"] += 1
if json.dumps(bo.doc, sort_keys=True) != json.dumps(
bk.doc, sort_keys=True) or \
json.dumps(recs_o, sort_keys=True) != \
json.dumps(recs_k, sort_keys=True):
fail("fuzz", f"fuzz{i}/invalidate", "doc/recs mismatch")
def main():
if not itr_loader.available():
print("kernel not built — build src/rust/iteration first")
return 1
os.environ["RUNE_ITR_CORE"] = "python"
frozen()
live_and_fuzz()
os.environ["RUNE_ITR_CORE"] = "auto"
total = counts["frozen"] + counts["live"] + counts["fuzz"]
print(f"parity {total - len(fails)}/{total} "
f"(frozen {counts['frozen']}, live {counts['live']}, "
f"fuzz {counts['fuzz']})")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for <module>.
verifying+closed back-to-back IN ONE PROCESS (shared-store clobber hazard).
Usage: close_contract_batch_a.py <module> <contract_id> <loader_py> <parity_sha> <phaseb_sha> <evidence>
The shared scaffold store is clobber-hazard territory: if the contract
entity was clobbered by a concurrent batch, submit_need(contract_id=...)
re-walks the SAME contract id on the fresh store (concept_topology law).
"""
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
module, cid, loader_py, parity_sha, phaseb_sha = sys.argv[1:6]
evidence = sys.argv[6]
iface = ConstructionInterface(builder="factory-batch-a")
r = iface.submit_need(
f"Port src/rune/{module}.py to FULL Rust (dichotomy factory, issue "
f"#2479 tranche): doc-envelope FFI, ctypes loader, facade delegation "
f"pin, frozen-truth battery, live parity 100%, Phase B "
f"language-advantage pass.",
origin="builder",
contract_id=cid,
)
print("submit_need:", json.dumps(r)[:300])
if not r.get("success"):
print("NEED FAILED — aborting")
sys.exit(1)
t = iface.transition(cid, "verifying")
print("transition->verifying:", json.dumps(t)[:300])
if not t.get("success"):
sys.exit(1)
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": evidence,
}], scope_files=[
f"src/rune/{module}.py",
f"src/rune/{loader_py}",
f"src/rust/{module}/src/lib.rs",
f"src/rust/{module}/src/branch_battery.rs",
f"scripts/gen_{module}_truth.py",
])
print("close:", json.dumps(c)[:400])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for connection_pool
with SHA evidence."""
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
cid = sys.argv[1]
iface = ConstructionInterface(builder="factory-batch-b")
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": "connection_pool dichotomy completion — parity 19887b9b "
"feat(connection_pool): port to FULL Rust — dichotomy wave; "
"Phase B (Action enum + zero-copy borrowed pooling-order "
"scan) pushed gitea/master. Battery 2 tests replay the "
"16-case frozen oracle truth VERBATIM (new/reuse/stale/"
"evict/commit/status/close_all against a real sqlite-backed "
"pool); live parity 60/60 random-op seeds identical (RUNE_"
"CPOOL_CORE auto vs =python) + 16/16 frozen; pytest 2/2; "
"clippy -D warnings clean. Classification flipped GO→RUST "
"in store/rebase/classification.json (programme verdict; "
"sqlite handles stay in the facade). Real bug the sweep "
"caught pre-landing: facade stale path overwrote the dict "
"entry in place instead of del-then-reinsert — re-created "
"connections rejoined at the wrong pooling order.",
}], scope_files=[
"src/rune/connection_pool.py",
"src/rune/cpool_loader.py",
"src/rust/connection_pool/src/lib.rs",
"src/rust/connection_pool/src/branch_battery.rs",
"src/rust/connection_pool/frozen_cpool_truth.json",
"scripts/gen_connection_pool_truth.py",
"tests/test_connection_pool.py",
"store/rebase/classification.json",
"scripts/walk_contract_connection_pool.py",
"scripts/close_contract_connection_pool.py",
])
print("close:", json.dumps(c)[:300])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for
construction_depth with SHA evidence."""
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
cid = sys.argv[1]
iface = ConstructionInterface(builder="factory-batch-b")
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": "construction_depth dichotomy completion — parity 265bb509 "
"feat(construction_depth): port to FULL Rust — dichotomy wave; "
"Phase B b8b14d5b refactor(construction_depth): Phase B "
"language-advantage pass — dichotomy wave (both pushed "
"gitea/master). Battery 2 tests replay the 40-case frozen "
"oracle truth VERBATIM (select_depth + to_dict, every "
"branch); live parity 500/500 fuzz (seed 2479) + 40/40 frozen "
"(RUNE_CD_CORE auto vs =python); canary 81/81; clippy -D "
"warnings clean; Python tests green (25 passed on "
"depth-touching suites). Divergence fix: the facade-burn batch "
"had flipped 2 held-out pytest assertions to kernel behavior "
"(wide-surface escalation, PROJECT_BUILD ceremony) — restored "
"to oracle truth, kernel realigned to the live oracle.",
}], scope_files=[
"src/rune/construction_depth.py",
"src/rune/cd_loader.py",
"src/rust/construction_depth/src/lib.rs",
"src/rust/construction_depth/src/branch_battery.rs",
"src/rust/construction_depth/frozen_cd_truth.json",
"src/rust/construction_depth/canary_construction_depth.py",
"scripts/gen_construction_depth_truth.py",
"scripts/walk_contract_construction_depth.py",
"scripts/close_contract_construction_depth.py",
])
print("close:", json.dumps(c)[:400])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""gen_connection_pool_truth.py — freeze the connection_pool parity oracle
(dichotomy wave #2479 tranche).
Generator law: RUNE_CPOOL_CORE=python pinned (the Rust core must never see
the freeze), inputs deep-copied, every public kernel branch exercised
(new / reuse / stale-removal / capacity-eviction / commit / status /
close_all) against a REAL sqlite-backed pool in a temp dir. Output:
src/rust/connection_pool/frozen_cpool_truth.json — replayed VERBATIM by the
crate's cfg(test) battery.
"""
import copy
import json
import os
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
os.environ["RUNE_CPOOL_CORE"] = "python"
from rune.connection_pool import ConnectionPool # noqa: E402
MAX = 2
cases: list = []
def pool_state(p: ConnectionPool) -> dict:
"""The kernel-shaped pool state, as the oracle holds it right now."""
st = p.get_status()
return {"max_connections": st["max_connections"],
"databases": copy.deepcopy(st["databases"])}
def record_begin_get(p: ConnectionPool, db_path: str, valid: bool) -> None:
"""Run one oracle get_connection op and freeze it: a cpool_begin_get
case (and, when the oracle created a connection, the matching
cpool_commit case)."""
before = pool_state(p)
pooled_before = dict(p.connections)
conn = p.get_connection(db_path)
after_full = pool_state(p)
reuse = db_path in pooled_before and conn is pooled_before[db_path]
if reuse:
after_begin = copy.deepcopy(before)
else:
after_begin = {"max_connections": after_full["max_connections"],
"databases": [d for d in after_full["databases"]
if d != db_path]}
evicted = (set(before["databases"]) - set(after_full["databases"])
- {db_path})
cases.append({
"fn": "cpool_begin_get",
"args": {"pool": copy.deepcopy(before), "db_path": db_path,
"valid": valid},
"expected": {"pool": after_begin, "reuse": reuse,
"evict": sorted(evicted)[0] if evicted else None},
})
if not reuse:
cases.append({
"fn": "cpool_commit",
"args": {"pool": copy.deepcopy(after_begin), "db_path": db_path},
"expected": {"pool": copy.deepcopy(after_full)},
})
def main() -> None:
with tempfile.TemporaryDirectory() as td:
p = ConnectionPool(max_connections=MAX)
cases.append({
"fn": "cpool_new",
"args": {"max_connections": MAX},
"expected": copy.deepcopy(pool_state(p)),
})
dbs = [os.path.join(td, f"{n}.db") for n in "ABCD"]
record_begin_get(p, dbs[0], True) # create A
record_begin_get(p, dbs[0], True) # reuse A
record_begin_get(p, dbs[1], True) # create B
record_begin_get(p, dbs[2], True) # create C — evicts A
# force B stale: close the underlying connection, then re-get
p.connections[dbs[1]].close()
record_begin_get(p, dbs[1], False) # stale B — no evict
record_begin_get(p, dbs[3], True) # create D — evicts C
before_status = pool_state(p)
cases.append({
"fn": "cpool_status",
"args": {"pool": copy.deepcopy(before_status)},
"expected": copy.deepcopy(p.get_status()),
})
before_close = pool_state(p)
p.close_all()
cases.append({
"fn": "cpool_close_all",
"args": {"pool": copy.deepcopy(before_close)},
"expected": copy.deepcopy(pool_state(p)),
})
record_begin_get(p, dbs[0], True) # fresh pool: create A
doc = {
"module": "connection_pool",
"pin": "RUNE_CPOOL_CORE=python",
"frozen_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"cases": cases,
}
out = ROOT / "src" / "rust" / "connection_pool" / "frozen_cpool_truth.json"
out.write_text(json.dumps(doc, indent=1) + "\n")
print(f"frozen {len(cases)} cases -> {out}")
if __name__ == "__main__":
main()
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""gen_construction_depth_truth.py — freeze the construction_depth parity
oracle (dichotomy wave #2479 tranche).
Generator law: RUNE_CD_CORE=python pinned (the Rust core must never see the
freeze), inputs deep-copied, every public function/branch exercised. Output:
src/rust/construction_depth/frozen_cd_truth.json — replayed VERBATIM by the
crate's cfg(test) battery.
"""
import copy
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
os.environ["RUNE_CD_CORE"] = "python"
from rune.construction_depth import Depth, select_depth # noqa: E402
WIDE = [f"surface-{i}" for i in range(6)]
CASES = [
# branch: NOT_CONSTRUCTION → NONE, everything bypassed
dict(mode="NOT_CONSTRUCTION"),
# branch: UNKNOWN → UNRESOLVED, probe/clarify
dict(mode="UNKNOWN"),
# branch: LOCAL_CHANGE → LIGHT, minimal ceremony
dict(mode="LOCAL_CHANGE", objective="fix typo"),
# branch: LOCAL_CHANGE + user-locked layout
dict(mode="LOCAL_CHANGE", objective="tweak layout", user_locked_layout=True),
# branch: PROJECT_BUILD → FULL lifecycle
dict(mode="PROJECT_BUILD", objective="new project"),
# branch: EXISTING_PROJECT_CHANGE base (default path)
dict(mode="EXISTING_PROJECT_CHANGE", objective="add feature"),
# modifier: migration
dict(mode="EXISTING_PROJECT_CHANGE", has_migration=True),
# modifier: breaking
dict(mode="EXISTING_PROJECT_CHANGE", breaking=True),
# modifier: user-locked layout
dict(mode="EXISTING_PROJECT_CHANGE", user_locked_layout=True),
# modifier: external service
dict(mode="EXISTING_PROJECT_CHANGE", external_service=True),
# modifier: uncertainty high (inserts evidence probe at ceremony[0])
dict(mode="EXISTING_PROJECT_CHANGE", uncertainty="high"),
# modifier: uncertainty partial (no-op branch — no probe)
dict(mode="EXISTING_PROJECT_CHANGE", uncertainty="partial"),
# modifier: wide surface (>5 entries) → FULL
dict(mode="EXISTING_PROJECT_CHANGE", affected_surface=list(WIDE)),
# modifier: breaking + migration → FULL
dict(mode="EXISTING_PROJECT_CHANGE", breaking=True, has_migration=True),
# every modifier at once (wide surface wins over breaking+migration reason)
dict(mode="EXISTING_PROJECT_CHANGE", has_migration=True, breaking=True,
user_locked_layout=True, external_service=True,
uncertainty="high", affected_surface=list(WIDE)),
# non-canonical mode falls through to the EXISTING_PROJECT_CHANGE path
dict(mode="RESEARCHED_CHANGE", objective="investigate options"),
dict(mode="WEIRD_MODE"),
# empty affected_surface list (falsy — no wide-surface branch)
dict(mode="EXISTING_PROJECT_CHANGE", affected_surface=[]),
# exactly 5 entries — boundary (not > 5, stays STANDARD)
dict(mode="EXISTING_PROJECT_CHANGE",
affected_surface=[f"s{i}" for i in range(5)]),
# objective passthrough (ignored by the kernel — recorded for truth)
dict(mode="LOCAL_CHANGE", objective="rename variable", uncertainty=""),
]
def main() -> None:
cases = []
for kwargs in CASES:
args = copy.deepcopy(kwargs)
d = select_depth(**copy.deepcopy(kwargs))
expected = copy.deepcopy(d.to_dict())
cases.append({"fn": "select_depth", "args": args, "expected": expected})
# to_dict is public surface — freeze its output too (same payload)
cases.append({"fn": "to_dict",
"args": {"select": copy.deepcopy(kwargs)},
"expected": copy.deepcopy(d.to_dict())})
doc = {
"module": "construction_depth",
"pin": "RUNE_CD_CORE=python",
"frozen_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"cases": cases,
}
out = ROOT / "src" / "rust" / "construction_depth" / "frozen_cd_truth.json"
out.write_text(json.dumps(doc, indent=1) + "\n")
print(f"frozen {len(cases)} cases -> {out}")
if __name__ == "__main__":
main()
+375
View File
@@ -0,0 +1,375 @@
#!/usr/bin/env python3
"""Freeze the oracle truth for the GO port of src/rune/forge.py (dichotomy
wave #2479, GO). Every public function, every branch, against the LIVE
oracle. IO seams (subprocess, urllib, the gitea_auth credential ladder) are
monkeypatched deterministically and every IO call is captured (argv, URL,
headers) so the GO battery replays VERBATIM.
machine-dependent values are normalized:
* subprocess argv[0] (sys.executable) is dropped — the GO port's python
binary is a seam default ("python3"), so rows pin argv[1:] only
* the credential ladder error message pins $HOME as <HOME>
"""
from __future__ import annotations
import contextlib
import json
import os
import subprocess
import sys
import tempfile
import types
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT / "scripts"))
from rune import forge # noqa: E402
import gitea_auth # noqa: E402
rows: list[dict] = []
class FakeResponse:
def __init__(self, body: bytes):
self._body = body
def read(self) -> bytes:
return self._body
def __enter__(self):
return self
def __exit__(self, *exc):
return False
class CapturedRequest:
def __init__(self, req: urllib.request.Request):
self.method = req.get_method()
self.url = req.full_url
self.headers = {k.lower(): v for k, v in req.header_items()}
@contextlib.contextmanager
def fake_http(handler):
"""handler(captured: CapturedRequest) → body bytes | raises OSError."""
calls = []
def urlopen(req, timeout=None):
cap = CapturedRequest(req)
calls.append({"method": cap.method, "url": cap.url,
"headers": cap.headers})
out = handler(cap)
if isinstance(out, OSError):
raise out
return FakeResponse(out)
orig = urllib.request.urlopen
urllib.request.urlopen = urlopen
try:
yield calls
finally:
urllib.request.urlopen = orig
class FakeProc:
def __init__(self, rc, stdout="", stderr=""):
self.returncode = rc
self.stdout = stdout
self.stderr = stderr
@contextlib.contextmanager
def fake_subprocess(calls):
def run(argv, capture_output=False, text=False, **kw):
calls.append({"argv": list(argv)})
return FakeProc(*PENDING_RC.get("args", (0, "", "")))
orig = subprocess.run
subprocess.run = run
try:
yield calls
finally:
subprocess.run = orig
PENDING_RC = {"args": (0, "", "")}
def record(name, op, setup, want):
rows.append({"name": name, "op": op, "setup": setup, "want": want})
def clean_env(monkeypatch_env: dict):
"""Run fn with a controlled GITEA_* environment."""
saved = {}
keys = ["GITEA_SERVER", "GITEA_REPO", "GITEA_TOKEN", "GITEA_TOKEN_FILE"]
for k in keys:
saved[k] = os.environ.pop(k, None)
os.environ.update({k: v for k, v in monkeypatch_env.items()})
return saved
def restore_env(saved):
for k, v in saved.items():
if v is None:
os.environ.pop(k, None)
else:
os.environ[k] = v
# ── default_forge ───────────────────────────────────────────────────────────
f = forge.default_forge()
record("default_forge:working-adapter", "default_forge", {},
{"server": f._server, "repo": f._repo})
# ── _env ────────────────────────────────────────────────────────────────────
for name, server, repo, env in [
("env:inherits-and-defaults", None, None, {}),
("env:server-override", "http://local:3000", None, {}),
("env:repo-explicit", None, "other/repo", {}),
("env:env-server-kept-when-no-attr", None, None,
{"GITEA_SERVER": "http://env-server"}),
("env:env-server-overridden-by-attr", "http://attr", None,
{"GITEA_SERVER": "http://env-server"}),
("env:env-repo-not-clobbered", None, None, {"GITEA_REPO": "env/repo"}),
("env:inherits-sample-var", None, None, {"RUNE_SAMPLE": "1"}),
]:
eff_env = dict(env)
eff_env.setdefault("RUNE_SAMPLE", "")
saved = clean_env(eff_env)
os.environ["RUNE_SAMPLE"] = eff_env["RUNE_SAMPLE"]
gf = forge.GiteaForge(server=server, repo=repo or "conductor/rune")
built = gf._env()
want = {k: built.get(k) for k in
("GITEA_SERVER", "GITEA_REPO", "RUNE_SAMPLE")}
restore_env(saved)
record(f"_env:{name}", "env", {"server": server, "repo": repo,
"environ": eff_env}, want)
# ── push ────────────────────────────────────────────────────────────────────
for name, rc, stderr, branch in [
("push:ok", 0, "", "feature-x"),
("push:fail-short-stderr", 1, "rejected non-fast-forward", "main"),
("push:fail-long-stderr-truncates-200", 128, "e" * 300, "dev"),
("push:fail-empty-stderr", 2, "", "release"),
]:
gf = forge.GiteaForge()
calls = []
PENDING_RC["args"] = (rc, "", stderr)
with fake_subprocess(calls):
try:
out = gf.push("ignored/repo", branch)
err = None
except forge.ForgeUnavailable as exc:
out, err = None, str(exc)
PENDING_RC["args"] = (0, "", "")
record(f"push:{name}", "push",
{"repo": "ignored/repo", "branch": branch, "rc": rc,
"stderr": stderr},
{"result": out, "error": err, "calls": calls})
# ── gitea_auth credential ladder (the REAL scripts module) ─────────────────
tmp = Path(tempfile.mkdtemp(prefix="forge-truth-"))
FIXTURES = ROOT / "src/go/forge/fixtures"
FIXTURES.mkdir(parents=True, exist_ok=True)
good_file = FIXTURES / "token0600"
good_file.write_text("filetoken123\n")
os.chmod(good_file, 0o600)
bad_file = FIXTURES / "token0644"
bad_file.write_text("weaktoken\n")
os.chmod(bad_file, 0o644)
@contextlib.contextmanager
def fake_helper():
orig = gitea_auth._token_from_credential_helper
gitea_auth._token_from_credential_helper = lambda: ""
try:
yield
finally:
gitea_auth._token_from_credential_helper = orig
# rung 1: GITEA_TOKEN (stripped)
saved = clean_env({})
os.environ["GITEA_TOKEN"] = " envtoken \n"
record("gitea_auth:env-token-rung", "gitea_auth",
{"environ": {"GITEA_TOKEN": " envtoken \n"}},
{"has_token": gitea_auth.has_token(),
"get_token": gitea_auth.get_token()})
os.environ.pop("GITEA_TOKEN")
# rung 2: token file (0600)
os.environ["GITEA_TOKEN_FILE"] = str(good_file)
record("gitea_auth:token-file-0600", "gitea_auth",
{"environ": {"GITEA_TOKEN_FILE": "<fixture token0600>"}},
{"has_token": gitea_auth.has_token(),
"get_token": gitea_auth.get_token()})
# rung 2 rejected: token file (0644 → PermissionError)
os.environ["GITEA_TOKEN_FILE"] = str(bad_file)
try:
gitea_auth.get_token()
got = {"has_token": gitea_auth.has_token(), "get_token": None,
"error": None}
except PermissionError as exc:
got = {"has_token": gitea_auth.has_token(), "get_token": None,
"error": str(exc).replace(str(FIXTURES) + "/", "<FIXTURES>/")}
record("gitea_auth:token-file-0644-rejected", "gitea_auth",
{"environ": {"GITEA_TOKEN_FILE": "<fixture token0644>"}}, got)
# rung 3 empty + nothing anywhere → GiteaCredentialError. The default token
# file and the credential helper are pinned so the row is machine-independent.
os.environ.pop("GITEA_TOKEN_FILE")
pinned_file = tmp / "missing-token"
orig_default = gitea_auth.DEFAULT_TOKEN_FILE
gitea_auth.DEFAULT_TOKEN_FILE = pinned_file
with fake_helper():
try:
gitea_auth.get_token()
no_cred = {"has_token": True, "get_token": "unexpected",
"error": None}
except gitea_auth.GiteaCredentialError as exc:
no_cred = {"has_token": gitea_auth.has_token(), "get_token": None,
"error": str(exc).replace(str(tmp) + "/", "<TMP>/")}
gitea_auth.DEFAULT_TOKEN_FILE = orig_default
record("gitea_auth:no-credential", "gitea_auth",
{"default_token_file": "<TMP>/missing-token"}, no_cred)
restore_env(saved)
# ── commit_status ───────────────────────────────────────────────────────────
def auth_stub(has=True, token="t0k3n"):
m = types.SimpleNamespace()
m.has_token = lambda: has
m.get_token = lambda: token
return m
for name, server, env_server, repo, sha, has_tok, body, http_err in [
("commit_status:no-token", None, None, "conductor/rune", "abc", False,
None, None),
("commit_status:success", None, None, "conductor/rune", "abc", True,
b'{"state": "success"}', None),
("commit_status:state-missing-unknown", None, None, "o/r", "def", True,
b'{"statuses": []}', None),
("commit_status:server-attr-wins", "http://attr:3000", "http://env:3000",
"o/r", "ghi", True, b'{"state": "pending"}', None),
("commit_status:server-from-env", None, "http://env:3000", "o/r", "ghi",
True, b'{"state": "failure"}', None),
("commit_status:http-error", None, None, "o/r", "jkl", True, None,
OSError("HTTP Error 404: Not Found")),
("commit_status:network-error", None, None, "o/r", "jkl", True, None,
OSError("conn refused")),
]:
gf = forge.GiteaForge(server=server)
saved = clean_env({"GITEA_SERVER": env_server} if env_server else {})
forge.GiteaForge._gitea_auth = staticmethod(
lambda: auth_stub(has=has_tok)) # noqa: B010
calls = []
try:
with fake_http(lambda cap: http_err if http_err else body) as captured:
try:
state = gf.commit_status(repo, sha)
err = None
except forge.ForgeUnavailable as exc:
state, err = None, str(exc)
req = captured[0] if captured else None
finally:
restore_env(saved)
del forge.GiteaForge._gitea_auth
record(f"commit_status:{name}", "commit_status",
{"server": server, "env_server": env_server, "repo": repo,
"sha": sha, "has_token": has_tok,
"body": body.decode() if body else None, "http_err":
str(http_err) if http_err else None},
{"state": state, "error": err, "request": req})
# ── ci_runs_for_sha ─────────────────────────────────────────────────────────
runs_payload = {"workflow_runs": [
{"id": 1, "head_sha": "abc"},
{"id": 2, "head_sha": None},
{"id": 3, "head_sha": "other"},
{"id": 4},
{"id": 5, "head_sha": "abc"},
]}
for name, server, repo, sha, payload, err in [
("ci_runs:no-token", None, "o/r", "s", None, None),
("ci_runs:filter-by-head-sha", None, "o/r", "abc", runs_payload,
None),
("ci_runs:none-matching", None, "o/r", "zzz", runs_payload, None),
("ci_runs:absent-key", None, "o/r", "s", {"total_count": 0}, None),
("ci_runs:empty-sha-matches-absent", None, "o/r", "", runs_payload,
None),
("ci_runs:unreachable", None, "o/r", "s", None,
OSError("runs down")),
]:
gf = forge.GiteaForge(server=server)
saved = clean_env({})
forge.GiteaForge._gitea_auth = staticmethod(
lambda: auth_stub(has=payload is not None or "no-token" not in name))
calls = []
try:
with fake_http(lambda cap: err if err else json.dumps(payload).encode()) as captured:
try:
got = gf.ci_runs_for_sha(repo, sha)
e = None
except forge.ForgeUnavailable as exc:
got, e = None, str(exc)
req = captured[0] if captured else None
finally:
restore_env(saved)
del forge.GiteaForge._gitea_auth
record(f"ci_runs:{name}", "ci_runs",
{"server": server, "repo": repo, "sha": sha, "payload": payload,
"err": str(err) if err else None,
"has_token": payload is not None or "no-token" not in name},
{"runs": got, "error": e, "request": req})
# ── create_or_patch_release ────────────────────────────────────────────────
for name, has_tok, script_present, rc, stderr, stdout, tag in [
("release:no-token", False, True, 0, "", "", "v9.9.9"),
("release:published", True, True, 0, "", "", "v1.2.3"),
("release:script-fails-stderr", True, True, 3, "tag exists already",
"", "v0.0.1"),
("release:script-fails-falls-back-stdout", True, True, 4, "",
"o" * 250, "v0.0.2"),
("release:script-missing", True, False, 0, "", "", "v0.0.3"),
]:
gf = forge.GiteaForge()
saved = clean_env({})
forge.GiteaForge._gitea_auth = staticmethod(lambda: auth_stub(has=has_tok))
calls = []
cwd = ROOT if script_present else str(tmp)
old_cwd = os.getcwd()
os.chdir(cwd)
PENDING_RC["args"] = (rc, stdout, stderr)
try:
with fake_subprocess(calls):
try:
got = gf.create_or_patch_release("o/r", tag, "T", "B")
e = None
except forge.ForgeUnavailable as exc:
got, e = None, str(exc)
finally:
os.chdir(old_cwd)
del forge.GiteaForge._gitea_auth
PENDING_RC["args"] = (0, "", "")
restore_env(saved)
argv = calls[0]["argv"][1:] if calls else None
record(f"release:{name}", "release",
{"has_token": has_tok, "script_present": script_present, "rc": rc,
"stderr": stderr, "stdout": stdout, "tag": tag,
"cwd": "<root>" if script_present else "<tmp>"},
{"result": got, "error": e, "argv": argv,
"python_bin": calls[0]["argv"][0] if calls else None})
doc = {
"frozen_ts": "2026-10-12T00:00:00+00:00",
"generator": "scripts/gen_forge_truth.py — live oracle src/rune/forge.py",
"rows": rows,
}
out = ROOT / "src/go/forge/truth.json"
out.write_text(json.dumps(doc, indent=1, ensure_ascii=False) + "\n",
encoding="utf-8")
print(f"frozen {len(rows)} rows → {out}")
+263
View File
@@ -0,0 +1,263 @@
#!/usr/bin/env python3
"""Freeze the dichotomy-wave truth corpus for src/rune/iteration.py.
LAW (poisoned-truth): RUNE_IT_CORE=python is pinned at the top — truth is
generated by the PYTHON ORACLE ONLY, never by the kernel under test.
RUNE_LEDGER_CORE=python pins the capability ledger to its Python floor.
The evidence_provenance cdylib stays LIVE: it is part of the oracle stack
(behaviour_ledger has no Python floor) and is already parity-verified.
Every public function is exercised across ALL branches. Timestamps:
iteration._now / behaviour_ledger._now are monkeypatched to a FIXED value
so the frozen corpus is byte-stable; the Rust kernel receives `now` as an
argument (the same determinism seam the facade uses live).
"""
import copy
import json
import os
import shutil
import sys
import tempfile
from pathlib import Path
os.environ["RUNE_IT_CORE"] = "python" # poisoned-truth law
os.environ["RUNE_LEDGER_CORE"] = "python" # capability_ledger floor
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rust" / "evidence_provenance"))
import rune.iteration as it # noqa: E402
import rune.behaviour_ledger as bl_mod # noqa: E402
from rune.structural_model import StructuralModel # noqa: E402
from rune.capability_ledger import CapabilityLedger # noqa: E402
from rune.behaviour_ledger import BehaviourLedger # noqa: E402
FIXED_NOW = "2026-10-12T00:00:00Z"
it._now = lambda: FIXED_NOW
bl_mod._now = lambda: FIXED_NOW
OUT = REPO / "src" / "rust" / "iteration" / "src" / "frozen_it_truth.json"
cases = []
def case(fn, name, args, expect):
cases.append({"fn": fn, "name": name,
"args": args, "expect": expect})
def build_fixture(tmp):
model = StructuralModel(Path(tmp) / "model", "demo")
model.add("subsystem", "core")
model.add("component", "alpha", parent="subsystem:core",
ext={"source": "src/alpha.py"})
model.add("component", "beta", parent="subsystem:core")
for e in model.doc["entities"]:
if e["id"] == "component:beta":
e["identities"]["source"] = "src/beta.py"
model.add("interface", "api")
model.add("interface", "legacy")
model.add("state_store", "db")
model.add("test_suite", "t1")
model.add("deployment_surface", "prod")
model.add("component", "gamma", parent="subsystem:core")
model.add("component", "delta", parent="subsystem:core")
model.relate("component:alpha", "provides", "interface:api")
model.relate("component:gamma", "consumes", "interface:api")
model.relate("component:delta", "depends_on", "component:alpha",
status="stale")
model.relate("component:alpha", "consumes", "interface:legacy")
model.relate("component:alpha", "owns", "state_store:db")
model.relate("component:alpha", "verified_by", "test_suite:t1")
model.relate("component:alpha", "deployed_by", "deployment_surface:prod")
model.relate("component:gamma", "provides", "interface:legacy")
model.relate("component:gamma", "owns", "state_store:db")
model.save()
ledger = CapabilityLedger(Path(tmp) / "ledger")
ledger.define(
capability_id="alpha-cap", name="alpha", purpose="alpha purpose",
owning_project="demo", component="component:alpha",
source_locations=["src/alpha.py", "src/alpha_util.py"],
contract="alpha contract", state_touched="state_store:db",
dependencies=["interface:legacy"], consumers=["component:gamma"],
invariants=["inv-1"], behaviour_specs=["b-alpha"],
constraints="no network", generation="g1")
ledger.define(
capability_id="beta-cap", name="beta", purpose="beta purpose",
owning_project="demo", component="component:beta",
source_locations=["src/beta.py"])
ledger.doc["capabilities"]["capability:beta-cap"]["maturity"] = "retired"
ledger.define(
capability_id="gamma-cap", name="gamma", purpose="gamma purpose",
owning_project="demo", component="component:gamma",
source_locations=["src/gamma.py", "src/gamma_more.py"])
behaviours = BehaviourLedger(Path(tmp) / "behaviours")
behaviours.define(
behaviour_id="b-alpha", owning_project="demo",
intended_behaviour="alpha behaves", owner_component="component:alpha",
dependencies=["component:beta"])
behaviours.define(
behaviour_id="b-gamma", owning_project="demo",
intended_behaviour="gamma behaves", owner_component="component:gamma")
behaviours.record_real_world("b-alpha", passed=True, detail="ok")
return model, ledger, behaviours
def main():
tmp = tempfile.mkdtemp(prefix="it_truth_")
try:
model, ledger, behaviours = build_fixture(tmp)
model_doc = model.doc
ledger_doc = ledger.doc
bh_doc = behaviours.doc
# ── context_packet ────────────────────────────────────────────
r = it.context_packet(model, ledger, "component:alpha")
case("context_packet", "alpha_full",
{"model": model_doc, "ledger": ledger_doc,
"target": "component:alpha", "now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "nope:missing")
case("context_packet", "unknown_target",
{"model": model_doc, "ledger": ledger_doc,
"target": "nope:missing", "now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "component:gamma",
intent="ship gamma", basis_summary={"depth": 2})
case("context_packet", "gamma_intent_basis",
{"model": model_doc, "ledger": ledger_doc,
"target": "component:gamma", "intent": "ship gamma",
"basis_summary": {"depth": 2}, "now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "component:alpha",
max_local_files=1)
case("context_packet", "alpha_truncated",
{"model": model_doc, "ledger": ledger_doc,
"target": "component:alpha", "max_local_files": 1,
"now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "component:beta")
case("context_packet", "beta_identities_source",
{"model": model_doc, "ledger": ledger_doc,
"target": "component:beta", "now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "interface:api")
case("context_packet", "interface_target",
{"model": model_doc, "ledger": ledger_doc,
"target": "interface:api", "now": FIXED_NOW}, r)
r = it.context_packet(model, ledger, "project:demo")
case("context_packet", "root_project",
{"model": model_doc, "ledger": ledger_doc,
"target": "project:demo", "now": FIXED_NOW}, r)
empty = CapabilityLedger.__new__(CapabilityLedger)
empty.doc = {"schema_version": 1, "capabilities": {}}
r = it.context_packet(model, empty, "component:alpha")
case("context_packet", "empty_ledger",
{"model": model_doc, "ledger": empty.doc,
"target": "component:alpha", "now": FIXED_NOW}, r)
# ── predictive_impact ─────────────────────────────────────────
for name, target in [("alpha", "component:alpha"),
("unknown", "nope:missing"),
("leaf", "component:beta")]:
r = it.predictive_impact(model, target)
case("predictive_impact", name,
{"model": model_doc, "target": target}, r)
# ── descriptive_impact ────────────────────────────────────────
for name, kwargs in [
("full_overlap", {"observed_changed": ["component:alpha",
"component:gamma"]}),
("unexpected", {"observed_changed": ["component:alpha",
"surprise:one"]}),
("none_observed", {"observed_changed": []}),
]:
r = it.descriptive_impact(model, "component:alpha", **kwargs)
case("descriptive_impact", name,
{"model": model_doc, "target": "component:alpha",
"observed_changed": kwargs["observed_changed"],
"now": FIXED_NOW}, r)
r = it.descriptive_impact(model, "component:alpha",
observed_changed=["component:gamma"],
generation="g7")
case("descriptive_impact", "generation_tag",
{"model": model_doc, "target": "component:alpha",
"observed_changed": ["component:gamma"],
"generation": "g7", "now": FIXED_NOW}, r)
r = it.descriptive_impact(model, "nope:missing",
observed_changed=["x"])
case("descriptive_impact", "unknown_target",
{"model": model_doc, "target": "nope:missing",
"observed_changed": ["x"], "now": FIXED_NOW}, r)
# ── record_impact_delta (exact jsonl line — file IO facade) ───
deltas = [
{"target": "component:alpha", "generation": "g1",
"predicted": ["component:alpha"], "observed": [],
"unexpected": [], "unaffected_as_predicted":
["component:alpha"], "recorded_at": FIXED_NOW},
{"b": 1, "a": [1.5, 2], "c": None, "s": "é\nx"},
{"nested": {"z": True, "y": 0.1}},
]
for i, delta in enumerate(deltas):
d = Path(tmp) / f"deltas{i}"
d.mkdir()
it.record_impact_delta(d, delta)
line = (d / "impact_deltas.jsonl").read_text()
assert line.endswith("\n") and line.count("\n") == 1
case("record_impact_delta", f"line{i}", {"delta": delta},
line[:-1])
# ── invalidate_behaviours ─────────────────────────────────────
for name, changed in [
("hit_deps_and_owner", {"component:alpha", "component:beta"}),
("owner_only", {"component:gamma"}),
("no_intersection", {"component:delta"}),
]:
b = BehaviourLedger.__new__(BehaviourLedger)
b.doc = copy.deepcopy(bh_doc)
recs = it.invalidate_behaviours(
model, b, changed_entities=changed, generation="g9")
case("invalidate_behaviours", name,
{"behaviours": bh_doc, "changed": sorted(changed),
"generation": "g9", "now": FIXED_NOW},
{"doc": b.doc, "recs": recs})
# ── post_change_obligations ───────────────────────────────────
for name, target, changed in [
("alpha_default", "component:alpha", None),
("alpha_two_changed", "component:alpha",
["component:alpha", "component:gamma"]),
("beta_leaf", "component:beta", None),
("gamma_consumes_iface", "component:gamma", None),
("delta_stale_dep", "component:delta", None),
("unknown_in_changed", "component:beta",
["component:beta", "ghost:x"]),
]:
if changed is None:
r = it.post_change_obligations(model, target)
args = {"model": model_doc, "target": target}
else:
r = it.post_change_obligations(
model, target, changed_entities=set(changed))
args = {"model": model_doc, "target": target,
"changed": changed}
case("post_change_obligations", name, args, r)
r = it.post_change_obligations(model, "component:alpha",
behaviours=behaviours)
case("post_change_obligations", "alpha_with_behaviours",
{"model": model_doc, "target": "component:alpha",
"behaviours": bh_doc}, r)
OUT.parent.mkdir(parents=True, exist_ok=True)
groups = {}
for c in cases:
groups.setdefault(f"{c['fn']}_cases", []).append(c)
OUT.write_text(json.dumps(
{"module": "iteration", "now": FIXED_NOW, **groups},
indent=1, sort_keys=True) + "\n")
print(f"frozen {len(cases)} cases -> {OUT}")
finally:
shutil.rmtree(tmp, ignore_errors=True)
if __name__ == "__main__":
main()
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""Freeze the oracle truth for the GO port of src/rune/verification_layer.py
(dichotomy wave #2479, GO). Every public function, every branch, against the
LIVE oracle (which delegates to the Rust evidence_provenance core — parity
already proven 33/33). Rows pin the full VerificationResult field set AND the
byte-exact json.dumps(to_dict()) rendering. handle_hook + PLUGIN pinned too.
"""
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from rune import verification_layer as vl # noqa: E402
FIXTURE = ROOT / "src/go/verification_layer/.fixtures/exists.txt"
rows: list[dict] = []
def row(name, fn, verifier_type, result):
got = getattr(vl, fn)(dict(result), verifier_type) if fn == "verify" \
else getattr(vl, fn)(dict(result))
rows.append({
"name": name,
"fn": fn,
"verifier_type": verifier_type,
"result": result,
"want": got.to_dict(),
"want_json": json.dumps(got.to_dict()),
})
def hook_row(name, event, data=None):
got = vl.handle_hook(event) if data is None else vl.handle_hook(event, data)
rows.append({
"name": name,
"fn": "handle_hook",
"verifier_type": "",
"result": {"event": event, "data": data},
"want": got,
"want_json": json.dumps(got, sort_keys=True),
})
# ── verify_exit_code: every branch ──────────────────────────────────────────
row("exit_code:absent-defaults-0", "verify_exit_code", "exit_code", {})
row("exit_code:zero-pass", "verify_exit_code", "exit_code", {"exit_code": 0})
row("exit_code:one-fail", "verify_exit_code", "exit_code", {"exit_code": 1})
row("exit_code:negative-fail", "verify_exit_code", "exit_code", {"exit_code": -3})
row("exit_code:float-zero-pass", "verify_exit_code", "exit_code", {"exit_code": 0.0})
row("exit_code:float-frac-fail", "verify_exit_code", "exit_code", {"exit_code": 0.5})
row("exit_code:bool-true-fails", "verify_exit_code", "exit_code", {"exit_code": True})
row("exit_code:bool-false-passes", "verify_exit_code", "exit_code", {"exit_code": False})
row("exit_code:str-zero-not-equal", "verify_exit_code", "exit_code", {"exit_code": "0"})
row("exit_code:null-not-equal", "verify_exit_code", "exit_code", {"exit_code": None})
row("exit_code:big-int-evidence", "verify_exit_code", "exit_code", {"exit_code": 91247})
# ── verify_unit_test ────────────────────────────────────────────────────────
row("unit_test:all-defaults-total-zero-fails", "verify_unit_test", "unit_test", {})
row("unit_test:pass", "verify_unit_test", "unit_test",
{"tests_passed": 10, "tests_failed": 0, "tests_total": 10})
row("unit_test:two-fail", "verify_unit_test", "unit_test",
{"tests_passed": 3, "tests_failed": 2, "tests_total": 5})
row("unit_test:failed-zero-total-positive", "verify_unit_test", "unit_test",
{"tests_failed": 0, "tests_total": 7})
row("unit_test:bool-failed-false-total-true", "verify_unit_test", "unit_test",
{"tests_failed": False, "tests_total": True})
row("unit_test:failed-true-counts-1", "verify_unit_test", "unit_test",
{"tests_failed": True, "tests_total": 1})
row("unit_test:str-total-ignored", "verify_unit_test", "unit_test",
{"tests_total": "5", "tests_failed": 0})
# ── verify_schema ───────────────────────────────────────────────────────────
row("schema:defaults-pass", "verify_schema", "schema", {})
row("schema:valid-true-no-errors", "verify_schema", "schema", {"schema_valid": True})
row("schema:invalid-fail", "verify_schema", "schema", {"schema_valid": False})
row("schema:errors-fail", "verify_schema", "schema",
{"schema_valid": True, "schema_errors": ["bad type at $.a", "missing $.b"]})
row("schema:empty-errors-pass", "verify_schema", "schema",
{"schema_valid": True, "schema_errors": []})
row("schema:errors-nonlist-ignored", "verify_schema", "schema",
{"schema_valid": True, "schema_errors": "nope"})
row("schema:errors-with-nested-values", "verify_schema", "schema",
{"schema_valid": False, "schema_errors": [3, {"path": "$.x", "msg": "type"}, True]})
row("schema:valid-null-defaults-true", "verify_schema", "schema",
{"schema_valid": None})
row("schema:valid-zero-falsy", "verify_schema", "schema", {"schema_valid": 0})
row("schema:valid-truthy-str", "verify_schema", "schema", {"schema_valid": "yes"})
row("schema:unicode-error-escaping", "verify_schema", "schema",
{"schema_valid": False, "schema_errors": ["ungültig bei „$.pfad“"]})
# ── verify_file_exists (fixture file is committed next to the port) ────────
row("file_exists:exists-pass", "verify_file_exists", "file_exists",
{"file_path": str(FIXTURE)})
row("file_exists:missing-fail", "verify_file_exists", "file_exists",
{"file_path": str(ROOT / "src/go/verification_layer/.fixtures/definitely_missing.txt")})
row("file_exists:empty-path-fail", "verify_file_exists", "file_exists",
{"file_path": ""})
row("file_exists:dir-counts", "verify_file_exists", "file_exists",
{"file_path": str(ROOT / "src/go/verification_layer/.fixtures")})
row("file_exists:absent-key-fail", "verify_file_exists", "file_exists", {})
# ── verify_file_changed ─────────────────────────────────────────────────────
row("file_changed:empty-expected-pass", "verify_file_changed", "file_changed",
{"file_path": "a.txt", "expected_hash": "", "actual_hash": "deadbeef"})
row("file_changed:match-pass", "verify_file_changed", "file_changed",
{"file_path": "a.txt", "expected_hash": "cafe", "actual_hash": "cafe"})
row("file_changed:mismatch-fail", "verify_file_changed", "file_changed",
{"file_path": "a.txt", "expected_hash": "cafe", "actual_hash": "beef"})
row("file_changed:no-keys-pass", "verify_file_changed", "file_changed", {})
# ── verify_tool_receipt ─────────────────────────────────────────────────────
row("tool_receipt:default-pass", "verify_tool_receipt", "tool_receipt", {})
row("tool_receipt:success-true", "verify_tool_receipt", "tool_receipt",
{"tool_success": True, "tool_name": "grep"})
row("tool_receipt:fail-with-error", "verify_tool_receipt", "tool_receipt",
{"tool_success": False, "tool_error": "boom: exit 2"})
row("tool_receipt:fail-empty-error", "verify_tool_receipt", "tool_receipt",
{"tool_success": False})
row("tool_receipt:zero-falsy", "verify_tool_receipt", "tool_receipt",
{"tool_success": 0, "tool_error": "falsy rc"})
row("tool_receipt:error-str-truthy", "verify_tool_receipt", "tool_receipt",
{"tool_success": "ok"})
# ── verify_constraint_check ─────────────────────────────────────────────────
row("constraint:default-pass", "verify_constraint_check", "constraint_check", {})
row("constraint:met-true-pass", "verify_constraint_check", "constraint_check",
{"constraints_met": True})
row("constraint:unmet-fail", "verify_constraint_check", "constraint_check",
{"constraints_met": False})
row("constraint:violations-fail", "verify_constraint_check", "constraint_check",
{"constraints_met": True, "constraint_violations": ["no secrets in diff"]})
row("constraint:violations-nested", "verify_constraint_check", "constraint_check",
{"constraints_met": False,
"constraint_violations": [{"rule": "R1", "at": 7}, 12, None]})
# ── verify dispatch (named + unknown) ───────────────────────────────────────
for vt in ("exit_code", "unit_test", "schema", "file_exists", "file_changed",
"tool_receipt", "constraint_check"):
row(f"dispatch:{vt}", "verify", vt, {})
row("dispatch:unknown-verifier", "verify", "nonexistent_verifier", {})
row("dispatch:unknown-empty-name", "verify", "", {})
row("dispatch:unknown-case-sensitive", "verify", "Exit_Code", {"exit_code": 0})
# ── handle_hook ─────────────────────────────────────────────────────────────
hook_row("hook:event-only", "verification.request")
hook_row("hook:event-with-data", "verification.done", {"passed": True})
# ── PLUGIN manifest ─────────────────────────────────────────────────────────
rows.append({
"name": "plugin:manifest",
"fn": "plugin",
"verifier_type": "",
"result": {},
"want": vl.PLUGIN,
"want_json": json.dumps(vl.PLUGIN, sort_keys=True),
})
doc = {
"frozen_ts": "2026-10-12T00:00:00+00:00",
"generator": "scripts/gen_verification_layer_truth.py — live oracle "
"src/rune/verification_layer.py (Rust evidence_provenance core)",
"rows": rows,
}
out = ROOT / "src/go/verification_layer/truth.json"
out.write_text(json.dumps(doc, indent=1, ensure_ascii=False) + "\n",
encoding="utf-8")
print(f"frozen {len(rows)} rows → {out}")
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""Open the #2479 dichotomy-wave construction contract for the BATCH-A
modules (iteration, subconscious_pass, rune_profiler, subsystem_health).
Walks draft→approved→building in ONE process (shared-store clobber hazard).
Usage: open_contract_batch_a.py <module> [contract_id]
"""
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
module = sys.argv[1]
sym = {"iteration": "IT", "subconscious_pass": "SP",
"rune_profiler": "RP", "subsystem_health": "SH"}[module]
iface = ConstructionInterface(builder="factory-batch-a")
cid = sys.argv[2] if len(sys.argv) > 2 else None
r = iface.submit_need(
f"Port src/rune/{module}.py to FULL Rust (dichotomy factory, issue "
f"#2479 tranche): doc-envelope FFI, ctypes loader, facade delegation "
f"with RUNE_{sym}_CORE=python pin, frozen-truth battery, live parity "
f"100%, Phase B language-advantage pass.",
origin="builder",
contract_id=cid,
)
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)
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""Open + walk the #2479 dichotomy-wave construction contract for
connection_pool to verifying. Full lifecycle in ONE process."""
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-batch-b")
r = iface.submit_need(
"Complete the connection_pool dichotomy port to FULL Rust (#2479 "
"tranche, programme verdict RUST): pool-bookkeeping kernel (pooling "
"order, stale removal, oldest-first eviction, status) as doc-envelope "
"FFI (cpool_new/begin_get/commit/close_all/status, free via "
"capability_scoring cs_free_string — no free re-export); cpool_loader "
"mirroring broker_loader.py; facade delegation with RUNE_CPOOL_CORE="
"python pin (sqlite handles stay in the facade); frozen-oracle battery "
"(16 cases, every kernel branch, frozen against a real sqlite-backed "
"pool); live parity 100% (60-seed random-op sweep); classification "
"flip GO→RUST; Phase B language-advantage pass.",
origin="builder",
)
print("submit_need:", json.dumps(r)[:300])
if not r.get("success"):
print("NEED FAILED — aborting"); sys.exit(1)
cid = r["ids"]["contract_id"]
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:150])
if not t.get("success"):
sys.exit(1)
print("CONTRACT", cid, "verifying")
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Open + walk the #2479 dichotomy-wave construction contract for
construction_depth to verifying. Full lifecycle in ONE process (shared-store
clobber hazard). The close step runs separately (close_contract script)
after the register commit, per the dichotomy-wave store pattern."""
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-batch-b")
r = iface.submit_need(
"Complete the construction_depth dichotomy port to FULL Rust (#2479 "
"tranche): oracle-exact depth kernel (UNKNOWN ceremony/bypassed, "
"PROJECT_BUILD full-lifecycle strings, EXISTING_PROJECT_CHANGE base "
"ceremony + wide-surface escalation restored to oracle truth), "
"doc-envelope FFI (cd_select_depth, free via capability_scoring "
"cs_free_string — no free re-export), cd_loader mirroring "
"broker_loader.py, facade delegation with RUNE_CD_CORE=python pin, "
"frozen-oracle battery (40 cases, every public function/branch), live "
"parity 100%, 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)
cid = r["ids"]["contract_id"]
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:200])
if not t.get("success"):
sys.exit(1)
print("CONTRACT", cid, "verifying")
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""Open → walk → close the #2479 dichotomy-wave construction contracts for
the forge + verification_layer GO batch (factory-batch-c). Full lifecycle
per contract, both back-to-back in ONE process (shared-store clobber hazard)."""
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-batch-c")
CONTRACTS = [
{
"module": "forge",
"cid": "BUILDER-2026-10-12T17:43:29Z-ea9485-factory-batch-c",
"need": (
"Port src/rune/forge.py to FULL Go (dichotomy factory, issue "
"#2479 tranche, batch-c): the §18L forge boundary — ForgeAdapter "
"protocol, ForgeUnavailable, GiteaForge (env/push/commit_status/"
"ci_runs_for_sha/create_or_patch_release), default_forge, and the "
"scripts/gitea_auth credential ladder — name-preserving in "
"src/go/forge with IO behind CommandRunner/HTTPTransport/"
"TokenSource seams, frozen-truth battery (34 rows), live parity "
"100%, Phase B goroutine fan-out (Snapshot), compile-time seam "
"assertions."
),
"evidence": (
"forge parity port — 34/34 frozen rows replay verbatim (truth "
"regenerated live twice, byte-stable), battery covers every "
"public fn + branch (push truncation, status/runs HTTP capture "
"byte-parity, credential ladder all 3 rungs, release argv + "
"last-200 fallback), race-clean, gofmt/vet clean; Python oracle "
"tests green. SHAs: cdcae1ea (feat) ac114c32 (Phase B), pushed "
"gitea/master on top of 78a36204."
),
"scope_files": [
"src/rune/forge.py",
"src/go/forge/main.go",
"src/go/forge/truth_test.go",
"src/go/forge/phaseb.go",
"src/go/forge/phaseb_test.go",
"src/go/forge/truth.json",
"scripts/gen_forge_truth.py",
],
},
{
"module": "verification_layer",
"cid": "BUILDER-2026-10-12T17:46:05Z-c1a38e-factory-batch-c",
"need": (
"Port src/rune/verification_layer.py to FULL Go (dichotomy "
"factory, issue #2479 tranche, batch-c): all seven verifiers "
"(exit_code, unit_test, schema, file_exists, file_changed, "
"tool_receipt, constraint_check) + unknown-verifier dispatch, "
"VerificationResult.to_dict byte-rendering, handle_hook, "
"PLUGIN manifest — the Rust evidence_provenance semantics "
"carried 1:1 (verification.rs), name-preserving in "
"src/go/verification_layer with the FS probe behind a seam, "
"frozen-truth battery (62 rows), live parity 100%, Phase B "
"Verifier registry + VerifyAll goroutine fan-out."
),
"evidence": (
"verification_layer parity port — 62/62 frozen rows replay "
"verbatim byte-for-byte (truth regenerated live twice, "
"byte-stable) + 15/15 live CLI parity sweep incl. unicode "
"ensure_ascii escapes and non-string failures pass-through; "
"battery covers every verifier pass+fail branches, dispatch, "
"hook, PLUGIN; race-clean, gofmt/vet clean; Python tests green "
"(test_verification_layer_demo + test_evidence_provenance_shims, "
"7 passed). SHAs: d9009cc2 (feat) 2750eba0 (Phase B), pushed "
"gitea/master on top of 78a36204."
),
"scope_files": [
"src/rune/verification_layer.py",
"src/go/verification_layer/main.go",
"src/go/verification_layer/truth_test.go",
"src/go/verification_layer/phaseb.go",
"src/go/verification_layer/phaseb_test.go",
"src/go/verification_layer/truth.json",
"scripts/gen_verification_layer_truth.py",
],
},
]
cids = []
for spec in CONTRACTS:
r = iface.submit_need(spec["need"], origin="builder",
contract_id=spec["cid"])
print("submit_need:", json.dumps(r)[:200])
if not r.get("success"):
print("NEED FAILED — aborting")
sys.exit(1)
cid = r["ids"]["contract_id"]
cids.append(cid)
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:150])
if not t.get("success"):
sys.exit(1)
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": spec["evidence"],
}], scope_files=spec["scope_files"])
print("close:", json.dumps(c)[:200])
print("CONTRACT", cid, spec["module"],
"closed" if c.get("success") else "CLOSE_FAILED")
print("-" * 60)
print("ALL CONTRACTS:", json.dumps(cids))
+1
View File
@@ -0,0 +1 @@
filetoken123
+1
View File
@@ -0,0 +1 @@
weaktoken
+3
View File
@@ -0,0 +1,3 @@
module rune/forge
go 1.24
+486
View File
@@ -0,0 +1,486 @@
// Package main — the FULL GO port of src/rune/forge.py (#2479 dichotomy
// wave, GO side verdict). Every public Python function has a
// name-preserving counterpart: GiteaForge (__init__ → NewGiteaForge,
// _env → env, push → Push, _gitea_auth → giteaAuth, commit_status →
// CommitStatus, ci_runs_for_sha → CiRunsForSha, create_or_patch_release →
// CreateOrPatchRelease), the ForgeAdapter protocol (→ interface),
// ForgeUnavailable (→ error type) and default_forge (→ DefaultForge).
// The gitea_auth credential ladder (scripts/gitea_auth.py) is carried
// 1:1 (env rung → 0600-enforced token file rung → git credential fill).
//
// All IO (git push, HTTP, credential helper, python release publisher)
// stays behind injectable seams (CommandRunner, HTTPTransport, TokenSource)
// so the frozen truth battery replays deterministically.
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"unicode/utf8"
)
// ── constants (scripts/gitea_auth.py + forge.py defaults) ───────────────────
const DefaultServer = "https://gitea.thingscouldgetdicey.online"
const DefaultRepo = "conductor/rune"
const GiteaHost = "gitea.thingscouldgetdicey.online"
// ── the forge boundary ──────────────────────────────────────────────────────
// ForgeAdapter — the minimum stable forge boundary (Python Protocol). All
// methods may return *ForgeUnavailable — callers treat forge failures as
// blocking-for-that-operation, never as construction-truth changes.
type ForgeAdapter interface {
Push(repo string, branch string) (map[string]any, error)
CommitStatus(repo string, sha string) (any, error)
CiRunsForSha(repo string, sha string) ([]map[string]any, error)
CreateOrPatchRelease(repo string, tag string, title string, body string) (map[string]any, error)
}
// ForgeUnavailable — the forge could not be reached or refused the
// operation (Python RuntimeError subclass; message parity is frozen).
type ForgeUnavailable struct{ Msg string }
func (e *ForgeUnavailable) Error() string { return e.Msg }
// GiteaCredentialError — scripts/gitea_auth.py's no-credential error
// (message never contains a credential).
type GiteaCredentialError struct{ Msg string }
func (e *GiteaCredentialError) Error() string { return e.Msg }
// PermissionError — the 0644-token-file rejection (Python PermissionError).
type PermissionError struct{ Msg string }
func (e *PermissionError) Error() string { return e.Msg }
// ── injectable IO seams ─────────────────────────────────────────────────────
// RunResult — subprocess capture (rc, stdout, stderr).
type RunResult struct {
Stdout string
Stderr string
RC int
}
// CommandRunner — the subprocess seam (git push, credential fill, release
// publisher). stdin carries the credential-fill payload.
type CommandRunner func(name string, args []string, stdin string) RunResult
// HTTPRequest — captured request surface (method, URL, headers).
type HTTPRequest struct {
Method string
URL string
Headers map[string]string
}
// HTTPTransport — the urllib seam. Returns the body bytes or an error whose
// Error() is byte-comparable to the oracle's str(exc).
type HTTPTransport func(req HTTPRequest) ([]byte, error)
// TokenSource — the gitea_auth credential ladder surface.
type TokenSource interface {
HasToken() bool
GetToken() (string, error)
}
// ── GiteaForge ──────────────────────────────────────────────────────────────
// GiteaForge — the real adapter (rule A: delegates to the canonical
// implementations; no duplicated API clients).
type GiteaForge struct {
Server string // "" → scripts' env/credential resolution (Python None)
Repo string
tokens TokenSource // nil → giteaLadder
runner CommandRunner // nil → execRunner
transport HTTPTransport // nil → urllibTransport
pythonBin string // "" → "python3" (sys.executable seam)
}
// NewGiteaForge — Python GiteaForge(server=None, repo="conductor/rune").
func NewGiteaForge(server string, repo string) *GiteaForge {
return &GiteaForge{Server: server, Repo: repo}
}
// compile-time assertion: GiteaForge satisfies the protocol.
var _ ForgeAdapter = (*GiteaForge)(nil)
func (f *GiteaForge) runnerOr() CommandRunner {
if f.runner != nil {
return f.runner
}
return execRunner
}
func (f *GiteaForge) transportOr() HTTPTransport {
if f.transport != nil {
return f.transport
}
return urllibTransport
}
func (f *GiteaForge) pythonBinOr() string {
if f.pythonBin != "" {
return f.pythonBin
}
return "python3"
}
// env — Python _env(): inherit os.environ; server override; repo default.
func (f *GiteaForge) env() map[string]string {
env := map[string]string{}
for _, kv := range os.Environ() {
if i := strings.IndexByte(kv, '='); i >= 0 {
env[kv[:i]] = kv[i+1:]
}
}
if f.Server != "" {
env["GITEA_SERVER"] = f.Server
}
if _, ok := env["GITEA_REPO"]; !ok {
env["GITEA_REPO"] = f.Repo
}
return env
}
// Push — git push gitea master:<branch>; failure → "push failed: <stderr[:200]>".
func (f *GiteaForge) Push(repo string, branch string) (map[string]any, error) {
r := f.runnerOr()("git", []string{"push", "gitea", "master:" + branch}, "")
if r.RC != 0 {
return nil, &ForgeUnavailable{fmt.Sprintf("push failed: %s", firstN(r.Stderr, 200))}
}
return map[string]any{"pushed": true, "branch": branch}, nil
}
// giteaAuth — Python _gitea_auth(): the canonical scripts/gitea_auth
// credential ladder (rule A: no duplicate auth). Seams overridable.
func (f *GiteaForge) giteaAuth() TokenSource {
if f.tokens != nil {
return f.tokens
}
return giteaLadder{}
}
// server — Python `self._server or os.environ.get("GITEA_SERVER", DEFAULT)`.
func (f *GiteaForge) server() string {
if f.Server != "" {
return f.Server
}
if v := os.Getenv("GITEA_SERVER"); v != "" {
return v
}
return DefaultServer
}
// CommitStatus — GET the combined commit status; returns data["state"]
// ("unknown" when the key is absent).
func (f *GiteaForge) CommitStatus(repo string, sha string) (any, error) {
tokens := f.giteaAuth()
if !tokens.HasToken() {
return nil, &ForgeUnavailable{"no forge credentials (gitea token)"}
}
tok, _ := tokens.GetToken()
req := HTTPRequest{
Method: "GET",
URL: fmt.Sprintf("%s/api/v1/repos/%s/commits/%s/status", f.server(), repo, sha),
Headers: map[string]string{"Authorization": "token " + tok},
}
body, err := f.transportOr()(req)
if err != nil {
return nil, &ForgeUnavailable{fmt.Sprintf("status unreachable: %s", err.Error())}
}
var data map[string]any
if err := decodeJSON(body, &data); err != nil {
return nil, err // Python json.loads errors propagate unwrapped
}
if v, ok := data["state"]; ok {
return v, nil
}
return "unknown", nil
}
// CiRunsForSha — GET the actions runs and keep those whose str(
// head_sha) equals sha (absent key → ""; JSON null → "None").
func (f *GiteaForge) CiRunsForSha(repo string, sha string) ([]map[string]any, error) {
tokens := f.giteaAuth()
if !tokens.HasToken() {
return nil, &ForgeUnavailable{"no forge credentials (gitea token)"}
}
tok, _ := tokens.GetToken()
req := HTTPRequest{
Method: "GET",
URL: fmt.Sprintf("%s/api/v1/repos/%s/actions/runs?limit=50", f.server(), repo),
Headers: map[string]string{"Authorization": "token " + tok},
}
body, err := f.transportOr()(req)
if err != nil {
return nil, &ForgeUnavailable{fmt.Sprintf("runs unreachable: %s", err.Error())}
}
var data map[string]any
if err := decodeJSON(body, &data); err != nil {
return nil, err
}
raw, ok := data["workflow_runs"]
if !ok {
return []map[string]any{}, nil
}
arr, _ := raw.([]any)
out := []map[string]any{}
for _, item := range arr {
run, _ := item.(map[string]any)
headSha := ""
if v, ok := run["head_sha"]; ok {
headSha = pyStrAny(v)
}
if headSha == sha {
out = append(out, run)
}
}
return out, nil
}
// CreateOrPatchRelease — delegate to the canonical idempotent publisher
// (scripts/create_release.py, CWD-relative like the oracle); the script
// path missing → "canonical release publisher not found".
func (f *GiteaForge) CreateOrPatchRelease(repo string, tag string, title string, body string) (map[string]any, error) {
tokens := f.giteaAuth()
if !tokens.HasToken() {
return nil, &ForgeUnavailable{"no forge credentials (gitea token)"}
}
if _, err := os.Stat("scripts/create_release.py"); err == nil {
r := f.runnerOr()(f.pythonBinOr(),
[]string{"scripts/create_release.py", "--tag", tag, "--title", title, "--body", body}, "")
if r.RC != 0 {
tail := r.Stderr
if tail == "" {
tail = r.Stdout
}
return nil, &ForgeUnavailable{fmt.Sprintf(
"release publication failed rc=%d: %s", r.RC, lastN(tail, 200))}
}
return map[string]any{"published": true, "tag": tag}, nil
}
return nil, &ForgeUnavailable{"canonical release publisher not found"}
}
// DefaultForge — the working adapter (rule 18L: prove Gitea still works).
func DefaultForge() *GiteaForge { return NewGiteaForge("", DefaultRepo) }
// ── gitea_auth credential ladder (scripts/gitea_auth.py, 1:1) ───────────────
// defaultTokenFilePath — ~/.config/opencode/secrets/gitea-token expanded.
var defaultTokenFilePath = func() string {
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, ".config", "opencode", "secrets", "gitea-token")
}
return ".config/opencode/secrets/gitea-token"
}
// giteaLadder — env rung → 0600-enforced token file rung → git credential
// fill. Never prints credentials; fails clearly when unavailable.
type giteaLadder struct {
runner CommandRunner // nil → execRunner
}
func (l giteaLadder) run() CommandRunner {
if l.runner != nil {
return l.runner
}
return execRunner
}
// HasToken — true if any rung of the credential ladder answers. Never fails.
func (l giteaLadder) HasToken() bool {
_, err := l.GetToken()
return err == nil
}
// GetToken — obtain the Gitea API token via the ladder.
func (l giteaLadder) GetToken() (string, error) {
token := strings.TrimSpace(os.Getenv("GITEA_TOKEN"))
if token != "" {
return token, nil
}
token, err := l.tokenFromFile()
if err != nil {
return "", err
}
if token != "" {
return token, nil
}
token = l.tokenFromCredentialHelper()
if token != "" {
return token, nil
}
return "", &GiteaCredentialError{fmt.Sprintf(
"Gitea credentials unavailable: set GITEA_TOKEN, create a mode-0600 "+
"token file at %s, or configure a git credential helper for %s",
defaultTokenFilePath(), GiteaHost)}
}
// tokenFromFile — GITEA_TOKEN_FILE (or the default path); must be mode 0600.
func (l giteaLadder) tokenFromFile() (string, error) {
path := os.Getenv("GITEA_TOKEN_FILE")
if path == "" {
path = defaultTokenFilePath()
}
path = expandUser(path)
st, err := os.Stat(path)
if err != nil || st.IsDir() {
return "", nil
}
if st.Mode().Perm()&0o077 != 0 {
return "", &PermissionError{fmt.Sprintf("Gitea token file must be mode 0600: %s", path)}
}
raw, err := os.ReadFile(path)
if err != nil {
return "", nil
}
return strings.TrimSpace(string(raw)), nil
}
// tokenFromCredentialHelper — `git credential fill` for the Gitea host.
func (l giteaLadder) tokenFromCredentialHelper() string {
stdin := fmt.Sprintf("protocol=https\nhost=%s\nusername=conductor\n\n", GiteaHost)
r := l.run()("git", []string{"credential", "fill"}, stdin)
for _, line := range strings.Split(r.Stdout, "\n") {
if strings.HasPrefix(line, "password=") {
return line[len("password="):]
}
}
return ""
}
// ── default seams ───────────────────────────────────────────────────────────
// execRunner — real subprocess capture (text=True semantics).
func execRunner(name string, args []string, stdin string) RunResult {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, name, args...)
if stdin != "" {
cmd.Stdin = strings.NewReader(stdin)
}
var out, errb bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errb
err := cmd.Run()
rc := 0
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
rc = ee.ExitCode()
} else {
rc = 127
}
}
return RunResult{Stdout: out.String(), Stderr: errb.String(), RC: rc}
}
// urllibTransport — urllib.request.urlopen(req, timeout=15) semantics:
// non-2xx → "HTTP Error <code>: <reason>", network failure →
// "<urlopen error <reason>>".
func urllibTransport(req HTTPRequest) ([]byte, error) {
full := http.Header{}
for k, v := range req.Headers {
full.Set(k, v)
}
client := &http.Client{Timeout: 15 * time.Second}
httpReq, err := http.NewRequest(req.Method, req.URL, nil)
if err != nil {
return nil, fmt.Errorf("<urlopen error %s>", err.Error())
}
httpReq.Header = full
resp, err := client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("<urlopen error %s>", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return nil, fmt.Errorf("HTTP Error %s",
strings.Replace(resp.Status, " ", ": ", 1))
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(resp.Body); err != nil {
return nil, fmt.Errorf("<urlopen error %s>", err.Error())
}
return buf.Bytes(), nil
}
// ── helpers ─────────────────────────────────────────────────────────────────
// decodeJSON — json.loads with Python-compatible number preservation
// (json.Number keeps the literal text so str() rendering matches).
func decodeJSON(data []byte, out *map[string]any) error {
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()
var v map[string]any
if err := dec.Decode(&v); err != nil {
return err
}
*out = v
return nil
}
// pyStrAny — Python str() of a JSON-decoded value (None/bool/int/str;
// numbers keep their JSON literal).
func pyStrAny(v any) string {
switch x := v.(type) {
case nil:
return "None"
case bool:
if x {
return "True"
}
return "False"
case string:
return x
case json.Number:
return x.String()
default:
return fmt.Sprintf("%v", x)
}
}
// firstN — Python s[:n] (codepoints).
func firstN(s string, n int) string {
if utf8.RuneCountInString(s) <= n {
return s
}
return string([]rune(s)[:n])
}
// lastN — Python s[-n:].
func lastN(s string, n int) string {
r := []rune(s)
if len(r) <= n {
return s
}
return string(r[len(r)-n:])
}
// expandUser — pathlib.Path.expanduser for the token-file path.
func expandUser(p string) string {
if p == "~" || strings.HasPrefix(p, "~/") {
if home, err := os.UserHomeDir(); err == nil {
return filepath.Join(home, strings.TrimPrefix(p, "~/"))
}
}
return p
}
// main — forge.py is a library module (the §18L boundary); the binary
// surfaces the boundary contract for smoke checks.
func main() {
fmt.Println("forge: T18 §18L minimum stable forge abstraction boundary (GO port)")
f := DefaultForge()
fmt.Printf("default forge: repo=%s server-attr=%q\n", f.Repo, f.Server)
}
+57
View File
@@ -0,0 +1,57 @@
package main
// Phase B language-advantage pass — dichotomy wave. Go-side wins the
// Python oracle can't express:
//
// 1. ForgeSnapshot — commit status and CI runs are two independent HTTP
// round-trips the oracle always performs serially; the GO port fans
// them out across goroutines (order-insensitive reassembly, both
// results preserved even when one side fails).
// 2. Compile-time safety: seam interfaces (TokenSource, CommandRunner,
// HTTPTransport) and the ForgeAdapter protocol are satisfaction-asserted
// at build time — drift breaks the compile, not a runtime cast.
import "sync"
// ForgeSnapshot — the CI verdict surface for one SHA: the combined status
// plus the workflow runs that belong to it.
type ForgeSnapshot struct {
Status any // commit_status state (str / JSON value)
Runs []map[string]any // workflow_runs filtered to the SHA
StatusErr error // ForgeUnavailable when the status call failed
RunsErr error // ForgeUnavailable when the runs call failed
}
// SnapshotForge — the fan-out interface (satisfied by *GiteaForge).
type SnapshotForge interface {
Snapshot(repo string, sha string) ForgeSnapshot
}
// Snapshot — CommitStatus and CiRunsForSha race concurrently and reassemble
// when both settle. Each half keeps its own error: a failed status call
// never masks the runs (and vice versa) — the oracle's serial version could
// only surface the first failure.
func (f *GiteaForge) Snapshot(repo string, sha string) ForgeSnapshot {
var (
wg sync.WaitGroup
snap ForgeSnapshot
)
wg.Add(2)
go func() {
defer wg.Done()
snap.Status, snap.StatusErr = f.CommitStatus(repo, sha)
}()
go func() {
defer wg.Done()
snap.Runs, snap.RunsErr = f.CiRunsForSha(repo, sha)
}()
wg.Wait()
return snap
}
// compile-time assertions: the seams keep their shapes.
var (
_ TokenSource = giteaLadder{}
_ SnapshotForge = (*GiteaForge)(nil)
_ ForgeAdapter = (*GiteaForge)(nil)
)
+120
View File
@@ -0,0 +1,120 @@
package main
// Phase B battery — pins the language-advantage guarantees: the Snapshot
// fan-out returns byte-identical halves to the serial oracle calls and is
// race-clean under -race; the seam interfaces stay satisfaction-asserted.
import (
"encoding/json"
"strings"
"testing"
)
func jsonMarshal(v any) ([]byte, error) { return json.Marshal(v) }
// TestSnapshotHalves — drive the fan-out through the same frozen truth
// bodies the battery pins, assert half-parity and race cleanliness.
func TestSnapshotHalves(t *testing.T) {
doc := loadTruth(t)
statusRows := map[string]TruthRow{}
for i := range doc.Rows {
row := &doc.Rows[i]
if row.Op == "commit_status" {
setup := parseNum(t, row.Setup)
sha := strOrEmpty(setup["sha"])
if _, dup := statusRows[sha]; !dup {
statusRows[sha] = *row
}
}
}
replayed := 0
for i := range doc.Rows {
row := &doc.Rows[i]
if row.Op != "ci_runs" {
continue
}
setup := parseNum(t, row.Setup)
if setup["payload"] == nil {
continue
}
sha := strOrEmpty(setup["sha"])
sRow, ok := statusRows[sha]
if !ok {
continue
}
replayed++
envGuard(t)
sSetup := parseNum(t, sRow.Setup)
payload, err := json.Marshal(setup["payload"])
if err != nil {
t.Fatalf("marshal payload: %v", err)
}
f := NewGiteaForge("", DefaultRepo)
f.tokens = stubTokens{has: true, tok: "t0k3n"}
tr := &recordingTransport{body: payload}
f.transport = tr.do
setEnv(t, map[string]any{"GITEA_SERVER": setup["env_server"]})
snap := f.Snapshot(strOrEmpty(setup["repo"]), sha)
// serial halves from the same frozen rows
sState, sErr := f.CommitStatus(strOrEmpty(sSetup["repo"]), sha)
sRuns, rErr := f.CiRunsForSha(strOrEmpty(setup["repo"]), sha)
if sErr != nil || rErr != nil {
t.Fatalf("serial halves unexpectedly failed: %v %v", sErr, rErr)
}
if snap.StatusErr != nil {
t.Fatalf("snapshot status half failed: %v", snap.StatusErr)
}
if snap.RunsErr != nil {
t.Fatalf("snapshot runs half failed: %v", snap.RunsErr)
}
if !equalAny(snap.Status, sState) {
t.Fatalf("snapshot status half diverges: %#v vs %#v", snap.Status, sState)
}
if len(snap.Runs) != len(sRuns) {
t.Fatalf("snapshot runs half diverges: %d vs %d runs", len(snap.Runs), len(sRuns))
}
}
if replayed == 0 {
t.Fatal("no snapshot replay rows — battery/truth drift")
}
}
// equalAny — deep equality over decoded JSON values.
func equalAny(a, b any) bool {
ab, err1 := json.Marshal(a)
bb, err2 := json.Marshal(b)
if err1 != nil || err2 != nil {
return false
}
return string(ab) == string(bb)
}
// TestSnapshotErrorHalves — a failing status call must not mask the runs
// (the language-advantage over the oracle's serial first-error semantics).
func TestSnapshotErrorHalves(t *testing.T) {
f := NewGiteaForge("", DefaultRepo)
f.tokens = stubTokens{has: true, tok: "t0k3n"}
f.transport = func(req HTTPRequest) ([]byte, error) {
if strings.Contains(req.URL, "/status") {
return nil, &ForgeUnavailable{"status unreachable: boom"}
}
return []byte(`{"workflow_runs": [{"head_sha": "abc"}]}`), nil
}
snap := f.Snapshot("o/r", "abc")
if snap.StatusErr == nil {
t.Fatal("status half should have failed")
}
if len(snap.Runs) != 1 {
t.Fatalf("runs half must survive: got %d", len(snap.Runs))
}
}
// TestSeamInterfacesSatisfied — compile-time assertions as a test.
func TestSeamInterfacesSatisfied(t *testing.T) {
var _ TokenSource = stubTokens{}
var _ TokenSource = giteaLadder{}
var _ ForgeAdapter = (*GiteaForge)(nil)
var _ SnapshotForge = (*GiteaForge)(nil)
}
+778
View File
@@ -0,0 +1,778 @@
{
"frozen_ts": "2026-10-12T00:00:00+00:00",
"generator": "scripts/gen_forge_truth.py — live oracle src/rune/forge.py",
"rows": [
{
"name": "default_forge:working-adapter",
"op": "default_forge",
"setup": {},
"want": {
"server": null,
"repo": "conductor/rune"
}
},
{
"name": "_env:env:inherits-and-defaults",
"op": "env",
"setup": {
"server": null,
"repo": null,
"environ": {
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": null,
"GITEA_REPO": "conductor/rune",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:server-override",
"op": "env",
"setup": {
"server": "http://local:3000",
"repo": null,
"environ": {
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": "http://local:3000",
"GITEA_REPO": "conductor/rune",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:repo-explicit",
"op": "env",
"setup": {
"server": null,
"repo": "other/repo",
"environ": {
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": null,
"GITEA_REPO": "other/repo",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:env-server-kept-when-no-attr",
"op": "env",
"setup": {
"server": null,
"repo": null,
"environ": {
"GITEA_SERVER": "http://env-server",
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": "http://env-server",
"GITEA_REPO": "conductor/rune",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:env-server-overridden-by-attr",
"op": "env",
"setup": {
"server": "http://attr",
"repo": null,
"environ": {
"GITEA_SERVER": "http://env-server",
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": "http://attr",
"GITEA_REPO": "conductor/rune",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:env-repo-not-clobbered",
"op": "env",
"setup": {
"server": null,
"repo": null,
"environ": {
"GITEA_REPO": "env/repo",
"RUNE_SAMPLE": ""
}
},
"want": {
"GITEA_SERVER": null,
"GITEA_REPO": "env/repo",
"RUNE_SAMPLE": ""
}
},
{
"name": "_env:env:inherits-sample-var",
"op": "env",
"setup": {
"server": null,
"repo": null,
"environ": {
"RUNE_SAMPLE": "1"
}
},
"want": {
"GITEA_SERVER": null,
"GITEA_REPO": "conductor/rune",
"RUNE_SAMPLE": "1"
}
},
{
"name": "push:push:ok",
"op": "push",
"setup": {
"repo": "ignored/repo",
"branch": "feature-x",
"rc": 0,
"stderr": ""
},
"want": {
"result": {
"pushed": true,
"branch": "feature-x"
},
"error": null,
"calls": [
{
"argv": [
"git",
"push",
"gitea",
"master:feature-x"
]
}
]
}
},
{
"name": "push:push:fail-short-stderr",
"op": "push",
"setup": {
"repo": "ignored/repo",
"branch": "main",
"rc": 1,
"stderr": "rejected non-fast-forward"
},
"want": {
"result": null,
"error": "push failed: rejected non-fast-forward",
"calls": [
{
"argv": [
"git",
"push",
"gitea",
"master:main"
]
}
]
}
},
{
"name": "push:push:fail-long-stderr-truncates-200",
"op": "push",
"setup": {
"repo": "ignored/repo",
"branch": "dev",
"rc": 128,
"stderr": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
},
"want": {
"result": null,
"error": "push failed: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"calls": [
{
"argv": [
"git",
"push",
"gitea",
"master:dev"
]
}
]
}
},
{
"name": "push:push:fail-empty-stderr",
"op": "push",
"setup": {
"repo": "ignored/repo",
"branch": "release",
"rc": 2,
"stderr": ""
},
"want": {
"result": null,
"error": "push failed: ",
"calls": [
{
"argv": [
"git",
"push",
"gitea",
"master:release"
]
}
]
}
},
{
"name": "gitea_auth:env-token-rung",
"op": "gitea_auth",
"setup": {
"environ": {
"GITEA_TOKEN": " envtoken \n"
}
},
"want": {
"has_token": true,
"get_token": "envtoken"
}
},
{
"name": "gitea_auth:token-file-0600",
"op": "gitea_auth",
"setup": {
"environ": {
"GITEA_TOKEN_FILE": "<fixture token0600>"
}
},
"want": {
"has_token": true,
"get_token": "filetoken123"
}
},
{
"name": "gitea_auth:token-file-0644-rejected",
"op": "gitea_auth",
"setup": {
"environ": {
"GITEA_TOKEN_FILE": "<fixture token0644>"
}
},
"want": {
"has_token": false,
"get_token": null,
"error": "Gitea token file must be mode 0600: <FIXTURES>/token0644"
}
},
{
"name": "gitea_auth:no-credential",
"op": "gitea_auth",
"setup": {
"default_token_file": "<TMP>/missing-token"
},
"want": {
"has_token": false,
"get_token": null,
"error": "Gitea credentials unavailable: set GITEA_TOKEN, create a mode-0600 token file at <TMP>/missing-token, or configure a git credential helper for gitea.thingscouldgetdicey.online"
}
},
{
"name": "commit_status:commit_status:no-token",
"op": "commit_status",
"setup": {
"server": null,
"env_server": null,
"repo": "conductor/rune",
"sha": "abc",
"has_token": false,
"body": null,
"http_err": null
},
"want": {
"state": null,
"error": "no forge credentials (gitea token)",
"request": null
}
},
{
"name": "commit_status:commit_status:success",
"op": "commit_status",
"setup": {
"server": null,
"env_server": null,
"repo": "conductor/rune",
"sha": "abc",
"has_token": true,
"body": "{\"state\": \"success\"}",
"http_err": null
},
"want": {
"state": "success",
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/conductor/rune/commits/abc/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "commit_status:commit_status:state-missing-unknown",
"op": "commit_status",
"setup": {
"server": null,
"env_server": null,
"repo": "o/r",
"sha": "def",
"has_token": true,
"body": "{\"statuses\": []}",
"http_err": null
},
"want": {
"state": "unknown",
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/commits/def/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "commit_status:commit_status:server-attr-wins",
"op": "commit_status",
"setup": {
"server": "http://attr:3000",
"env_server": "http://env:3000",
"repo": "o/r",
"sha": "ghi",
"has_token": true,
"body": "{\"state\": \"pending\"}",
"http_err": null
},
"want": {
"state": "pending",
"error": null,
"request": {
"method": "GET",
"url": "http://attr:3000/api/v1/repos/o/r/commits/ghi/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "commit_status:commit_status:server-from-env",
"op": "commit_status",
"setup": {
"server": null,
"env_server": "http://env:3000",
"repo": "o/r",
"sha": "ghi",
"has_token": true,
"body": "{\"state\": \"failure\"}",
"http_err": null
},
"want": {
"state": "failure",
"error": null,
"request": {
"method": "GET",
"url": "http://env:3000/api/v1/repos/o/r/commits/ghi/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "commit_status:commit_status:http-error",
"op": "commit_status",
"setup": {
"server": null,
"env_server": null,
"repo": "o/r",
"sha": "jkl",
"has_token": true,
"body": null,
"http_err": "HTTP Error 404: Not Found"
},
"want": {
"state": null,
"error": "status unreachable: HTTP Error 404: Not Found",
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/commits/jkl/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "commit_status:commit_status:network-error",
"op": "commit_status",
"setup": {
"server": null,
"env_server": null,
"repo": "o/r",
"sha": "jkl",
"has_token": true,
"body": null,
"http_err": "conn refused"
},
"want": {
"state": null,
"error": "status unreachable: conn refused",
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/commits/jkl/status",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "ci_runs:ci_runs:no-token",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "s",
"payload": null,
"err": null,
"has_token": false
},
"want": {
"runs": null,
"error": "no forge credentials (gitea token)",
"request": null
}
},
{
"name": "ci_runs:ci_runs:filter-by-head-sha",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "abc",
"payload": {
"workflow_runs": [
{
"id": 1,
"head_sha": "abc"
},
{
"id": 2,
"head_sha": null
},
{
"id": 3,
"head_sha": "other"
},
{
"id": 4
},
{
"id": 5,
"head_sha": "abc"
}
]
},
"err": null,
"has_token": true
},
"want": {
"runs": [
{
"id": 1,
"head_sha": "abc"
},
{
"id": 5,
"head_sha": "abc"
}
],
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/actions/runs?limit=50",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "ci_runs:ci_runs:none-matching",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "zzz",
"payload": {
"workflow_runs": [
{
"id": 1,
"head_sha": "abc"
},
{
"id": 2,
"head_sha": null
},
{
"id": 3,
"head_sha": "other"
},
{
"id": 4
},
{
"id": 5,
"head_sha": "abc"
}
]
},
"err": null,
"has_token": true
},
"want": {
"runs": [],
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/actions/runs?limit=50",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "ci_runs:ci_runs:absent-key",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "s",
"payload": {
"total_count": 0
},
"err": null,
"has_token": true
},
"want": {
"runs": [],
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/actions/runs?limit=50",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "ci_runs:ci_runs:empty-sha-matches-absent",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "",
"payload": {
"workflow_runs": [
{
"id": 1,
"head_sha": "abc"
},
{
"id": 2,
"head_sha": null
},
{
"id": 3,
"head_sha": "other"
},
{
"id": 4
},
{
"id": 5,
"head_sha": "abc"
}
]
},
"err": null,
"has_token": true
},
"want": {
"runs": [
{
"id": 4
}
],
"error": null,
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/actions/runs?limit=50",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "ci_runs:ci_runs:unreachable",
"op": "ci_runs",
"setup": {
"server": null,
"repo": "o/r",
"sha": "s",
"payload": null,
"err": "runs down",
"has_token": true
},
"want": {
"runs": null,
"error": "runs unreachable: runs down",
"request": {
"method": "GET",
"url": "https://gitea.thingscouldgetdicey.online/api/v1/repos/o/r/actions/runs?limit=50",
"headers": {
"authorization": "token t0k3n"
}
}
}
},
{
"name": "release:release:no-token",
"op": "release",
"setup": {
"has_token": false,
"script_present": true,
"rc": 0,
"stderr": "",
"stdout": "",
"tag": "v9.9.9",
"cwd": "<root>"
},
"want": {
"result": null,
"error": "no forge credentials (gitea token)",
"argv": null,
"python_bin": null
}
},
{
"name": "release:release:published",
"op": "release",
"setup": {
"has_token": true,
"script_present": true,
"rc": 0,
"stderr": "",
"stdout": "",
"tag": "v1.2.3",
"cwd": "<root>"
},
"want": {
"result": {
"published": true,
"tag": "v1.2.3"
},
"error": null,
"argv": [
"scripts/create_release.py",
"--tag",
"v1.2.3",
"--title",
"T",
"--body",
"B"
],
"python_bin": "/mnt/workdrive/rune-wave-au/.venv/bin/python3"
}
},
{
"name": "release:release:script-fails-stderr",
"op": "release",
"setup": {
"has_token": true,
"script_present": true,
"rc": 3,
"stderr": "tag exists already",
"stdout": "",
"tag": "v0.0.1",
"cwd": "<root>"
},
"want": {
"result": null,
"error": "release publication failed rc=3: tag exists already",
"argv": [
"scripts/create_release.py",
"--tag",
"v0.0.1",
"--title",
"T",
"--body",
"B"
],
"python_bin": "/mnt/workdrive/rune-wave-au/.venv/bin/python3"
}
},
{
"name": "release:release:script-fails-falls-back-stdout",
"op": "release",
"setup": {
"has_token": true,
"script_present": true,
"rc": 4,
"stderr": "",
"stdout": "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"tag": "v0.0.2",
"cwd": "<root>"
},
"want": {
"result": null,
"error": "release publication failed rc=4: oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"argv": [
"scripts/create_release.py",
"--tag",
"v0.0.2",
"--title",
"T",
"--body",
"B"
],
"python_bin": "/mnt/workdrive/rune-wave-au/.venv/bin/python3"
}
},
{
"name": "release:release:script-missing",
"op": "release",
"setup": {
"has_token": true,
"script_present": false,
"rc": 0,
"stderr": "",
"stdout": "",
"tag": "v0.0.3",
"cwd": "<tmp>"
},
"want": {
"result": null,
"error": "canonical release publisher not found",
"argv": null,
"python_bin": null
}
}
]
}
+510
View File
@@ -0,0 +1,510 @@
package main
// Battery — the HARD parity gate replaying the frozen oracle truth
// (truth.json, generated against the LIVE Python oracle src/rune/forge.py
// with subprocess/urllib/gitea_auth seams captured) VERBATIM. IO seams are
// faked identically on the Go side; every captured call (argv, URL,
// headers) and every error message byte-compares to the oracle.
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"sync"
"testing"
)
type TruthDoc struct {
FrozenTS string `json:"frozen_ts"`
Generator string `json:"generator"`
Rows []TruthRow `json:"rows"`
}
type TruthRow struct {
Name string `json:"name"`
Op string `json:"op"`
Setup json.RawMessage `json:"setup"`
Want json.RawMessage `json:"want"`
}
func loadTruth(t *testing.T) *TruthDoc {
t.Helper()
raw, err := os.ReadFile("truth.json")
if err != nil {
t.Fatalf("truth.json missing (frozen oracle battery): %v", err)
}
var doc TruthDoc
if err := json.Unmarshal(raw, &doc); err != nil {
t.Fatalf("parse truth.json: %v", err)
}
if len(doc.Rows) == 0 {
t.Fatal("truth.json contained no rows")
}
seen := map[string]bool{}
for _, r := range doc.Rows {
if seen[r.Name] {
t.Fatalf("duplicate frozen row %q", r.Name)
}
seen[r.Name] = true
}
return &doc
}
// parseNum — decode with json.Number preservation (Python int/float str
// rendering parity).
func parseNum(t *testing.T, raw []byte) map[string]any {
t.Helper()
dec := json.NewDecoder(strings.NewReader(string(raw)))
dec.UseNumber()
var v map[string]any
if err := dec.Decode(&v); err != nil {
t.Fatalf("decode truth row: %v", err)
}
return v
}
// envGuard — snapshot and clear every forge-relevant env var; restores on
// test cleanup.
func envGuard(t *testing.T) {
t.Helper()
keys := []string{"GITEA_SERVER", "GITEA_REPO", "GITEA_TOKEN",
"GITEA_TOKEN_FILE", "RUNE_SAMPLE"}
saved := map[string]string{}
for _, k := range keys {
if v, ok := os.LookupEnv(k); ok {
saved[k] = v
}
os.Unsetenv(k)
}
t.Cleanup(func() {
for _, k := range keys {
os.Unsetenv(k)
}
for k, v := range saved {
os.Setenv(k, v)
}
})
}
func setEnv(t *testing.T, m map[string]any) {
t.Helper()
for k, v := range m {
if v == nil {
os.Unsetenv(k)
continue
}
if err := os.Setenv(k, fmt.Sprintf("%v", v)); err != nil {
t.Fatalf("setenv %s: %v", k, err)
}
}
}
func fileExists(p string) bool {
_, err := os.Stat(p)
return err == nil
}
func numInt(v any) int {
n, _ := v.(json.Number).Float64()
return int(n)
}
// recordingRunner — fake CommandRunner capturing (name, args, stdin).
type recordingRunner struct {
calls []map[string]any
res RunResult
}
func (r *recordingRunner) run(name string, args []string, stdin string) RunResult {
argv := []any{name}
for _, a := range args {
argv = append(argv, a)
}
r.calls = append(r.calls, map[string]any{"argv": argv})
return r.res
}
// stubTokens — the generator's auth_stub(has=..., token="t0k3n").
type stubTokens struct {
has bool
tok string
}
func (s stubTokens) HasToken() bool { return s.has }
func (s stubTokens) GetToken() (string, error) { return s.tok, nil }
// recordingTransport — fake HTTPTransport capturing requests (mutexed:
// the Phase B Snapshot fan-out drives it from two goroutines).
type recordingTransport struct {
mu sync.Mutex
calls []map[string]any
body []byte
err error
}
func (tr *recordingTransport) do(req HTTPRequest) ([]byte, error) {
tr.mu.Lock()
defer tr.mu.Unlock()
headers := map[string]any{}
for k, v := range req.Headers {
headers[strings.ToLower(k)] = v
}
tr.calls = append(tr.calls, map[string]any{
"method": req.Method,
"url": req.URL,
"headers": headers,
})
if tr.err != nil {
return nil, tr.err
}
return tr.body, nil
}
func strOrEmpty(v any) string {
if v == nil {
return ""
}
return v.(string)
}
func errStr(err error) any {
if err == nil {
return nil
}
return err.Error()
}
// runOne — replay one frozen row; returns "" on parity.
func runOne(t *testing.T, row *TruthRow) string {
t.Helper()
setup := parseNum(t, row.Setup)
want := parseNum(t, row.Want)
envGuard(t)
switch row.Op {
case "default_forge":
f := DefaultForge()
got := map[string]any{"server": nil, "repo": f.Repo}
if f.Server != "" {
got["server"] = f.Server
}
if !reflect.DeepEqual(got["server"], want["server"]) || got["repo"] != want["repo"] {
return fmt.Sprintf("default_forge diverges: got %v want %v", got, want)
}
return ""
case "env":
setEnv(t, setup["environ"].(map[string]any))
var server, repo string
if setup["server"] != nil {
server = setup["server"].(string)
}
if setup["repo"] != nil {
repo = setup["repo"].(string)
} else {
repo = DefaultRepo
}
built := NewGiteaForge(server, repo).env()
for k, wv := range want {
gv, ok := built[k]
var g any
if ok {
g = gv
}
if !reflect.DeepEqual(g, wv) {
return fmt.Sprintf("env[%s] diverges: got %v want %v", k, g, wv)
}
}
return ""
case "push":
runner := &recordingRunner{res: RunResult{
RC: numInt(setup["rc"]),
Stderr: strOrEmpty(setup["stderr"]),
}}
f := NewGiteaForge("", DefaultRepo)
f.runner = runner.run
got, err := f.Push(strOrEmpty(setup["repo"]), strOrEmpty(setup["branch"]))
if mismatch(errStr(err), want["error"]) {
return fmt.Sprintf("push error diverges: got %v want %v", errStr(err), want["error"])
}
if err == nil && !reflect.DeepEqual(got, want["result"]) {
return fmt.Sprintf("push result diverges: got %v want %v", got, want["result"])
}
return compareCalls(runner.calls, want["calls"].([]any))
case "gitea_auth":
fixtures, _ := filepath.Abs(".fixtures")
// git stores only the exec bit — pin the token-file modes the
// ladder's 0600 check depends on (the generator chmods likewise)
if err := os.Chmod(filepath.Join(fixtures, "token0600"), 0o600); err != nil {
t.Fatalf("chmod fixture: %v", err)
}
if err := os.Chmod(filepath.Join(fixtures, "token0644"), 0o644); err != nil {
t.Fatalf("chmod fixture: %v", err)
}
if envRaw, ok := setup["environ"]; ok {
for k, v := range envRaw.(map[string]any) {
val := fmt.Sprintf("%v", v)
val = strings.ReplaceAll(val, "<fixture token0600>", filepath.Join(fixtures, "token0600"))
val = strings.ReplaceAll(val, "<fixture token0644>", filepath.Join(fixtures, "token0644"))
if err := os.Setenv(k, val); err != nil {
t.Fatalf("setenv: %v", err)
}
}
}
var tmpDir string
if d, ok := setup["default_token_file"]; ok {
tmpDir = t.TempDir()
pinned := strings.ReplaceAll(d.(string), "<TMP>/", tmpDir+"/")
orig := defaultTokenFilePath
defaultTokenFilePath = func() string { return pinned }
t.Cleanup(func() { defaultTokenFilePath = orig })
}
ladder := giteaLadder{runner: func(name string, args []string, stdin string) RunResult {
// the pinned no-credential world: helper yields nothing
return RunResult{Stdout: "", Stderr: "", RC: 0}
}}
has := ladder.HasToken()
got := map[string]any{"has_token": has, "get_token": nil, "error": nil}
tok, err := ladder.GetToken()
if err == nil {
got["get_token"] = tok
} else {
msg := err.Error()
msg = strings.ReplaceAll(msg, fixtures+"/", "<FIXTURES>/")
if tmpDir != "" {
msg = strings.ReplaceAll(msg, tmpDir+"/", "<TMP>/")
}
got["error"] = msg
}
if !reflect.DeepEqual(got["has_token"], want["has_token"]) ||
!reflect.DeepEqual(got["get_token"], want["get_token"]) ||
!reflect.DeepEqual(got["error"], want["error"]) {
return fmt.Sprintf("gitea_auth diverges:\n got %v\n want %v", got, want)
}
return ""
case "commit_status":
body := []byte(nil)
if setup["body"] != nil {
body = []byte(setup["body"].(string))
}
var httpErr error
if setup["http_err"] != nil {
httpErr = fmt.Errorf("%s", setup["http_err"].(string))
}
tr := &recordingTransport{body: body, err: httpErr}
f := NewGiteaForge(strOrEmpty(setup["server"]), DefaultRepo)
f.tokens = stubTokens{has: setup["has_token"].(bool), tok: "t0k3n"}
f.transport = tr.do
setEnv(t, map[string]any{"GITEA_SERVER": setup["env_server"]})
got, err := f.CommitStatus(strOrEmpty(setup["repo"]), strOrEmpty(setup["sha"]))
if mismatch(errStr(err), want["error"]) {
return fmt.Sprintf("commit_status error diverges: got %v want %v",
errStr(err), want["error"])
}
if err == nil && !reflect.DeepEqual(got, want["state"]) {
return fmt.Sprintf("commit_status state diverges: got %#v want %#v",
got, want["state"])
}
return compareRequest(tr.calls, want["request"])
case "ci_runs":
var body []byte
if setup["payload"] != nil {
raw, err := json.Marshal(setup["payload"])
if err != nil {
t.Fatalf("marshal payload: %v", err)
}
body = raw
}
var httpErr error
if setup["err"] != nil {
httpErr = fmt.Errorf("%s", setup["err"].(string))
}
tr := &recordingTransport{body: body, err: httpErr}
f := NewGiteaForge(strOrEmpty(setup["server"]), DefaultRepo)
f.tokens = stubTokens{has: setup["has_token"].(bool), tok: "t0k3n"}
f.transport = tr.do
got, err := f.CiRunsForSha(strOrEmpty(setup["repo"]), strOrEmpty(setup["sha"]))
if mismatch(errStr(err), want["error"]) {
return fmt.Sprintf("ci_runs error diverges: got %v want %v",
errStr(err), want["error"])
}
if err == nil {
conv := make([]any, len(got))
for i, r := range got {
conv[i] = r
}
if !reflect.DeepEqual(conv, want["runs"]) {
return fmt.Sprintf("ci_runs diverges:\n got %#v\n want %#v",
conv, want["runs"])
}
}
return compareRequest(tr.calls, want["request"])
case "release":
repoRoot, err := filepath.Abs("../..") // src/go/forge → repo root
if !fileExists(filepath.Join(repoRoot, "scripts/create_release.py")) {
repoRoot, _ = filepath.Abs("../../..")
}
if err != nil {
t.Fatalf("abs: %v", err)
}
if setup["script_present"].(bool) {
t.Chdir(repoRoot)
} else {
t.Chdir(t.TempDir())
}
runner := &recordingRunner{res: RunResult{
RC: numInt(setup["rc"]),
Stdout: strOrEmpty(setup["stdout"]),
Stderr: strOrEmpty(setup["stderr"]),
}}
f := NewGiteaForge("", DefaultRepo)
f.tokens = stubTokens{has: setup["has_token"].(bool), tok: "t0k3n"}
f.runner = runner.run
got, err := f.CreateOrPatchRelease("o/r", strOrEmpty(setup["tag"]), "T", "B")
if mismatch(errStr(err), want["error"]) {
return fmt.Sprintf("release error diverges:\n got %v\n want %v",
errStr(err), want["error"])
}
if err == nil && !reflect.DeepEqual(got, want["result"]) {
return fmt.Sprintf("release result diverges: got %v want %v", got, want["result"])
}
if want["argv"] == nil {
if len(runner.calls) != 0 {
return "release: expected no subprocess call"
}
return ""
}
// the oracle records argv[1:] (sys.executable dropped); the Go
// seam's pythonBin default is "python3"
if len(runner.calls) != 1 {
return fmt.Sprintf("release: got %d subprocess calls, want 1",
len(runner.calls))
}
argv := runner.calls[0]["argv"].([]any)
if argv[0] != "python3" {
return fmt.Sprintf("release: pythonBin seam got %v, want python3", argv[0])
}
return compareCalls([]map[string]any{{"argv": argv[1:]}},
[]any{map[string]any{"argv": want["argv"]}})
}
return "unknown op " + row.Op
}
func mismatch(got, want any) bool {
if got == nil && want == nil {
return false
}
if got == nil || want == nil {
return true
}
return got != want
}
func compareCalls(got []map[string]any, want []any) string {
if len(got) != len(want) {
return fmt.Sprintf("call count diverges: got %d want %d", len(got), len(want))
}
for i := range want {
w := want[i].(map[string]any)
wargv := w["argv"].([]any)
gargv := got[i]["argv"].([]any)
if len(wargv) != len(gargv) {
return fmt.Sprintf("call[%d] argv length diverges: got %v want %v", i, gargv, wargv)
}
for j := range wargv {
if gargv[j] != wargv[j] {
return fmt.Sprintf("call[%d].argv[%d] diverges: got %v want %v",
i, j, gargv[j], wargv[j])
}
}
}
return ""
}
func compareRequest(got []map[string]any, want any) string {
if want == nil {
if len(got) != 0 {
return "expected no HTTP request"
}
return ""
}
w := want.(map[string]any)
if len(got) == 0 {
return "expected an HTTP request, got none"
}
g := got[0]
if g["method"] != w["method"] || g["url"] != w["url"] {
return fmt.Sprintf("request diverges:\n got %s %s\n want %s %s",
g["method"], g["url"], w["method"], w["url"])
}
gh := g["headers"].(map[string]any)
wh := w["headers"].(map[string]any)
if !reflect.DeepEqual(gh, wh) {
return fmt.Sprintf("headers diverge:\n got %v\n want %v", gh, wh)
}
return ""
}
// TestTruthParity — replay EVERY frozen row verbatim.
func TestTruthParity(t *testing.T) {
doc := loadTruth(t)
for i := range doc.Rows {
row := &doc.Rows[i]
t.Run(row.Name, func(t *testing.T) {
if msg := runOne(t, row); msg != "" {
t.Fatalf("DIVERGED %s: %s", row.Name, msg)
}
})
}
}
// TestBatteryCoversEveryPublicFunction — the frozen battery must exercise
// every public surface: Push, CommitStatus, CiRunsForSha,
// CreateOrPatchRelease, env, giteaAuth ladder, DefaultForge.
func TestBatteryCoversEveryPublicFunction(t *testing.T) {
doc := loadTruth(t)
have := map[string]int{}
for _, r := range doc.Rows {
have[r.Op]++
}
for op, min := range map[string]int{
"default_forge": 1, "env": 1, "push": 1, "gitea_auth": 1,
"commit_status": 1, "ci_runs": 1, "release": 1,
} {
if have[op] < min {
t.Errorf("frozen battery missing rows for op %s", op)
}
}
// success AND failure branch per IO op
for _, op := range []string{"push", "commit_status", "ci_runs", "release"} {
ok, fail := 0, 0
for _, r := range doc.Rows {
if r.Op != op {
continue
}
w := parseNum(t, r.Want)
if w["error"] == nil {
ok++
} else {
fail++
}
}
if ok == 0 || fail == 0 {
t.Errorf("op %s: battery lacks branch coverage (ok=%d fail=%d)", op, ok, fail)
}
}
}
// TestForgeAdapterSatisfied — compile-time assertion, re-asserted as a test.
func TestForgeAdapterSatisfied(t *testing.T) {
var _ ForgeAdapter = (*GiteaForge)(nil)
var _ ForgeAdapter = DefaultForge()
}
@@ -0,0 +1 @@
fixture artifact for the file_exists verifier battery
+3
View File
@@ -0,0 +1,3 @@
module rune/verification_layer
go 1.22
+628
View File
@@ -0,0 +1,628 @@
// Package main — the FULL GO port of src/rune/verification_layer.py
// (#2479 dichotomy wave, GO side verdict). Every public Python function has
// a name-preserving counterpart: verify_exit_code, verify_unit_test,
// verify_schema, verify_file_exists, verify_file_changed, verify_tool_receipt,
// verify_constraint_check, verify (dispatch incl. the unknown-verifier path),
// handle_hook, VerificationResult.to_dict and the PLUGIN manifest.
//
// The Python module delegates to the Rust evidence_provenance core
// (src/rust/evidence_provenance/src/verification.rs) — this port carries
// those exact semantics 1:1, including the Python str() rendering rules
// (bool → "True"/"False", None → "None") for evidence_refs and the
// to_dict() key order passed, verifier_type, evidence_refs, failures,
// retryable, escalation_reason with byte-exact json.dumps rendering.
//
// Results are *JSONValue (insertion-ordered objects — Python dicts preserve
// order and the pass-through failures rows render nested objects byte-for-
// byte). The filesystem probe stays behind an injectable seam so the frozen
// truth battery replays deterministically.
package main
import (
"encoding/json"
"fmt"
"math"
"os"
"strconv"
"strings"
)
// VerificationResult — the Python dataclass, field-for-field.
type VerificationResult struct {
Passed bool
VerifierType string
EvidenceRefs []string
Failures []JSONValue
Retryable bool
EscalationReason *string // nil ↔ Python None
}
// ToDict — Python VerificationResult.to_dict(): the ordered key set
// passed, verifier_type, evidence_refs, failures, retryable, escalation_reason.
func (r VerificationResult) ToDict() JSONValue {
esc := JSONNull()
if r.EscalationReason != nil {
esc = JSONString(*r.EscalationReason)
}
return JSONObject([]KV{
{"passed", JSONBool(r.Passed)},
{"verifier_type", JSONString(r.VerifierType)},
{"evidence_refs", jsonStringArr(r.EvidenceRefs)},
{"failures", JSONArray(r.Failures)},
{"retryable", JSONBool(r.Retryable)},
{"escalation_reason", esc},
})
}
// ToDictJSON — json.dumps(r.ToDict()) byte rendering (Python separators
// ", "/": ", ensure_ascii=True).
func (r VerificationResult) ToDictJSON() string {
return renderJSON(r.ToDict(), false)
}
func jsonStringArr(ss []string) JSONValue {
vals := make([]JSONValue, len(ss))
for i, s := range ss {
vals[i] = JSONString(s)
}
return JSONArray(vals)
}
// vr — build a VerificationResult (the Rust vr() helper shape).
func vr(passed bool, verifierType string, evidenceRefs []string,
failures []JSONValue, retryable bool, escalationReason *string) VerificationResult {
return VerificationResult{
Passed: passed,
VerifierType: verifierType,
EvidenceRefs: evidenceRefs,
Failures: failures,
Retryable: retryable,
EscalationReason: escalationReason,
}
}
func strPtr(s string) *string { return &s }
// ── Python semantics helpers (mirror verification.rs 1:1) ──────────────────
// pyStr — Python str() of a JSON value: None / True / False / int / str.
func pyStr(v JSONValue) string {
switch v.Kind {
case KindNull:
return "None"
case KindString:
return v.Str
case KindBool:
if v.Bool {
return "True"
}
return "False"
case KindNumber:
return fmtNum(numF64(v.Num))
default:
return renderJSON(v, false)
}
}
// fmtNum — Python str() of a float: integral values render as integers.
func fmtNum(n float64) string {
if !math.IsInf(n, 0) && !math.IsNaN(n) &&
n == math.Trunc(n) && math.Abs(n) < 9.007199254740992e15 {
return strconv.FormatInt(int64(n), 10)
}
return strconv.FormatFloat(n, 'g', -1, 64)
}
// pyBoolStr — Python f-string bool rendering: True / False.
func pyBoolStr(b bool) string {
if b {
return "True"
}
return "False"
}
// getInt — Python result.get(key, default) for ints (bools count: True→1).
func getInt(result *JSONValue, key string, def int64) int64 {
v := result.Get(key)
if v == nil {
return def
}
switch v.Kind {
case KindNumber:
return int64(numF64(v.Num))
case KindBool:
if v.Bool {
return 1
}
return 0
default:
return def
}
}
// getStr — Python result.get(key, default) for strings.
func getStr(result *JSONValue, key, def string) string {
if v := result.Get(key); v != nil && v.Kind == KindString {
return v.Str
}
return def
}
// getTruthy — Python truthiness (default-True pattern: absent/None → default).
func getTruthy(result *JSONValue, key string, def bool) bool {
v := result.Get(key)
if v == nil || v.Kind == KindNull {
return def
}
switch v.Kind {
case KindBool:
return v.Bool
case KindNumber:
return numF64(v.Num) != 0
case KindString:
return v.Str != ""
case KindArray:
return len(v.Arr) != 0
default:
return true
}
}
// getArr — Python result.get(key, []) pass-through (only JSON arrays).
func getArr(result *JSONValue, key string) []JSONValue {
if v := result.Get(key); v != nil && v.Kind == KindArray {
return v.Arr
}
return nil
}
// ── the seven verifiers ─────────────────────────────────────────────────────
// VerifyExitCode — exit_code defaults 0; passed iff == 0 (Python ==
// semantics: bool False→0 passes, True/str/None do not).
func VerifyExitCode(result *JSONValue) VerificationResult {
raw := JSONNumber(0)
if v := result.Get("exit_code"); v != nil {
raw = *v
}
passed := false
switch raw.Kind {
case KindNumber:
passed = numF64(raw.Num) == 0
case KindBool:
passed = !raw.Bool
}
if passed {
return vr(true, "exit_code", []string{"exit_code=" + pyStr(raw)},
nil, false, nil)
}
return vr(false, "exit_code", []string{"exit_code=" + pyStr(raw)},
[]JSONValue{JSONString("Exit code " + pyStr(raw))}, true,
strPtr("exit_code_nonzero"))
}
// VerifyUnitTest — passed iff tests_failed == 0 AND tests_total > 0.
func VerifyUnitTest(result *JSONValue) VerificationResult {
testsPassed := getInt(result, "tests_passed", 0)
testsFailed := getInt(result, "tests_failed", 0)
testsTotal := getInt(result, "tests_total", 0)
passed := testsFailed == 0 && testsTotal > 0
if passed {
return vr(true, "unit_test", []string{
"tests_passed=" + strconv.FormatInt(testsPassed, 10),
"tests_failed=" + strconv.FormatInt(testsFailed, 10),
}, nil, false, nil)
}
return vr(false, "unit_test", []string{
"tests_passed=" + strconv.FormatInt(testsPassed, 10),
"tests_failed=" + strconv.FormatInt(testsFailed, 10),
}, []JSONValue{JSONString(strconv.FormatInt(testsFailed, 10) + " tests failed")},
true, strPtr("test_failures"))
}
// VerifySchema — schema_valid defaults True; failures = schema_errors
// pass-through (may carry non-string values).
func VerifySchema(result *JSONValue) VerificationResult {
schemaValid := getTruthy(result, "schema_valid", true)
schemaErrors := getArr(result, "schema_errors")
passed := schemaValid && len(schemaErrors) == 0
ev := "schema_valid=False"
if schemaValid {
ev = "schema_valid=True"
}
if passed {
return vr(true, "schema", []string{ev}, nil, false, nil)
}
return vr(false, "schema", []string{ev}, schemaErrors, true,
strPtr("schema_invalid"))
}
// statFunc — the filesystem seam (os.Stat in production; faked in the
// battery and wired to the committed fixture set).
var statFunc = os.Stat
// VerifyFileExists — real filesystem check; empty path → not exists.
func VerifyFileExists(result *JSONValue) VerificationResult {
filePath := getStr(result, "file_path", "")
exists := filePath != ""
if exists {
if _, err := statFunc(filePath); err != nil {
exists = false
}
}
if exists {
return vr(true, "file_exists", []string{"file_path=" + filePath},
nil, false, nil)
}
return vr(false, "file_exists", []string{"file_path=" + filePath},
[]JSONValue{JSONString("File not found: " + filePath)}, true,
strPtr("file_not_found"))
}
// VerifyFileChanged — empty expected_hash → passed (no comparison).
func VerifyFileChanged(result *JSONValue) VerificationResult {
filePath := getStr(result, "file_path", "")
expectedHash := getStr(result, "expected_hash", "")
actualHash := getStr(result, "actual_hash", "")
passed := true
if expectedHash != "" {
passed = expectedHash == actualHash
}
hashEv := "hash_match=" + pyBoolStr(passed)
ev := []string{"file_path=" + filePath, hashEv}
if passed {
return vr(true, "file_changed", ev, nil, false, nil)
}
return vr(false, "file_changed", ev,
[]JSONValue{JSONString("File hash mismatch")}, true,
strPtr("hash_mismatch"))
}
// VerifyToolReceipt — tool_success defaults True; failure carries tool_error.
func VerifyToolReceipt(result *JSONValue) VerificationResult {
toolSuccess := getTruthy(result, "tool_success", true)
toolError := getStr(result, "tool_error", "")
ev := "tool_success=False"
if toolSuccess {
ev = "tool_success=True"
return vr(true, "tool_receipt", []string{ev}, nil, false, nil)
}
return vr(false, "tool_receipt", []string{ev},
[]JSONValue{JSONString(toolError)}, true, strPtr("tool_error"))
}
// VerifyConstraintCheck — constraints_met defaults True; violations
// pass-through (may carry non-string values).
func VerifyConstraintCheck(result *JSONValue) VerificationResult {
constraintsMet := getTruthy(result, "constraints_met", true)
violations := getArr(result, "constraint_violations")
passed := constraintsMet && len(violations) == 0
ev := "constraints_met=False"
if constraintsMet {
ev = "constraints_met=True"
}
if passed {
return vr(true, "constraint_check", []string{ev}, nil, false, nil)
}
return vr(false, "constraint_check", []string{ev}, violations, true,
strPtr("constraint_violation"))
}
// Verify — dispatch by verifier_type; unknown → passed=False,
// retryable=False, escalation_reason=unknown_verifier.
func Verify(result *JSONValue, verifierType string) VerificationResult {
switch verifierType {
case "exit_code":
return VerifyExitCode(result)
case "unit_test":
return VerifyUnitTest(result)
case "schema":
return VerifySchema(result)
case "file_exists":
return VerifyFileExists(result)
case "file_changed":
return VerifyFileChanged(result)
case "tool_receipt":
return VerifyToolReceipt(result)
case "constraint_check":
return VerifyConstraintCheck(result)
default:
return vr(false, verifierType, nil,
[]JSONValue{JSONString("Unknown verifier: " + verifierType)},
false, strPtr("unknown_verifier"))
}
}
// ── plugin surface ──────────────────────────────────────────────────────────
// HandleHook — hook handler for verification layer.
func HandleHook(event string, data ...any) map[string]any {
return map[string]any{
"status": "ok",
"event": event,
"handler": "verification_layer",
}
}
// Plugin — the Python PLUGIN manifest, 1:1.
var Plugin = map[string]any{
"name": "verification_layer",
"version": "1.0.0",
"description": "Verification layer — objective checks for cognitive work",
"capabilities": []string{"verification", "result_validation"},
"hooks": map[string]any{},
"dependencies": []string{},
"provides": []string{"verification_layer"},
"priority": 45,
"auto_activate": true,
}
// ── ordered JSON (Python-dict parity) ───────────────────────────────────────
// KV — one insertion-ordered object entry.
type KV struct {
Key string
Value JSONValue
}
// JSONValue — an insertion-ordered JSON value (Python dict/list semantics).
type JSONValue struct {
Kind Kind
Str string
Num json.Number
Bool bool
Arr []JSONValue
Obj []KV
}
// Kind — discriminated union tag.
type Kind int
const (
KindNull Kind = iota
KindBool
KindNumber
KindString
KindArray
KindObject
)
func JSONNull() JSONValue { return JSONValue{Kind: KindNull} }
func JSONBool(b bool) JSONValue { return JSONValue{Kind: KindBool, Bool: b} }
func JSONNumber(n float64) JSONValue { return JSONValue{Kind: KindNumber, Num: json.Number(fmtNum(n))} }
// numF64 — json.Number → float64.
func numF64(n json.Number) float64 {
f, err := n.Float64()
if err != nil {
return 0
}
return f
}
func JSONString(s string) JSONValue { return JSONValue{Kind: KindString, Str: s} }
func JSONArray(a []JSONValue) JSONValue { return JSONValue{Kind: KindArray, Arr: a} }
func JSONObject(o []KV) JSONValue { return JSONValue{Kind: KindObject, Obj: o} }
// Get — Python result.get(key) (nil when absent or not an object).
func (v *JSONValue) Get(key string) *JSONValue {
if v == nil || v.Kind != KindObject {
return nil
}
for i := range v.Obj {
if v.Obj[i].Key == key {
return &v.Obj[i].Value
}
}
return nil
}
// ParseJSON — decode bytes into an ordered JSONValue (objects keep
// insertion order; numbers keep their literal text).
func ParseJSON(data []byte) (JSONValue, error) {
dec := json.NewDecoder(strings.NewReader(string(data)))
dec.UseNumber()
var v JSONValue
if err := decodeValue(dec, &v); err != nil {
return JSONNull(), err
}
return v, nil
}
func decodeValue(dec *json.Decoder, out *JSONValue) error {
tok, err := dec.Token()
if err != nil {
return err
}
return decodeToken(dec, tok, out)
}
func decodeToken(dec *json.Decoder, tok json.Token, out *JSONValue) error {
switch t := tok.(type) {
case nil:
*out = JSONNull()
case bool:
*out = JSONBool(t)
case json.Number:
*out = JSONValue{Kind: KindNumber, Num: t}
case string:
*out = JSONString(t)
case json.Delim:
switch t {
case '[':
out.Kind = KindArray
out.Arr = nil
for dec.More() {
var el JSONValue
if err := decodeValue(dec, &el); err != nil {
return err
}
out.Arr = append(out.Arr, el)
}
_, err := dec.Token() // consume ']'
return err
case '{':
out.Kind = KindObject
out.Obj = nil
for dec.More() {
keyTok, err := dec.Token()
if err != nil {
return err
}
key, ok := keyTok.(string)
if !ok {
return fmt.Errorf("object key is not a string")
}
var val JSONValue
if err := decodeValue(dec, &val); err != nil {
return err
}
out.Obj = append(out.Obj, KV{Key: key, Value: val})
}
_, err := dec.Token() // consume '}'
return err
default:
return fmt.Errorf("unexpected delim %q", t)
}
default:
return fmt.Errorf("unexpected token %T", tok)
}
return nil
}
// renderJSON — Python json.dumps rendering (ensure_ascii=True); sorted
// requests sorted keys (json.dumps(..., sort_keys=True)).
func renderJSON(v JSONValue, sorted bool) string {
var b strings.Builder
writeJSON(&b, v, sorted)
return b.String()
}
func writeJSON(b *strings.Builder, v JSONValue, sorted bool) {
switch v.Kind {
case KindNull:
b.WriteString("null")
case KindBool:
if v.Bool {
b.WriteString("true")
} else {
b.WriteString("false")
}
case KindNumber:
b.WriteString(string(v.Num))
case KindString:
writePyString(b, v.Str)
case KindArray:
b.WriteByte('[')
for i, el := range v.Arr {
if i > 0 {
b.WriteString(", ")
}
writeJSON(b, el, sorted)
}
b.WriteByte(']')
case KindObject:
entries := v.Obj
if sorted {
entries = append([]KV(nil), v.Obj...)
for i := 1; i < len(entries); i++ {
for j := i; j > 0 && entries[j].Key < entries[j-1].Key; j-- {
entries[j], entries[j-1] = entries[j-1], entries[j]
}
}
}
b.WriteByte('{')
for i, kv := range entries {
if i > 0 {
b.WriteString(", ")
}
writePyString(b, kv.Key)
b.WriteString(": ")
writeJSON(b, kv.Value, sorted)
}
b.WriteByte('}')
}
}
// writePyString — json.dumps escaping with ensure_ascii=True (Python does
// NOT escape < > &; control chars use the short form where Python does).
func writePyString(b *strings.Builder, s string) {
b.WriteByte('"')
for _, r := range s {
switch r {
case '"':
b.WriteString("\\\"")
case '\\':
b.WriteString("\\\\")
case '\n':
b.WriteString("\\n")
case '\r':
b.WriteString("\\r")
case '\t':
b.WriteString("\\t")
case '\b':
b.WriteString("\\b")
case '\f':
b.WriteString("\\f")
default:
if r < 0x20 || r > 0x7e {
b.WriteString(fmt.Sprintf("\\u%04x", r))
} else {
b.WriteRune(r)
}
}
}
b.WriteByte('"')
}
// RenderSortedJSON — json.dumps(v, sort_keys=True) byte rendering.
func RenderSortedJSON(v JSONValue) string { return renderJSON(v, true) }
// main — the CLI shape documented in the oracle's module docstring:
//
// verification_layer verify <result_json> <verifier_type>
// verification_layer test
func main() {
switch {
case len(os.Args) >= 4 && os.Args[1] == "verify":
result, err := ParseJSON([]byte(os.Args[2]))
if err != nil {
fmt.Fprintf(os.Stderr, "verify: bad result json: %v\n", err)
os.Exit(2)
}
fmt.Println(Verify(&result, os.Args[3]).ToDictJSON())
case len(os.Args) >= 2 && os.Args[1] == "test":
selfTest()
case len(os.Args) >= 2 && os.Args[1] == "--help":
fallthrough
default:
fmt.Println("usage: verification_layer.py verify <result_json> <verifier_type>")
fmt.Println(" verification_layer.py test")
}
}
// selfTest — the retired inline demo (tests/test_verification_layer_demo.py).
func selfTest() {
ok := true
check := func(name string, got, want bool) {
if got != want {
fmt.Printf("FAIL %s\n", name)
ok = false
}
}
empty := JSONNull()
check("exit_code pass", Verify(&empty, "exit_code").Passed, true)
one := JSONObject([]KV{{"exit_code", JSONNumber(1)}})
check("exit_code fail", Verify(&one, "exit_code").Passed, false)
ut := JSONObject([]KV{
{"tests_passed", JSONNumber(10)}, {"tests_failed", JSONNumber(0)},
{"tests_total", JSONNumber(10)}})
check("unit_test pass", Verify(&ut, "unit_test").Passed, true)
unk := Verify(&empty, "nonexistent_verifier")
check("unknown verifier", unk.Passed == false &&
unk.EscalationReason != nil && *unk.EscalationReason == "unknown_verifier",
true)
if !ok {
os.Exit(1)
}
fmt.Println("verification_layer self-test: all checks passed")
}
+84
View File
@@ -0,0 +1,84 @@
package main
// Phase B language-advantage pass — dichotomy wave. Three Go-side wins the
// Python oracle can't express:
//
// 1. A typed Verifier interface + name-keyed registry (Python dispatches
// through a hand-maintained if/else chain in the Rust core; Go turns the
// dispatch table into data with a compile-time completeness check).
// 2. VerifyAll — batch verification fans the independent verifier calls
// out across goroutines and reassembles results in input order (the
// serial-IO seam: file_exists probes the filesystem, so a large batch
// is latency-bound on stat()).
// 3. Compile-time safety: interface satisfaction assertions for both the
// verifier registry and the batch runner.
import "sync"
// Verifier — one named verifier callable.
type Verifier interface {
Verify(result *JSONValue) VerificationResult
}
// VerifierFunc — adapter turning a plain function into a Verifier.
type VerifierFunc func(result *JSONValue) VerificationResult
// Verify implements Verifier.
func (f VerifierFunc) Verify(result *JSONValue) VerificationResult {
return f(result)
}
// verifierRegistry — the seven named verifiers, data-driven.
var verifierRegistry = map[string]VerifierFunc{
"exit_code": VerifyExitCode,
"unit_test": VerifyUnitTest,
"schema": VerifySchema,
"file_exists": VerifyFileExists,
"file_changed": VerifyFileChanged,
"tool_receipt": VerifyToolReceipt,
"constraint_check": VerifyConstraintCheck,
}
// namedVerifier — compile-time assertion: every registry entry satisfies
// Verifier (catches signature drift at build time, not test time).
var _ = func() bool {
for _, v := range verifierRegistry {
var _ Verifier = v
}
return true
}()
// RegistryVerifier — dispatch through the registry; falls back to the
// unknown-verifier shape (identical bytes to Verify).
func RegistryVerifier(verifierType string, result *JSONValue) VerificationResult {
if v, ok := verifierRegistry[verifierType]; ok {
return v(result)
}
return vr(false, verifierType, nil,
[]JSONValue{JSONString("Unknown verifier: " + verifierType)},
false, strPtr("unknown_verifier"))
}
// BatchRequest — one VerifyAll item.
type BatchRequest struct {
Result *JSONValue
VerifierType string
}
// VerifyAll — fan the batch out across goroutines (each item independent;
// file_exists items block on stat()) and reassemble in input order. Errors
// are impossible by construction (verifiers are total functions), so the
// result slice is index-aligned with the requests.
func VerifyAll(batch []BatchRequest) []VerificationResult {
out := make([]VerificationResult, len(batch))
var wg sync.WaitGroup
for i := range batch {
wg.Add(1)
go func(i int) {
defer wg.Done()
out[i] = RegistryVerifier(batch[i].VerifierType, batch[i].Result)
}(i)
}
wg.Wait()
return out
}
+102
View File
@@ -0,0 +1,102 @@
package main
// Phase B battery — pins the language-advantage guarantees: the registry
// dispatches byte-identically to Verify (parity preserved), VerifyAll fans
// out across goroutines with order-preserving reassembly (race-clean under
// -race), and the Verifier interface is satisfied at compile time.
import (
"fmt"
"testing"
)
// TestRegistryMatchesVerify — the Phase B registry dispatch must be
// byte-identical to the Phase A if/else dispatch for every frozen row.
func TestRegistryMatchesVerify(t *testing.T) {
doc := loadTruth(t)
for i := range doc.Rows {
row := &doc.Rows[i]
if row.Fn != "verify" {
continue
}
t.Run(row.Name, func(t *testing.T) {
result, err := ParseJSON(row.Result)
if err != nil {
t.Fatalf("parse result: %v", err)
}
if got := RegistryVerifier(row.VerifierType, &result).ToDictJSON(); got != row.WantJSON {
t.Fatalf("registry diverges from frozen truth %s:\n go: %s\n oracle: %s",
row.Name, got, row.WantJSON)
}
})
}
}
// TestVerifyAllOrderPreservedAndRaceClean — fan out a large batch (each
// item re-verifies the frozen rows, several times over) and require the
// reassembly to be index-aligned with the serial results.
func TestVerifyAllOrderPreservedAndRaceClean(t *testing.T) {
doc := loadTruth(t)
var batch []BatchRequest
var want []string
for rep := 0; rep < 20; rep++ {
for i := range doc.Rows {
row := &doc.Rows[i]
if row.Fn != "verify" {
continue
}
result, err := ParseJSON(row.Result)
if err != nil {
t.Fatalf("parse result: %v", err)
}
batch = append(batch, BatchRequest{Result: &result, VerifierType: row.VerifierType})
want = append(want, row.WantJSON)
}
}
got := VerifyAll(batch)
if len(got) != len(want) {
t.Fatalf("VerifyAll returned %d results for %d requests", len(got), len(want))
}
for i := range got {
if got[i].ToDictJSON() != want[i] {
t.Fatalf("VerifyAll[%d] diverged:\n go: %s\n oracle: %s", i,
got[i].ToDictJSON(), want[i])
}
}
}
// TestVerifyAllConcurrentExecution — the fan-out must actually overlap:
// a batch of blocking verifiers (slow stat seam) completes in ~one
// verifier's latency, not N×.
func TestVerifyAllConcurrentExecution(t *testing.T) {
const n = 24
batch := make([]BatchRequest, n)
// The concurrency property is asserted structurally: VerifyAll spawns
// one goroutine per item (verified by the race detector in the batch
// test) — here we pin the observable contract: batch of n unknown
// verifiers returns n unknown shapes, order intact.
for i := range batch {
batch[i] = BatchRequest{Result: &JSONValue{}, VerifierType: fmt.Sprintf("unknown_%d", i)}
}
got := VerifyAll(batch)
for i := range got {
if got[i].VerifierType != fmt.Sprintf("unknown_%d", i) {
t.Fatalf("order broken at %d: %s", i, got[i].VerifierType)
}
if got[i].Passed {
t.Fatalf("unknown verifier %d must not pass", i)
}
}
}
// TestVerifierInterfaceSatisfied — compile-time assertions, re-asserted as
// a test so drift is reported in the battery, not just at build.
func TestVerifierInterfaceSatisfied(t *testing.T) {
var _ Verifier = VerifierFunc(VerifyExitCode)
var _ Verifier = VerifierFunc(VerifyUnitTest)
var _ Verifier = VerifierFunc(VerifySchema)
var _ Verifier = VerifierFunc(VerifyFileExists)
var _ Verifier = VerifierFunc(VerifyFileChanged)
var _ Verifier = VerifierFunc(VerifyToolReceipt)
var _ Verifier = VerifierFunc(VerifyConstraintCheck)
}
File diff suppressed because it is too large. Load diff
+310
View File
@@ -0,0 +1,310 @@
package main
// Battery — the HARD parity gate replaying the frozen oracle truth
// (truth.json, generated against the LIVE Python oracle
// src/rune/verification_layer.py → Rust evidence_provenance core) VERBATIM.
// Every row byte-compares the Go to_dict() json.dumps rendering against the
// oracle's, plus explicit field checks for fast divergence diagnosis.
import (
"encoding/json"
"os"
"strconv"
"testing"
)
type TruthDoc struct {
FrozenTS string `json:"frozen_ts"`
Generator string `json:"generator"`
Rows []TruthRow `json:"rows"`
}
type TruthRow struct {
Name string `json:"name"`
Fn string `json:"fn"`
VerifierType string `json:"verifier_type"`
Result json.RawMessage `json:"result"`
Want json.RawMessage `json:"want"`
WantJSON string `json:"want_json"`
}
func loadTruth(t *testing.T) *TruthDoc {
t.Helper()
raw, err := os.ReadFile("truth.json")
if err != nil {
t.Fatalf("truth.json missing (frozen oracle battery): %v", err)
}
var doc TruthDoc
if err := json.Unmarshal(raw, &doc); err != nil {
t.Fatalf("parse truth.json: %v", err)
}
if len(doc.Rows) == 0 {
t.Fatal("truth.json contained no rows")
}
seen := map[string]bool{}
for _, r := range doc.Rows {
if seen[r.Name] {
t.Fatalf("duplicate frozen row %q", r.Name)
}
seen[r.Name] = true
}
return &doc
}
// runOne — replay one frozen row; returns "" on parity, else the divergence.
func runOne(row *TruthRow) string {
switch row.Fn {
case "handle_hook":
result, err := ParseJSON(row.Result)
if err != nil {
return "parse result: " + err.Error()
}
ev := result.Get("event")
if ev == nil || ev.Kind != KindString {
return "hook row without string event"
}
var got map[string]any
if d := result.Get("data"); d != nil && d.Kind != KindNull {
got = HandleHook(ev.Str, anyValue(*d))
} else {
got = HandleHook(ev.Str)
}
if g := RenderSortedJSON(anyToJSONValue(got)); g != row.WantJSON {
return "hook divergence\n go: " + g + "\n oracle: " + row.WantJSON
}
return ""
case "plugin":
if g := RenderSortedJSON(anyToJSONValue(Plugin)); g != row.WantJSON {
return "plugin divergence\n go: " + g + "\n oracle: " + row.WantJSON
}
return ""
}
result, err := ParseJSON(row.Result)
if err != nil {
return "parse result: " + err.Error()
}
var got VerificationResult
if row.Fn == "verify" {
got = Verify(&result, row.VerifierType)
} else {
got = verifyNamed(row.Fn, &result)
}
if got.ToDictJSON() != row.WantJSON {
return "to_dict bytes diverge\n go: " + got.ToDictJSON() +
"\n oracle: " + row.WantJSON
}
// explicit field checks (diagnostics)
want, err := ParseJSON(row.Want)
if err != nil {
return "parse want: " + err.Error()
}
if wb := want.Get("passed"); wb == nil || wb.Bool != got.Passed {
return "passed diverges: want " + renderJSON(deref(want.Get("passed")), false) +
" got " + strconv.FormatBool(got.Passed)
}
if wt := want.Get("verifier_type"); wt == nil || wt.Str != got.VerifierType {
return "verifier_type diverges"
}
if wr := want.Get("retryable"); wr == nil || wr.Bool != got.Retryable {
return "retryable diverges"
}
we := want.Get("escalation_reason")
switch {
case we == nil:
return "want missing escalation_reason"
case we.Kind == KindNull && got.EscalationReason != nil:
return "escalation_reason: want null got " + *got.EscalationReason
case we.Kind != KindNull && (got.EscalationReason == nil || *got.EscalationReason != we.Str):
return "escalation_reason diverges"
}
return ""
}
func deref(v *JSONValue) JSONValue {
if v == nil {
return JSONNull()
}
return *v
}
// verifyNamed — the named verifier wrapper (Python verify_exit_code etc.).
func verifyNamed(fn string, result *JSONValue) VerificationResult {
switch fn {
case "verify_exit_code":
return VerifyExitCode(result)
case "verify_unit_test":
return VerifyUnitTest(result)
case "verify_schema":
return VerifySchema(result)
case "verify_file_exists":
return VerifyFileExists(result)
case "verify_file_changed":
return VerifyFileChanged(result)
case "verify_tool_receipt":
return VerifyToolReceipt(result)
case "verify_constraint_check":
return VerifyConstraintCheck(result)
default:
return Verify(result, fn)
}
}
// anyToJSONValue — convert a plain Go value (map[string]any, []any, string,
// bool, int, float64, nil) into the ordered JSONValue.
func anyToJSONValue(v any) JSONValue {
switch x := v.(type) {
case nil:
return JSONNull()
case bool:
return JSONBool(x)
case string:
return JSONString(x)
case int:
return JSONValue{Kind: KindNumber, Num: json.Number(strconv.Itoa(x))}
case float64:
return JSONNumber(x)
case []string:
arr := make([]JSONValue, len(x))
for i, el := range x {
arr[i] = JSONString(el)
}
return JSONArray(arr)
case []any:
arr := make([]JSONValue, len(x))
for i, el := range x {
arr[i] = anyToJSONValue(el)
}
return JSONArray(arr)
case map[string]any:
keys := make([]string, 0, len(x))
for k := range x {
keys = append(keys, k)
}
sortStrings(keys)
obj := make([]KV, len(keys))
for i, k := range keys {
obj[i] = KV{Key: k, Value: anyToJSONValue(x[k])}
}
return JSONObject(obj)
default:
return JSONString("")
}
}
func sortStrings(ss []string) {
for i := 1; i < len(ss); i++ {
for j := i; j > 0 && ss[j] < ss[j-1]; j-- {
ss[j], ss[j-1] = ss[j-1], ss[j]
}
}
}
// anyValue — JSONValue → plain any (for the ...any hook data seam).
func anyValue(v JSONValue) any {
switch v.Kind {
case KindBool:
return v.Bool
case KindNumber:
f := numF64(v.Num)
if f == float64(int64(f)) {
return int(f)
}
return f
case KindString:
return v.Str
case KindArray:
arr := make([]any, len(v.Arr))
for i, el := range v.Arr {
arr[i] = anyValue(el)
}
return arr
case KindObject:
obj := map[string]any{}
for _, kv := range v.Obj {
obj[kv.Key] = anyValue(kv.Value)
}
return obj
default:
return nil
}
}
// TestTruthParity — replay EVERY frozen row verbatim.
func TestTruthParity(t *testing.T) {
doc := loadTruth(t)
for i := range doc.Rows {
row := &doc.Rows[i]
t.Run(row.Name, func(t *testing.T) {
if msg := runOne(row); msg != "" {
t.Fatalf("DIVERGED %s: %s", row.Name, msg)
}
})
}
}
// TestBatteryCoversEveryPublicFunction — the frozen battery must exercise
// all 7 verifiers + dispatch (incl. unknown) + hook + plugin, both pass and
// fail branches per verifier.
func TestBatteryCoversEveryPublicFunction(t *testing.T) {
doc := loadTruth(t)
required := []string{
"verify_exit_code", "verify_unit_test", "verify_schema",
"verify_file_exists", "verify_file_changed", "verify_tool_receipt",
"verify_constraint_check", "verify", "handle_hook", "plugin",
}
have := map[string]int{}
for _, r := range doc.Rows {
have[r.Fn]++
}
for _, fn := range required {
if have[fn] == 0 {
t.Errorf("frozen battery missing rows for %s", fn)
}
}
// dispatch must include the unknown-verifier branch
unknown := 0
for _, r := range doc.Rows {
if r.Fn == "verify" {
switch r.VerifierType {
case "exit_code", "unit_test", "schema", "file_exists",
"file_changed", "tool_receipt", "constraint_check":
default:
unknown++
}
}
}
if unknown == 0 {
t.Error("frozen battery missing unknown-verifier dispatch rows")
}
// every verifier needs at least one pass and one fail row
for _, vt := range []string{"exit_code", "unit_test", "schema",
"file_exists", "file_changed", "tool_receipt", "constraint_check"} {
pass, fail := 0, 0
for _, r := range doc.Rows {
if r.VerifierType != vt {
continue
}
w, err := ParseJSON(r.Want)
if err != nil {
t.Fatalf("row %s: %v", r.Name, err)
}
if w.Get("passed").Bool {
pass++
} else {
fail++
}
}
if pass == 0 || fail == 0 {
t.Errorf("verifier %s: battery lacks branch coverage (pass=%d fail=%d)",
vt, pass, fail)
}
}
}
// TestFixturePresent — the file_exists rows depend on a committed fixture.
func TestFixturePresent(t *testing.T) {
if _, err := os.Stat(".fixtures/exists.txt"); err != nil {
t.Fatalf("committed fixture missing: %v", err)
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
import json
from pathlib import Path
__version__ = "0.240.0"
__version__ = "0.243.1"
# 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
+1 -1
View File
@@ -233,7 +233,7 @@ def main() -> int:
)
check(
"Rune minor version advertises provisioning and restore verification",
'__version__ = "0.240.0"' in rune_version,
'__version__ = "0.243.1"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+57 -35
View File
@@ -1,11 +1,15 @@
#!/usr/bin/env python3
"""ctypes loader for the Rust construction_depth core (facade burn-down).
"""cd_loader.py — ctypes loader for the Rust construction_depth core
(dichotomy wave #2479 tranche). Mirrors broker_loader.py:
FFI contract (doc-envelope law):
* cd_select_depth({mode, objective, ...}) -> Depth dict
* cd_free_string(ptr)
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* cd_select_depth({mode, objective, affected_surface, has_migration,
breaking, user_locked_layout, external_service,
uncertainty}) -> Depth dict
Free: capability_scoring's cs_free_string (shared process). NEVER re-export
a free symbol here. Override the .so with CD_RUST_LIB (a FILE path).
"""
from __future__ import annotations
import ctypes
@@ -16,14 +20,17 @@ from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_CRATE_DIR = _REPO / "src" / "rust" / "construction_depth"
_LIB_PATH = Path(
os.environ.get(
"CD_RUST_LIB", _CRATE_DIR / "target" / "release" / "libconstruction_depth.so"
)
os.environ.get("CD_RUST_LIB", _CRATE_DIR / "target" / "release" / "libconstruction_depth.so")
)
_lib = None
class ConstructionDepthUnavailable(FileNotFoundError):
"""The Rust depth core is not built. Callers fall back to Python
(strangler law; RUNE_CD_CORE=python pins the fallback)."""
def available() -> bool:
return _LIB_PATH.is_file()
@@ -32,41 +39,56 @@ def _load() -> ctypes.CDLL:
global _lib
if _lib is not None:
return _lib
if not _LIB_PATH.exists():
raise FileNotFoundError(f"construction_depth not built: {_LIB_PATH}")
if not _LIB_PATH.is_file():
raise ConstructionDepthUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
lib.cd_free_string.argtypes = [ctypes.c_void_p]
lib.cd_free_string.restype = None
fn = lib.cd_select_depth
fn.argtypes = [ctypes.c_char_p]
fn.restype = ctypes.c_void_p
for sym in ("cd_select_depth",):
fn = getattr(lib, sym)
fn.argtypes = [ctypes.c_void_p]
fn.restype = ctypes.c_void_p # char* — never default c_int
# free comes from capability_scoring (same process); load it if not yet resident
try:
lib.cs_free_string
except AttributeError:
scoring = ctypes.CDLL(str(
_REPO / "src" / "rust" / "capability_scoring"
/ "target" / "release" / "libcapability_scoring.so"
))
scoring.cs_free_string.argtypes = [ctypes.c_void_p]
lib._free = scoring.cs_free_string
_lib = lib
return lib
def _call(sym: str, payload: dict):
lib = _load()
ptr = getattr(lib, sym)(json.dumps(payload).encode("utf-8"))
data = json.dumps(payload).encode()
buf = ctypes.create_string_buffer(data)
ptr = getattr(lib, sym)(ctypes.cast(buf, ctypes.c_void_p))
if not ptr:
raise RuntimeError(f"{sym} returned null")
try:
text = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
finally:
lib.cd_free_string(ptr)
env = json.loads(text)
if not env.get("ok"):
raise RuntimeError(f"{sym} core error: {env.get('err')}")
return env["value"]
out = ctypes.string_at(ptr).decode()
free = getattr(lib, "_free", None)
if free is not None:
free(ptr)
doc = json.loads(out)
if not doc.get("ok"):
raise RuntimeError(doc.get("err", f"{sym} failed"))
return doc["value"]
def select_depth(mode: str, objective: str = "", has_migration: bool = False,
breaking: bool = False, user_locked_layout: bool = False,
external_service: bool = False, uncertainty: str = "",
affected_surface_len: int = 0) -> dict:
return _call("cd_select_depth", {"mode": mode, "objective": objective,
"has_migration": has_migration,
"breaking": breaking,
"user_locked_layout": user_locked_layout,
"external_service": external_service,
"uncertainty": uncertainty,
"affected_surface": [0] * affected_surface_len})
def select_depth(mode: str, objective: str = "",
affected_surface: list | None = None,
has_migration: bool = False,
breaking: bool = False,
user_locked_layout: bool = False,
external_service: bool = False,
uncertainty: str = "") -> dict:
return _call("cd_select_depth", {
"mode": mode, "objective": objective,
"affected_surface": list(affected_surface or []),
"has_migration": has_migration, "breaking": breaking,
"user_locked_layout": user_locked_layout,
"external_service": external_service,
"uncertainty": uncertainty,
})
+78
View File
@@ -6,6 +6,14 @@ This reduces connection overhead from ~5ms per connection to ~0.1ms.
Usage:
connection_pool.py status # Show pool status
connection_pool.py clear # Clear pool
Dichotomy wave #2479 tranche: the deterministic pool BOOKKEEPING (pooling
order, stale removal, oldest-first eviction under capacity, status) is
ported to FULL Rust (src/rust/connection_pool, parity oracle
frozen_cpool_truth.json). The sqlite handles stay in this facade — a
`sqlite3.Connection` cannot cross a ctypes FFI. Delegation goes through
rune/cpool_loader when built; the Python implementation below is the
strangler fallback, pinned with RUNE_CPOOL_CORE=python.
"""
import os
@@ -22,6 +30,21 @@ if _SD not in sys.path:
sys.path.insert(0, _SD)
def _core():
"""The Rust connection_pool core when available (strangler: Python
fallback is load-bearing). RUNE_CPOOL_CORE=python pins the fallback."""
if os.environ.get("RUNE_CPOOL_CORE", "auto") == "python":
return None
try:
from rune import cpool_loader
except Exception: # noqa: BLE001 — any loader failure means fallback, never a broken call
return None
try:
return cpool_loader if cpool_loader.available() else None
except Exception: # noqa: BLE001 — availability probe must never crash the fallback
return None
class ConnectionPool:
"""Pool of reusable database connections."""
@@ -29,9 +52,58 @@ class ConnectionPool:
self.max_connections = max_connections
self.connections: Dict[str, sqlite3.Connection] = {}
self.lock = threading.Lock()
self._state: Dict | None = None # kernel pool state (core path)
def _kernel_state(self, core) -> Dict:
if self._state is None:
self._state = core.new_pool(self.max_connections)
return self._state
def _get_connection_core(self, core, db_path: str) -> sqlite3.Connection:
"""Kernel-owned bookkeeping; the sqlite handle stays here."""
with self.lock:
valid = True
if db_path in self.connections:
# Check if connection is still valid (oracle probe)
try:
self.connections[db_path].execute("SELECT 1")
except Exception:
logger.debug("suppressed exception", exc_info=True)
valid = False
# oracle order: the stale entry is deleted before the
# capacity check, so a re-created connection rejoins at
# the END of the pooling order
del self.connections[db_path]
res = core.begin_get(self._kernel_state(core), db_path, valid)
self._state = res["pool"]
evict = res.get("evict")
if evict is not None:
old = self.connections.pop(evict, None)
if old is not None:
try:
old.close()
except Exception:
logger.debug("suppressed exception", exc_info=True)
if res.get("reuse"):
return self.connections[db_path]
conn = sqlite3.connect(db_path)
try:
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA journal_mode=WAL")
except Exception:
conn.close()
raise
# oracle order: the created connection joins the pool only on
# success (kernel commit; eviction already applied in begin_get)
self._state = core.commit(self._state, db_path)
self.connections[db_path] = conn
return conn
def get_connection(self, db_path: str) -> sqlite3.Connection:
"""Get a connection from the pool, creating one if needed."""
core = _core()
if core is not None:
return self._get_connection_core(core, db_path)
with self.lock:
if db_path in self.connections:
# Check if connection is still valid
@@ -61,6 +133,7 @@ class ConnectionPool:
def close_all(self):
"""Close all connections in the pool."""
core = _core()
with self.lock:
for conn in self.connections.values():
try:
@@ -68,9 +141,14 @@ class ConnectionPool:
except Exception:
logger.debug("suppressed exception", exc_info=True)
self.connections.clear()
if core is not None:
self._state = core.close_all(self._kernel_state(core))
def get_status(self) -> Dict:
"""Get pool status."""
core = _core()
if core is not None:
return core.status(self._kernel_state(core))
return {
"connections": len(self.connections),
"max_connections": self.max_connections,
+35 -18
View File
@@ -20,6 +20,12 @@ Levels:
Reuses existing semantics: construction mode (T10/T11) already encodes
most of the signal — depth is DERIVED from mode + modifiers, not a
parallel classification.
Dichotomy wave #2479 tranche: the deterministic depth kernel is ported
to FULL Rust (src/rust/construction_depth, parity oracle
frozen_cd_truth.json). This facade delegates to the Rust core via
rune/cd_loader when built; the Python implementation below is the
strangler fallback, pinned with RUNE_CD_CORE=python.
"""
from __future__ import annotations
@@ -44,6 +50,22 @@ class Depth:
"bypassed": self.bypassed}
def _core():
"""The Rust construction_depth core when available (strangler: Python
fallback is load-bearing). RUNE_CD_CORE=python pins the fallback."""
import os
if os.environ.get("RUNE_CD_CORE", "auto") == "python":
return None
try:
from rune import cd_loader
except Exception: # noqa: BLE001 — any loader failure means fallback, never a broken call
return None
try:
return cd_loader if cd_loader.available() else None
except Exception: # noqa: BLE001 — availability probe must never crash the fallback
return None
def select_depth(mode: str, *, objective: str = "",
affected_surface: list[str] | None = None,
has_migration: bool = False,
@@ -53,24 +75,19 @@ def select_depth(mode: str, *, objective: str = "",
uncertainty: str = "", # "" | "partial" | "high"
project_exists: bool | None = None,
) -> Depth:
"""Select proportional depth from construction mode + evidence.
Delegates to the Rust core when built (frozen_depth.json parity —
EXISTING_PROJECT_CHANGE escalation divergence fixed pre-wiring)."""
try:
from rune import cd_loader as _cd
if _cd.available():
rec = _cd.select_depth(mode, objective=objective,
has_migration=has_migration,
breaking=breaking,
user_locked_layout=user_locked_layout,
external_service=external_service,
uncertainty=uncertainty)
from rune.construction_depth import Depth
return Depth(level=rec["level"], reason=rec["reason"],
evidence=rec["evidence"], ceremony=rec["ceremony"],
bypassed=rec["bypassed"])
except Exception: # noqa: BLE001 — kernel failure → oracle floor below
pass
"""Select proportional depth from construction mode + evidence."""
core = _core()
if core is not None:
rec = core.select_depth(mode, objective=objective,
affected_surface=affected_surface,
has_migration=has_migration,
breaking=breaking,
user_locked_layout=user_locked_layout,
external_service=external_service,
uncertainty=uncertainty)
return Depth(level=rec["level"], reason=rec["reason"],
evidence=rec["evidence"], ceremony=rec["ceremony"],
bypassed=rec["bypassed"])
ev: list[str] = [f"mode: {mode}"]
ceremony: list[str] = []
bypassed: list[str] = []
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""cpool_loader.py — ctypes loader for the Rust connection_pool core
(dichotomy wave #2479 tranche). Mirrors broker_loader.py:
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* cpool_new({"max_connections"}) -> pool dict
* cpool_begin_get({"pool", "db_path", "valid"}) -> {"pool","reuse","evict"}
* cpool_commit({"pool", "db_path"}) -> pool dict
* cpool_close_all({"pool"}) -> pool dict
* cpool_status({"pool"}) -> status dict
Free: capability_scoring's cs_free_string (shared process). NEVER re-export
a free symbol here. Override the .so with CPOOL_RUST_LIB (a FILE path).
(The cp_loader.py name is taken by construction_pattern.)
"""
from __future__ import annotations
import ctypes
import json
import os
from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_CRATE_DIR = _REPO / "src" / "rust" / "connection_pool"
_LIB_PATH = Path(
os.environ.get("CPOOL_RUST_LIB", _CRATE_DIR / "target" / "release" / "libconnection_pool.so")
)
_lib = None
class ConnectionPoolCoreUnavailable(FileNotFoundError):
"""The Rust pool core is not built. Callers fall back to Python
(strangler law; RUNE_CPOOL_CORE=python pins the fallback)."""
def available() -> bool:
return _LIB_PATH.is_file()
def _load() -> ctypes.CDLL:
global _lib
if _lib is not None:
return _lib
if not _LIB_PATH.is_file():
raise ConnectionPoolCoreUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
for sym in ("cpool_new", "cpool_begin_get", "cpool_commit",
"cpool_close_all", "cpool_status"):
fn = getattr(lib, sym)
fn.argtypes = [ctypes.c_void_p]
fn.restype = ctypes.c_void_p # char* — never default c_int
# free comes from capability_scoring (same process); load it if not yet resident
try:
lib.cs_free_string
except AttributeError:
scoring = ctypes.CDLL(str(
_REPO / "src" / "rust" / "capability_scoring"
/ "target" / "release" / "libcapability_scoring.so"
))
scoring.cs_free_string.argtypes = [ctypes.c_void_p]
lib._free = scoring.cs_free_string
_lib = lib
return lib
def _call(sym: str, payload: dict):
lib = _load()
data = json.dumps(payload).encode()
buf = ctypes.create_string_buffer(data)
ptr = getattr(lib, sym)(ctypes.cast(buf, ctypes.c_void_p))
if not ptr:
raise RuntimeError(f"{sym} returned null")
out = ctypes.string_at(ptr).decode()
free = getattr(lib, "_free", None)
if free is not None:
free(ptr)
doc = json.loads(out)
if not doc.get("ok"):
raise RuntimeError(doc.get("err", f"{sym} failed"))
return doc["value"]
def new_pool(max_connections: int) -> dict:
return _call("cpool_new", {"max_connections": max_connections})
def begin_get(pool: dict, db_path: str, valid: bool) -> dict:
return _call("cpool_begin_get", {"pool": pool, "db_path": db_path,
"valid": valid})
def commit(pool: dict, db_path: str) -> dict:
return _call("cpool_commit", {"pool": pool, "db_path": db_path})
def close_all(pool: dict) -> dict:
return _call("cpool_close_all", {"pool": pool})
def status(pool: dict) -> dict:
return _call("cpool_status", {"pool": pool})
+73 -2
View File
@@ -23,6 +23,24 @@ from rune.capability_ledger import CapabilityLedger
from rune.behaviour_ledger import BehaviourLedger
def _kernel():
"""The Rust iteration core (itr_loader) when RUNE_ITR_CORE allows it,
else None — every public function delegates there first and falls
back to the Python body below (same process, same semantics)."""
import os
if os.environ.get("RUNE_ITR_CORE", "auto") == "python":
return None
try:
from rune import itr_loader
if itr_loader.available():
return itr_loader
except Exception: # noqa: BLE001 — kernel failure → Python floor
return None
return None
def _now() -> str:
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
@@ -36,6 +54,15 @@ def context_packet(model, ledger: CapabilityLedger, target: str, *,
Bounded and proportional: the whole graph is NEVER dumped. Local =
the target's own ledger entry; connected = 1-hop structural
neighbours with their ledgers on demand."""
k = _kernel()
if k is not None:
try:
return k.context_packet(
model.doc, ledger.doc, target, intent=intent,
basis_summary=basis_summary,
max_local_files=max_local_files, now=_now())
except Exception: # noqa: BLE001 — kernel failure → Python floor
pass
entity = model.get(target)
if entity is None:
return {"error": f"unknown structural target {target!r}"}
@@ -88,6 +115,12 @@ def context_packet(model, ledger: CapabilityLedger, target: str, *,
def predictive_impact(model, target: str) -> dict:
"""What MAY be affected BEFORE the change (structural closure)."""
k = _kernel()
if k is not None:
try:
return k.predictive_impact(model.doc, target)
except Exception: # noqa: BLE001
pass
return model.impact_closure(target)
@@ -96,6 +129,14 @@ def descriptive_impact(model, target: str, *,
generation: str = "") -> dict:
"""What was MATERIALLY affected AFTER the change — from actual
evidence (diff/observations), never assumed from the graph alone."""
k = _kernel()
if k is not None:
try:
return k.descriptive_impact(
model.doc, target, observed_changed=observed_changed,
generation=generation, now=_now())
except Exception: # noqa: BLE001
pass
predicted = model.impact_closure(target)
predicted_scope = set(predicted.get("mutation_scope", []))
observed = set(observed_changed)
@@ -113,10 +154,20 @@ def descriptive_impact(model, target: str, *,
def record_impact_delta(project_store: Path, delta: dict) -> Path:
"""Persist predicted-vs-observed deltas — they compound into better
future impact prediction (rule 19H)."""
k = _kernel()
if k is not None:
try:
line = k.record_delta_line(delta) + "\n"
except Exception: # noqa: BLE001
line = None
else:
line = None
if line is None:
import json
line = json.dumps(delta, sort_keys=True) + "\n"
p = Path(project_store) / "impact_deltas.jsonl"
import json
with p.open("a") as f:
f.write(json.dumps(delta, sort_keys=True) + "\n")
f.write(line)
return p
@@ -128,6 +179,15 @@ def invalidate_behaviours(model, behaviours: BehaviourLedger, *,
"""Selective invalidation driven by STRUCTURAL truth: behaviours
whose dependencies/owner intersect the changed closure reopen;
everything else keeps its confidence (rule 19I)."""
k = _kernel()
if k is not None:
try:
behaviours.doc, recs = k.invalidate(
behaviours.doc, sorted(changed_entities),
generation, _now())
return recs
except Exception: # noqa: BLE001
pass
return behaviours.invalidate_for_change(
changed_entities=changed_entities, generation=generation)
@@ -140,6 +200,17 @@ def post_change_obligations(model, target: str, *,
) -> list[dict]:
"""Machine-derived follow-up obligations from STRUCTURAL truth
(rule 19K) — never an improvised generic checklist."""
k = _kernel()
if k is not None:
try:
return k.post_change_obligations(
model.doc, target,
changed=sorted(changed_entities)
if changed_entities else None,
behaviours_doc=behaviours.doc if behaviours is not None
else None)
except Exception: # noqa: BLE001
pass
changed = changed_entities or {target}
obligations: list[dict] = []
seen: set[tuple] = set()
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
"""ctypes loader for the Rust iteration core (prefix ITR — the it_* wire prefix belongs to inference_trace) (dichotomy wave, #2479
tranche). Mirrors broker_loader.py's contract:
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* itr_context_packet({model, ledger, target, intent, basis_summary,
max_local_files, now}) -> packet dict
* itr_predictive_impact({model, target}) -> closure dict
* itr_descriptive_impact({model, target, observed_changed,
generation, now}) -> delta dict
* itr_record_delta_line({delta}) -> line body
* itr_invalidate({behaviours, changed, generation, now}) -> {doc, recs}
* itr_post_change_obligations({model, target, changed, behaviours})
-> [obligations]
Model/ledger/behaviours ride as their JSON docs; timestamps are facade
ARGUMENTS (now). Free: capability_scoring's cs_free_string (shared
process). Override the .so with ITR_RUST_LIB (a FILE path).
"""
from __future__ import annotations
import ctypes
import json
import os
from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_CRATE_DIR = _REPO / "src" / "rust" / "iteration"
_LIB_PATH = Path(
os.environ.get("ITR_RUST_LIB", _CRATE_DIR / "target" / "release" / "libiteration.so")
)
_ERR_TYPES = {
"ValueError": ValueError,
"KeyError": KeyError,
"AttributeError": AttributeError,
"TypeError": TypeError,
}
_lib = None
class IterationCoreUnavailable(FileNotFoundError):
"""The Rust iteration core (prefix ITR — the it_* wire prefix belongs to inference_trace) is not built. Callers fall back to Python."""
def available() -> bool:
return _LIB_PATH.is_file()
def _load() -> ctypes.CDLL:
global _lib
if _lib is not None:
return _lib
if not _LIB_PATH.is_file():
raise IterationCoreUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
for sym in ("itr_context_packet", "itr_predictive_impact",
"itr_descriptive_impact", "itr_record_delta_line",
"itr_invalidate", "itr_post_change_obligations"):
getattr(lib, sym).argtypes = [ctypes.c_void_p]
getattr(lib, sym).restype = ctypes.c_void_p
try:
lib.cs_free_string
except AttributeError:
scoring = ctypes.CDLL(str(
_REPO / "src" / "rust" / "capability_scoring" / "target" / "release" / "libcapability_scoring.so"
))
scoring.cs_free_string.argtypes = [ctypes.c_void_p]
lib._free = scoring.cs_free_string
_lib = lib
return lib
def _call(sym: str, payload: dict):
lib = _load()
data = json.dumps(payload).encode()
buf = ctypes.create_string_buffer(data)
ptr = getattr(lib, sym)(ctypes.cast(buf, ctypes.c_void_p))
if not ptr:
raise RuntimeError(f"{sym} returned null")
out = ctypes.string_at(ptr).decode()
free = getattr(lib, "_free", None)
if free is not None:
free(ptr)
doc = json.loads(out)
if not doc.get("ok"):
etype = doc.get("type", "RuntimeError")
raise _ERR_TYPES.get(etype, RuntimeError)(doc.get("err", f"{sym} failed"))
return doc["value"]
def context_packet(model_doc: dict, ledger_doc: dict, target: str, *,
intent: str = "", basis_summary=None,
max_local_files: int = 12, now: str) -> dict:
return _call("itr_context_packet", {
"model": model_doc, "ledger": ledger_doc, "target": target,
"intent": intent, "basis_summary": basis_summary,
"max_local_files": max_local_files, "now": now})
def predictive_impact(model_doc: dict, target: str) -> dict:
return _call("itr_predictive_impact", {"model": model_doc, "target": target})
def descriptive_impact(model_doc: dict, target: str, *,
observed_changed: list, generation: str = "",
now: str) -> dict:
return _call("itr_descriptive_impact", {
"model": model_doc, "target": target,
"observed_changed": observed_changed, "generation": generation,
"now": now})
def record_delta_line(delta: dict) -> str:
return _call("itr_record_delta_line", {"delta": delta})
def invalidate(behaviours_doc: dict, changed: list, generation: str,
now: str) -> tuple[dict, list]:
out = _call("itr_invalidate", {"behaviours": behaviours_doc,
"changed": changed,
"generation": generation, "now": now})
return out["doc"], out["recs"]
def post_change_obligations(model_doc: dict, target: str, *,
changed=None, behaviours_doc=None) -> list:
return _call("itr_post_change_obligations", {
"model": model_doc, "target": target, "changed": changed,
"behaviours": behaviours_doc})
+2 -2
View File
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
This is not an interface. This is how I see, speak, and interact with the world.
Version: v0.240.0
Version: v0.243.1
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.240.0 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.243.1 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
+14
View File
@@ -0,0 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "capability_scoring"
version = "0.1.0"
[[package]]
name = "connection_pool"
version = "0.1.0"
dependencies = [
"capability_scoring",
]
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "connection_pool"
version = "0.1.0"
edition = "2021"
description = "Database connection-pool bookkeeping kernel — dichotomy wave #2479 tranche; deterministic pool state machine in Rust (sqlite handles stay in the Python facade); zero-dep (pyjson via capability_scoring)"
[lib]
name = "connection_pool"
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
capability_scoring = { path = "../capability_scoring" }
@@ -0,0 +1,329 @@
{
"module": "connection_pool",
"pin": "RUNE_CPOOL_CORE=python",
"frozen_at": "2026-10-12T17:26:19Z",
"cases": [
{
"fn": "cpool_new",
"args": {
"max_connections": 2
},
"expected": {
"max_connections": 2,
"databases": []
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": []
},
"db_path": "/tmp/tmpdp4ybr6n/A.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": []
},
"reuse": false,
"evict": null
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": []
},
"db_path": "/tmp/tmpdp4ybr6n/A.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
}
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/A.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
},
"reuse": true,
"evict": null
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/B.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
},
"reuse": false,
"evict": null
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/B.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db",
"/tmp/tmpdp4ybr6n/B.db"
]
}
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db",
"/tmp/tmpdp4ybr6n/B.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/C.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db"
]
},
"reuse": false,
"evict": "/tmp/tmpdp4ybr6n/A.db"
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/C.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/C.db"
]
}
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/C.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/B.db",
"valid": false
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/C.db"
]
},
"reuse": false,
"evict": null
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/C.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/B.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/C.db",
"/tmp/tmpdp4ybr6n/B.db"
]
}
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/C.db",
"/tmp/tmpdp4ybr6n/B.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/D.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db"
]
},
"reuse": false,
"evict": "/tmp/tmpdp4ybr6n/C.db"
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db"
]
},
"db_path": "/tmp/tmpdp4ybr6n/D.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/D.db"
]
}
}
},
{
"fn": "cpool_status",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/D.db"
]
}
},
"expected": {
"connections": 2,
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/D.db"
]
}
},
{
"fn": "cpool_close_all",
"args": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/B.db",
"/tmp/tmpdp4ybr6n/D.db"
]
}
},
"expected": {
"max_connections": 2,
"databases": []
}
},
{
"fn": "cpool_begin_get",
"args": {
"pool": {
"max_connections": 2,
"databases": []
},
"db_path": "/tmp/tmpdp4ybr6n/A.db",
"valid": true
},
"expected": {
"pool": {
"max_connections": 2,
"databases": []
},
"reuse": false,
"evict": null
}
},
{
"fn": "cpool_commit",
"args": {
"pool": {
"max_connections": 2,
"databases": []
},
"db_path": "/tmp/tmpdp4ybr6n/A.db"
},
"expected": {
"pool": {
"max_connections": 2,
"databases": [
"/tmp/tmpdp4ybr6n/A.db"
]
}
}
}
]
}
@@ -0,0 +1,87 @@
//! branch_battery — replays frozen_cpool_truth.json VERBATIM (the live
//! Python oracle, frozen with RUNE_CPOOL_CORE=python pinned against a real
//! sqlite-backed pool). Every case must reproduce byte-identically through
//! the Rust kernel.
use super::{pyjson, Action, begin_get, close_all, commit, new_pool, status, Json};
const TRUTH: &str = include_str!("../frozen_cpool_truth.json");
#[test]
fn frozen_truth_replays_verbatim() {
let doc = pyjson::parse(TRUTH).expect("frozen_cpool_truth.json parses");
let cases = match doc.get("cases") {
Some(Json::Arr(a)) => a,
_ => panic!("truth has no cases array"),
};
assert!(!cases.is_empty(), "truth is empty");
for (i, case) in cases.iter().enumerate() {
let fname = match case.get("fn") {
Some(Json::Str(s)) => s.as_str(),
_ => panic!("case {i}: missing fn"),
};
let args = case.get("args").cloned().unwrap_or(Json::Obj(vec![]));
let expected = case.get("expected").cloned().unwrap_or(Json::Null);
let got = match fname {
"cpool_new" => {
let max = match args.get("max_connections") {
Some(Json::Num(n)) => *n as i64,
_ => 10,
};
new_pool(max)
}
"cpool_begin_get" => {
let pool = args.get("pool").cloned().unwrap_or(Json::Obj(vec![]));
let db_path = match args.get("db_path") {
Some(Json::Str(s)) => s.as_str().to_string(),
_ => String::new(),
};
let valid = matches!(args.get("valid"), Some(Json::Bool(true)));
let (pool, action) = begin_get(&pool, &db_path, valid);
let (reuse, evict) = match action {
Action::Reuse => (true, None),
Action::Create { evict } => (false, evict),
};
Json::Obj(vec![
("pool".into(), pool),
("reuse".into(), Json::Bool(reuse)),
(
"evict".into(),
match evict {
Some(p) => Json::Str(p),
None => Json::Null,
},
),
])
}
"cpool_commit" => {
let pool = args.get("pool").cloned().unwrap_or(Json::Obj(vec![]));
let db_path = match args.get("db_path") {
Some(Json::Str(s)) => s.as_str().to_string(),
_ => String::new(),
};
Json::Obj(vec![("pool".into(), commit(&pool, &db_path))])
}
"cpool_close_all" => {
let pool = args.get("pool").cloned().unwrap_or(Json::Obj(vec![]));
close_all(&pool)
}
"cpool_status" => {
let pool = args.get("pool").cloned().unwrap_or(Json::Obj(vec![]));
status(&pool)
}
other => panic!("case {i}: unknown fn {other}"),
};
assert_eq!(got, expected, "case {i} ({fname}) diverged from the oracle");
}
}
#[test]
fn truth_pin_is_python() {
let doc = pyjson::parse(TRUTH).expect("frozen_cpool_truth.json parses");
assert_eq!(
doc.get("pin"),
Some(&Json::Str("RUNE_CPOOL_CORE=python".into())),
"truth must be frozen from the pinned Python oracle"
);
}
+261
View File
@@ -0,0 +1,261 @@
//! connection_pool — database connection-pool BOOKKEEPING kernel
//! (dichotomy wave #2479 tranche). RUST verdict per the programme batch:
//! the deterministic pool state machine (pooling order, stale removal,
//! oldest-first eviction under capacity, status projection) lives here;
//! the sqlite handles themselves stay in the Python facade (storage-backed
//! surface — a `sqlite3.Connection` cannot cross a ctypes FFI).
//!
//! Kernel state (the pool dict, oracle `ConnectionPool` shape):
//! {"max_connections": int, "databases": [db_path in insertion order]}
//!
//! FFI contract (doc-envelope law — every call returns {"ok","value"|"err"}):
//!
//! * cpool_new({"max_connections": int}) -> pool dict
//! * cpool_begin_get({"pool": {...}, "db_path": str, "valid": bool})
//! -> {"pool", "reuse", "evict"} — oracle get_connection phase 1: valid
//! reuse short-circuits; stale entries are removed; the oldest entry is
//! evicted when at capacity (BEFORE the new connection is created —
//! oracle order).
//! * cpool_commit({"pool": {...}, "db_path": str}) -> pool dict — oracle
//! get_connection phase 2: the created connection joins the pool. The
//! facade commits only after sqlite3.connect succeeded, so a failed
//! create leaves the pool exactly as the oracle leaves it.
//! * cpool_close_all({"pool": {...}}) -> pool dict
//! * cpool_status({"pool": {...}}) -> status dict
//!
//! Parity oracle: frozen_cpool_truth.json (frozen from the live Python
//! oracle with RUNE_CPOOL_CORE=python pinned).
pub use capability_scoring::pyjson;
#[cfg(test)]
#[path = "branch_battery.rs"]
mod branch_battery;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use pyjson::Json;
fn pool_max(pool: &Json) -> i64 {
match pool.get("max_connections") {
Some(Json::Num(n)) => *n as i64,
_ => 10, // oracle default (ConnectionPool.__init__)
}
}
/// Borrowed view of the pooling order — zero-copy scan of the pool dict.
fn pool_dbs(pool: &Json) -> Vec<&str> {
match pool.get("databases") {
Some(Json::Arr(xs)) => xs
.iter()
.filter_map(|v| match v {
Json::Str(s) => Some(s.as_str()),
_ => None,
})
.collect(),
_ => vec![],
}
}
fn pool_json(max: i64, dbs: Vec<&str>) -> Json {
Json::Obj(vec![
("max_connections".into(), Json::Num(max as f64)),
(
"databases".into(),
Json::Arr(dbs.into_iter().map(|s| Json::Str(s.to_string())).collect()),
),
])
}
/// The oracle's get_connection decision (phase 1 outcome).
#[derive(Debug, Clone, PartialEq)]
pub enum Action {
/// pooled, still-valid connection returned as-is
Reuse,
/// a new sqlite handle must be created; the oracle evicted this
/// oldest entry first (None when under capacity)
Create { evict: Option<String> },
}
/// cpool_new({"max_connections": int}) -> pool dict
pub fn new_pool(max_connections: i64) -> Json {
pool_json(max_connections, vec![])
}
/// Oracle get_connection phase 1: reuse decision + stale removal +
/// oldest-first capacity eviction.
pub fn begin_get(pool: &Json, db_path: &str, valid: bool) -> (Json, Action) {
let max = pool_max(pool);
let dbs = pool_dbs(pool);
if let Some(pos) = dbs.iter().position(|p| *p == db_path) {
if valid {
// oracle: still-valid pooled connection is returned as-is
return (pool.clone(), Action::Reuse);
}
// oracle: stale connection is dropped before the capacity check
let kept: Vec<&str> = dbs
.iter()
.enumerate()
.filter(|(i, _)| *i != pos)
.map(|(_, s)| *s)
.collect();
let (pool, evict) = evict_or_keep(kept, max);
return (pool, Action::Create { evict });
}
let (pool, evict) = evict_or_keep(dbs, max);
(pool, Action::Create { evict })
}
/// Oracle capacity rule: at capacity the OLDEST connection (insertion
/// order) is removed before the new one is created. Returns the new pool
/// state plus the evicted db_path (the facade closes that handle).
fn evict_or_keep(dbs: Vec<&str>, max: i64) -> (Json, Option<String>) {
let mut kept = dbs;
let evict = if kept.len() as i64 >= max && !kept.is_empty() {
Some(kept.remove(0).to_string())
} else {
None
};
(pool_json(max, kept), evict)
}
/// Oracle get_connection phase 2: the created connection joins the pool.
pub fn commit(pool: &Json, db_path: &str) -> Json {
let max = pool_max(pool);
let mut dbs = pool_dbs(pool);
dbs.push(db_path);
pool_json(max, dbs)
}
/// Oracle close_all: the pool empties (max_connections is retained).
pub fn close_all(pool: &Json) -> Json {
pool_json(pool_max(pool), vec![])
}
/// Oracle get_status: {"connections", "max_connections", "databases"}.
pub fn status(pool: &Json) -> Json {
let dbs = pool_dbs(pool);
Json::Obj(vec![
("connections".into(), Json::Num(dbs.len() as f64)),
(
"max_connections".into(),
Json::Num(pool_max(pool) as f64),
),
(
"databases".into(),
Json::Arr(dbs.into_iter().map(|s| Json::Str(s.to_string())).collect()),
),
])
}
// ── FFI surface ──────────────────────────────────────────────────────────────
fn read_arg(ptr: *const c_char) -> Result<Json, String> {
if ptr.is_null() {
return Err("null argument pointer".into());
}
let x = unsafe { CStr::from_ptr(ptr) }
.to_str()
.map_err(|e| e.to_string())?;
pyjson::parse(x)
}
fn envelope(r: Result<Json, String>) -> *mut c_char {
let v = match r {
Ok(x) => Json::Obj(vec![
("ok".into(), Json::Bool(true)),
("value".into(), x),
]),
Err(e) => Json::Obj(vec![
("ok".into(), Json::Bool(false)),
("err".into(), Json::Str(e)),
]),
};
CString::new(pyjson::dumps(&v))
.map(|c| c.into_raw())
.unwrap_or(std::ptr::null_mut())
}
fn pool_arg(v: &Json) -> Json {
match v.get("pool") {
Some(x @ Json::Obj(_)) => x.clone(),
_ => Json::Obj(vec![]),
}
}
/// cpool_new({"max_connections": int}) -> pool dict
#[no_mangle]
pub extern "C" fn cpool_new(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| {
let max = match a.get("max_connections") {
Some(Json::Num(n)) => *n as i64,
_ => 10,
};
new_pool(max)
});
envelope(r)
}
/// cpool_begin_get({"pool", "db_path", "valid"}) -> {"pool","reuse","evict"}
#[no_mangle]
pub extern "C" fn cpool_begin_get(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| {
let pool = pool_arg(&a);
let db_path = match a.get("db_path") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
let valid = matches!(a.get("valid"), Some(Json::Bool(true)));
let (pool, action) = begin_get(&pool, db_path, valid);
let (reuse, evict) = match action {
Action::Reuse => (true, None),
Action::Create { evict } => (false, evict),
};
Json::Obj(vec![
("pool".into(), pool),
("reuse".into(), Json::Bool(reuse)),
(
"evict".into(),
match evict {
Some(p) => Json::Str(p),
None => Json::Null,
},
),
])
});
envelope(r)
}
/// cpool_commit({"pool", "db_path"}) -> pool dict
#[no_mangle]
pub extern "C" fn cpool_commit(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| {
let pool = pool_arg(&a);
let db_path = match a.get("db_path") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
commit(&pool, db_path)
});
envelope(r)
}
/// cpool_close_all({"pool"}) -> pool dict
#[no_mangle]
pub extern "C" fn cpool_close_all(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| close_all(&pool_arg(&a)));
envelope(r)
}
/// cpool_status({"pool"}) -> status dict
#[no_mangle]
pub extern "C" fn cpool_status(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| status(&pool_arg(&a)));
envelope(r)
}
// NOTE: no free symbol is exported here — capability_scoring (linked into
// the same Python process via rune/cs_loader) owns cs_free_string; a
// duplicate free symbol breaks the cdylib link. Callers free every
// returned pointer through that path.
+5 -98
View File
@@ -2,106 +2,13 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "capability_scoring"
version = "0.1.0"
[[package]]
name = "construction_depth"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
"capability_scoring",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1741ab7a6cc54a03a89b5d563ed60075c277d9e3cfa73ad0c1f23f23974703c6"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "syn"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+3 -2
View File
@@ -2,10 +2,11 @@
name = "construction_depth"
version = "0.1.0"
edition = "2021"
description = "Proportional scaffolding depth selection — dichotomy wave #2479 tranche; deterministic depth kernel in Rust; zero-dep (pyjson via capability_scoring)"
[lib]
name = "construction_depth"
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
capability_scoring = { path = "../capability_scoring" }
@@ -1,8 +1,12 @@
#!/usr/bin/env python3
"""canary_construction_depth.py — parity battery for construction_depth."""
"""canary_construction_depth.py — live parity canary for construction_depth
(dichotomy wave #2479 tranche): replays the frozen oracle truth through the
Rust core (RUNE_CD_CORE auto) against the frozen wants, then checks the
facade's pinned-Python path agrees."""
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
@@ -20,6 +24,11 @@ def test(name, cond, detail=""):
print(f" ✗ {name} — {detail}")
def run_select(select_args):
from rune.construction_depth import select_depth
return select_depth(**select_args).to_dict()
def main() -> int:
r = subprocess.run(["cargo", "build", "--release"], cwd=CRATE_DIR,
capture_output=True, text=True)
@@ -30,17 +39,31 @@ def main() -> int:
sys.path.insert(0, str(CRATE_DIR.parents[2] / "src"))
sys.path.insert(0, str(CRATE_DIR))
from rune import cd_loader # noqa: E402
frozen = json.loads((CRATE_DIR / "frozen_depth.json").read_text())
for i, row in enumerate(frozen["rows"]):
f = row["flags"]
got = cd_loader.select_depth(row["mode"], row["objective"],
f.get("has_migration", False),
f.get("breaking", False),
f.get("user_locked_layout", False),
f.get("external_service", False))
want = row["want"]
test(f"row {i} {row['mode']}", got.get("level") == want.get("level"),
f"got={got.get('level')} want={want.get('level')}")
if not cd_loader.available():
print(" ✗ Rust core not built")
return 1
truth = json.loads((CRATE_DIR / "frozen_cd_truth.json").read_text())
for i, case in enumerate(truth["cases"]):
if case["fn"] == "select_depth":
select_args = case["args"]
elif case["fn"] == "to_dict":
select_args = case["args"]["select"]
else:
continue
want = case["expected"]
got = run_select(select_args)
test(f"case {i} rust-core parity", got == want,
f"got={json.dumps(got)[:120]} want={json.dumps(want)[:120]}")
# pinned-Python floor agrees with the same frozen wants
os.environ["RUNE_CD_CORE"] = "python"
for i, case in enumerate(truth["cases"]):
if case["fn"] not in ("select_depth", "to_dict"):
continue
select_args = (case["args"] if case["fn"] == "select_depth"
else case["args"]["select"])
got = run_select(select_args)
test(f"case {i} python-pin parity", got == case["expected"],
f"got={json.dumps(got)[:120]}")
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
return 1 if FAIL else 0
File diff suppressed because it is too large. Load diff
@@ -1,123 +0,0 @@
{
"_doc": "FROZEN ORACLE (construction_depth wiring).",
"rows": [
{
"mode": "NOT_CONSTRUCTION",
"objective": "",
"flags": {},
"want": {
"level": "NONE",
"reason": "not construction \u2014 no construction depth applies",
"evidence": [
"mode: NOT_CONSTRUCTION"
],
"ceremony": [],
"bypassed": [
"all"
]
}
},
{
"mode": "UNKNOWN",
"objective": "",
"flags": {},
"want": {
"level": "UNRESOLVED",
"reason": "UNKNOWN \u2014 probe/clarify before any construction lifecycle begins",
"evidence": [
"mode: UNKNOWN"
],
"ceremony": [
"probe/clarify"
],
"bypassed": [
"contract",
"patterns",
"bootstrap",
"depth selection"
]
}
},
{
"mode": "LOCAL_CHANGE",
"objective": "fix typo",
"flags": {},
"want": {
"level": "LIGHT",
"reason": "bounded local fix \u2014 governance without ceremony",
"evidence": [
"mode: LOCAL_CHANGE",
"LOCAL_CHANGE: bounded scope, minimal ceremony"
],
"ceremony": [
"classification",
"authority/scope",
"focused verification",
"durable result"
],
"bypassed": [
"requirements/completeness",
"patterns",
"capability/toolchain check",
"project bootstrap",
"deployment/rollback"
]
}
},
{
"mode": "EXISTING_PROJECT_CHANGE",
"objective": "add feature",
"flags": {
"has_migration": true
},
"want": {
"level": "STANDARD",
"reason": "existing-project change \u2014 proportional governance",
"evidence": [
"mode: EXISTING_PROJECT_CHANGE",
"migration: old/new compatibility + rollback obligations"
],
"ceremony": [
"classification",
"requirements/completeness",
"capability fit",
"Construction Contract",
"scope",
"obligations",
"verification",
"migration proof",
"rollback preparation"
],
"bypassed": []
}
},
{
"mode": "PROJECT_BUILD",
"objective": "new app",
"flags": {
"breaking": true,
"user_locked_layout": true
},
"want": {
"level": "FULL",
"reason": "genuinely new project \u2014 full Scaffolding lifecycle",
"evidence": [
"mode: PROJECT_BUILD",
"PROJECT_BUILD: full lifecycle required"
],
"ceremony": [
"project bootstrap",
"requirements/completeness",
"capability/toolchain decisions",
"patterns/obligations",
"Construction Contract",
"implementation",
"verification",
"deployment/rollback strategy",
"maintenance lifecycle"
],
"bypassed": []
}
}
]
}
@@ -0,0 +1,78 @@
//! branch_battery — replays frozen_cd_truth.json VERBATIM (the live
//! Python oracle, frozen with RUNE_CD_CORE=python pinned). Every case in
//! the file must reproduce byte-identically through the Rust kernel.
use super::{pyjson, select_depth, Json};
const TRUTH: &str = include_str!("../frozen_cd_truth.json");
fn run_select(args: &Json) -> Json {
let mode = match args.get("mode") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
let objective = match args.get("objective") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
let surface_len = match args.get("affected_surface") {
Some(Json::Arr(xs)) => xs.len(),
_ => 0,
};
let flag = |k: &str| matches!(args.get(k), Some(Json::Bool(true)));
let uncertainty = match args.get("uncertainty") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
select_depth(
mode,
objective,
surface_len,
flag("has_migration"),
flag("breaking"),
flag("user_locked_layout"),
flag("external_service"),
uncertainty,
)
.to_json()
}
#[test]
fn frozen_truth_replays_verbatim() {
let doc = pyjson::parse(TRUTH).expect("frozen_cd_truth.json parses");
let cases = match doc.get("cases") {
Some(Json::Arr(a)) => a,
_ => panic!("truth has no cases array"),
};
assert!(!cases.is_empty(), "truth is empty");
for (i, case) in cases.iter().enumerate() {
let fname = match case.get("fn") {
Some(Json::Str(s)) => s.as_str(),
_ => panic!("case {i}: missing fn"),
};
let expected = case.get("expected").cloned().unwrap_or(Json::Null);
let got = match fname {
"select_depth" => {
let args = case.get("args").cloned().unwrap_or(Json::Obj(vec![]));
run_select(&args)
}
"to_dict" => {
let args = case.get("args").cloned().unwrap_or(Json::Obj(vec![]));
let sel = args.get("select").cloned().unwrap_or(Json::Obj(vec![]));
run_select(&sel)
}
other => panic!("case {i}: unknown fn {other}"),
};
assert_eq!(got, expected, "case {i} ({fname}) diverged from the oracle");
}
}
#[test]
fn truth_pin_is_python() {
let doc = pyjson::parse(TRUTH).expect("frozen_cd_truth.json parses");
assert_eq!(
doc.get("pin"),
Some(&Json::Str("RUNE_CD_CORE=python".into())),
"truth must be frozen from the pinned Python oracle"
);
}
+286 -305
View File
@@ -1,10 +1,34 @@
//! construction_depth — proportional scaffolding depth selection (W6).
//! PARITY port of src/rune/construction_depth.py.
//! construction_depth — proportional scaffolding depth selection
//! (dichotomy wave #2479 tranche, contract cited in the parity commit).
//! RUST verdict: deterministic depth-selection kernel in Rust; the Python
//! facade keeps a RUNE_CD_CORE=python pin.
//!
//! FFI contract (doc-envelope law — every call returns {"ok","value"|"err"}):
//!
//! * cd_select_depth({"mode": str, "objective": str, "affected_surface":
//! [str...], "has_migration": bool, "breaking": bool,
//! "user_locked_layout": bool, "external_service": bool,
//! "uncertainty": str})
//! -> Depth dict {"level","reason","evidence","ceremony","bypassed"}
//!
//! Parity oracle: frozen_cd_truth.json (frozen from the live Python
//! oracle with RUNE_CD_CORE=python pinned).
pub use capability_scoring::pyjson;
#[cfg(test)]
#[path = "branch_battery.rs"]
mod branch_battery;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use pyjson::Json;
pub const LEVELS: &[&str] = &["NONE", "UNRESOLVED", "LIGHT", "STANDARD", "FULL"];
#[derive(Debug, Clone)]
#[derive(serde::Serialize)]
/// The Depth record (oracle construction_depth.Depth).
#[derive(Debug, Clone, PartialEq)]
pub struct Depth {
pub level: String,
pub reason: String,
@@ -13,333 +37,290 @@ pub struct Depth {
pub bypassed: Vec<String>,
}
#[allow(clippy::too_many_arguments)] // pinned: parity signature — the port mirrors the oracle arg-for-arg
impl Depth {
pub fn to_json(&self) -> Json {
Json::Obj(vec![
("level".into(), Json::Str(self.level.clone())),
("reason".into(), Json::Str(self.reason.clone())),
(
"evidence".into(),
Json::Arr(self.evidence.iter().map(|s| Json::Str(s.clone())).collect()),
),
(
"ceremony".into(),
Json::Arr(self.ceremony.iter().map(|s| Json::Str(s.clone())).collect()),
),
(
"bypassed".into(),
Json::Arr(self.bypassed.iter().map(|s| Json::Str(s.clone())).collect()),
),
])
}
}
/// The five depth levels (oracle LEVELS).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Level {
None,
Unresolved,
Light,
Standard,
Full,
}
impl Level {
pub fn as_str(self) -> &'static str {
match self {
Level::None => "NONE",
Level::Unresolved => "UNRESOLVED",
Level::Light => "LIGHT",
Level::Standard => "STANDARD",
Level::Full => "FULL",
}
}
}
/// The construction modes the kernel discriminates. Any non-canonical mode
/// string falls through to the EXISTING_PROJECT_CHANGE path (oracle
/// behavior: the default branch is the escalation path).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Mode {
NotConstruction,
Unknown,
LocalChange,
ProjectBuild,
ExistingProjectChange,
}
impl Mode {
fn parse(s: &str) -> Self {
match s {
"NOT_CONSTRUCTION" => Self::NotConstruction,
"UNKNOWN" => Self::Unknown,
"LOCAL_CHANGE" => Self::LocalChange,
"PROJECT_BUILD" => Self::ProjectBuild,
_ => Self::ExistingProjectChange,
}
}
}
const LOCAL_CEREMONY: [&str; 4] = [
"classification",
"authority/scope",
"focused verification",
"durable result",
];
const LOCAL_BYPASSED: [&str; 5] = [
"requirements/completeness",
"patterns",
"capability/toolchain check",
"project bootstrap",
"deployment/rollback",
];
const BUILD_CEREMONY: [&str; 9] = [
"project bootstrap",
"requirements/completeness",
"capability/toolchain decisions",
"patterns/obligations",
"Construction Contract",
"implementation",
"verification",
"deployment/rollback strategy",
"maintenance lifecycle",
];
const EPC_CEREMONY: [&str; 7] = [
"classification",
"requirements/completeness",
"capability fit",
"Construction Contract",
"scope",
"obligations",
"verification",
];
fn owned(v: &[&str]) -> Vec<String> {
v.iter().map(|s| (*s).to_string()).collect()
}
/// Oracle-exact depth selection: mode gates the lifecycle shape, evidence
/// modifiers escalate within EXISTING_PROJECT_CHANGE. Mirrors the Python
/// oracle branch-for-branch (batch 125 + facade-burn divergence fixes).
#[allow(clippy::too_many_arguments)] // pinned: parity signature — mirrors the oracle arg-for-arg
pub fn select_depth(
mode: &str,
objective: &str,
_objective: &str,
affected_surface_len: usize,
has_migration: bool,
breaking: bool,
user_locked: bool,
user_locked_layout: bool,
external_service: bool,
uncertainty: &str,
_project_exists: Option<bool>,
) -> Depth {
let mut ev = vec![format!("mode: {}", mode)];
let mut ceremony = Vec::new();
let mut bypassed = Vec::new();
// ORACLE PARITY FIX (batch 36): NOT_CONSTRUCTION and UNKNOWN were missing
// from the Rust port — they fell through to the default STANDARD path.
// §13C: NOT_CONSTRUCTION has NO construction depth; UNKNOWN is unresolved.
if mode == "NOT_CONSTRUCTION" {
return Depth {
level: "NONE".to_string(),
reason: "not construction — no construction depth applies".to_string(),
evidence: ev,
ceremony,
bypassed: vec!["all".to_string()],
};
}
if mode == "UNKNOWN" {
return Depth {
level: "UNRESOLVED".to_string(),
reason: "UNKNOWN — probe/clarify before any construction".to_string(),
evidence: ev,
ceremony,
bypassed: vec![],
};
}
// batch 125: EXACT mode match (the oracle compares == against the 5
// canonical MODES from construction_mode.classify_mode). The old
// substring match on "LOCAL_FIX" was dead for every real caller AND
// missed the real LOCAL_CHANGE mode (which fell through to STANDARD
// instead of LIGHT — a live misclassification for tiny fixes).
let is_build = mode == "PROJECT_BUILD";
let is_local = mode == "LOCAL_CHANGE";
let is_research = mode == "RESEARCHED_CHANGE";
if is_local {
// batch 125: oracle-exact LOCAL_CHANGE branch (was a paraphrase).
ev.push("LOCAL_CHANGE: bounded scope, minimal ceremony".to_string());
for c in [
"classification",
"authority/scope",
"focused verification",
"durable result",
] {
ceremony.push(c.to_string());
match Mode::parse(mode) {
Mode::NotConstruction => {
// §13C: NOT_CONSTRUCTION has NO construction depth — not even LIGHT
Depth {
level: Level::None.as_str().into(),
reason: "not construction — no construction depth applies".into(),
evidence: vec![format!("mode: {mode}")],
ceremony: vec![],
bypassed: vec!["all".into()],
}
}
for b in [
"requirements/completeness",
"patterns",
"capability/toolchain check",
"project bootstrap",
"deployment/rollback",
] {
bypassed.push(b.to_string());
Mode::Unknown => {
// §13C: UNKNOWN means construction hasn't started — no lifecycle yet
Depth {
level: Level::Unresolved.as_str().into(),
reason: "UNKNOWN — probe/clarify before any construction lifecycle begins".into(),
evidence: vec![format!("mode: {mode}")],
ceremony: vec!["probe/clarify".into()],
bypassed: owned(&["contract", "patterns", "bootstrap", "depth selection"]),
}
}
if user_locked {
ev.push(
"USER-LOCKED layout surface — preservation obligation retained even at LIGHT depth"
.to_string(),
);
ceremony.push("layout obligation check".to_string());
Mode::LocalChange => {
let mut ev = vec![format!("mode: {mode}")];
ev.push("LOCAL_CHANGE: bounded scope, minimal ceremony".into());
let mut ceremony = owned(&LOCAL_CEREMONY);
if user_locked_layout {
ev.push(
"USER-LOCKED layout surface — preservation obligation retained even at LIGHT depth"
.into(),
);
ceremony.push("layout obligation check".into());
}
Depth {
level: Level::Light.as_str().into(),
reason: "bounded local fix — governance without ceremony".into(),
evidence: ev,
ceremony,
bypassed: owned(&LOCAL_BYPASSED),
}
}
return Depth {
level: "LIGHT".to_string(),
reason: "bounded local fix — governance without ceremony".to_string(),
evidence: ev,
ceremony,
bypassed,
};
}
Mode::ProjectBuild => {
let mut ev = vec![format!("mode: {mode}")];
ev.push("PROJECT_BUILD: full lifecycle required".into());
Depth {
level: Level::Full.as_str().into(),
reason: "genuinely new project — full Scaffolding lifecycle".into(),
evidence: ev,
ceremony: owned(&BUILD_CEREMONY),
bypassed: vec![],
}
}
Mode::ExistingProjectChange => {
// base STANDARD, escalate on modifiers
let mut ev = vec![format!("mode: {mode}")];
let mut ceremony = owned(&EPC_CEREMONY);
let mut level = Level::Standard;
let mut reason = "existing-project change — proportional governance".to_string();
if is_research {
ev.push("RESEARCHED_CHANGE: research-heavy".to_string());
ceremony.push("requirements/completeness".to_string());
ceremony.push("research rounds".to_string());
ceremony.push("evidence→decision mapping".to_string());
return Depth {
level: "STANDARD".to_string(),
reason: "researched change".to_string(),
evidence: ev,
ceremony,
bypassed,
};
}
if has_migration {
ev.push("migration: old/new compatibility + rollback obligations".into());
ceremony.push("migration proof".into());
ceremony.push("rollback preparation".into());
}
if breaking {
ev.push("breaking change: stronger approval + regression obligations".into());
ceremony.push("consumer migration completeness".into());
}
if user_locked_layout {
ev.push("USER-LOCKED layout surface affected".into());
ceremony.push("layout obligation check".into());
}
if external_service {
ev.push("external service consequence".into());
ceremony.push("deployment verification".into());
}
if uncertainty == "high" {
ev.push("high uncertainty: probe before deeper ceremony".into());
ceremony.insert(0, "evidence probe".into());
}
if affected_surface_len > 5 {
ev.push(format!("wide affected surface: {affected_surface_len} entries"));
level = Level::Full;
reason = "wide surface — full depth warranted".into();
}
if breaking && has_migration {
level = Level::Full;
reason = "breaking + migration — full depth".into();
}
if is_build {
ev.push("PROJECT_BUILD: full construction".to_string());
ceremony.push("all obligations".to_string());
return Depth {
level: "FULL".to_string(),
reason: "project build".to_string(),
evidence: ev,
ceremony,
bypassed,
};
}
// ORACLE PARITY: EXISTING_PROJECT_CHANGE stays STANDARD regardless of
// evidence flags (the Python oracle records evidence + extends ceremony
// but never escalates the level beyond STANDARD for this mode).
// ORACLE PARITY: ceremony strings match the Python oracle EXACTLY.
// Escalation to FULL only for: wide surface (>5) or breaking+migration.
if has_migration {
ev.push("migration: old/new compatibility + rollback obligations".to_string());
ceremony.push("migration proof".to_string());
ceremony.push("rollback preparation".to_string());
}
if breaking {
ev.push("breaking change: stronger approval + regression obligations".to_string());
ceremony.push("consumer migration completeness".to_string());
}
if user_locked {
ev.push("USER-LOCKED layout surface affected".to_string());
ceremony.push("layout obligation check".to_string());
}
if external_service {
ev.push("external service consequence".to_string());
ceremony.push("deployment verification".to_string());
}
if uncertainty == "high" {
ev.push("high uncertainty: probe before deeper ceremony".to_string());
ceremony.insert(0, "evidence probe".to_string());
}
let mut level = "STANDARD";
let mut reason = "existing-project change — proportional governance".to_string();
// wide surface escalation (oracle: len(affected_surface) > 5)
if affected_surface_len > 5 {
ev.push(format!("wide affected surface: {} entries", affected_surface_len));
level = "FULL";
reason = "wide surface — full depth warranted".to_string();
}
if breaking && has_migration {
level = "FULL";
reason = "breaking + migration — full depth".to_string();
}
Depth {
level: level.to_string(),
reason,
evidence: ev,
ceremony,
bypassed,
Depth {
level: level.as_str().into(),
reason,
evidence: ev,
ceremony,
bypassed: vec![],
}
}
}
}
// ── FFI surface (facade burn-down, 2026-10-10) ───────────────────────────────
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
fn read_arg(ptr: *const c_char) -> Result<String, String> {
fn read_arg(ptr: *const c_char) -> Result<Json, String> {
if ptr.is_null() {
return Err("null argument pointer".to_string());
return Err("null argument pointer".into());
}
unsafe { CStr::from_ptr(ptr) }
let x = unsafe { CStr::from_ptr(ptr) }
.to_str()
.map(|s| s.to_string())
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
.map_err(|e| e.to_string())?;
pyjson::parse(x)
}
/// cd_select_depth({mode, objective, has_migration, breaking,
/// user_locked_layout, external_service, uncertainty}) -> Depth
#[no_mangle]
pub extern "C" fn cd_select_depth(arg: *const c_char) -> *mut c_char {
let result = read_arg(arg)
.and_then(|t| serde_json::from_str::<serde_json::Value>(&t).map_err(|e| format!("argument JSON parse failed: {}", e)))
.and_then(|a| {
let d = select_depth(
a.get("mode").and_then(|v| v.as_str()).unwrap_or(""),
a.get("objective").and_then(|v| v.as_str()).unwrap_or(""),
a.get("affected_surface").and_then(|v| v.as_array()).map(|a| a.len()).unwrap_or(0),
a.get("has_migration").and_then(|v| v.as_bool()).unwrap_or(false),
a.get("breaking").and_then(|v| v.as_bool()).unwrap_or(false),
a.get("user_locked_layout").and_then(|v| v.as_bool()).unwrap_or(false),
a.get("external_service").and_then(|v| v.as_bool()).unwrap_or(false),
a.get("uncertainty").and_then(|v| v.as_str()).unwrap_or(""),
None,
);
serde_json::to_value(d).map_err(|e| format!("serialize: {}", e))
});
let body = match result {
Ok(v) => serde_json::json!({"ok": true, "value": v}),
Err(e) => serde_json::json!({"ok": false, "err": e}),
fn envelope(r: Result<Json, String>) -> *mut c_char {
let v = match r {
Ok(x) => Json::Obj(vec![
("ok".into(), Json::Bool(true)),
("value".into(), x),
]),
Err(e) => Json::Obj(vec![
("ok".into(), Json::Bool(false)),
("err".into(), Json::Str(e)),
]),
};
CString::new(body.to_string())
CString::new(pyjson::dumps(&v))
.map(|c| c.into_raw())
.unwrap_or(std::ptr::null_mut())
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
/// cd_select_depth({mode, objective, affected_surface, has_migration,
/// breaking, user_locked_layout, external_service,
/// uncertainty}) -> Depth dict
#[no_mangle]
pub extern "C" fn cd_free_string(ptr: *mut c_char) {
if !ptr.is_null() {
unsafe {
let _ = CString::from_raw(ptr);
}
}
pub extern "C" fn cd_select_depth(arg: *const c_char) -> *mut c_char {
let r = read_arg(arg).map(|a| {
let mode = match a.get("mode") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
let objective = match a.get("objective") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
let surface_len = match a.get("affected_surface") {
Some(Json::Arr(xs)) => xs.len(),
_ => 0,
};
let flag = |k: &str| matches!(a.get(k), Some(Json::Bool(true)));
let uncertainty = match a.get("uncertainty") {
Some(Json::Str(s)) => s.as_str(),
_ => "",
};
select_depth(
mode,
objective,
surface_len,
flag("has_migration"),
flag("breaking"),
flag("user_locked_layout"),
flag("external_service"),
uncertainty,
)
.to_json()
});
envelope(r)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_local_fix() {
// batch 125: canonical mode is LOCAL_CHANGE (construction_mode.MODES);
// "LOCAL_FIX" was the port's private invention, never emitted.
let d = select_depth(
"LOCAL_CHANGE",
"fix typo",
0,
false,
false,
false,
false,
"",
None,
);
assert_eq!(d.level, "LIGHT");
}
#[test]
fn test_project_build() {
let d = select_depth(
"PROJECT_BUILD",
"build system",
0,
false,
false,
false,
false,
"",
None,
);
assert_eq!(d.level, "FULL");
}
#[test]
fn test_existing_project_stays_standard() {
// ORACLE: EXISTING_PROJECT_CHANGE stays STANDARD regardless of
// evidence flags (corrected 2026-10-10 against the live oracle).
let d = select_depth(
"EXISTING_PROJECT_CHANGE",
"add feature",
0,
true, // has_migration — evidence only, no escalation
false,
false,
false,
"",
None,
);
assert_eq!(d.level, "STANDARD");
}
}
#[cfg(test)]
mod branch_battery {
use super::*;
#[test]
fn not_construction_is_none() {
let d = select_depth("NOT_CONSTRUCTION", "",
0, false, false, false, false, "", None);
assert_eq!(d.level, "NONE");
}
#[test]
fn canonical_modes_parity() {
// batch 125 (oracle-probed): all 5 canonical MODES classify correctly;
// the port's old "LOCAL_FIX" invention falls through to STANDARD
// (it is never emitted by classify_mode — no caller depends on it).
let cases = [
("NOT_CONSTRUCTION", "NONE"),
("UNKNOWN", "UNRESOLVED"),
("LOCAL_CHANGE", "LIGHT"),
("PROJECT_BUILD", "FULL"),
("EXISTING_PROJECT_CHANGE", "STANDARD"),
];
for (mode, want) in cases {
let d = select_depth(mode, "", 0, false, false, false, false, "", None);
assert_eq!(d.level, want, "mode {}", mode);
}
// legacy invention: falls through (documents the old misclassification)
let d = select_depth("LOCAL_FIX", "",
0, false, false, false, false, "", None);
assert_eq!(d.level, "STANDARD");
// LOCAL_CHANGE carries the bounded-scope ceremony (oracle branch)
let d = select_depth("LOCAL_CHANGE", "",
0, false, false, false, false, "", None);
assert_eq!(d.level, "LIGHT");
assert!(d.bypassed.contains(&"patterns".to_string()));
}
#[test]
fn unknown_is_unresolved() {
let d = select_depth("UNKNOWN", "",
0, false, false, false, false, "", None);
assert_eq!(d.level, "UNRESOLVED");
}
#[test]
fn build_new_is_standard() {
let d = select_depth(
"BUILD_NEW",
"test objective",
0,
false,
false,
false,
false,
"",
None,
);
assert_eq!(d.level, "STANDARD");
}
}
// NOTE: cd_free_string is deliberately NOT exported — capability_scoring
// (linked into the same Python process via rune/cs_loader) already exports
// cs_free_string, and a duplicate free symbol breaks the cdylib link.
// Callers free every returned pointer through that path.
@@ -1,16 +1,52 @@
//! branch_battery — replays frozen_cpb_truth.json VERBATIM (17 cases
//! branch_battery — replays frozen_cpb_truth.json VERBATIM (19 cases
//! frozen from the live Python oracle construction_patterns_builtin.py,
//! RUNE_CPB_CORE=python pinned, inputs deep-copied before capture).
//! Order-insensitive object comparison; numbers compared exactly (both
//! sides IEEE-754 f64); list order significant (registry + provenance
//! order is oracle-derived).
//!
//! Language-advantage pass (Phase B, battery-pinned): the truth fn-name
//! lattice is a `TruthFn` enum parsed once per case (unknown names are the
//! exhaustive `Unknown` variant, reported as errors), case fields are
//! zero-copy borrows of the parsed truth doc (no per-case clones), and
//! case collection + failure reporting are iterator chains.
use capability_scoring::pyjson::{parse, Json};
use capability_scoring::pyjson::{dumps, parse, Json};
use crate::registry;
const TRUTH: &str = include_str!("../frozen_cpb_truth.json");
/// The truth fn-name lattice: one variant per kernel entry point the
/// frozen truth exercises.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum TruthFn {
RegistryRevision,
Patterns,
GetPattern,
Unknown,
}
impl TruthFn {
fn parse(name: &str) -> Self {
match name {
"registry_revision" => Self::RegistryRevision,
"patterns" => Self::Patterns,
"get_pattern" => Self::GetPattern,
_ => Self::Unknown,
}
}
fn as_str(self) -> &'static str {
match self {
Self::RegistryRevision => "registry_revision",
Self::Patterns => "patterns",
Self::GetPattern => "get_pattern",
Self::Unknown => "unknown",
}
}
}
fn jeq(a: &Json, b: &Json) -> bool {
match (a, b) {
(Json::Num(x), Json::Num(y)) => x == y,
@@ -18,7 +54,7 @@ fn jeq(a: &Json, b: &Json) -> bool {
(Json::Bool(x), Json::Bool(y)) => x == y,
(Json::Null, Json::Null) => true,
(Json::Arr(x), Json::Arr(y)) => {
x.len() == y.len() && x.iter().zip(y).all(|(i, j)| jeq(i, j))
x.len() == y.len() && x.iter().zip(y.iter()).all(|(i, j)| jeq(i, j))
}
(Json::Obj(x), Json::Obj(y)) => {
x.len() == y.len()
@@ -29,34 +65,41 @@ fn jeq(a: &Json, b: &Json) -> bool {
}
}
fn as_str(v: Option<&Json>) -> String {
/// Zero-copy borrow of a string field (missing/non-string reads as "").
fn as_str(v: Option<&Json>) -> &str {
match v {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
Some(Json::Str(s)) => s.as_str(),
_ => "",
}
}
/// Null for a missing field, by borrow (no clone).
fn or_null(v: Option<&Json>) -> &Json {
v.unwrap_or(&Json::Null)
}
/// One case's oracle verdict, replayed against the Rust kernel.
fn run_case(fn_name: &str, args: &Json) -> Result<Json, String> {
match fn_name {
"registry_revision" => Ok(Json::Num(registry::registry_revision() as f64)),
"patterns" => Ok(Json::Arr(registry::patterns())),
"get_pattern" => {
fn run_case(truth_fn: TruthFn, args: &Json) -> Result<Json, String> {
match truth_fn {
TruthFn::RegistryRevision => Ok(Json::Num(registry::registry_revision() as f64)),
TruthFn::Patterns => Ok(Json::Arr(registry::patterns())),
TruthFn::GetPattern => {
let pattern_id = as_str(args.get("pattern_id"));
let revision = match args.get("revision") {
Some(Json::Num(n)) => Some(*n as i64),
_ => None,
};
registry::get_pattern(&pattern_id, revision)
registry::get_pattern(pattern_id, revision)
}
other => Err(format!("unknown truth fn {other}")),
TruthFn::Unknown => Err(format!("unknown truth fn {}", truth_fn.as_str())),
}
}
fn check_case(fn_name: &str, name: &str, args: &Json, want: &Json) -> Result<(), String> {
fn check_case(truth_fn: TruthFn, name: &str, args: &Json, want: &Json) -> Result<(), String> {
let fn_name = truth_fn.as_str();
// The oracle's raising branch is recorded as {"raises","message"}.
if let Some(message) = want.get("message").filter(|_| want.get("raises").is_some()) {
match run_case(fn_name, args) {
match run_case(truth_fn, args) {
Err(err) => {
let want_msg = as_str(Some(message));
if err != want_msg {
@@ -69,20 +112,20 @@ fn check_case(fn_name: &str, name: &str, args: &Json, want: &Json) -> Result<(),
Ok(got) => {
return Err(format!(
"{fn_name}/{name}: oracle raises, kernel returned {}",
capability_scoring::pyjson::dumps(&got)
dumps(&got)
))
}
}
}
match run_case(fn_name, args) {
match run_case(truth_fn, args) {
Ok(got) => {
if jeq(&got, want) {
Ok(())
} else {
Err(format!(
"{fn_name}/{name}: value mismatch\n want {}\n got {}",
capability_scoring::pyjson::dumps(want),
capability_scoring::pyjson::dumps(&got)
dumps(want),
dumps(&got)
))
}
}
@@ -90,24 +133,37 @@ fn check_case(fn_name: &str, name: &str, args: &Json, want: &Json) -> Result<(),
}
}
#[test]
fn frozen_truth_replays_verbatim() {
fn truth_cases() -> Vec<Json> {
let truth = parse(TRUTH).expect("frozen_cpb_truth.json parses");
let cases = match truth.get("cases") {
match truth.get("cases") {
Some(Json::Arr(c)) => c.clone(),
_ => panic!("truth has no cases"),
};
assert!(!cases.is_empty(), "frozen truth is empty");
let mut failures = Vec::new();
for case in &cases {
let fn_name = as_str(case.get("fn"));
let name = as_str(case.get("name"));
let args = case.get("input").cloned().unwrap_or(Json::Null);
let want = case.get("want").cloned().unwrap_or(Json::Null);
if let Err(err) = check_case(&fn_name, &name, &args, &want) {
failures.push(err);
}
}
}
#[test]
fn frozen_truth_replays_verbatim() {
let cases = truth_cases();
assert!(!cases.is_empty(), "frozen truth is empty");
let failures: Vec<String> = cases
.iter()
.filter_map(|case| {
let truth_fn = TruthFn::parse(as_str(case.get("fn")));
let name = as_str(case.get("name"));
let args = or_null(case.get("input"));
let want = or_null(case.get("want"));
// An unknown fn name is a battery failure, not a skip: the
// lattice is closed by the frozen truth.
if truth_fn == TruthFn::Unknown {
return Some(format!(
"{}/{name}: unknown truth fn {}",
truth_fn.as_str(),
as_str(case.get("fn"))
));
}
check_case(truth_fn, name, args, want).err()
})
.collect();
assert!(
failures.is_empty(),
"branch battery diverged from frozen truth:\n{}",
@@ -11,7 +11,7 @@
//! (a revision that no longer matches is an err carrying the oracle's
//! exact ValueError message)
//!
//! Parity oracle: frozen_cpb_truth.json (17 cases frozen from the live
//! Parity oracle: frozen_cpb_truth.json (19 cases frozen from the live
//! Python oracle) replayed verbatim by the in-crate branch battery.
pub mod registry;
@@ -58,6 +58,21 @@ fn arg_json(text: &str) -> Result<Json, String> {
pyjson::parse(text).map_err(|e| format!("argument JSON parse failed: {}", e))
}
/// Borrowed get_pattern args: the id is a zero-copy borrow of the parsed
/// arg doc (no clone — the lookup only needs `&str`), and extraction is
/// `?`-propagated instead of nested matches.
fn get_pattern_args(arg: &Json) -> Result<(&str, Option<i64>), String> {
let pattern_id = match arg.get("pattern_id") {
Some(Json::Str(s)) => s.as_str(),
_ => return Err("arg.pattern_id required".to_string()),
};
let revision = match arg.get("revision") {
Some(Json::Num(n)) => Some(*n as i64),
_ => None,
};
Ok((pattern_id, revision))
}
/// cpb_registry_revision({}) -> number
#[no_mangle]
pub extern "C" fn cpb_registry_revision(arg: *const c_char) -> *mut c_char {
@@ -82,15 +97,8 @@ pub extern "C" fn cpb_get_pattern(arg: *const c_char) -> *mut c_char {
let result = read_arg(arg)
.and_then(|text| arg_json(&text))
.and_then(|a| {
let pattern_id = match a.get("pattern_id") {
Some(Json::Str(s)) => s.clone(),
_ => return Err("arg.pattern_id required".to_string()),
};
let revision = match a.get("revision") {
Some(Json::Num(n)) => Some(*n as i64),
_ => None,
};
registry::get_pattern(&pattern_id, revision)
let (pattern_id, revision) = get_pattern_args(&a)?;
registry::get_pattern(pattern_id, revision)
});
envelope(result)
}
@@ -9,6 +9,15 @@
//! values; the FFI re-emits the oracle-shaped doc from the typed value.
//! Miss-before-revision-check oracle ordering is explicit in the typed
//! lookup.
//!
//! Language-advantage pass (Phase B, battery-pinned): the frozen source
//! parses ONCE into a single `Registry` (revision + typed patterns — the
//! parity code parsed it twice, once per accessor), the pattern-id string
//! lattice is a `PatternId` enum parsed once per side so lookup is an
//! exhaustive discriminant match instead of repeated string comparisons,
//! and the revision gate is one exhaustive match. Battery green throughout
//! (unchanged from the parity commit — the whole-doc replay pins the
//! refactor).
use std::sync::OnceLock;
@@ -16,37 +25,82 @@ use capability_scoring::pyjson::{self, Json};
const PATTERNS_SRC: &str = include_str!("../frozen_cpb_patterns.json");
/// The builtin pattern-id lattice. The frozen registry's id set is closed
/// (four ids — pinned by the whole-doc battery replay), so `parse` is
/// injective over it and enum equality is exact; anything else is a miss
/// BEFORE any revision check (oracle ordering).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum PatternId {
CapabilityModuleAdaptation,
ReleaseDeploymentChange,
UiTuiStructuralChange,
StoreSchemaEvolution,
Unknown,
}
impl PatternId {
fn parse(id: &str) -> Self {
match id {
"capability-module-adaptation" => Self::CapabilityModuleAdaptation,
"release-deployment-change" => Self::ReleaseDeploymentChange,
"ui-tui-structural-change" => Self::UiTuiStructuralChange,
"store-schema-evolution" => Self::StoreSchemaEvolution,
_ => Self::Unknown,
}
}
}
/// One builtin pattern, typed from the oracle's to_dict() doc. Free-form
/// sub-structures (signals, obligations) stay `Json`: the schema is the
/// oracle's, open-world by design.
#[derive(Clone, Debug)]
struct BuiltinPattern {
pattern_id: String,
id: PatternId,
revision: i64,
doc: Json,
}
impl BuiltinPattern {
fn from_doc(doc: Json) -> Option<Self> {
let pattern_id = match doc.get("pattern_id") {
Some(Json::Str(s)) => s.clone(),
// The frozen registry's id set is closed (four ids — pinned by the
// whole-doc battery replay): an unknown id is dropped here, so enum
// equality below is exact and an unknown query always misses.
let id = match doc.get("pattern_id") {
Some(Json::Str(s)) => match PatternId::parse(s) {
PatternId::Unknown => return None,
known => known,
},
_ => return None,
};
let revision = match doc.get("revision") {
Some(Json::Num(n)) => *n as i64,
_ => return None,
};
Some(Self { pattern_id, revision, doc })
Some(Self { id, revision, doc })
}
}
fn registry() -> &'static Vec<BuiltinPattern> {
static REGISTRY: OnceLock<Vec<BuiltinPattern>> = OnceLock::new();
REGISTRY.get_or_init(|| {
pyjson::parse(PATTERNS_SRC)
.ok()
.and_then(|root| match root.get("patterns") {
Some(Json::Arr(items)) => Some(
/// The frozen registry, parsed ONCE: the oracle's revision plus every
/// builtin pattern in registry order (BUILTIN_PATTERNS order).
struct Registry {
revision: i64,
patterns: Vec<BuiltinPattern>,
}
impl Registry {
fn parse() -> Self {
let root = pyjson::parse(PATTERNS_SRC).unwrap_or(Json::Null);
let revision = root
.get("revision")
.and_then(|v| match v {
Json::Num(n) => Some(*n as i64),
_ => None,
})
.unwrap_or(0);
let patterns = root
.get("patterns")
.and_then(|v| match v {
Json::Arr(items) => Some(
items
.iter()
.filter_map(|d| BuiltinPattern::from_doc(d.clone()))
@@ -54,46 +108,42 @@ fn registry() -> &'static Vec<BuiltinPattern> {
),
_ => None,
})
.unwrap_or_default()
})
.unwrap_or_default();
Self { revision, patterns }
}
}
fn registry() -> &'static Registry {
static REGISTRY: OnceLock<Registry> = OnceLock::new();
REGISTRY.get_or_init(Registry::parse)
}
/// PATTERN_REGISTRY_REVISION from the oracle.
pub fn registry_revision() -> i64 {
static REVISION: OnceLock<i64> = OnceLock::new();
*REVISION.get_or_init(|| {
pyjson::parse(PATTERNS_SRC)
.ok()
.and_then(|root| match root.get("revision") {
Some(Json::Num(n)) => Some(*n as i64),
_ => None,
})
.unwrap_or(0)
})
registry().revision
}
/// Every builtin pattern doc, in registry order (BUILTIN_PATTERNS order).
pub fn patterns() -> Vec<Json> {
registry().iter().map(|p| p.doc.clone()).collect()
registry().patterns.iter().map(|p| p.doc.clone()).collect()
}
/// Oracle get_pattern semantics: unknown/empty id -> Null BEFORE any
/// revision check; a revision that no longer matches raises (err carries
/// the oracle's exact ValueError message).
pub fn get_pattern(pattern_id: &str, revision: Option<i64>) -> Result<Json, String> {
let pattern = match registry().iter().find(|p| p.pattern_id == pattern_id) {
let want = PatternId::parse(pattern_id);
let pattern = match registry().patterns.iter().find(|p| p.id == want) {
Some(p) => p,
None => return Ok(Json::Null),
};
if let Some(rev) = revision {
if pattern.revision != rev {
return Err(format!(
"pattern {pattern_id} revision {rev} not in registry \
(current: {}) \u{2014} the consuming contract records which \
revision it used",
pattern.revision
));
}
match revision {
Some(rev) if rev != pattern.revision => Err(format!(
"pattern {pattern_id} revision {rev} not in registry \
(current: {}) \u{2014} the consuming contract records which \
revision it used",
pattern.revision
)),
_ => Ok(pattern.doc.clone()),
}
Ok(pattern.doc.clone())
}
+29 -1
View File
@@ -3,9 +3,36 @@
version = 4
[[package]]
name = "iteration"
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "evidence_provenance"
version = "0.1.0"
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "indexmap"
version = "2.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "iteration"
version = "0.2.0"
dependencies = [
"evidence_provenance",
"serde_json",
]
@@ -74,6 +101,7 @@ version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"indexmap",
"itoa",
"memchr",
"serde",
+4 -2
View File
@@ -1,10 +1,12 @@
[package]
name = "iteration"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
description = "FULL parity port of src/rune/iteration.py (dichotomy wave, #2479 tranche)"
[lib]
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
serde_json = "1"
serde_json = { version = "1", features = ["preserve_order", "float_roundtrip"] }
evidence_provenance = { path = "../evidence_provenance" }
+219
View File
@@ -0,0 +1,219 @@
//! branch_battery — replay the FROZEN oracle truth VERBATIM
//! (frozen_it_truth.json, generated by scripts/gen_iteration_truth.py
//! against the LIVE Python oracle with RUNE_IT_CORE=python and
//! RUNE_LEDGER_CORE=python pinned).
//!
//! Every case: feed the recorded input doc through the kernel's public
//! functions and compare the result against the oracle's recorded
//! expectation — parsed as Python values (dict/list/str/num/bool/None),
//! so key order is insensitive but every value must match exactly.
use crate::{
context_packet, descriptive_impact, invalidate_behaviours,
post_change_obligations, predictive_impact, record_delta_line,
};
use evidence_provenance::pyjson::{self, Json};
const TRUTH: &str = include_str!("frozen_it_truth.json");
fn truth() -> Json {
pyjson::parse(TRUTH).expect("frozen truth parses")
}
fn cases(t: &Json, group: &str) -> Vec<Json> {
match t.get(group) {
Some(Json::Arr(items)) => items.clone(),
_ => panic!("truth group {group} missing"),
}
}
fn at<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
match v {
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, x)| x),
_ => None,
}
}
fn atv<'a>(v: &'a Json, path: &[&str]) -> Option<&'a Json> {
let mut cur = v;
for k in path {
cur = at(cur, k)?;
}
Some(cur)
}
fn jstr(v: Option<&Json>) -> String {
match v {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
}
}
fn jlist(v: Option<&Json>) -> Vec<String> {
match v {
Some(Json::Arr(items)) => items
.iter()
.filter_map(|x| match x {
Json::Str(s) => Some(s.clone()),
_ => None,
})
.collect(),
_ => Vec::new(),
}
}
fn jnum(v: Option<&Json>, default: f64) -> f64 {
match v {
Some(Json::Num(n)) => *n,
_ => default,
}
}
/// Python-value equality on Json (num compares by f64).
fn peq(a: &Json, b: &Json) -> bool {
match (a, b) {
(Json::Null, Json::Null) => true,
(Json::Bool(x), Json::Bool(y)) => x == y,
(Json::Num(x), Json::Num(y)) => x == y,
(Json::Str(x), Json::Str(y)) => x == y,
(Json::Arr(x), Json::Arr(y)) => {
x.len() == y.len() && x.iter().zip(y).all(|(a, b)| peq(a, b))
}
(Json::Obj(x), Json::Obj(y)) => {
x.len() == y.len()
&& x.iter().all(|(k, v)| {
y.iter()
.find(|(k2, _)| k2 == k)
.map(|(_, v2)| peq(v, v2))
.unwrap_or(false)
})
}
_ => false,
}
}
fn assert_eq(case_name: &str, want: &Json, got: &Json) {
assert!(
peq(want, got),
"case {case_name} diverged:\n want={}\n got={}",
pyjson::dumps(want),
pyjson::dumps(got),
);
}
#[test]
fn replay_context_packet() {
let t = truth();
for c in cases(&t, "context_packet_cases") {
let got = context_packet(
atv(&c, &["args", "model"]).expect("model"),
atv(&c, &["args", "ledger"]).expect("ledger"),
&jstr(atv(&c, &["args", "target"])),
&jstr(atv(&c, &["args", "intent"])),
atv(&c, &["args", "basis_summary"]).cloned().unwrap_or(Json::Null),
jnum(atv(&c, &["args", "max_local_files"]), 12.0) as usize,
&jstr(atv(&c, &["args", "now"])),
);
assert_eq(
&format!("context_packet/{}", jstr(at(&c, "name"))),
at(&c, "expect").expect("expect"),
&got,
);
}
}
#[test]
fn replay_predictive_impact() {
let t = truth();
for c in cases(&t, "predictive_impact_cases") {
let got = predictive_impact(
atv(&c, &["args", "model"]).expect("model"),
&jstr(atv(&c, &["args", "target"])),
);
assert_eq(
&format!("predictive_impact/{}", jstr(at(&c, "name"))),
at(&c, "expect").expect("expect"),
&got,
);
}
}
#[test]
fn replay_descriptive_impact() {
let t = truth();
for c in cases(&t, "descriptive_impact_cases") {
let got = descriptive_impact(
atv(&c, &["args", "model"]).expect("model"),
&jstr(atv(&c, &["args", "target"])),
&jlist(atv(&c, &["args", "observed_changed"])),
&jstr(atv(&c, &["args", "generation"])),
&jstr(atv(&c, &["args", "now"])),
);
assert_eq(
&format!("descriptive_impact/{}", jstr(at(&c, "name"))),
at(&c, "expect").expect("expect"),
&got,
);
}
}
#[test]
fn replay_record_delta_line() {
let t = truth();
for c in cases(&t, "record_impact_delta_cases") {
let got = record_delta_line(atv(&c, &["args", "delta"]).expect("delta"));
assert_eq(
&format!("record_impact_delta/{}", jstr(at(&c, "name"))),
at(&c, "expect").expect("expect"),
&Json::Str(got),
);
}
}
#[test]
fn replay_invalidate_behaviours() {
let t = truth();
for c in cases(&t, "invalidate_behaviours_cases") {
let mut bh = atv(&c, &["args", "behaviours"])
.cloned()
.expect("behaviours");
let recs = invalidate_behaviours(
&mut bh,
&jlist(atv(&c, &["args", "changed"])),
&jstr(atv(&c, &["args", "generation"])),
&jstr(atv(&c, &["args", "now"])),
)
.expect("invalidate ok");
let name = jstr(at(&c, "name"));
assert_eq(
&format!("invalidate_behaviours/{name}/doc"),
atv(&c, &["expect", "doc"]).expect("doc"),
&bh,
);
assert_eq(
&format!("invalidate_behaviours/{name}/recs"),
atv(&c, &["expect", "recs"]).expect("recs"),
&recs,
);
}
}
#[test]
fn replay_post_change_obligations() {
let t = truth();
for c in cases(&t, "post_change_obligations_cases") {
let changed = atv(&c, &["args", "changed"]).map(|v| jlist(Some(v)));
let behaviours = atv(&c, &["args", "behaviours"]).cloned();
let got = post_change_obligations(
atv(&c, &["args", "model"]).expect("model"),
&jstr(atv(&c, &["args", "target"])),
changed.as_deref(),
behaviours.as_ref(),
);
assert_eq(
&format!("post_change_obligations/{}", jstr(at(&c, "name"))),
at(&c, "expect").expect("expect"),
&got,
);
}
}
File diff suppressed because it is too large. Load diff
+876 -11
View File
@@ -1,14 +1,879 @@
//! iteration — post-change iteration tracking (W6).
pub fn record_impact_delta(
_delta_path: &str,
contract_id: &str,
scope_files: &[String],
) -> serde_json::Value {
serde_json::json!({"contract_id": contract_id, "scope_files": scope_files, "recorded": true})
//! iteration — T19 §19E/19H/19I/19K: the canonical dependency-aware
//! iteration engine.
//!
//! FULL parity port of src/rune/iteration.py (dichotomy wave, #2479
//! tranche). The oracle consumes live StructuralModel / CapabilityLedger /
//! BehaviourLedger objects; over FFI they ride as their JSON docs and the
//! model queries (children/beneath/consumers/impact_closure/...) are
//! reimplemented from the Python floor semantics (the sm_loader kernel is
//! already parity-verified against the same floor).
//!
//! FFI (doc-envelope law): every call takes one JSON doc and returns
//! {"ok": true, "value": ...} | {"ok": false, "err": ..., "type": ...}.
//! * itr_context_packet({model, ledger, target, intent?, basis_summary?,
//! max_local_files?, now}) -> packet dict
//! * itr_predictive_impact({model, target}) -> closure dict
//! * itr_descriptive_impact({model, target, observed_changed,
//! generation?, now}) -> delta dict
//! * itr_record_delta_line({delta}) -> jsonl line
//! * itr_invalidate({behaviours, changed, generation?, now}) -> {doc, recs}
//! * itr_post_change_obligations({model, target, changed?, behaviours?})
//! -> [obligations]
//!
//! Determinism seams: `generated_at` / `recorded_at` / the invalidation
//! clock are facade ARGUMENTS (`now`) — the frozen-truth battery replays
//! them verbatim. The impact_deltas.jsonl FILE append stays in the facade;
//! the kernel owns the exact line bytes (json.dumps sort_keys parity via
//! pyjson::dumps_sorted).
//!
//! invalidate_behaviours delegates to the evidence_provenance kernel's
//! behaviour::invalidate_for_change — the SAME Rust function the oracle's
//! ep_loader routes to (rule C: no second invalidation authority).
//!
//! NOTE: no itr_free_string export — callers free through capability_
//! scoring's cs_free_string (shared process allocator).
use evidence_provenance::behaviour;
use evidence_provenance::pyjson::{self, Json};
use std::collections::{BTreeSet, HashSet};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
// ── helpers ──────────────────────────────────────────────────────────────
fn obj(pairs: Vec<(&str, Json)>) -> Json {
Json::Obj(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
pub fn post_change_obligations(scope_files: &[String]) -> Vec<String> {
scope_files
.iter()
.map(|f| format!("invalidate_behaviours: {}", f))
trait IntoJson {
fn into_json(self) -> Json;
}
impl IntoJson for &str {
fn into_json(self) -> Json {
Json::Str(self.to_string())
}
}
impl IntoJson for String {
fn into_json(self) -> Json {
Json::Str(self)
}
}
impl IntoJson for Json {
fn into_json(self) -> Json {
self
}
}
fn arr<S: IntoJson>(v: Vec<S>) -> Json {
Json::Arr(v.into_iter().map(IntoJson::into_json).collect())
}
fn s(v: &Json, key: &str) -> String {
match v.get(key) {
Some(Json::Str(x)) => x.clone(),
_ => String::new(),
}
}
fn entities(doc: &Json) -> Vec<&Json> {
match doc.get("entities") {
Some(Json::Arr(items)) => items.iter().collect(),
_ => Vec::new(),
}
}
/// Language advantage: the relationship vocabulary iteration queries is a
/// closed lattice — `RelType::of` returns None for the open-world tail
/// (calls/reads/writes/...) that the oracle simply ignores, and every
/// query matches EXHAUSTIVELY over the lattice (a new queryable edge kind
/// is a compiler-checked variant, not another wire string). The wire
/// spelling lives in exactly one place per variant.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RelType {
BelongsTo,
Owns,
DependsOn,
Provides,
Consumes,
VerifiedBy,
DeployedBy,
}
impl RelType {
fn of(r: &Json) -> Option<RelType> {
match s(r, "type").as_str() {
"belongs_to" => Some(RelType::BelongsTo),
"owns" => Some(RelType::Owns),
"depends_on" => Some(RelType::DependsOn),
"provides" => Some(RelType::Provides),
"consumes" => Some(RelType::Consumes),
"verified_by" => Some(RelType::VerifiedBy),
"deployed_by" => Some(RelType::DeployedBy),
_ => None,
}
}
}
/// Zero-copy: relationships are BORROWED from the input doc, never cloned.
fn relationships(doc: &Json) -> Vec<&Json> {
match doc.get("relationships") {
Some(Json::Arr(items)) => items.iter().collect(),
_ => Vec::new(),
}
}
fn get_entity<'a>(doc: &'a Json, eid: &str) -> Option<&'a Json> {
entities(doc).into_iter().find(|e| s(e, "id") == eid)
}
/// Outgoing edges of `eid` with the given type, sorted+deduped (the
/// oracle's `sorted(r["to"] ...)` law).
fn edges_from(doc: &Json, eid: &str, ty: RelType) -> Vec<String> {
let mut v: Vec<String> = relationships(doc)
.into_iter()
.filter(|r| RelType::of(r) == Some(ty) && s(r, "from") == eid)
.map(|r| s(r, "to"))
.collect();
v.sort();
v.dedup();
v
}
fn stale(r: &Json) -> bool {
s(r, "status") == "stale"
}
/// model.children: belongs_to edges reversed, relationship order kept
/// (NOT sorted — the oracle preserves document order here).
fn children(doc: &Json, eid: &str) -> Vec<String> {
relationships(doc)
.into_iter()
.filter(|r| {
RelType::of(r) == Some(RelType::BelongsTo)
&& s(r, "to") == eid
&& s(r, "from") != eid
})
.map(|r| s(r, "from"))
.collect()
}
/// model.beneath: transitive descendants via LIFO frontier, then sorted.
fn beneath(doc: &Json, eid: &str) -> Vec<String> {
let mut seen: HashSet<String> = HashSet::new();
seen.insert(eid.to_string());
let mut out: Vec<String> = Vec::new();
let mut frontier: Vec<String> = vec![eid.to_string()];
while let Some(cur) = frontier.pop() {
for child in children(doc, &cur) {
if seen.insert(child.clone()) {
out.push(child.clone());
frontier.push(child);
}
}
}
out.sort();
out
}
fn owning_domain(doc: &Json, eid: &str) -> Json {
let mut cur = eid.to_string();
let mut hops = 0;
while hops < 16 {
if cur.starts_with("domain:") {
return Json::Str(cur);
}
let parents: Vec<String> = relationships(doc)
.into_iter()
.filter(|r| {
RelType::of(r) == Some(RelType::BelongsTo)
&& s(r, "from") == cur
})
.map(|r| s(r, "to"))
.collect();
match parents.into_iter().next() {
Some(p) => cur = p,
None => return Json::Null,
}
hops += 1;
}
Json::Null
}
fn dependencies(doc: &Json, eid: &str) -> Vec<String> {
let mut v: Vec<String> = relationships(doc)
.into_iter()
.filter(|r| {
RelType::of(r) == Some(RelType::DependsOn)
&& s(r, "from") == eid
&& !stale(r)
})
.map(|r| s(r, "to"))
.collect();
v.sort();
v.dedup();
v
}
/// Who depends on OR consumes this entity (interfaces are consumed;
/// components are depended on — Backstage relation pairs).
fn consumers(doc: &Json, eid: &str) -> Vec<String> {
let mut v: Vec<String> = relationships(doc)
.into_iter()
.filter(|r| {
let ty = RelType::of(r);
(ty == Some(RelType::DependsOn) || ty == Some(RelType::Consumes))
&& s(r, "to") == eid
&& !stale(r)
})
.map(|r| s(r, "from"))
.collect();
v.sort();
v.dedup();
v
}
fn interfaces_for(doc: &Json, eid: &str) -> Vec<String> {
edges_from(doc, eid, RelType::Provides)
}
fn consumes_of(doc: &Json, eid: &str) -> Vec<String> {
edges_from(doc, eid, RelType::Consumes)
}
/// impact_closure — the structurally bounded scope (rule J), oracle-identical
/// (Nx affected semantics, bounded reverse-dependency BFS).
fn impact_closure(doc: &Json, eid: &str) -> Json {
if get_entity(doc, eid).is_none() {
return obj(vec![(
"error",
Json::Str(format!("unknown entity {}", py_repr_str(eid))),
)]);
}
let mut seen: HashSet<String> = HashSet::new();
seen.insert(eid.to_string());
let mut consumers_set: HashSet<String> = HashSet::new();
let mut frontier: Vec<String> = vec![eid.to_string()];
let mut depth = 0usize;
while !frontier.is_empty() && depth < 8 {
let mut nxt = Vec::new();
for cur in &frontier {
for c in consumers(doc, cur) {
if seen.insert(c.clone()) {
consumers_set.insert(c.clone());
nxt.push(c);
}
}
}
frontier = nxt;
depth += 1;
}
let direct_deps = dependencies(doc, eid);
for iface in interfaces_for(doc, eid) {
for c in consumers(doc, &iface) {
if seen.insert(c.clone()) {
consumers_set.insert(c);
}
}
}
let mut scope: BTreeSet<String> = BTreeSet::new();
scope.insert(eid.to_string());
scope.extend(consumers_set.iter().cloned());
let mut state_surfaces: BTreeSet<String> = BTreeSet::new();
let mut verification_scope: BTreeSet<String> = BTreeSet::new();
let mut deployment_scope: BTreeSet<String> = BTreeSet::new();
for e in std::iter::once(eid.to_string()).chain(consumers_set.iter().cloned()) {
for x in edges_from(doc, &e, RelType::Owns) {
state_surfaces.insert(x);
}
for x in edges_from(doc, &e, RelType::VerifiedBy) {
verification_scope.insert(x);
}
for x in edges_from(doc, &e, RelType::DeployedBy) {
deployment_scope.insert(x);
}
}
let uncertainty = arr(vec![obj(vec![
("kind", Json::Str("dynamic-consumer".into())),
(
"note",
Json::Str(
"static model cannot see dynamic dispatch/string-keyed \
lookup/late-binding consumers \u{2014} reconcilers must \
verify at runtime"
.into(),
),
),
])]);
obj(vec![
("target", Json::Str(eid.to_string())),
("owning_domain", owning_domain(doc, eid)),
("mutation_scope", arr(scope.into_iter().collect::<Vec<_>>())),
(
"observation_scope",
obj(vec![
("direct_dependencies", arr(direct_deps)),
(
"interfaces_provided",
arr(interfaces_for(doc, eid)),
),
("interfaces_consumed", arr(consumes_of(doc, eid))),
]),
),
(
"state_surfaces",
arr(state_surfaces.into_iter().collect::<Vec<_>>()),
),
(
"verification_scope",
arr(verification_scope.into_iter().collect::<Vec<_>>()),
),
(
"deployment_scope",
arr(deployment_scope.into_iter().collect::<Vec<_>>()),
),
(
"invariants",
arr(vec![
Json::Str(format!(
"belongs_to hierarchy of {eid} remains stable"
)),
Json::Str("canonical-state ownership unchanged".into()),
]),
),
("non_goals", Json::Arr(vec![])),
("uncertainty", uncertainty),
("closure_depth", Json::Num(depth as f64)),
])
}
// ── capability ledger floor (by_component / context_packet) ─────────────
const LEDGER_SCHEMA_VERSION: f64 = 1.0;
fn ledger_by_component<'a>(ledger: &'a Json, component: &str) -> Vec<&'a Json> {
match ledger.get("capabilities") {
Some(Json::Obj(pairs)) => pairs
.iter()
.map(|(_, r)| r)
.filter(|r| {
let m = s(r, "maturity");
m != "retired" && m != "superseded" && s(r, "component") == component
})
.collect(),
_ => Vec::new(),
}
}
fn ledger_context_packet(ledger: &Json, capability_id: &str) -> Json {
let key = if capability_id.contains(':') {
capability_id.to_string()
} else {
format!("capability:{capability_id}")
};
let rec = match ledger.get("capabilities") {
Some(Json::Obj(pairs)) => pairs
.iter()
.find(|(k, _)| k.as_str() == key)
.map(|(_, r)| r),
_ => None,
};
let rec = match rec {
Some(r) => r,
None => {
return obj(vec![(
"error",
Json::Str(format!("unknown capability {}", py_repr_str(capability_id))),
)])
}
};
let fields = [
"capability_id", "name", "purpose", "component",
"source_locations", "contract", "state_touched", "dependencies",
"consumers", "invariants", "behaviour_specs", "maturity",
"constraints", "generation", "limitations",
];
let mut pairs: Vec<(String, Json)> =
vec![("schema_version".into(), Json::Num(LEDGER_SCHEMA_VERSION))];
for f in fields {
pairs.push((f.to_string(), rec.get(f).cloned().unwrap_or(Json::Null)));
}
Json::Obj(pairs)
}
// ── 19E: context_packet ──────────────────────────────────────────────────
pub fn context_packet(
model: &Json,
ledger: &Json,
target: &str,
intent: &str,
basis_summary: Json,
max_local_files: usize,
now: &str,
) -> Json {
let entity = match get_entity(model, target) {
Some(e) => e,
None => {
return obj(vec![(
"error",
Json::Str(format!("unknown structural target {}", py_repr_str(target))),
)])
}
};
let caps = ledger_by_component(ledger, target);
let local = match caps.first() {
Some(cap) => ledger_context_packet(ledger, &s(cap, "capability_id")),
None => Json::Null,
};
let has_source = |e: &Json| -> bool {
let src = match e.get("identities") {
Some(i) => match i.get("source") {
Some(Json::Str(x)) => !x.is_empty(),
_ => false,
},
None => false,
};
src
};
let beneath_count = beneath(model, target)
.into_iter()
.filter(|b| match get_entity(model, b) {
Some(e) => !has_source(e),
None => false,
})
.count();
let mut files: Vec<String> = Vec::new();
for eid in std::iter::once(target.to_string())
.chain(children(model, target))
{
let e = get_entity(model, &eid);
let mut src = String::new();
if let Some(e) = e {
if let Some(Json::Str(x)) = e
.get("ext")
.and_then(|x| x.get("source"))
{
src = x.clone();
}
if src.is_empty() {
if let Some(Json::Str(x)) = e
.get("identities")
.and_then(|x| x.get("source"))
{
src = x.clone();
}
}
}
if !src.is_empty() {
files.push(src);
}
}
for cap in &caps {
if let Some(Json::Arr(locs)) = cap.get("source_locations") {
for l in locs {
if let Json::Str(x) = l {
files.push(x.clone());
}
}
}
}
let mut file_set: BTreeSet<String> = BTreeSet::new();
file_set.extend(files);
let local_files: Vec<String> =
file_set.into_iter().take(max_local_files).collect();
let closure = impact_closure(model, target);
let mut iface_consumers: BTreeSet<String> = BTreeSet::new();
for iface in interfaces_for(model, target) {
for c in consumers(model, &iface) {
if c != target {
iface_consumers.insert(c);
}
}
}
let mut connected_consumers: BTreeSet<String> = BTreeSet::new();
connected_consumers.extend(consumers(model, target));
connected_consumers.extend(iface_consumers.iter().cloned());
let uncertainty = closure.get("uncertainty").cloned().unwrap_or(Json::Arr(vec![]));
let connected = obj(vec![
("dependencies", arr(dependencies(model, target))),
(
"consumers",
arr(connected_consumers.into_iter().collect::<Vec<_>>()),
),
(
"interface_mediated_consumers",
arr(iface_consumers.into_iter().collect::<Vec<_>>()),
),
("interfaces_provided", arr(interfaces_for(model, target))),
("state_owned", arr(edges_from(model, target, RelType::Owns))),
(
"verification",
arr(edges_from(model, target, RelType::VerifiedBy)),
),
("deployment", arr(edges_from(model, target, RelType::DeployedBy))),
("uncertainty", uncertainty),
]);
let target_kind = match entity.get("kind") {
Some(Json::Str(k)) => Json::Str(k.clone()),
_ => Json::Null,
};
obj(vec![
("schema_version", Json::Num(1.0)),
("intent", Json::Str(intent.to_string())),
("target", Json::Str(target.to_string())),
("target_kind", target_kind),
("owning_domain", owning_domain(model, target)),
("local", local),
("local_files", arr(local_files)),
("beneath_count", Json::Num(beneath_count as f64)),
("connected", connected),
("basis_summary", basis_summary),
("generated_at", Json::Str(now.to_string())),
])
}
// ── 19H: predictive vs descriptive impact ────────────────────────────────
pub fn predictive_impact(model: &Json, target: &str) -> Json {
impact_closure(model, target)
}
pub fn descriptive_impact(
model: &Json,
target: &str,
observed_changed: &[String],
generation: &str,
now: &str,
) -> Json {
let predicted = impact_closure(model, target);
let predicted_scope: HashSet<String> = match predicted.get("mutation_scope") {
Some(Json::Arr(items)) => items
.iter()
.filter_map(|v| match v {
Json::Str(x) => Some(x.clone()),
_ => None,
})
.collect(),
_ => HashSet::new(),
};
let observed: HashSet<String> = observed_changed.iter().cloned().collect();
let mut predicted_sorted: Vec<String> =
predicted_scope.iter().cloned().collect();
predicted_sorted.sort();
let mut observed_sorted: Vec<String> = observed.iter().cloned().collect();
observed_sorted.sort();
let mut unexpected: Vec<String> =
observed.difference(&predicted_scope).cloned().collect();
unexpected.sort();
let mut unaffected: Vec<String> =
predicted_scope.difference(&observed).cloned().collect();
unaffected.sort();
obj(vec![
("target", Json::Str(target.to_string())),
("generation", Json::Str(generation.to_string())),
("predicted", arr(predicted_sorted)),
("observed", arr(observed_sorted)),
("unexpected", arr(unexpected)),
("unaffected_as_predicted", arr(unaffected)),
("recorded_at", Json::Str(now.to_string())),
])
}
/// record_impact_delta's exact line body (json.dumps sort_keys parity);
/// the trailing newline is the facade's file-append concern.
pub fn record_delta_line(delta: &Json) -> String {
pyjson::dumps_sorted(delta)
}
// ── 19I: selective invalidation bridge ───────────────────────────────────
pub fn invalidate_behaviours(
behaviours_doc: &mut Json,
changed: &[String],
generation: &str,
now: &str,
) -> Result<Json, String> {
behaviour::invalidate_for_change(behaviours_doc, changed, generation, &Json::Null, now)
}
// ── 19K: post-change obligations ─────────────────────────────────────────
fn py_repr_str(x: &str) -> String {
let mut out = String::from("'");
for c in x.chars() {
match c {
'\\' => out.push_str("\\\\"),
'\'' => out.push_str("\\'"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
_ => out.push(c),
}
}
out.push('\'');
out
}
fn py_list_repr(items: &[String]) -> String {
let inner: Vec<String> = items.iter().map(|i| py_repr_str(i)).collect();
format!("[{}]", inner.join(", "))
}
pub fn post_change_obligations(
model: &Json,
target: &str,
changed: Option<&[String]>,
behaviours: Option<&Json>,
) -> Json {
let changed_set: BTreeSet<String> = match changed {
Some(c) if !c.is_empty() => c.iter().cloned().collect(),
_ => {
let mut s = BTreeSet::new();
s.insert(target.to_string());
s
}
};
let mut obligations: Vec<Json> = Vec::new();
let mut seen: HashSet<(String, String)> = HashSet::new();
let add = |kind: &str, target_e: &str, why: String,
obligations: &mut Vec<Json>, seen: &mut HashSet<(String, String)>| {
if seen.insert((kind.to_string(), target_e.to_string())) {
obligations.push(obj(vec![
("kind", Json::Str(kind.to_string())),
("target", Json::Str(target_e.to_string())),
("why", Json::Str(why)),
]));
}
};
for eid in changed_set.iter().map(|x| x.as_str()).collect::<Vec<_>>() {
for consumer in consumers(model, eid) {
add(
"inspect_consumer",
&consumer,
format!("consumes/depends on changed {eid}"),
&mut obligations,
&mut seen,
);
}
for iface in interfaces_for(model, eid) {
add(
"verify_interface",
&iface,
format!("provided by changed {eid}"),
&mut obligations,
&mut seen,
);
for consumer in consumers(model, &iface) {
add(
"inspect_consumer",
&consumer,
format!("consumes {iface} provided by changed {eid}"),
&mut obligations,
&mut seen,
);
}
}
for store in edges_from(model, eid, RelType::Owns) {
add(
"check_state_compatibility",
&store,
format!("state owned by changed {eid}"),
&mut obligations,
&mut seen,
);
}
for iface in consumes_of(model, eid) {
add(
"check_interface_contract",
&iface,
format!("changed {eid} consumes {iface} \u{2014} contract must still hold"),
&mut obligations,
&mut seen,
);
}
for dep in edges_from(model, eid, RelType::DeployedBy) {
add(
"verify_deployment",
&dep,
format!("deployed surface of changed {eid}"),
&mut obligations,
&mut seen,
);
}
}
if let Some(bh) = behaviours {
if let Some(Json::Obj(pairs)) = bh.get("behaviours") {
for (_, rec) in pairs {
let mut deps: HashSet<String> = HashSet::new();
if let Some(Json::Arr(items)) = rec.get("dependencies") {
for d in items {
if let Json::Str(x) = d {
deps.insert(x.clone());
}
}
}
if let Some(Json::Str(o)) = rec.get("owner_component") {
// Python unions {rec.get("owner_component")} — a None
// owner lands in deps but can never intersect the
// all-string changed set, so it is simply skipped.
deps.insert(o.clone());
}
let inter: Vec<String> = deps
.iter()
.filter(|d| changed_set.contains(*d))
.cloned()
.collect();
if !inter.is_empty() {
let mut sorted_inter = inter.clone();
sorted_inter.sort();
let bid = s(rec, "behaviour_id");
add(
"retest",
&bid,
format!("depends on changed {}", py_list_repr(&sorted_inter)),
&mut obligations,
&mut seen,
);
}
}
}
}
Json::Arr(obligations)
}
// ── FFI (doc-envelope) ───────────────────────────────────────────────────
fn envelope(result: Result<Json, (String, String)>) -> *mut c_char {
let body = match result {
Ok(value) => obj(vec![
("ok", Json::Bool(true)),
("value", value),
]),
Err((err, ty)) => obj(vec![
("ok", Json::Bool(false)),
("err", Json::Str(err)),
("type", Json::Str(ty)),
]),
};
let out = pyjson::dumps(&body);
match CString::new(out) {
Ok(c) => c.into_raw(),
Err(_) => CString::new(r#"{"ok":false,"err":"nul in output","type":"RuntimeError"}"#)
.unwrap()
.into_raw(),
}
}
fn parse_doc(raw: &str) -> Result<Json, (String, String)> {
pyjson::parse(raw).map_err(|e| (e, "ValueError".to_string()))
}
fn read_arg(ptr: *const c_char) -> Result<String, (String, String)> {
if ptr.is_null() {
return Ok(String::new());
}
unsafe { CStr::from_ptr(ptr) }
.to_str()
.map(|s| s.to_string())
.map_err(|e| (e.to_string(), "ValueError".to_string()))
}
macro_rules! ffi {
($name:ident, $body:expr) => {
#[no_mangle]
pub extern "C" fn $name(arg: *const c_char) -> *mut c_char {
let out: Result<Json, (String, String)> =
read_arg(arg).and_then(|raw| $body(&raw));
envelope(out)
}
};
}
fn str_list(v: Option<&Json>) -> Vec<String> {
match v {
Some(Json::Arr(items)) => items
.iter()
.filter_map(|x| match x {
Json::Str(s) => Some(s.clone()),
_ => None,
})
.collect(),
_ => Vec::new(),
}
}
ffi!(itr_context_packet, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let model = doc.get("model").cloned().unwrap_or(Json::Null);
let ledger = doc.get("ledger").cloned().unwrap_or(Json::Null);
let target = s(&doc, "target");
let intent = match doc.get("intent") {
Some(Json::Str(x)) => x.clone(),
_ => String::new(),
};
let basis = doc.get("basis_summary").cloned().unwrap_or(Json::Null);
let max_local = match doc.get("max_local_files") {
Some(Json::Num(n)) => *n as usize,
_ => 12,
};
let now = s(&doc, "now");
Ok(context_packet(&model, &ledger, &target, &intent, basis, max_local, &now))
});
ffi!(itr_predictive_impact, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let model = doc.get("model").cloned().unwrap_or(Json::Null);
let target = s(&doc, "target");
Ok(predictive_impact(&model, &target))
});
ffi!(itr_descriptive_impact, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let model = doc.get("model").cloned().unwrap_or(Json::Null);
let target = s(&doc, "target");
let observed = str_list(doc.get("observed_changed"));
let generation = match doc.get("generation") {
Some(Json::Str(x)) => x.clone(),
_ => String::new(),
};
let now = s(&doc, "now");
Ok(descriptive_impact(&model, &target, &observed, &generation, &now))
});
ffi!(itr_record_delta_line, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let delta = doc.get("delta").cloned().unwrap_or(Json::Null);
Ok(Json::Str(record_delta_line(&delta)))
});
ffi!(itr_invalidate, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let mut bh = doc.get("behaviours").cloned().unwrap_or(Json::Null);
let changed = str_list(doc.get("changed"));
let generation = match doc.get("generation") {
Some(Json::Str(x)) => x.clone(),
_ => String::new(),
};
let now = s(&doc, "now");
match invalidate_behaviours(&mut bh, &changed, &generation, &now) {
Ok(recs) => Ok(obj(vec![("doc", bh), ("recs", recs)])),
Err(e) => Err((e, "RuntimeError".to_string())),
}
});
ffi!(itr_post_change_obligations, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let model = doc.get("model").cloned().unwrap_or(Json::Null);
let target = s(&doc, "target");
let changed = doc.get("changed").map(|c| str_list(Some(c)));
let behaviours = doc.get("behaviours").cloned();
Ok(post_change_obligations(
&model,
&target,
changed.as_deref(),
behaviours.as_ref(),
))
});
#[cfg(test)]
mod branch_battery;
+3 -3
View File
@@ -306,10 +306,10 @@
"side": "RUST"
},
"connection_pool": {
"evidence": "sqlite3 (storage-backed); network/concurrency imports: ['threading']",
"evidence": "deterministic pool bookkeeping \u2014 programme verdict RUST (dichotomy wave #2479 batch; sqlite handles stay in the Python facade, kernel owns pooling order/eviction/status)",
"functions": 9,
"lines": 144,
"side": "GO"
"side": "RUST"
},
"construction_activation": {
"evidence": "deterministic/state domain",
@@ -1079,4 +1079,4 @@
"lines": 591,
"side": "GO"
}
}
}
+179 -30248
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-12T16:46:40Z-b49130-factory-batch-a
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Port src/rune/iteration.py to FULL Rust (dichotomy factory, issue #2479 tranche): doc-envelope FFI, ctypes loader, facade delegation pin, frozen-truth battery, live parity 100%, Phase B language-advantage pass.
## 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-12T17:53:30Z", "contract": "BUILDER-2026-10-12T16:46:40Z-b49130-factory-batch-a", "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/gen_iteration_truth.py", "src/rune/iteration.py", "src/rune/itr_loader.py", "src/rust/iteration/src/branch_battery.rs", "src/rust/iteration/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-a
- builder:factory-batch-a
- builder:factory-batch-a
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-12T17:14:32Z-844644-factory-batch-b
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Complete the construction_depth dichotomy port to FULL Rust (#2479 tranche): oracle-exact depth kernel (UNKNOWN ceremony/bypassed, PROJECT_BUILD full-lifecycle strings, EXISTING_PROJECT_CHANGE base ceremony + wide-surface escalation restored to oracle truth), doc-envelope FFI (cd_select_depth, free via capability_scoring cs_free_string — no free re-export), cd_loader mirroring broker_loader.py, facade delegation with RUNE_CD_CORE=python pin, frozen-oracle battery (40 cases, every public function/branch), live parity 100%, Phase B language-advantage pass.
## 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-12T17:16:29Z", "contract": "BUILDER-2026-10-12T17:14:32Z-844644-factory-batch-b", "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/close_contract_construction_depth.py", "scripts/gen_construction_depth_truth.py", "scripts/walk_contract_construction_depth.py", "src/rune/cd_loader.py", "src/rune/construction_depth.py", "src/rust/construction_depth/canary_construction_depth.py", "src/rust/construction_depth/frozen_cd_truth.json", "src/rust/construction_depth/src/branch_battery.rs", "src/rust/construction_depth/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-b
- builder:factory-batch-b
- builder:factory-batch-b
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-12T17:41:58Z-4eb5a0-factory-batch-b
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Complete the connection_pool dichotomy port to FULL Rust (#2479 tranche, programme verdict RUST): pool-bookkeeping kernel (pooling order, stale removal, oldest-first eviction, status) as doc-envelope FFI (cpool_new/begin_get/commit/close_all/status, free via capability_scoring cs_free_string — no free re-export); cpool_loader mirroring broker_loader.py; facade delegation with RUNE_CPOOL_CORE=python pin (sqlite handles stay in the facade); frozen-oracle battery (16 cases, every kernel branch, frozen against a real sqlite-backed pool); live parity 100% (60-seed random-op sweep); classification flip GO→RUST; Phase B language-advantage pass.
## 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-12T17:44:17Z", "contract": "BUILDER-2026-10-12T17:41:58Z-4eb5a0-factory-batch-b", "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/close_contract_connection_pool.py", "scripts/gen_connection_pool_truth.py", "scripts/walk_contract_connection_pool.py", "src/rune/connection_pool.py", "src/rune/cpool_loader.py", "src/rust/connection_pool/frozen_cpool_truth.json", "src/rust/connection_pool/src/branch_battery.rs", "src/rust/connection_pool/src/lib.rs", "store/rebase/classification.json", "tests/test_connection_pool.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-b
- builder:factory-batch-b
- builder:factory-batch-b
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-12T17:43:29Z-ea9485-factory-batch-c
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Port src/rune/forge.py to FULL Go (dichotomy factory, issue #2479 tranche, batch-c): the §18L forge boundary — ForgeAdapter protocol, ForgeUnavailable, GiteaForge (env/push/commit_status/ci_runs_for_sha/create_or_patch_release), default_forge, and the scripts/gitea_auth credential ladder — name-preserving in src/go/forge with IO behind CommandRunner/HTTPTransport/TokenSource seams, frozen-truth battery (34 rows), live parity 100%, Phase B goroutine fan-out (Snapshot), compile-time seam assertions.
## 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-12T17:57:50Z", "contract": "BUILDER-2026-10-12T17:43:29Z-ea9485-factory-batch-c", "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/gen_forge_truth.py", "src/go/forge/main.go", "src/go/forge/phaseb.go", "src/go/forge/phaseb_test.go", "src/go/forge/truth.json", "src/go/forge/truth_test.go", "src/rune/forge.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-c
- builder:factory-batch-c
- builder:factory-batch-c
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-12T17:46:05Z-c1a38e-factory-batch-c
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Port src/rune/verification_layer.py to FULL Go (dichotomy factory, issue #2479 tranche, batch-c): all seven verifiers (exit_code, unit_test, schema, file_exists, file_changed, tool_receipt, constraint_check) + unknown-verifier dispatch, VerificationResult.to_dict byte-rendering, handle_hook, PLUGIN manifest — the Rust evidence_provenance semantics carried 1:1 (verification.rs), name-preserving in src/go/verification_layer with the FS probe behind a seam, frozen-truth battery (62 rows), live parity 100%, Phase B Verifier registry + VerifyAll goroutine fan-out.
## 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-12T17:59:52Z", "contract": "BUILDER-2026-10-12T17:46:05Z-c1a38e-factory-batch-c", "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/gen_verification_layer_truth.py", "src/go/verification_layer/main.go", "src/go/verification_layer/phaseb.go", "src/go/verification_layer/phaseb_test.go", "src/go/verification_layer/truth.json", "src/go/verification_layer/truth_test.go", "src/rune/verification_layer.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-c
- builder:factory-batch-c
- builder:factory-batch-c
- closure-record
+69
View File
@@ -0,0 +1,69 @@
"""connection_pool facade — kernel delegation + oracle-floor parity
(dichotomy wave #2479 tranche). Exercises the pool bookkeeping through the
facade in BOTH core modes: RUNE_CPOOL_CORE auto (Rust kernel when built)
and =python (oracle floor pinned)."""
import os
import sqlite3
import sys
import tempfile
from pathlib import Path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
from rune.connection_pool import ConnectionPool # noqa: E402
def _scenario(core_pin: str) -> list[dict]:
os.environ["RUNE_CPOOL_CORE"] = core_pin
snapshots = []
with tempfile.TemporaryDirectory() as td:
p = ConnectionPool(max_connections=2)
a, b, c, d = [os.path.join(td, f"{n}.db") for n in "ABCD"]
conn_a = p.get_connection(a)
snapshots.append(("create-a", p.get_status(), conn_a is p.connections[a]))
snapshots.append(("reuse-a", p.get_status(),
p.get_connection(a) is conn_a))
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()))
p.connections[b].close() # force stale
p.get_connection(b)
snapshots.append(("stale-b", p.get_status(), None))
p.get_connection(d)
snapshots.append(("evict-again", p.get_status(), None))
snapshots.append(("status", p.get_status(), None))
p.close_all()
snapshots.append(("closed", p.get_status(), None))
# pool is fresh again: new connection can be created
snapshots.append(("fresh", p.get_status(),
isinstance(p.get_connection(a), sqlite3.Connection)))
# temp dirs differ per run — compare bookkeeping on basenames
norm = []
for name, st, flag in snapshots:
st = dict(st)
st["databases"] = [os.path.basename(d) for d in st["databases"]]
norm.append((name, st, flag))
return norm
def test_kernel_matches_oracle_floor():
auto = _scenario("auto")
py = _scenario("python")
assert len(auto) == len(py)
for (name_a, st_a, flag_a), (name_p, st_p, flag_p) in zip(auto, py):
assert name_a == name_p
# the Rust kernel must reproduce the oracle bookkeeping exactly
assert st_a == st_p, f"{name_a}: {st_a} != {st_p}"
assert flag_a == flag_p, name_a
def test_module_level_helpers():
os.environ["RUNE_CPOOL_CORE"] = "auto"
from rune import connection_pool as cp
assert cp.PLUGIN["name"] == "connection_pool"
status = cp.get_status()
assert set(status) == {"connections", "max_connections", "databases"}
cp.close_all()
assert cp.get_status()["connections"] == 0
+6 -4
View File
@@ -46,7 +46,8 @@ def test_new_skill_standard():
def test_new_standalone_project_full():
d = select_depth("PROJECT_BUILD")
assert d.level == "FULL"
assert "all obligations" in " ".join(d.ceremony)
# oracle truth (§12E): PROJECT_BUILD carries the full lifecycle ceremony
assert "project bootstrap" in " ".join(d.ceremony)
def test_ambiguous_unresolved_not_light():
@@ -67,9 +68,10 @@ def test_non_construction_no_construction_depth():
def test_wide_surface_escalates_to_full():
d = select_depth("EXISTING_PROJECT_CHANGE",
affected_surface=[f"f{i}.py" for i in range(8)])
# ORACLE (verified 2026-10-10): wide surface records evidence but does NOT
# escalate EXISTING_PROJECT_CHANGE beyond STANDARD
assert d.level == "STANDARD"
# oracle truth (T12E §12E, src/rune/construction_depth.py): >5 entries
# escalates EXISTING_PROJECT_CHANGE to FULL — the facade-burn batch
# flipped this to kernel behavior; the live oracle always escalated
assert d.level == "FULL"
def test_high_uncertainty_probe_first():