Files
rune/scripts/gen_scaffold_store_truth.py
T
Nick 5dda590588 feat(go): scaffold batch 2 — the transactional store layer (contract BUILDER-2026-10-07T17:47:00Z-960f12)
The §21 transactional boundary ported to Go:
- CanonicalDigest: sha256 of the sorted+redacted semantic payload (byte
  parity with json.dumps(sort_keys=True): Python default separators,
  ensure_ascii escaping) — the §12B real commit semantics
- RedactSecrets (exact names + credential substrings), SortedNorm
  (recursive; lists sort by their dumps repr)
- Commit (intended-vs-on-disk digest readback), VerifyOnDisk (the
  forgotten-save lie detector), SaveVerified — exact Python assertion
  texts including the %r single-quote form
- SaveDoc: schema guard + indent=1 sort_keys write (the disk format)
- ImpactFrontier: the bounded Spine-edges-only walk — change_kind
  inference, NON_OBLIGATION/STALE/CANDIDATE skips, contract expansion
  (implements/consumes); the ORACLE corrected my inverted party
  computation (c==b → party=a)
- SnapshotPredictedFrontier + SpineBridgeEntity (identity-only bridge)

PARITY: truth_store.json — 10 cases incl. digest key-order stability,
secret redaction shape, forgotten-save detection with exact text, three
frontier modes. Frontier docs SHIP in the truth inputs (batch-1 lesson).
The ratchet blocked the first commit attempt (new generator handler) —
the bare-command law held; annotated and re-landed.
2026-10-07 18:56:17 +01:00

179 lines
7.2 KiB
Python

#!/usr/bin/env python3
"""gen_scaffold_store_truth.py — scaffold batch 2 truth battery
(contract BUILDER-2026-10-07T17:47:00Z-960f12).
The LIVE oracle (scaffold.Scaffold + structural_store) on a tmp store with
now() frozen. Cases: canonical digest stability + secret redaction, commit
semantics (success + exact failure texts), verify_on_disk forgotten-save
detection, impact frontier (contract_change / implementation_change /
contextual), snapshot_predicted_frontier, spine_bridge_entity.
Usage: python3 scripts/gen_scaffold_store_truth.py (from repo root)
"""
import json
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
from rune import scaffold as sc # noqa: E402
from rune import structural_store as ss # noqa: E402
FROZEN = "2026-10-07T17:50:00"
def main():
sc.now = lambda: FROZEN
ss.now = lambda: FROZEN
tmp = Path(tempfile.mkdtemp(prefix="scaffold-store-truth-"))
s = sc.Scaffold(tmp, "truth-project")
s.init(purpose="store battery")
cases = []
# ── canonical digest: stability + redaction ───────────────────────────
doc = s.load()
d1 = ss.canonical_digest(doc)
# key-order permutation must NOT change the digest (semantic content)
permuted = {k: doc[k] for k in reversed(list(doc.keys()))}
d2 = ss.canonical_digest(permuted)
cases.append({
"fn": "digest", "name": "key_order_stable",
"input": {},
"expected": {"digest": d1, "permuted_same": d2 == d1},
})
secret_doc = {"entities": [{"id": "repo:x", "identities": {
"token": "hunter2", "api_key": "sk-123", "full_name": "o/r",
"api_token": "zz", "password": "pw", "private_key": "-----BEGIN",
"note": "keepme", "my_secret_sauce": "redacted-too"}}]}
cases.append({
"fn": "digest", "name": "secret_redaction",
"input": {},
"expected": {"redacted": ss._redact_secrets(secret_doc)},
})
# ── commit: success + digest readback ─────────────────────────────────
s.commit(doc, what="battery")
cases.append({
"fn": "commit", "name": "success",
"input": {},
"expected": {"ok": True, "on_disk_schema": s.load()["schema_version"]},
})
# forgotten-save detection: mutate in memory, DON'T save
doc2 = s.load()
doc2["entities"].append({"id": "ghost:1", "kind": "ghost", "identities": {}})
try:
s.verify_on_disk(lambda d: d["entities"], None, what="battery") if False else None
# the real call: selector/expect form
s.verify_on_disk(lambda d: [e for e in d["entities"] if e["id"] == "ghost:1"],
lambda v: bool(v), what="battery")
forgotten = {"ok": True}
except AssertionError as ex:
forgotten = {"ok": False, "error": str(ex)}
cases.append({
"fn": "verify_on_disk", "name": "forgotten_save",
"input": {},
"expected": forgotten,
})
# corrupt store -> commit-style load returns None -> reload failure path
# (simulate: point at a nonexistent path)
class FakeScaffold:
current = tmp / "nonexistent" / "current.json"
try:
ss_load = ss.load(FakeScaffold.current)
reload_none = ss_load is None
except Exception: # noqa: BLE001 — intentional: the case IS the degrade verdict (load failure → loads_none=False); error text is not the truth column here
reload_none = False
cases.append({
"fn": "load", "name": "missing_store",
"input": {},
"expected": {"loads_none": reload_none},
})
# ── impact frontier ───────────────────────────────────────────────────
doc3 = new_frontier_doc()
cases.append({
"fn": "frontier", "name": "contract_change",
"input": {"seeds": ["contract:c1"], "doc": doc3},
"expected": ss.impact_frontier(doc3, ["contract:c1"]),
})
cases.append({
"fn": "frontier", "name": "implementation_change",
"input": {"seeds": ["module:impl_a"], "doc": doc3},
"expected": ss.impact_frontier(doc3, ["module:impl_a"]),
})
cases.append({
"fn": "frontier", "name": "violation_escalation",
"input": {"seeds": ["module:impl_a"], "change_kind": "contract_violation", "doc": doc3},
"expected": ss.impact_frontier(doc3, ["module:impl_a"], change_kind="contract_violation"),
})
# ── snapshot_predicted_frontier + spine bridge ────────────────────────
doc4 = new_frontier_doc()
s4 = sc.Scaffold(tmp / "p4", "frontier-project")
s4.init(purpose="frontier battery")
doc4 = s4.load()
s4.new_contract(doc4, contract_id="f1", need="n", scope=["src/"])
# wire the frontier doc entities into the project doc
doc4["entities"].extend(e for e in doc3["entities"] if e["id"] not in {x["id"] for x in doc4["entities"]})
doc4["relationships"].extend(doc3["relationships"])
frontier = s4.snapshot_predicted_frontier(doc4, "f1", ["contract:c1"])
e = s4.contract(doc4, "f1")
cases.append({
"fn": "snapshot_frontier", "name": "persisted",
"input": {"doc": doc4},
"expected": {
"frontier": frontier,
"checkpoint_note": e["checkpoints"][-1]["note"],
"ext_has": sorted((e.get("ext", {}).get("predicted_frontier") or {}).keys()),
},
})
cases.append({
"fn": "bridge", "name": "identity_only",
"input": {},
"expected": {"bridge": s4.spine_bridge_entity()},
})
out = {
"oracle": "src/rune/scaffold.py + structural_store.py (live, now frozen)",
"generated": "2026-10-07",
"frozen_now": FROZEN,
"cases": cases,
}
target = REPO / "src/go/scaffold" / "truth_store.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
import shutil
shutil.rmtree(tmp, ignore_errors=True)
def new_frontier_doc():
"""A small structural doc exercising the frontier walk."""
doc = ss.new_doc()
ss.add_entity(doc, id="contract:c1", kind="contract", identities={})
ss.add_entity(doc, id="module:impl_a", kind="module", identities={})
ss.add_entity(doc, id="module:impl_b", kind="module", identities={})
ss.add_entity(doc, id="module:lib", kind="module", identities={})
ss.add_entity(doc, id="canary:x", kind="canary", identities={})
ss.add_entity(doc, id="deploy:live", kind="deployment", identities={})
for rel in (
{"type": "implements", "from": "module:impl_a", "to": "contract:c1"},
{"type": "implements", "from": "module:impl_b", "to": "contract:c1"},
{"type": "depends_on", "from": "module:impl_a", "to": "module:lib"},
{"type": "verified_by", "from": "contract:c1", "to": "canary:x"},
{"type": "deployed_as", "from": "module:impl_a", "to": "deploy:live"},
{"type": "supersedes", "from": "module:impl_b", "to": "module:impl_a"}, # non-obligation
):
doc["relationships"].append(rel)
return doc
if __name__ == "__main__":
main()