#!/usr/bin/env python3 """scaffolding_coverage.py — CI gate: every Go/Rust implementation module must map to a construction contract in store/scaffold/. The absolute-scaffolding law (Nick, 2026-10-07): scaffolding is not optional process, it is the record. A Go/Rust unit without a contract whose affected_surface covers it is ungoverned code — this gate fails the build. Rules: * Every directory under src/go/ (and every crate under src/rust/) must appear in at least one contract's scope. * Contracts are read from store/scaffold/ (the durable trace). * EXEMPT: crates that pre-date the pipeline (the 10 original kernels) are mapped via the legacy bootstrap contract; test fixtures and _test.go are not units. Exit 0 = all covered. Exit 1 = ungoverned units (listed). """ from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SCAFFOLD = ROOT / "store" / "scaffold" GO = ROOT / "src" / "go" RUST = ROOT / "src" / "rust" # Units predating the absolute law, retro-adopted 2026-10-07 (contracts # BUILDER-2026-10-07T11:32-33Z-*). The map is the adoption record; new units # MUST get their contract BEFORE their first commit lands. RETRO_ADOPTED = { "adaptive-router", "memory-store-deep", "operator-deep", "curator-core", # SRE sweep retro-adoptions (2026-10-10, contracts # BUILDER-2026-10-10T01:50:13Z-504272 / 5bc1c7): "auto-detect", "forge-client", # Original kernels + infra from the pre-pipeline era (bootstrap contract): "event-bus", "message-queue", "subsystem-health", "parallel-processor", "connection-pool", "recall-router", "cron-engine", "cache", "night-mode", "work-manager", "failure-filer", "microkernel", "tool-executor", "rune-entry", "hook-engine", "model-connect", "operator", "operator-support", "memory-ops", "sleep-time", "core-server", "context-broker", "stage-guards", "tool-protocol", "tool-protocol-rw", "witness", "curator", "elastic-cognition", "persona-gate", "scaffold", "abstraction", "tui", "warm-router", "provider-registry", "local-tool-runtime", "memory-store-deep", "cognition", # Rust kernels (the 10 originals + W6 wave — bootstrap-era + parity ports) "route_risk_flags", "impact_preview", "programme_gates", "structural_migration", "rune_spinner", "warm_neuron_store", "graph_projection", "failure_recovery", "construction_depth", "intent_continuity", "wait_guard", "task_persist", "response_adapter", "salience_gate", "time_awareness", "recall_uplift", "verification_layer", "project_registry", "behaviour_ledger", "audit_ledger", "cognitive_budgeter", "progressive_escalation", "shard_manager", "task_gate", "drift_core", "self_improve", "token_optimizer", "dependency_tracker", "context_pressure", "inference_trace", "wait_guard_corpus", "rune_profiler", "construction_projection", "outcome_ledger", "construction_mode", "drift_resume", "toolchain", "construction_commands", "construction_activation", "subconscious_pass", "attention_capsule", "contracts", "capability_fit", "capability_ledger", "memory_selector", "graph_memory", "claim_audit", "build_basis", "prompt_sync", "voice_sync", "layout_contract", "system_registry", "voice_hybrid", "capability_broker", "structural_store", "spine", "behavior", "construction_intent", "construction_decision", "construction_pattern", "structural_model", "programme_continuation", "cognition_core", "memory_retrieval", "memory_storage", "scaffold_core", "evidence_provenance", "rune_spine", "memory_scoring", "capability_scoring", "token_counting", "query_memory", "drift_observability", "iteration", "spine_loader", "testing_mode", "construction_interface", "construction_patterns_builtin", "drift_cache", "drift_ledger", "scaffold-membrane", } def contract_scopes() -> set[str]: """Every surface named in any persisted contract under store/scaffold/.""" scopes: set[str] = set() if not SCAFFOLD.exists(): return scopes for f in SCAFFOLD.rglob("*.json"): try: data = json.loads(f.read_text()) except (json.JSONDecodeError, OSError): continue blobs = _iter_dicts(data) for d in blobs: for key in ("scope_files", "affected_surface", "surfaces", "scope"): v = d.get(key) if isinstance(v, list): for item in v: if isinstance(item, str): scopes.add(item) scopes.add(item.rstrip("/").split("/")[-1]) elif isinstance(v, str): scopes.add(v) scopes.add(v.rstrip("/").split("/")[-1]) return scopes def _iter_dicts(obj): if isinstance(obj, dict): yield obj for v in obj.values(): yield from _iter_dicts(v) elif isinstance(obj, list): for v in obj: yield from _iter_dicts(v) def main() -> int: scopes = contract_scopes() ungoverned = [] if GO.exists(): for d in sorted(GO.iterdir()): if d.is_dir() and (d / "go.mod").exists(): if d.name not in scopes and d.name not in RETRO_ADOPTED: ungoverned.append(f"src/go/{d.name}/") if RUST.exists(): for d in sorted(RUST.iterdir()): if (d / "Cargo.toml").exists(): if d.name not in scopes and d.name not in RETRO_ADOPTED: ungoverned.append(f"src/rust/{d.name}/") if ungoverned: print("UNGOVERNED UNITS — no construction contract covers them") print("(absolute-scaffolding law 2026-10-07: open a contract via") print(" construction_interface.submit_need BEFORE the next commit):") for u in ungoverned: print(f" {u}") return 1 print(f"scaffolding coverage: all Go/Rust units governed " f"({len(RETRO_ADOPTED)} retro-adopted/bootstrap, " f"{len(scopes)} contract scopes)") return 0 if __name__ == "__main__": raise SystemExit(main())