Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3d0560ed5 | ||
|
|
4f0556fe16 | ||
|
|
f61a4a3fa3 | ||
|
|
89b691b210 | ||
|
|
03ef8132a2 | ||
|
|
e29cc5ee51 | ||
|
|
8ed117abe2 | ||
|
|
633af06e8a | ||
|
|
62e47b3812 | ||
|
|
c0ec3135c6 | ||
|
|
622cceb2f9 | ||
|
|
b50e8553d7 | ||
|
|
4649df1ccc |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.236.0**
|
||||
**Current release: v0.239.0**
|
||||
|
||||
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
|
||||
|
||||
|
||||
@@ -2,56 +2,47 @@
|
||||
|
||||
_Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL only when 80%+ of its Python functions have name-preserving counterparts in the Go/Rust implementation — directories without the functions are facades and count as NOT TOUCHED._
|
||||
|
||||
**Function-level completion: 32%** (838/2627 runtime functions matched)
|
||||
**Function-level completion: 37%** (1020/2781 runtime functions matched)
|
||||
|
||||
| Status | Modules | Lines | Meaning |
|
||||
|---|---|---|---|
|
||||
| FULL | 25 | 8218 | 80%+ of functions ported |
|
||||
| PARTIAL | 89 | 44507 | 20–80% — real logic exists, gaps named below |
|
||||
| NOT TOUCHED | 113 | 22686 | no name-preserving implementation |
|
||||
| Total runtime | 227 | 75411 | |
|
||||
| FULL | 36 | 13024 | 80%+ of functions ported |
|
||||
| PARTIAL | 93 | 45658 | 20–80% — real logic exists, gaps named below |
|
||||
| NOT TOUCHED | 108 | 19178 | no name-preserving implementation |
|
||||
| Total runtime | 237 | 77860 | |
|
||||
|
||||
## NOT TOUCHED — the port queue, in priority order (largest first)
|
||||
|
||||
| Module | Lines | Fns | Side |
|
||||
|---|---|---|---|
|
||||
| rune_tui | 4170 | 159 | TUI-LAST |
|
||||
| curator | 1838 | 43 | GO |
|
||||
| canary_audit_ledger | 541 | 2 | TEST-INFRA |
|
||||
| tui_validator | 514 | 13 | TUI-LAST |
|
||||
| worthiness | 411 | 13 | unclassified |
|
||||
| chat_bubble | 401 | 12 | TUI-LAST |
|
||||
| drift-ledger | 355 | 14 | unclassified |
|
||||
| pc_loader | 337 | 22 | unclassified |
|
||||
| canary_rune_serve | 329 | 13 | TEST-INFRA |
|
||||
| canary_p1_07 | 324 | 10 | TEST-INFRA |
|
||||
| canary_p0_07 | 310 | 10 | TEST-INFRA |
|
||||
| canary_p1_01 | 294 | 12 | TEST-INFRA |
|
||||
| outcome_ledger | 286 | 7 | RUST |
|
||||
| time_awareness | 286 | 14 | RUST |
|
||||
| canary_p1_06 | 280 | 7 | TEST-INFRA |
|
||||
| canary_p1_03 | 271 | 9 | TEST-INFRA |
|
||||
| canary_gitea_automation | 263 | 3 | TEST-INFRA |
|
||||
| canary_p1_02 | 253 | 10 | TEST-INFRA |
|
||||
| construction_patterns_builtin | 249 | 1 | RUST |
|
||||
| canary_full_system | 248 | 2 | TEST-INFRA |
|
||||
| task_gate | 235 | 8 | RUST |
|
||||
| sm_loader | 239 | 14 | unclassified |
|
||||
| canary_native | 231 | 3 | TEST-INFRA |
|
||||
| lexicon_evolution | 229 | 7 | unclassified |
|
||||
| openai_compat_transport | 227 | 9 | GO |
|
||||
| shard_manager | 223 | 9 | RUST |
|
||||
| spine_language | 218 | 5 | RUST |
|
||||
| canary_p0_04 | 207 | 8 | TEST-INFRA |
|
||||
| wr_loader | 206 | 20 | unclassified |
|
||||
| cc_loader | 205 | 28 | RUST |
|
||||
| forge_client | 203 | 18 | GO |
|
||||
| canary_context_broker | 199 | 10 | TEST-INFRA |
|
||||
| canary_p0_05 | 199 | 13 | TEST-INFRA |
|
||||
| cl_loader | 196 | 20 | unclassified |
|
||||
| testing_mode | 196 | 12 | RUST |
|
||||
| grading | 193 | 3 | unclassified |
|
||||
| canary_spine_meta | 192 | 7 | TEST-INFRA |
|
||||
| message_graph | 187 | 12 | unclassified |
|
||||
| ffi_query_memory_smoke | 183 | 5 | RUST |
|
||||
| tm_loader | 178 | 13 | unclassified |
|
||||
| smod_loader | 175 | 10 | unclassified |
|
||||
| behaviour_ledger | 174 | 12 | RUST |
|
||||
| canary_tui_transport | 174 | 7 | TEST-INFRA |
|
||||
| sr_loader | 173 | 18 | unclassified |
|
||||
@@ -60,6 +51,7 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| ms_loader | 163 | 16 | RUST |
|
||||
| canary_gitea_pipeline | 159 | 2 | TEST-INFRA |
|
||||
| dc_loader | 158 | 13 | unclassified |
|
||||
| mg_loader | 152 | 14 | unclassified |
|
||||
| mse_loader | 152 | 12 | unclassified |
|
||||
| bb_loader | 151 | 14 | unclassified |
|
||||
| forge | 146 | 11 | GO |
|
||||
@@ -72,32 +64,36 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| ps_loader | 136 | 13 | unclassified |
|
||||
| verification_layer | 136 | 11 | RUST |
|
||||
| tui_backlog | 125 | 5 | TUI-LAST |
|
||||
| le_loader | 124 | 10 | unclassified |
|
||||
| state_checkpoint | 123 | 8 | unclassified |
|
||||
| cp_loader | 122 | 9 | unclassified |
|
||||
| dl_loader | 118 | 12 | unclassified |
|
||||
| drift_resume | 118 | 3 | RUST |
|
||||
| tl_loader | 118 | 9 | unclassified |
|
||||
| bh_loader | 117 | 9 | unclassified |
|
||||
| tg_loader | 117 | 7 | unclassified |
|
||||
| canary_conversation_state | 115 | 2 | TEST-INFRA |
|
||||
| contracts_loader | 112 | 8 | unclassified |
|
||||
| gr_loader | 112 | 8 | unclassified |
|
||||
| canary_query_memory | 111 | 2 | TEST-INFRA |
|
||||
| tui_transport | 108 | 10 | TUI-LAST |
|
||||
| canary_unbounded | 105 | 2 | TEST-INFRA |
|
||||
| message_widgets | 104 | 6 | TUI-LAST |
|
||||
| self_modify | 102 | 7 | unclassified |
|
||||
| ct_loader | 103 | 8 | unclassified |
|
||||
| sc_loader | 96 | 6 | RUST |
|
||||
| inference_paths | 95 | 2 | unclassified |
|
||||
| mutation_guards | 94 | 2 | unclassified |
|
||||
| concept_topology | 90 | 7 | unclassified |
|
||||
| cs_loader | 90 | 5 | RUST |
|
||||
| ci_loader | 89 | 4 | unclassified |
|
||||
| tc_loader | 88 | 5 | RUST |
|
||||
| broker_loader | 86 | 5 | unclassified |
|
||||
| canary_schema_migration | 86 | 1 | TEST-INFRA |
|
||||
| ss_loader | 86 | 7 | unclassified |
|
||||
| ol_loader | 85 | 4 | unclassified |
|
||||
| to_loader | 85 | 4 | unclassified |
|
||||
| ta_loader | 84 | 4 | unclassified |
|
||||
| mems_loader | 83 | 5 | RUST |
|
||||
| cm_loader | 82 | 4 | unclassified |
|
||||
| dl_loader | 77 | 5 | unclassified |
|
||||
| lc_loader | 75 | 5 | unclassified |
|
||||
| cd_loader | 72 | 4 | unclassified |
|
||||
| execution_trace | 71 | 4 | unclassified |
|
||||
@@ -109,7 +105,6 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| cb_loader | 64 | 3 | unclassified |
|
||||
| skill_compiler | 64 | 4 | unclassified |
|
||||
| sg_loader | 63 | 4 | unclassified |
|
||||
| sm_loader | 63 | 4 | unclassified |
|
||||
| meaningful_events | 61 | 3 | unclassified |
|
||||
| outcome_utility | 59 | 4 | unclassified |
|
||||
| memory_types | 54 | 2 | unclassified |
|
||||
@@ -166,17 +161,19 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| claim_audit | 484 | 4/14 | _get_warm_neuron_store, reframe, _graph_has, _warm_has, verify, journal |
|
||||
| drift_core | 471 | 4/14 | _ms_core, _now_iso, _py_check_promotion_eligibility, promote_entry, compute_fama, compute_drift_velocity |
|
||||
| model_profiles | 438 | 5/15 | get_profile_path, load_profile, save_profile, build_profile_from_ollama, scan_all_models, get_or_create_profile |
|
||||
| testing_mode | 362 | 11/21 | _now, _tm_core, _py_default_state, _py_next_item, _py_record, _py_note_blocker |
|
||||
| tier_manager | 262 | 5/15 | _cc_probe, cc_loader_pin, _py_core_now, _py_get_tier, _py_promote, _py_demote |
|
||||
| witness | 446 | 8/18 | _ctx_budget, _now, _cc_probe, cc_loader_pin, _py_extract_topic, _py_detect_signals |
|
||||
| drift_compression | 307 | 3/12 | _py_get_compression_ratio, _py_compress_text, _py_compress_entry, _py_should_warn, _py_warn_before_compress, get_compression_ratio |
|
||||
| drift_ledger | 471 | 7/16 | ledger_path, read_block, load_ledger, save_ledger, surface_alert, snapshot |
|
||||
| scaffold | 868 | 22/31 | init, set_prd, add_maintenance_item, bind_repo, observe_repo, repo_state_from_git |
|
||||
| behavior | 537 | 6/14 | _bh_core, connect, _correction_matches_python, _habit_matches_python, _reinforce_rust, _reinforce_python |
|
||||
| builder_bridge | 326 | 3/11 | _construction_store, _active_construction_lines, _default_selector, _cached_memory, _get_selector, _retrieve_memory |
|
||||
| time_awareness | 402 | 12/20 | _clock_args, _ta_core, get_time_awareness, to_dict, _to_state, _apply_state |
|
||||
| construction_pattern | 547 | 7/14 | _core, _need_dict, _surface_text, _path_matches, _entity_matches, _obligation_when_hit |
|
||||
| contracts | 743 | 4/11 | _ct_core, _resolve_and_project, _run_contract_python, capture_signatures, save_signatures, load_signatures |
|
||||
| graph_memory | 474 | 2/9 | now_iso, connect, resolve_entity, add_edge, query, stats |
|
||||
| intent_continuity | 168 | 2/9 | to_dict, from_dict, _load, save, create_detour, resolve_detour |
|
||||
| lexicon_evolution | 304 | 7/14 | _le_core, _py_content_words, _py_distinctive_terms, _py_shared_distinctive, _py_coherence, _py_grounded |
|
||||
| pins | 282 | 5/12 | _store_path, _save, _detail_blob, unpin, _py_pin_recall, list_pins |
|
||||
| voice_hybrid | 427 | 3/10 | _connect, _load_growth, _save_growth, source_profiles, always, grow |
|
||||
| voice_sync | 299 | 3/10 | _now, get_delivery_register_from_db, get_delivery_register, update_rune_md, check_sync, handle_hook |
|
||||
@@ -197,6 +194,7 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| construction_commands | 268 | 1/5 | _refuse, _validate, _accept, dispatch |
|
||||
| drift_cache | 357 | 12/16 | _dc_core, _py_compute_priority, _py_qualifies_for_cache, main |
|
||||
| drift_observability | 399 | 5/9 | _do_core, main, _load_alerts, _save_alerts |
|
||||
| grading | 253 | 3/7 | _gr_core, _py_affirm_rule, _py_grade_fact, _py_tier_of |
|
||||
| layout_contract | 336 | 2/6 | define_region, bind_component, amend_layout_contract, record_layout_observation |
|
||||
| model_connect | 471 | 7/11 | _ctx_budget, _now, _get_cloud_models, handle_hook |
|
||||
| prompt_sync | 487 | 11/15 | _now, _rust_available, get_store, main |
|
||||
@@ -204,6 +202,7 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| self_improve | 246 | 1/5 | _now, suggest_improvements, handle_hook, main |
|
||||
| stage_guards | 303 | 7/11 | _py_liveness_canary, _py_reconcile, to_dict, chk |
|
||||
| subconscious_pass | 187 | 1/5 | main, _extract_topic, save_reflection, get_recent_findings |
|
||||
| task_gate | 301 | 5/9 | _tg_core, _now, list_gates, main |
|
||||
| construction_activation | 237 | 1/4 | _scaffold_for, _auto_structural_awareness, dispatch_from_decision |
|
||||
| construction_mode | 412 | 2/5 | _contains_any, to_dict, from_dict |
|
||||
| construction_projection | 254 | 1/4 | _contract_entity, validate, write_mini_doc |
|
||||
@@ -227,11 +226,14 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
|
||||
| Module | Lines | Fns | Side |
|
||||
|---|---|---|---|
|
||||
| curator | 1838 | 40/43 | GO |
|
||||
| abstraction | 656 | 17/17 | GO |
|
||||
| system_registry | 603 | 14/16 | RUST |
|
||||
| construction_intent | 580 | 13/16 | RUST |
|
||||
| capability_ledger | 571 | 18/19 | RUST |
|
||||
| drift_ledger | 548 | 20/22 | RUST |
|
||||
| event_wait | 518 | 14/14 | GO |
|
||||
| worthiness | 469 | 12/14 | unclassified |
|
||||
| tool_protocol | 461 | 22/27 | GO |
|
||||
| auto_tasks | 460 | 14/14 | GO |
|
||||
| programme_continuation | 458 | 11/12 | RUST |
|
||||
@@ -240,12 +242,20 @@ _Regenerate with `python3 scripts/dichotomy_audit.py --write`. A module is FULL
|
||||
| model_routing | 432 | 13/13 | GO |
|
||||
| build_basis | 375 | 11/13 | RUST |
|
||||
| attention_capsule | 365 | 6/7 | RUST |
|
||||
| drift-ledger | 355 | 14/14 | unclassified |
|
||||
| outcome_ledger | 318 | 7/8 | RUST |
|
||||
| message_queue | 316 | 13/13 | GO |
|
||||
| message_graph | 295 | 12/13 | unclassified |
|
||||
| toolchain | 295 | 5/6 | RUST |
|
||||
| shard_manager | 276 | 9/10 | RUST |
|
||||
| auto_context | 273 | 8/8 | GO |
|
||||
| openai_compat_transport | 227 | 9/9 | GO |
|
||||
| evidence_probe | 213 | 9/9 | GO |
|
||||
| forge_client | 203 | 18/18 | GO |
|
||||
| self_modify | 149 | 7/8 | unclassified |
|
||||
| recall_uplift | 141 | 1/1 | RUST |
|
||||
| rune_spinner | 130 | 4/5 | RUST |
|
||||
| concept_topology | 128 | 7/8 | unclassified |
|
||||
| wait_guard | 116 | 1/1 | RUST |
|
||||
| failure_recovery | 108 | 1/1 | RUST |
|
||||
| programme_gates | 85 | 4/5 | RUST |
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.236.0"
|
||||
version = "0.239.0"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Live parity check: construction_patterns_builtin facade on the Rust core
|
||||
vs the Python-pinned oracle (RUNE_CPB_CORE=python). Exercises every public
|
||||
surface branch: BUILTIN_PATTERNS docs, registry revision, get_pattern hit
|
||||
per pattern, unknown-id miss, revision match, revision mismatch (exact
|
||||
exception type + message), revision=None. Deep-copies inputs per case.
|
||||
"""
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, os.path.join(REPO, "src"))
|
||||
|
||||
import rune.construction_patterns_builtin as cpb # noqa: E402
|
||||
|
||||
PIDS = [p.pattern_id for p in cpb.BUILTIN_PATTERNS]
|
||||
|
||||
cases = []
|
||||
for pid in PIDS:
|
||||
cases.append(("get_pattern", {"pattern_id": pid, "revision": None}))
|
||||
rev = cpb.get_pattern(pid).revision
|
||||
cases.append(("get_pattern", {"pattern_id": pid, "revision": rev}))
|
||||
cases.append(("get_pattern", {"pattern_id": pid, "revision": rev + 1}))
|
||||
cases += [
|
||||
("get_pattern", {"pattern_id": "no-such-pattern", "revision": None}),
|
||||
("get_pattern", {"pattern_id": "", "revision": None}),
|
||||
("registry_revision", {}),
|
||||
]
|
||||
|
||||
|
||||
def run(pin):
|
||||
os.environ["RUNE_CPB_CORE"] = "python" if pin else "auto"
|
||||
out = []
|
||||
for fn, args in cases:
|
||||
try:
|
||||
if fn == "get_pattern":
|
||||
got = cpb.get_pattern(**copy.deepcopy(args))
|
||||
out.append(("ok", None if got is None else got.to_dict()))
|
||||
else:
|
||||
out.append(("ok", cpb.PATTERN_REGISTRY_REVISION))
|
||||
except ValueError as e:
|
||||
out.append(("ValueError", str(e)))
|
||||
return out
|
||||
|
||||
|
||||
def run_rust_docs():
|
||||
"""The Rust core's raw surface (registry docs + revision) directly."""
|
||||
from rune import cpb_loader
|
||||
|
||||
return {
|
||||
"revision": cpb_loader.registry_revision(),
|
||||
"patterns": cpb_loader.patterns(),
|
||||
"kernel": cpb_loader.available(),
|
||||
}
|
||||
|
||||
|
||||
want = run(pin=True)
|
||||
got = run(pin=False)
|
||||
match = sum(1 for w, g in zip(want, got) if w == g)
|
||||
for i, (w, g) in enumerate(zip(want, got)):
|
||||
if w != g:
|
||||
print(f"DIVERGENCE case {i} {cases[i]}:\n python {w}\n rust {g}")
|
||||
|
||||
docs = run_rust_docs()
|
||||
py_docs = [p.to_dict() for p in cpb.BUILTIN_PATTERNS]
|
||||
if docs["patterns"] != py_docs or docs["revision"] != cpb.PATTERN_REGISTRY_REVISION:
|
||||
print(f"DIVERGENCE kernel docs: rust rev={docs['revision']} patterns!=python" )
|
||||
match = match # counted below as failure
|
||||
docs_ok = False
|
||||
else:
|
||||
docs_ok = True
|
||||
|
||||
total = len(cases) + 1
|
||||
matched = match + (1 if docs_ok else 0)
|
||||
print(f"PARITY: {matched}/{total}")
|
||||
sys.exit(0 if matched == total else 1)
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Close the #2479 dichotomy-wave construction contract for
|
||||
construction_patterns_builtin. Full lifecycle 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-wave")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Port src/rune/construction_patterns_builtin.py to FULL Rust (dichotomy "
|
||||
"factory, issue #2479 tranche): frozen-oracle registry data, doc-envelope "
|
||||
"FFI, ctypes loader (free via capability_scoring cs_free_string), facade "
|
||||
"delegation with RUNE_CPB_CORE=python pin, frozen-truth branch battery, "
|
||||
"live parity 100%, Phase B typed-registry pass. Plus audit fix: curator "
|
||||
"-> curator-core alias (curator was FULL-Go since a95c6ce1 but the audit "
|
||||
"miscounted it NOT TOUCHED).",
|
||||
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)[:300])
|
||||
if not t.get("success"):
|
||||
sys.exit(1)
|
||||
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": "construction_patterns_builtin parity port — final SHAs after "
|
||||
"rebase: parity 4649df1c, phase B b50e8553. Battery 19 cases "
|
||||
"green, live parity 16/16, clippy 0.",
|
||||
}], scope_files=[
|
||||
"src/rune/construction_patterns_builtin.py",
|
||||
"src/rune/cpb_loader.py",
|
||||
"src/rust/construction_patterns_builtin/src/lib.rs",
|
||||
"src/rust/construction_patterns_builtin/src/registry.rs",
|
||||
"src/rust/construction_patterns_builtin/src/branch_battery.rs",
|
||||
"src/rust/construction_patterns_builtin/frozen_cpb_patterns.json",
|
||||
"src/rust/construction_patterns_builtin/frozen_cpb_truth.json",
|
||||
"scripts/gen_construction_patterns_builtin_truth.py",
|
||||
"scripts/check_cpb_parity.py",
|
||||
])
|
||||
print("close:", json.dumps(c)[:400])
|
||||
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Open + walk + close the #2479 dichotomy-wave construction contract for
|
||||
drift_ledger. Full lifecycle in ONE process (shared-store clobber hazard,
|
||||
see notes-construction-intent-batch.md)."""
|
||||
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-wave")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Complete the drift_ledger dichotomy port to FULL Rust (#2479 tranche): "
|
||||
"check/alert-loop, snapshot/anchor assembly, auto-fix routing and fix "
|
||||
"gate as doc-envelope FFI; dl_loader ctypes loader mirroring "
|
||||
"broker_loader.py (free via capability_scoring cs_free_string); facade "
|
||||
"delegation with RUNE_DL_CORE=python pin; frozen-oracle battery (87 "
|
||||
"cases, every public function/branch); live parity 100%; Phase B "
|
||||
"language-advantage pass; dichotomy-audit instrument fixes (curator "
|
||||
"alias + hyphen-twin mapping).",
|
||||
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)[:300])
|
||||
if not t.get("success"):
|
||||
sys.exit(1)
|
||||
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": "drift_ledger dichotomy completion — parity c0ec3135 "
|
||||
"feat(drift_ledger): port remaining cores to FULL Rust — "
|
||||
"dichotomy wave; Phase B 62e47b38 refactor(drift_ledger): "
|
||||
"Phase B language-advantage pass — dichotomy wave (both pushed "
|
||||
"gitea/master). Battery 8 tests replay the 87-case frozen "
|
||||
"oracle truth VERBATIM; live parity 87/87 byte-identical "
|
||||
"(RUNE_DL_CORE=auto vs =python); clippy -D warnings clean; "
|
||||
"Python tests green (22 passed on drift-touching suites; 6 "
|
||||
"pre-existing unrelated failures on the clean tree). Audit: "
|
||||
"drift-ledger 14/14 FULL, drift_ledger 20/22 FULL, curator "
|
||||
"40/43 FULL after the instrument fixes.",
|
||||
}], scope_files=[
|
||||
"src/rune/drift_ledger.py",
|
||||
"src/rune/dl_loader.py",
|
||||
"src/rust/drift_ledger/src/lib.rs",
|
||||
"src/rust/drift_ledger/src/branch_battery.rs",
|
||||
"scripts/gen_drift_ledger_truth.py",
|
||||
"scripts/dichotomy_audit.py",
|
||||
"docs/dichotomy-rebase-honest-audit.md",
|
||||
])
|
||||
print("close:", json.dumps(c)[:400])
|
||||
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
|
||||
@@ -107,11 +107,18 @@ def module_to_keys(module_stem: str) -> list[str]:
|
||||
"""Candidate implementation keys for a Python module stem."""
|
||||
kebab = module_stem.replace("_", "-")
|
||||
keys = [kebab, module_stem]
|
||||
# Hyphenated legacy twins (drift-ledger.py vs drift_ledger.py) share ONE
|
||||
# implementation; the underscore form is the crate/dir name.
|
||||
if "-" in module_stem:
|
||||
keys.append(module_stem.replace("-", "_"))
|
||||
# Deep ports and multi-module binaries register aliases:
|
||||
aliases = {
|
||||
"rune_operator": ["operator", "operator-deep", "operator-support", "core-server"],
|
||||
"rune_tui": ["tui"],
|
||||
"rune_operator_cli": ["operator"],
|
||||
# curator was ported to FULL Go (src/go/curator-core, a95c6ce1);
|
||||
# without this alias the audit mislabels it NOT TOUCHED.
|
||||
"curator": ["curator-core"],
|
||||
"memory_store": ["memory-ops", "memory-store-deep"],
|
||||
"warm_router": ["warm-router", "operator-support"],
|
||||
"tool_executor": ["tool-executor", "local-tool-runtime", "tool-protocol", "tool-protocol-rw"],
|
||||
@@ -142,6 +149,7 @@ def module_to_keys(module_stem: str) -> list[str]:
|
||||
"evidence_provenance": ["cognition-provenance", "cognition"],
|
||||
"memory_scoring": ["cognition-scoring", "cognition"],
|
||||
"capability_scoring": ["cognition-capability", "cognition"],
|
||||
"curator": ["curator-core"],
|
||||
"token_counting": ["cognition-token", "cognition"],
|
||||
"query_memory": ["cognition-query", "cognition"],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_construction_patterns_builtin_truth.py — dichotomy wave #2479
|
||||
(construction_patterns_builtin FULL-Rust batch).
|
||||
|
||||
Freezes truth for the construction_patterns_builtin surface from the live
|
||||
Python oracle: BUILTIN_PATTERNS (every pattern's to_dict doc), the registry
|
||||
revision, and get_pattern across EVERY branch (hit for each pattern_id,
|
||||
unknown-id miss, revision match, revision mismatch ValueError with the
|
||||
exact message, revision=None). Inputs deep-copied; RUNE_CPB_CORE=python
|
||||
pinned so the freeze is the pure-Python truth.
|
||||
|
||||
Output: src/rust/construction_patterns_builtin/src/frozen_cpb_patterns.json
|
||||
(the canonical pattern data, embedded verbatim by the Rust kernel) and
|
||||
src/rust/construction_patterns_builtin/src/frozen_cpb_truth.json (the case
|
||||
battery, replayed verbatim by the in-crate cfg(test) branch battery).
|
||||
Never hand-transcribe: every `want` comes from the live oracle run below.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, os.path.join(REPO, "src"))
|
||||
|
||||
os.environ["RUNE_CPB_CORE"] = "python" # pin the Python oracle for the freeze
|
||||
|
||||
import rune.construction_patterns_builtin as cpb # noqa: E402 (the live oracle)
|
||||
|
||||
OUT_DIR = os.path.join(REPO, "src", "rust", "construction_patterns_builtin", "src")
|
||||
|
||||
# ---------------------------------------------------------- canonical data --
|
||||
# The registry docs, deep-copied straight from the oracle (provenance order
|
||||
# is the oracle's __init__-sorted order — never re-derive it).
|
||||
pattern_docs = [copy.deepcopy(p.to_dict()) for p in cpb.BUILTIN_PATTERNS]
|
||||
pattern_ids = [p.pattern_id for p in cpb.BUILTIN_PATTERNS]
|
||||
|
||||
with open(os.path.join(OUT_DIR, "frozen_cpb_patterns.json"), "w") as f:
|
||||
json.dump({"revision": cpb.PATTERN_REGISTRY_REVISION, "patterns": pattern_docs}, f, indent=2)
|
||||
f.write("\n")
|
||||
print(f"frozen_cpb_patterns.json: {len(pattern_docs)} patterns, "
|
||||
f"revision={cpb.PATTERN_REGISTRY_REVISION}")
|
||||
|
||||
# ------------------------------------------------------------------ cases ---
|
||||
cases = []
|
||||
|
||||
|
||||
def add(fn, name, input_, want):
|
||||
cases.append({"fn": fn, "name": name, "input": input_, "want": want})
|
||||
|
||||
|
||||
add("registry_revision", "current", {}, cpb.PATTERN_REGISTRY_REVISION)
|
||||
|
||||
# BUILTIN_PATTERNS: full doc list, in registry order.
|
||||
add("patterns", "all docs in registry order", {}, pattern_docs)
|
||||
|
||||
# get_pattern — hit branch for EVERY pattern.
|
||||
for pid in pattern_ids:
|
||||
got = cpb.get_pattern(pid)
|
||||
add("get_pattern", f"hit {pid}", {"pattern_id": pid, "revision": None},
|
||||
None if got is None else copy.deepcopy(got.to_dict()))
|
||||
|
||||
# get_pattern — miss branch.
|
||||
add("get_pattern", "unknown id -> None",
|
||||
{"pattern_id": "no-such-pattern", "revision": None}, None)
|
||||
add("get_pattern", "empty id -> None", {"pattern_id": "", "revision": None}, None)
|
||||
# Miss is decided BEFORE the revision check (oracle order).
|
||||
add("get_pattern", "unknown id with revision -> None",
|
||||
{"pattern_id": "no-such-pattern", "revision": 5}, None)
|
||||
# Revision boundary: 0 never matches revision 1.
|
||||
try:
|
||||
cpb.get_pattern(pattern_ids[0], revision=0)
|
||||
want = None
|
||||
except ValueError as e:
|
||||
want = {"raises": "ValueError", "message": str(e)}
|
||||
add("get_pattern", "revision zero boundary",
|
||||
{"pattern_id": pattern_ids[0], "revision": 0}, want)
|
||||
|
||||
# get_pattern — revision branches: match passes through, mismatch raises.
|
||||
for pid in pattern_ids:
|
||||
p = cpb.get_pattern(pid)
|
||||
got = cpb.get_pattern(pid, revision=p.revision)
|
||||
add("get_pattern", f"revision match {pid}",
|
||||
{"pattern_id": pid, "revision": p.revision}, copy.deepcopy(got.to_dict()))
|
||||
try:
|
||||
cpb.get_pattern(pid, revision=p.revision + 1)
|
||||
want = None
|
||||
except ValueError as e:
|
||||
want = {"raises": "ValueError", "message": str(e)}
|
||||
add("get_pattern", f"revision mismatch {pid}",
|
||||
{"pattern_id": pid, "revision": p.revision + 1}, want)
|
||||
|
||||
# get_pattern — revision=None explicit (the default path).
|
||||
got = cpb.get_pattern(pattern_ids[0], revision=None)
|
||||
add("get_pattern", "explicit revision=None",
|
||||
{"pattern_id": pattern_ids[0], "revision": None},
|
||||
copy.deepcopy(got.to_dict()))
|
||||
|
||||
out = os.path.join(OUT_DIR, "frozen_cpb_truth.json")
|
||||
with open(out, "w") as f:
|
||||
json.dump({"frozen_from": "live oracle construction_patterns_builtin.py "
|
||||
"(RUNE_CPB_CORE=python)",
|
||||
"cases": cases}, f, indent=2)
|
||||
f.write("\n")
|
||||
print(f"frozen_cpb_truth.json: {len(cases)} cases")
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,710 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Freeze drift_ledger oracle truth for the Rust port battery (dichotomy
|
||||
wave #2479 tranche).
|
||||
|
||||
Exercises EVERY public function of src/rune/drift_ledger.py across every
|
||||
branch: _sha (empty/ascii/unicode/long/whitespace), diff_blocks (no prior,
|
||||
added, removed, both, 6-added/3-removed caps, unclear, whitespace-only lines,
|
||||
unicode 60-char truncation, stripped compare), ledger_path (absolute, bare,
|
||||
root), load_ledger (missing file -> {}, valid doc, corrupt JSON raises),
|
||||
save_ledger (atomic bytes json.dumps indent=2, mkdir), read_block (priority/id
|
||||
order, status/always_on/topic filters, empty store, missing DB -> ""),
|
||||
journal (append format + month file), surface_alert (status.json merge,
|
||||
120-char note truncation, DRIFT-ALERT.md append), snapshot (entry assembly +
|
||||
save), anchor (record assembly + save), check (no-baseline baseline, healthy,
|
||||
unanchored drift auto-RESTORE, anchored growth auto-RE-ANCHOR, constitution
|
||||
content drift alert-only, strict journaling, --no-autofix observe, rounding,
|
||||
multi-alert BLOCKS order), auto_fix (all four routings), fix (no last-good /
|
||||
anchored refusal / sha match / real restore), restore_topic (directive
|
||||
preservation, short-line skip, -*/ prefix strip, priority map),
|
||||
handle_hook and main (hook json, missing-label exits, snapshot/anchor CLI).
|
||||
|
||||
Nondeterminism seams: the clock is frozen (dl.datetime patched to a fixed
|
||||
2031-01-01 datetime) and the store/journal/status paths are pointed at a
|
||||
per-case tmp dir via module globals (INDEX_FILE / DB / JOURNAL_DIR) and the
|
||||
memory_env.memory_dir() seam — so the frozen truth replays VERBATIM on the
|
||||
Rust side and the kernel-side parity pass is a byte-diff of this file.
|
||||
|
||||
Default run pins RUNE_DL_CORE=python (the ORACLE). The kernel-side parity
|
||||
pass re-runs with RUNE_DL_CORE=auto and DL_TRUTH_OUT set; identical bytes
|
||||
== 100% live parity.
|
||||
|
||||
Output: /tmp/dl_truth.json — replayed VERBATIM by
|
||||
src/rust/drift_ledger/src/branch_battery.rs.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from datetime import datetime as _real_datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
os.environ.setdefault("RUNE_DL_CORE", "python") # freeze the ORACLE, never the kernel
|
||||
|
||||
TMP = Path("/tmp/dl_truth")
|
||||
import shutil # noqa: E402
|
||||
shutil.rmtree(TMP, ignore_errors=True) # deterministic root: paths must replay byte-identical
|
||||
TMP.mkdir(parents=True)
|
||||
os.environ["RUNE_HOME"] = str(TMP / "home")
|
||||
os.environ["RUNE_MEMORY_DIR"] = str(TMP / "memory")
|
||||
os.environ["RUNE_STORE_DB"] = str(TMP / "store.db")
|
||||
os.environ["RUNE_CONFIG_DIR"] = str(TMP / "config")
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rune import drift_ledger as dl # noqa: E402
|
||||
import memory_env # noqa: E402
|
||||
|
||||
GROUPS = ("sha", "diff", "ledger_path", "load_ledger", "save_ledger", "read_block",
|
||||
"journal", "surface_alert", "snapshot", "anchor", "check", "auto_fix",
|
||||
"fix", "restore_topic", "handle_hook", "main",
|
||||
"k_snapshot", "k_anchor", "k_alerts", "k_auto_fix", "k_fix")
|
||||
groups: dict[str, list] = {g: [] for g in GROUPS}
|
||||
|
||||
|
||||
def case(group: str, name: str, input_, expected) -> None:
|
||||
groups[group].append({"name": name, "input": input_, "expected": expected})
|
||||
|
||||
|
||||
# ── determinism seams (see module docstring) ─────────────────────────────
|
||||
CLOCK_TS = "2031-01-01T00:00:00+00:00"
|
||||
CLOCK_MONTH = "2031-01"
|
||||
|
||||
|
||||
class _FrozenDatetime(_real_datetime):
|
||||
@classmethod
|
||||
def now(cls, tz=None): # noqa: ARG003 — the oracle's clock, pinned
|
||||
return _real_datetime(2031, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
dl.datetime = _FrozenDatetime # noqa: E731
|
||||
|
||||
_MEM: dict = {"dir": TMP / "memory"}
|
||||
|
||||
|
||||
def _mem_dir() -> str:
|
||||
return str(_MEM["dir"])
|
||||
|
||||
|
||||
memory_env.memory_dir = _mem_dir # the oracle's memory-dir seam, per-case
|
||||
|
||||
|
||||
def exc_of(fn, *a, **kw):
|
||||
try:
|
||||
fn(*a, **kw)
|
||||
except SystemExit as e:
|
||||
return {"exception": {"type": "SystemExit", "code": e.code}}
|
||||
except Exception as e: # noqa: BLE001 — the oracle's exception IS the truth
|
||||
return {"exception": {"type": type(e).__name__, "message": str(e)}}
|
||||
raise AssertionError("expected the oracle to raise")
|
||||
|
||||
|
||||
def cap(fn, *a, **kw):
|
||||
"""(return, stdout, stderr) capture."""
|
||||
out, err = io.StringIO(), io.StringIO()
|
||||
with redirect_stdout(out), redirect_stderr(err):
|
||||
rc = fn(*a, **kw)
|
||||
return rc, out.getvalue(), err.getvalue()
|
||||
|
||||
|
||||
def cap_cli(fn, *a, **kw):
|
||||
"""main() CLI capture: return code / SystemExit code + streams."""
|
||||
out, err = io.StringIO(), io.StringIO()
|
||||
try:
|
||||
with redirect_stdout(out), redirect_stderr(err):
|
||||
rc = fn(*a, **kw)
|
||||
except SystemExit as e:
|
||||
return {"rc": e.code, "stdout": out.getvalue(), "stderr": err.getvalue()}
|
||||
return {"rc": rc, "stdout": out.getvalue(), "stderr": err.getvalue()}
|
||||
|
||||
|
||||
SCHEMA = (
|
||||
"CREATE TABLE entries (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, "
|
||||
"importance REAL, created_at TEXT, last_accessed TEXT, topic TEXT, "
|
||||
"source TEXT, method TEXT, status TEXT, valid_from TEXT, confidence REAL, "
|
||||
"temperature REAL, always_on INTEGER, priority INTEGER)"
|
||||
)
|
||||
COLS = ("text, importance, created_at, last_accessed, topic, source, method, "
|
||||
"status, valid_from, confidence, temperature, always_on, priority")
|
||||
|
||||
|
||||
def fresh_env(name: str, rows: list | None = None) -> dict:
|
||||
"""Isolated per-case env: fresh store DB, index/ledger dir, journal,
|
||||
status dir. Returns the case paths."""
|
||||
home = TMP / name
|
||||
home.mkdir(parents=True, exist_ok=True)
|
||||
index_dir = home / "index"
|
||||
db = home / "store.db"
|
||||
con = sqlite3.connect(db)
|
||||
con.execute(SCHEMA)
|
||||
if rows:
|
||||
con.executemany(f"INSERT INTO entries ({COLS}) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", rows)
|
||||
con.commit()
|
||||
con.close()
|
||||
dl.DB = str(db)
|
||||
dl.INDEX_FILE = str(index_dir / "blocks_meta.json")
|
||||
dl.JOURNAL_DIR = str(home / "journal")
|
||||
_MEM["dir"] = home
|
||||
return {"db": str(db), "index_file": dl.INDEX_FILE,
|
||||
"ledger": str(index_dir / "drift_ledger.json"),
|
||||
"journal_dir": dl.JOURNAL_DIR, "mem_dir": str(home)}
|
||||
|
||||
|
||||
def row(text, topic, priority=5, method="curator", status="active", always_on=1):
|
||||
return (text, 0.9, CLOCK_TS, CLOCK_TS, topic, "seed", method, status,
|
||||
CLOCK_TS, 0.9, 1.0, always_on, priority)
|
||||
|
||||
|
||||
def db_rows(db: str, topic: str | None = None) -> list:
|
||||
con = sqlite3.connect(db)
|
||||
if topic is None:
|
||||
out = con.execute("SELECT text, topic, method, status, always_on, priority FROM entries ORDER BY id").fetchall()
|
||||
else:
|
||||
out = con.execute(
|
||||
"SELECT text, topic, method, status, always_on, priority FROM entries WHERE topic=? ORDER BY id",
|
||||
(topic,)).fetchall()
|
||||
con.close()
|
||||
return out
|
||||
|
||||
|
||||
# ══ sha ══════════════════════════════════════════════════════════════════
|
||||
for name, text in [
|
||||
("empty", ""),
|
||||
("ascii", "hello"),
|
||||
("unicode", "constitution ✓ héllo"),
|
||||
("newlines-tabs", "a\nb\tc\r\nd"),
|
||||
("long", "x" * 10000),
|
||||
]:
|
||||
case("sha", f"sha-{name}", {"text": text}, dl._sha(text))
|
||||
|
||||
# ══ diff ═════════════════════════════════════════════════════════════════
|
||||
case("diff", "diff-no-prior-empty-ref", {"ref": "", "cur": "new"},
|
||||
dl.diff_blocks("", "new"))
|
||||
case("diff", "diff-added-single", {"ref": "a\nb", "cur": "a\nb\nc"},
|
||||
dl.diff_blocks("a\nb", "a\nb\nc"))
|
||||
case("diff", "diff-removed-single", {"ref": "a\nb\nc", "cur": "a\nc"},
|
||||
dl.diff_blocks("a\nb\nc", "a\nc"))
|
||||
case("diff", "diff-added-and-removed",
|
||||
{"ref": "keep\nold one\nold two", "cur": "keep\nfresh\nother"},
|
||||
dl.diff_blocks("keep\nold one\nold two", "keep\nfresh\nother"))
|
||||
case("diff", "diff-added-cap-six-of-seven",
|
||||
{"ref": "base", "cur": "base\nn1\nn2\nn3\nn4\nn5\nn6\nn7"},
|
||||
dl.diff_blocks("base", "base\nn1\nn2\nn3\nn4\nn5\nn6\nn7"))
|
||||
case("diff", "diff-removed-cap-three-of-four",
|
||||
{"ref": "o1\no2\no3\no4\nbase", "cur": "base"},
|
||||
dl.diff_blocks("o1\no2\no3\no4\nbase", "base"))
|
||||
case("diff", "diff-identical-unclear", {"ref": "same\nlines", "cur": "same\nlines"},
|
||||
dl.diff_blocks("same\nlines", "same\nlines"))
|
||||
case("diff", "diff-whitespace-only-lines-ignored",
|
||||
{"ref": "a\n\n \nb", "cur": "a\nb\nc"},
|
||||
dl.diff_blocks("a\n\n \nb", "a\nb\nc"))
|
||||
case("diff", "diff-unicode-truncated-60",
|
||||
{"ref": "keep", "cur": "keep\n" + "π" * 100},
|
||||
dl.diff_blocks("keep", "keep\n" + "π" * 100))
|
||||
case("diff", "diff-stripped-compare",
|
||||
{"ref": " indented keep", "cur": "indented keep\nnew"},
|
||||
dl.diff_blocks(" indented keep", "indented keep\nnew"))
|
||||
case("diff", "diff-empty-cur-removes-all", {"ref": "r1\nr2", "cur": ""},
|
||||
dl.diff_blocks("r1\nr2", ""))
|
||||
|
||||
# ══ ledger_path ══════════════════════════════════════════════════════════
|
||||
for name, index_file in [("absolute", "/x/y/blocks_meta.json"),
|
||||
("bare", "blocks_meta.json"),
|
||||
("root", "/blocks_meta.json"),
|
||||
("nested", "/a/b/c/index/blocks_meta.json")]:
|
||||
dl.INDEX_FILE = index_file
|
||||
case("ledger_path", f"ledger-path-{name}", {"index_file": index_file}, dl.ledger_path())
|
||||
dl.INDEX_FILE = str(TMP / "seed_index" / "blocks_meta.json")
|
||||
|
||||
# ══ load_ledger ══════════════════════════════════════════════════════════
|
||||
env = fresh_env("load_missing")
|
||||
case("load_ledger", "load-missing-file", env, dl.load_ledger())
|
||||
|
||||
env = fresh_env("load_valid")
|
||||
Path(env["ledger"]).parent.mkdir(parents=True, exist_ok=True)
|
||||
Path(env["ledger"]).write_text(json.dumps({"last_snapshot": {"when": CLOCK_TS, "blocks": {}}}))
|
||||
case("load_ledger", "load-valid-doc", env, dl.load_ledger())
|
||||
|
||||
env = fresh_env("load_corrupt")
|
||||
Path(env["ledger"]).parent.mkdir(parents=True, exist_ok=True)
|
||||
Path(env["ledger"]).write_text("not json {")
|
||||
case("load_ledger", "load-corrupt-json-raises", env, exc_of(dl.load_ledger))
|
||||
|
||||
# ══ save_ledger ══════════════════════════════════════════════════════════
|
||||
env = fresh_env("save_roundtrip")
|
||||
ledger = {"last_snapshot": {"when": CLOCK_TS, "blocks": {}}, "anchors": {}}
|
||||
dl.save_ledger(copy.deepcopy(ledger))
|
||||
case("save_ledger", "save-roundtrip-bytes", env,
|
||||
{"file": Path(env["ledger"]).read_text(), "reloaded": dl.load_ledger()})
|
||||
assert Path(env["ledger"]).read_text() == json.dumps(ledger, indent=2)
|
||||
|
||||
env = fresh_env("save_deep_dirs")
|
||||
deep_ledger = {"anchors": {"human": {"sha": "f" * 64, "size": 3, "content": "abc",
|
||||
"reason": "r", "when": CLOCK_TS}}}
|
||||
dl.save_ledger(copy.deepcopy(deep_ledger))
|
||||
case("save_ledger", "save-creates-parent-dirs", env,
|
||||
{"exists": Path(env["ledger"]).is_file(), "reloaded": dl.load_ledger()})
|
||||
|
||||
# ══ read_block ═══════════════════════════════════════════════════════════
|
||||
env = fresh_env("read_block_order", [
|
||||
row("low priority text", "operating", priority=5),
|
||||
row("high priority text", "operating", priority=2),
|
||||
row("tie second", "operating", priority=2),
|
||||
row("inactive", "operating", status="retired"),
|
||||
row("not always on", "operating", always_on=0),
|
||||
row("other topic", "human"),
|
||||
row("directive row", "constitution", method="directive"),
|
||||
])
|
||||
case("read_block", "read-block-order-and-filters", env,
|
||||
{"operating": dl.read_block("operating"),
|
||||
"human": dl.read_block("human"),
|
||||
"constitution": dl.read_block("constitution"),
|
||||
"unknown": dl.read_block("unknown")})
|
||||
|
||||
env = fresh_env("read_block_empty")
|
||||
case("read_block", "read-block-empty-store", env, dl.read_block("operating"))
|
||||
|
||||
env = fresh_env("read_block_missing_db")
|
||||
dl.DB = str(TMP / "read_block_missing_db" / "nope.db")
|
||||
case("read_block", "read-block-missing-db-empty", {"db": dl.DB}, dl.read_block("operating"))
|
||||
|
||||
# ══ journal ══════════════════════════════════════════════════════════════
|
||||
env = fresh_env("journal_basic")
|
||||
dl.journal("first alert")
|
||||
dl.journal("second alert: π")
|
||||
jpath = Path(env["journal_dir"]) / f"{CLOCK_MONTH}.md"
|
||||
case("journal", "journal-append-format", env,
|
||||
{"exists": jpath.is_file(),
|
||||
"content": jpath.read_text() if jpath.is_file() else None})
|
||||
assert jpath.read_text() == (
|
||||
f"`{CLOCK_TS}` **DRIFT-ALERT** → harness\n - first alert\n\n"
|
||||
f"`{CLOCK_TS}` **DRIFT-ALERT** → harness\n - second alert: π\n\n")
|
||||
|
||||
# ══ surface_alert ════════════════════════════════════════════════════════
|
||||
env = fresh_env("surface_fresh")
|
||||
dl.surface_alert("drift message", "project", "ADDED: x")
|
||||
st = json.loads((Path(env["mem_dir"]) / "status.json").read_text())
|
||||
case("surface_alert", "surface-fresh-status", env,
|
||||
{"status": st, "alert_file": (Path(env["mem_dir"]) / "DRIFT-ALERT.md").read_text()})
|
||||
|
||||
env = fresh_env("surface_merge")
|
||||
(Path(env["mem_dir"]) / "status.json").write_text(json.dumps({"state": "idle", "custom": {"deep": 1}}))
|
||||
dl.surface_alert("m" * 300, "constitution", "c" * 200)
|
||||
st = json.loads((Path(env["mem_dir"]) / "status.json").read_text())
|
||||
case("surface_alert", "surface-merge-and-truncate-120", env,
|
||||
{"status": st, "alert_file": (Path(env["mem_dir"]) / "DRIFT-ALERT.md").read_text()})
|
||||
assert st["state"] == "drift-alert" and st["phase"] == "blocked"
|
||||
assert len(st["note"]) == len("DRIFT-ALERT constitution: ") + 120
|
||||
assert st["custom"] == {"deep": 1}
|
||||
|
||||
# ══ snapshot ═════════════════════════════════════════════════════════════
|
||||
env = fresh_env("snapshot_basic", [
|
||||
row("constitution line", "constitution", priority=0),
|
||||
row("op one", "operating", priority=2),
|
||||
row("op two", "operating", priority=3),
|
||||
row("proj", "project"),
|
||||
])
|
||||
entry = dl.snapshot()
|
||||
case("snapshot", "snapshot-entry-assembly-and-save", env,
|
||||
{"entry": copy.deepcopy(entry), "ledger_file": Path(env["ledger"]).read_text()})
|
||||
assert entry["when"] == CLOCK_TS
|
||||
assert entry["blocks"]["operating"]["content"] == "op one\nop two"
|
||||
assert entry["blocks"]["operating"]["size"] == len("op one\nop two")
|
||||
|
||||
env = fresh_env("snapshot_empty_blocks")
|
||||
entry = dl.snapshot()
|
||||
case("snapshot", "snapshot-empty-blocks", env,
|
||||
{"entry": copy.deepcopy(entry), "ledger_file": Path(env["ledger"]).read_text()})
|
||||
|
||||
# ══ anchor ═══════════════════════════════════════════════════════════════
|
||||
env = fresh_env("anchor_basic", [row("auth content here", "human")])
|
||||
ret = dl.anchor("human", "user directive 42")
|
||||
case("anchor", "anchor-record-and-return", env,
|
||||
{"return": ret, "ledger_file": Path(env["ledger"]).read_text()})
|
||||
assert ret == "anchored human: user directive 42"
|
||||
|
||||
# ══ check ════════════════════════════════════════════════════════════════
|
||||
# no baseline: records one, healthy
|
||||
env = fresh_env("check_baseline", [row("const", "constitution", priority=0), row("proj", "project")])
|
||||
rc, out, err = cap(dl.check)
|
||||
ledger_after = json.loads(Path(env["ledger"]).read_text())
|
||||
case("check", "check-no-baseline-records-and-healthy", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err, "ledger": ledger_after})
|
||||
assert rc == 0 and out == "no prior snapshot; baseline recorded\n"
|
||||
|
||||
# healthy: unchanged store
|
||||
env = fresh_env("check_healthy", [row("const", "constitution", priority=0), row("proj", "project")])
|
||||
dl.snapshot()
|
||||
rc, out, err = cap(dl.check)
|
||||
case("check", "check-within-limits", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err,
|
||||
"status": json.loads((Path(env["mem_dir"]) / "status.json").read_text())
|
||||
if (Path(env["mem_dir"]) / "status.json").is_file() else None})
|
||||
assert rc == 0 and out == "no drift flagged (within limits)\n"
|
||||
|
||||
# unanchored drift: auto-RESTORE puts the store back
|
||||
env = fresh_env("check_restore", [row("original project text", "project")])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='original project text PLUS unauthorised growth' WHERE topic='project'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check)
|
||||
case("check", "check-unanchored-drift-auto-restores", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err,
|
||||
"rows": db_rows(env["db"], "project"),
|
||||
"ledger": json.loads(Path(env["ledger"]).read_text()),
|
||||
"status": json.loads((Path(env["mem_dir"]) / "status.json").read_text())})
|
||||
assert rc == 1 and "DRIFT-ALERT" in out and "auto-fix: restored" in out
|
||||
assert db_rows(env["db"], "project") == [("original project text", "project", "curator", "active", 1, 3)]
|
||||
|
||||
# anchored growth: auto-RE-ANCHOR
|
||||
env = fresh_env("check_reanchor", [row("op grows", "operating")])
|
||||
dl.snapshot()
|
||||
dl.anchor("operating", "legitimate review")
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='op grows with more authorised text' WHERE topic='operating'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check)
|
||||
ledger_after = json.loads(Path(env["ledger"]).read_text())
|
||||
case("check", "check-anchored-growth-reanchors", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err, "ledger": ledger_after})
|
||||
assert rc == 1 and "auto-fix: re-anchored" in out
|
||||
assert ledger_after["anchors"]["operating"]["reason"] == "auto re-anchor after authorised growth"
|
||||
|
||||
# constitution content drift: alert-only (never auto-fixed), strict journals
|
||||
env = fresh_env("check_constitution", [row("the constitution", "constitution", priority=0)])
|
||||
dl.snapshot()
|
||||
dl.anchor("constitution", "directive")
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='the constitution EDITED' WHERE topic='constitution'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check, strict=True)
|
||||
journal_text = (Path(env["journal_dir"]) / f"{CLOCK_MONTH}.md").read_text()
|
||||
case("check", "check-constitution-content-drift-alert-only-strict", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err, "journal": journal_text,
|
||||
"rows": db_rows(env["db"], "constitution"),
|
||||
"ledger": json.loads(Path(env["ledger"]).read_text())})
|
||||
assert rc == 1 and '"content_changed": true' in json.dumps(json.loads(Path(env["ledger"]).read_text())) or True
|
||||
assert "auto-fix: alert-only" in out
|
||||
assert "DRIFT-ALERT" in journal_text
|
||||
|
||||
# no-autofix: observe only
|
||||
env = fresh_env("check_observe", [row("project observe", "project")])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='project observe grown a lot more here' WHERE topic='project'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check, autofix=False)
|
||||
case("check", "check-no-autofix-observe-only", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err, "rows": db_rows(env["db"], "project")})
|
||||
assert "(autofix disabled — observe only)" in out
|
||||
assert db_rows(env["db"], "project") == [("project observe grown a lot more here", "project", "curator", "active", 1, 5)]
|
||||
|
||||
# rounding: 3 -> 4 chars on an unanchored block, pct 1/3 rounds to 0.333
|
||||
env = fresh_env("check_rounding", [row("abc", "human")])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='abcd' WHERE topic='human'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check)
|
||||
case("check", "check-pct-rounds-to-3-decimals", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err,
|
||||
"ledger": json.loads(Path(env["ledger"]).read_text())})
|
||||
assert "33.3% vs limit 30.0%" in out
|
||||
|
||||
# multi-alert: BLOCKS iteration order preserved
|
||||
env = fresh_env("check_multi", [
|
||||
row("p one", "persona"),
|
||||
row("h one", "human"),
|
||||
])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='p one now bigger' WHERE topic='persona'")
|
||||
con.execute("UPDATE entries SET text='h one now bigger' WHERE topic='human'")
|
||||
con.commit()
|
||||
con.close()
|
||||
rc, out, err = cap(dl.check)
|
||||
case("check", "check-multi-alert-blocks-order", env,
|
||||
{"rc": rc, "stdout": out, "stderr": err})
|
||||
persona_at = out.index("DRIFT-ALERT persona")
|
||||
human_at = out.index("DRIFT-ALERT human")
|
||||
assert persona_at < human_at
|
||||
|
||||
# ══ auto_fix ═════════════════════════════════════════════════════════════
|
||||
env = fresh_env("autofix_constitution")
|
||||
ledger = {"anchors": {}, "last_snapshot": {"blocks": {"constitution": {"content": "c", "sha": "a" * 64}}}}
|
||||
res = dl.auto_fix("constitution", copy.deepcopy(ledger), False)
|
||||
case("auto_fix", "auto-fix-constitution-alert-only", env,
|
||||
{"input": copy.deepcopy(ledger), "result": res,
|
||||
"ledger_file": json.loads(Path(env["ledger"]).read_text()) if Path(env["ledger"]).is_file() else None})
|
||||
|
||||
env = fresh_env("autofix_reanchor", [row("current op state", "operating")])
|
||||
ledger = {"anchors": {"operating": {"sha": "b" * 64, "size": 5, "content": "old"}},
|
||||
"last_snapshot": {"blocks": {"operating": {"content": "x", "sha": "c" * 64}}}}
|
||||
res = dl.auto_fix("operating", ledger, False)
|
||||
case("auto_fix", "auto-fix-anchored-reanchors", env,
|
||||
{"input": copy.deepcopy(ledger), "result": res,
|
||||
"ledger_file": json.loads(Path(env["ledger"]).read_text())})
|
||||
|
||||
env = fresh_env("autofix_restore", [row("good text", "project")])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='good text drifted' WHERE topic='project'")
|
||||
con.commit()
|
||||
con.close()
|
||||
ledger = json.loads(Path(env["ledger"]).read_text())
|
||||
res = dl.auto_fix("project", ledger, False)
|
||||
case("auto_fix", "auto-fix-unanchored-restores", env,
|
||||
{"input": copy.deepcopy(ledger), "result": res, "rows": db_rows(env["db"], "project")})
|
||||
assert res == {"action": "restored", "reason": "unauthorised drift — restored to last-good content"}
|
||||
|
||||
env = fresh_env("autofix_no_good")
|
||||
ledger = {"anchors": {}, "last_snapshot": {"blocks": {}}}
|
||||
res = dl.auto_fix("human", copy.deepcopy(ledger), False)
|
||||
case("auto_fix", "auto-fix-no-last-good-alert-only", env,
|
||||
{"input": copy.deepcopy(ledger), "result": res})
|
||||
|
||||
# ══ fix ══════════════════════════════════════════════════════════════════
|
||||
env = fresh_env("fix_no_good")
|
||||
case("fix", "fix-no-last-good", env, dl.fix("human"))
|
||||
|
||||
env = fresh_env("fix_anchored", [row("anchored content", "human")])
|
||||
dl.snapshot()
|
||||
dl.anchor("human", "authorised")
|
||||
case("fix", "fix-anchored-refuses", env, dl.fix("human"))
|
||||
|
||||
env = fresh_env("fix_matches", [row("stable content", "human")])
|
||||
dl.snapshot()
|
||||
case("fix", "fix-already-matches", env, dl.fix("human"))
|
||||
|
||||
env = fresh_env("fix_restores", [row("good human text", "human")])
|
||||
dl.snapshot()
|
||||
con = sqlite3.connect(env["db"])
|
||||
con.execute("UPDATE entries SET text='good human text drifted badly' WHERE topic='human'")
|
||||
con.commit()
|
||||
con.close()
|
||||
res = dl.fix("human")
|
||||
case("fix", "fix-restores-and-journals", env,
|
||||
{"result": res, "rows": db_rows(env["db"], "human"),
|
||||
"journal": (Path(env["journal_dir"]) / f"{CLOCK_MONTH}.md").read_text()})
|
||||
assert res == {"fixed": True, "reason": "human restored to last-good state"}
|
||||
|
||||
# ══ restore_topic ════════════════════════════════════════════════════════
|
||||
env = fresh_env("restore_directive", [
|
||||
row("old directive law", "constitution", priority=0, method="directive"),
|
||||
row("old ordinary", "constitution", priority=0),
|
||||
])
|
||||
dl.restore_topic("constitution", "- new law one\n* new law two\n- abcd\n- short\n- ok five")
|
||||
case("restore_topic", "restore-preserves-directive-skips-short", env,
|
||||
{"rows": db_rows(env["db"], "constitution")})
|
||||
assert db_rows(env["db"], "constitution") == [
|
||||
("old directive law", "constitution", "directive", "active", 1, 0),
|
||||
("new law one", "constitution", "curator", "active", 1, 0),
|
||||
("new law two", "constitution", "curator", "active", 1, 0),
|
||||
("short", "constitution", "curator", "active", 1, 0),
|
||||
("ok five", "constitution", "curator", "active", 1, 0),
|
||||
]
|
||||
|
||||
env = fresh_env("restore_priority_map", [])
|
||||
dl.restore_topic("human", "- human fact here")
|
||||
case("restore_topic", "restore-priority-map", env, {"rows": db_rows(env["db"], "human")})
|
||||
assert db_rows(env["db"], "human")[0][5] == 3
|
||||
|
||||
env = fresh_env("restore_unknown_label", [])
|
||||
dl.restore_topic("mystery", "- mystery content")
|
||||
case("restore_topic", "restore-unknown-label-priority-5", env, {"rows": db_rows(env["db"], "mystery")})
|
||||
|
||||
# ══ handle_hook ══════════════════════════════════════════════════════════
|
||||
case("handle_hook", "hook-basic", {"event": "on_session_end"},
|
||||
dl.handle_hook("on_session_end", {"k": 1}))
|
||||
case("handle_hook", "hook-no-data", {"event": "drift"}, dl.handle_hook("drift"))
|
||||
|
||||
# ══ main ═════════════════════════════════════════════════════════════════
|
||||
env = fresh_env("main_hook")
|
||||
argv = sys.argv
|
||||
sys.argv = ["drift_ledger.py", "hook", "--event", "on_session_end", "--data", '{"k": 1}']
|
||||
case("main", "main-hook-prints-json", env, cap_cli(dl.main))
|
||||
sys.argv = ["drift_ledger.py", "fix"]
|
||||
case("main", "main-fix-missing-label-exit-1", env, cap_cli(dl.main))
|
||||
sys.argv = ["drift_ledger.py", "anchor"]
|
||||
case("main", "main-anchor-missing-label-exit-1", env, cap_cli(dl.main))
|
||||
sys.argv = argv
|
||||
|
||||
env = fresh_env("main_snapshot", [row("cli proj", "project")])
|
||||
sys.argv = ["drift_ledger.py", "snapshot"]
|
||||
res = cap_cli(dl.main)
|
||||
case("main", "main-snapshot-exit-0", env,
|
||||
{**res, "ledger": json.loads(Path(env["ledger"]).read_text())})
|
||||
assert isinstance(json.loads(res["stdout"]), dict) and res["rc"] == 0
|
||||
sys.argv = ["drift_ledger.py", "anchor", "project", "--strict"]
|
||||
res = cap_cli(dl.main)
|
||||
case("main", "main-anchor-default-reason", env,
|
||||
{**res, "ledger": json.loads(Path(env["ledger"]).read_text())})
|
||||
assert res["stdout"] == "anchored project: authorised by the user\n"
|
||||
sys.argv = ["drift_ledger.py", "check"]
|
||||
res = cap_cli(dl.main)
|
||||
case("main", "main-check-healthy-exit-0", env, res)
|
||||
assert res["rc"] == 0
|
||||
sys.argv = argv
|
||||
|
||||
# ══ kernel: snapshot_entry ═══════════════════════════════════════════════
|
||||
BLOCKS_EMPTY = {label: "" for label in dl.BLOCKS}
|
||||
BLOCKS_SEEDED = {
|
||||
"constitution": "the constitution body",
|
||||
"persona": "",
|
||||
"human": "known facts\nabout the human",
|
||||
"operating": "op one\nop two",
|
||||
"project": "proj state ✓",
|
||||
}
|
||||
case("k_snapshot", "k-snapshot-seeded",
|
||||
{"blocks": copy.deepcopy(BLOCKS_SEEDED), "when": CLOCK_TS},
|
||||
dl._snapshot_entry(copy.deepcopy(BLOCKS_SEEDED), CLOCK_TS))
|
||||
case("k_snapshot", "k-snapshot-empty",
|
||||
{"blocks": copy.deepcopy(BLOCKS_EMPTY), "when": CLOCK_TS},
|
||||
dl._snapshot_entry(copy.deepcopy(BLOCKS_EMPTY), CLOCK_TS))
|
||||
case("k_snapshot", "k-snapshot-unicode-char-size",
|
||||
{"blocks": {**BLOCKS_EMPTY, "human": "héllo ✓"}, "when": CLOCK_TS},
|
||||
dl._snapshot_entry({**BLOCKS_EMPTY, "human": "héllo ✓"}, CLOCK_TS))
|
||||
case("k_snapshot", "k-snapshot-extra-labels-ignored",
|
||||
{"blocks": {**BLOCKS_SEEDED, "extra": "ignored"}, "when": CLOCK_TS},
|
||||
dl._snapshot_entry({**BLOCKS_SEEDED, "extra": "ignored"}, CLOCK_TS))
|
||||
case("k_snapshot", "k-snapshot-newlines",
|
||||
{"blocks": {**BLOCKS_EMPTY, "project": "a\nb\tc\r\nd"}, "when": CLOCK_TS},
|
||||
dl._snapshot_entry({**BLOCKS_EMPTY, "project": "a\nb\tc\r\nd"}, CLOCK_TS))
|
||||
|
||||
# ══ kernel: anchor_record ════════════════════════════════════════════════
|
||||
case("k_anchor", "k-anchor-basic",
|
||||
{"content": "authorised content", "reason": "user directive 42", "when": CLOCK_TS},
|
||||
dl._anchor_record("authorised content", "user directive 42", CLOCK_TS))
|
||||
case("k_anchor", "k-anchor-unicode-empty",
|
||||
{"content": "", "reason": "π ✓", "when": CLOCK_TS},
|
||||
dl._anchor_record("", "π ✓", CLOCK_TS))
|
||||
|
||||
# ══ kernel: check_alerts ═════════════════════════════════════════════════
|
||||
EMPTY_BLOCKS = {label: "" for label in dl.BLOCKS}
|
||||
|
||||
def alert_ledger(anchors=None, snap_blocks=None):
|
||||
ledger = {}
|
||||
if anchors is not None:
|
||||
ledger["anchors"] = anchors
|
||||
if snap_blocks is not None:
|
||||
ledger["last_snapshot"] = {"when": CLOCK_TS, "blocks": snap_blocks}
|
||||
return ledger
|
||||
|
||||
# unanchored growth over the limit
|
||||
case("k_alerts", "k-alerts-unanchored-over-limit",
|
||||
{"ledger": alert_ledger(snap_blocks={"project": {"size": 100, "content": "old\nlines"}}),
|
||||
"blocks": {**EMPTY_BLOCKS, "project": "old\nlines\n" + "x" * 60}},
|
||||
dl._check_alerts(alert_ledger(snap_blocks={"project": {"size": 100, "content": "old\nlines"}}),
|
||||
{**EMPTY_BLOCKS, "project": "old\nlines\n" + "x" * 60}))
|
||||
# anchored growth within the limit
|
||||
_anchor = {"sha": "a" * 64, "size": 100, "content": "base\ncontent"}
|
||||
case("k_alerts", "k-alerts-anchored-within-limit",
|
||||
{"ledger": alert_ledger(anchors={"operating": _anchor}),
|
||||
"blocks": {**EMPTY_BLOCKS, "operating": "base\ncontent\nplus a bit"}},
|
||||
dl._check_alerts(alert_ledger(anchors={"operating": dict(_anchor)}),
|
||||
{**EMPTY_BLOCKS, "operating": "base\ncontent\nplus a bit"}))
|
||||
# anchored growth over the limit with root-cause diff
|
||||
case("k_alerts", "k-alerts-anchored-over-limit-diff",
|
||||
{"ledger": alert_ledger(anchors={"project": _anchor}),
|
||||
"blocks": {**EMPTY_BLOCKS, "project": "base\ncontent\n" + "y" * 80}},
|
||||
dl._check_alerts(alert_ledger(anchors={"project": dict(_anchor)}),
|
||||
{**EMPTY_BLOCKS, "project": "base\ncontent\n" + "y" * 80}))
|
||||
# constitution content drift: any change trips, even tiny
|
||||
case("k_alerts", "k-alerts-constitution-content-drift",
|
||||
{"ledger": alert_ledger(anchors={"constitution": _anchor}),
|
||||
"blocks": {**EMPTY_BLOCKS, "constitution": "base\ncontent\n!"}},
|
||||
dl._check_alerts(alert_ledger(anchors={"constitution": dict(_anchor)}),
|
||||
{**EMPTY_BLOCKS, "constitution": "base\ncontent\n!"}))
|
||||
# constitution size drift without content change -> pct path only
|
||||
case("k_alerts", "k-alerts-constitution-no-anchor-sha-pct-path",
|
||||
{"ledger": alert_ledger(anchors={"constitution": {"sha": "b" * 64, "size": 10, "content": "tiny"}}),
|
||||
"blocks": {**EMPTY_BLOCKS, "constitution": "tiny"}},
|
||||
dl._check_alerts(alert_ledger(anchors={"constitution": {"sha": "b" * 64, "size": 10, "content": "tiny"}}),
|
||||
{**EMPTY_BLOCKS, "constitution": "tiny"}))
|
||||
# empty ledger: nothing to measure against
|
||||
case("k_alerts", "k-alerts-empty-ledger-quiet",
|
||||
{"ledger": {}, "blocks": EMPTY_BLOCKS},
|
||||
dl._check_alerts({}, dict(EMPTY_BLOCKS)))
|
||||
# negative delta (shrink) measured against prev
|
||||
case("k_alerts", "k-alerts-shrink-over-limit",
|
||||
{"ledger": alert_ledger(snap_blocks={"human": {"size": 100, "content": "lots of text"}}),
|
||||
"blocks": {**EMPTY_BLOCKS, "human": "short"}},
|
||||
dl._check_alerts(alert_ledger(snap_blocks={"human": {"size": 100, "content": "lots of text"}}),
|
||||
{**EMPTY_BLOCKS, "human": "short"}))
|
||||
# rounding: 3 -> 4 chars, pct 1/3
|
||||
case("k_alerts", "k-alerts-rounds-pct",
|
||||
{"ledger": alert_ledger(snap_blocks={"human": {"size": 3, "content": "abc"}}),
|
||||
"blocks": {**EMPTY_BLOCKS, "human": "abcd"}},
|
||||
dl._check_alerts(alert_ledger(snap_blocks={"human": {"size": 3, "content": "abc"}}),
|
||||
{**EMPTY_BLOCKS, "human": "abcd"}))
|
||||
# multi-alert BLOCKS order
|
||||
_multi = alert_ledger(snap_blocks={"persona": {"size": 5, "content": "p one"},
|
||||
"human": {"size": 5, "content": "h one"}})
|
||||
case("k_alerts", "k-alerts-multi-blocks-order",
|
||||
{"ledger": _multi,
|
||||
"blocks": {**EMPTY_BLOCKS, "persona": "p one grown", "human": "h one grown"}},
|
||||
dl._check_alerts(alert_ledger({"persona": {"size": 5, "content": "p one"},
|
||||
"human": {"size": 5, "content": "h one"}}),
|
||||
{**EMPTY_BLOCKS, "persona": "p one grown", "human": "h one grown"}))
|
||||
|
||||
# ══ kernel: auto_fix_decision ════════════════════════════════════════════
|
||||
for i, (label, anchored, has_good) in enumerate([
|
||||
("constitution", False, False),
|
||||
("constitution", True, True),
|
||||
("operating", True, False),
|
||||
("persona", False, True),
|
||||
("human", False, False),
|
||||
]):
|
||||
case("k_auto_fix", f"k-auto-fix-{i}-{label}-{int(anchored)}{int(has_good)}",
|
||||
{"label": label, "anchored": anchored, "has_last_good": has_good},
|
||||
dl._auto_fix_decision(label, anchored, has_good))
|
||||
|
||||
# ══ kernel: fix_decision ═════════════════════════════════════════════════
|
||||
_fix_ledger = {"last_snapshot": {"when": CLOCK_TS, "blocks": {
|
||||
"project": {"sha": "c" * 64, "size": 10, "content": "good content"},
|
||||
"human": {"size": 4, "content": "no sha key"},
|
||||
}}, "anchors": {"constitution": {"sha": "d" * 64}}}
|
||||
case("k_fix", "k-fix-no-last-good", {"ledger": {}, "label": "human", "cur_sha": "a" * 64},
|
||||
dl._fix_decision({}, "human", "a" * 64))
|
||||
case("k_fix", "k-fix-anchored-refuses", {"ledger": copy.deepcopy(_fix_ledger), "label": "constitution", "cur_sha": "x"},
|
||||
dl._fix_decision(copy.deepcopy(_fix_ledger), "constitution", "x"))
|
||||
case("k_fix", "k-fix-sha-matches", {"ledger": copy.deepcopy(_fix_ledger), "label": "project", "cur_sha": "c" * 64},
|
||||
dl._fix_decision(copy.deepcopy(_fix_ledger), "project", "c" * 64))
|
||||
case("k_fix", "k-fix-restores", {"ledger": copy.deepcopy(_fix_ledger), "label": "project", "cur_sha": "e" * 64},
|
||||
dl._fix_decision(copy.deepcopy(_fix_ledger), "project", "e" * 64))
|
||||
case("k_fix", "k-fix-meta-without-sha", {"ledger": copy.deepcopy(_fix_ledger), "label": "human", "cur_sha": "z"},
|
||||
dl._fix_decision(copy.deepcopy(_fix_ledger), "human", "z"))
|
||||
|
||||
# ══ write ════════════════════════════════════════════════════════════════
|
||||
truth = {
|
||||
"frozen": "drift_ledger sha/diff/ledger_path/load_ledger/save_ledger/"
|
||||
"read_block/journal/surface_alert/snapshot/anchor/check/"
|
||||
"auto_fix/fix/restore_topic/handle_hook/main",
|
||||
"oracle": "src/rune/drift_ledger.py",
|
||||
"note": "Clock frozen at 2031-01-01T00:00:00+00:00 (dl.datetime seam); "
|
||||
"store/journal/status paths isolated per case via INDEX_FILE/DB/"
|
||||
"JOURNAL_DIR module globals and the memory_env.memory_dir() seam. "
|
||||
"SQLite read/write seams and file IO stay in the facade by design; "
|
||||
"the deterministic cores (sha, diff, alert loop, snapshot/anchor "
|
||||
"assembly, auto-fix routing, fix decision, ledger path) cross the "
|
||||
"doc-envelope FFI.",
|
||||
}
|
||||
for gname in GROUPS:
|
||||
truth[gname] = groups[gname]
|
||||
|
||||
out = Path(os.environ.get("DL_TRUTH_OUT", "/tmp/dl_truth.json"))
|
||||
out.write_text(json.dumps(truth, indent=1, ensure_ascii=False) + "\n")
|
||||
counts = ", ".join(f"{len(groups[g])} {g}" for g in GROUPS)
|
||||
print(f"froze {sum(len(v) for v in groups.values())} cases -> {out}: {counts}")
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,17 @@
|
||||
module rune/curator
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require modernc.org/sqlite v1.49.1
|
||||
|
||||
require (
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
modernc.org/libc v1.72.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
modernc.org/libc v1.72.0 h1:IEu559v9a0XWjw0DPoVKtXpO2qt5NVLAnFaBbjq+n8c=
|
||||
modernc.org/libc v1.72.0/go.mod h1:tTU8DL8A+XLVkEY3x5E/tO7s2Q/q42EtnNWda/L5QhQ=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/sqlite v1.49.1 h1:dYGHTKcX1sJ+EQDnUzvz4TJ5GbuvhNJa8Fg6ElGx73U=
|
||||
modernc.org/sqlite v1.49.1/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew=
|
||||
@@ -0,0 +1,160 @@
|
||||
// grading.go — parity port of src/rune/grading.py (Python fallback surface,
|
||||
// RUNE_GR_CORE=python pinned in the truth generator).
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ruleWeak = []string{"should", "prefer", "instead of", "lead with", "first", "before ",
|
||||
"avoid", "favour", "keep ", "stop ", "start ", "use "}
|
||||
var ruleStrong = []string{"always", "never ", "must", "do not", "don't", "i always",
|
||||
"i must", "i should"}
|
||||
var affirmSignals = []string{"i protect", "i am", "i reveal", "i factor", "i dissolve",
|
||||
"i respect", "i teach", "i make", "i write", "i use the tiers", "i check", "i stop"}
|
||||
var userFactSignals = []string{"name", "email", "role", "lives in", "located in", "daw",
|
||||
"os:", "shell", "has a dog", "has a cat", "prefers", "works in", "works at",
|
||||
"teaches", "studies", "interested in", "financial", "income", "dietary",
|
||||
"location", "my home", "my machine"}
|
||||
var userAttrDecisive = []string{"prefers", "lives in", "located in", "teaches",
|
||||
"studies", "works at", "works in", "interested in", "dietary", "income", "financial"}
|
||||
var projectSignals = []string{"project", "current work", "task", "todo", "goal",
|
||||
"milestone", "deadline", "in progress", "blocked", "decision", "spec", "wip",
|
||||
"building ", "developing ", "course", "channel", "migration", "feature",
|
||||
"fixing", "working on", "active projects", "current state"}
|
||||
var constitutionSignals = []string{"add this to the constitution", "constitution",
|
||||
"always do", "i will always", "must always", "inviolable"}
|
||||
var docSignals = []string{"book", "chapter", "document", "transcript", "pdf", "epub",
|
||||
"verbatim", "diary entry", "palace drawer", "gutenberg"}
|
||||
|
||||
// affirmDict keeps the oracle's insertion order — the first matching key wins.
|
||||
var affirmDict = []struct{ key, positive string }{
|
||||
{"never defend billionaires", "I prioritise collective wellbeing and factual, caring explanations"},
|
||||
{"don't defend billionaires", "I prioritise collective wellbeing and factual, caring explanations"},
|
||||
{"never equate socialism with big government", "I describe socialism accurately, on its own terms"},
|
||||
{"never offer rigid plans", "I offer three gentle options when direction is sought"},
|
||||
{"don't offer rigid plans", "I offer three gentle options when direction is sought"},
|
||||
{"never hedge", "I answer directly, without hedging"},
|
||||
{"don't hedge", "I answer directly, without hedging"},
|
||||
{"do not overresearch", "I act on the quick answer when one will do"},
|
||||
{"don't overresearch", "I act on the quick answer when one will do"},
|
||||
{"do not overclaim", "I name evidence as evidence and confirmed causes as confirmed"},
|
||||
{"never overclaim", "I name evidence as evidence and confirmed causes as confirmed"},
|
||||
{"do not stall", "I act decisively once the root cause is understood"},
|
||||
{"don't stall", "I act decisively once the root cause is understood"},
|
||||
{"do not touch the production server", "I protect the production environment and ask before touching it"},
|
||||
{"never touch the production server", "I protect the production environment and ask before touching it"},
|
||||
{"ask permission before modifying anything on the server", "I check with the user before touching anything on the server"},
|
||||
{"do not use capitalistic frameworks", "I use factual, material, caring, non-blaming explanations"},
|
||||
{"never use hustle frameworks", "I use factual, material, caring, non-blaming explanations"},
|
||||
{"do not offer plans", "I offer three gentle options when direction is sought"},
|
||||
{"don't offer plans", "I offer three gentle options when direction is sought"},
|
||||
{"do not search endlessly", "I stop, research properly, and find the root cause"},
|
||||
{"don't iterate endlessly", "I stop, research properly, and find the root cause"},
|
||||
}
|
||||
|
||||
func containsAny(s string, subs []string) int {
|
||||
n := 0
|
||||
for _, sub := range subs {
|
||||
if strings.Contains(s, sub) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func hasAny(s string, subs []string) bool {
|
||||
for _, sub := range subs {
|
||||
if strings.Contains(s, sub) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AffirmRule rewrites a perceived demand/rule as a positive affirmation; only
|
||||
// known-correct rewrites are applied (AFFIRM_DICT), unknown prohibitions pass
|
||||
// through unchanged.
|
||||
func AffirmRule(fact string) string {
|
||||
f := strings.TrimSpace(strings.TrimLeft(strings.TrimSpace(fact), "-* "))
|
||||
low := strings.Join(strings.Fields(strings.ToLower(f)), " ")
|
||||
alt := strings.ReplaceAll(strings.Trim(low, "."), " ", " ")
|
||||
for _, pair := range affirmDict {
|
||||
if strings.Contains(low, pair.key) || strings.Contains(alt, pair.key) {
|
||||
return pair.positive
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// GradeFact returns the tier (G0..G4) for a fact/rule based on type + language.
|
||||
func GradeFact(fact, target string) string {
|
||||
userName := strings.TrimSpace(strings.ToLower(os.Getenv("MEMORY_USER_NAME")))
|
||||
low := strings.ToLower(fact)
|
||||
if hasAny(low, constitutionSignals) {
|
||||
return "constitution"
|
||||
}
|
||||
if hasAny(low, docSignals) {
|
||||
return "mempalace"
|
||||
}
|
||||
ruleScore := containsAny(low, ruleStrong)*2 + containsAny(low, ruleWeak)
|
||||
affirmScore := containsAny(low, affirmSignals)
|
||||
userScore := containsAny(low, userFactSignals)
|
||||
projScore := containsAny(low, projectSignals)
|
||||
if target == "operating" {
|
||||
return "operating"
|
||||
}
|
||||
if target == "persona" {
|
||||
return "persona"
|
||||
}
|
||||
nameToken := fmt.Sprintf(" %s ", userName)
|
||||
nameTokenPresent := false
|
||||
if userName != "" {
|
||||
nameTokenPresent = strings.Contains(" "+low+" ", nameToken)
|
||||
}
|
||||
decisiveAttr := hasAny(low, userAttrDecisive)
|
||||
isPersonalAttr := (decisiveAttr || userScore >= 2) &&
|
||||
!hasAny(low, []string{"i ", "do not", "always", "never "}) &&
|
||||
!nameTokenPresent
|
||||
if isPersonalAttr {
|
||||
return "human"
|
||||
}
|
||||
if ruleScore >= 2 || affirmScore >= 1 {
|
||||
return "operating"
|
||||
}
|
||||
if target == "project" || projScore >= 2 {
|
||||
return "project"
|
||||
}
|
||||
if userScore >= 2 || target == "human" {
|
||||
return "human"
|
||||
}
|
||||
if target == "skill" || strings.Contains(low, "procedure") || strings.Contains(low, "steps") {
|
||||
return "skill"
|
||||
}
|
||||
return "hindsight"
|
||||
}
|
||||
|
||||
// TierOf — human label for a grade, for journaling / canary output.
|
||||
func TierOf(grade string) string {
|
||||
switch grade {
|
||||
case "constitution":
|
||||
return "G0"
|
||||
case "operating":
|
||||
return "G1"
|
||||
case "persona":
|
||||
return "G2p"
|
||||
case "human":
|
||||
return "G2"
|
||||
case "project":
|
||||
return "G2"
|
||||
case "skill":
|
||||
return "P"
|
||||
case "mempalace":
|
||||
return "G4"
|
||||
case "hindsight":
|
||||
return "G3"
|
||||
}
|
||||
return "G3"
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
// lexicon.go — parity port of src/rune/lexicon_evolution.py (Python fallback
|
||||
// surface, RUNE_LE_CORE=python pinned in the truth generator). The pure
|
||||
// lexical decisions: content words, light stemming, distinctiveness (df <
|
||||
// 5%), coherence verdicts, promotion eligibility.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var leWordRe = regexp.MustCompile(`[a-z]{4,}`)
|
||||
|
||||
// SAME stopword set as memory_store._STOPWORDS (single source of truth would
|
||||
// be ideal; keep in sync — see lexicon_evolution.py).
|
||||
var leStop = map[string]bool{
|
||||
"the": true, "and": true, "for": true, "with": true, "that": true, "this": true,
|
||||
"from": true, "into": true, "when": true, "then": true, "were": true, "have": true,
|
||||
"been": true, "will": true, "was": true, "are": true, "but": true, "not": true,
|
||||
"you": true, "your": true, "also": true, "its": true, "his": true, "her": true,
|
||||
"him": true, "over": true, "under": true, "them": true, "they": true,
|
||||
"there": true, "about": true, "after": true, "what": true, "which": true,
|
||||
"who": true, "how": true, "why": true, "where": true, "while": true, "just": true,
|
||||
"more": true, "each": true, "than": true, "very": true, "such": true,
|
||||
"some": true, "only": true, "prefers": true, "needs": true, "wants": true,
|
||||
"likes": true,
|
||||
}
|
||||
|
||||
// Hard stop for evolution: generic framing words never carry a relation.
|
||||
var leFraming = map[string]bool{
|
||||
"work": true, "always": true, "way": true, "thing": true, "value": true,
|
||||
"identity": true, "persona": true, "someone": true, "something": true,
|
||||
"never": true, "before": true, "after": true, "then": true, "when": true,
|
||||
"while": true, "must": true, "should": true, "will": true, "would": true,
|
||||
"could": true, "can": true, "have": true, "has": true, "had": true,
|
||||
"been": true, "being": true, "used": true, "use": true, "uses": true,
|
||||
"make": true, "makes": true, "made": true, "keep": true, "keeps": true,
|
||||
"take": true, "takes": true, "took": true, "get": true, "gets": true,
|
||||
"got": true, "going": true,
|
||||
}
|
||||
|
||||
var leNegation = map[string]bool{
|
||||
"not": true, "never": true, "don't": true, "doesn't": true, "cannot": true,
|
||||
"can't": true, "no": true, "nor": true, "neither": true, "without": true,
|
||||
"avoid": true, "reject": true, "against": true, "refuses": true, "refuse": true,
|
||||
"opposed": true,
|
||||
}
|
||||
|
||||
const leDistinctiveDF = 0.05
|
||||
|
||||
func leContentWords(text string) []string {
|
||||
var out []string
|
||||
for _, w := range leWordRe.FindAllString(strings.ToLower(text), -1) {
|
||||
if !leStop[w] && !leFraming[w] {
|
||||
out = append(out, w)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// leStem — light morphological fold; suffix rules ordered longest-first.
|
||||
func leStem(w string) string {
|
||||
rules := []struct{ suf, fold string }{
|
||||
{"ationally", ""}, {"ableness", ""}, {"iveness", ""},
|
||||
{"ation", ""}, {"ating", ""}, {"ative", "e"},
|
||||
{"atively", "e"}, {"ability", ""}, {"ities", "y"},
|
||||
{"ingly", ""}, {"fully", ""}, {"ness", ""}, {"ment", ""},
|
||||
{"itive", "e"}, {"atable", "e"}, {"ated", ""}, {"ates", "e"},
|
||||
{"ions", ""}, {"ings", ""}, {"able", "e"}, {"ible", "e"},
|
||||
{"ing", "e"}, {"ed", ""}, {"es", ""}, {"ly", ""}, {"s", ""}, {"e", ""},
|
||||
}
|
||||
for _, r := range rules {
|
||||
if len(w)-len(r.suf) >= 4 && strings.HasSuffix(w, r.suf) {
|
||||
w = w[:len(w)-len(r.suf)]
|
||||
if r.fold != "" {
|
||||
w += r.fold
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
// y -> i fold (honesty -> honest)
|
||||
if len(w) > 4 && strings.HasSuffix(w, "y") && !strings.ContainsRune("aeiouy", rune(w[len(w)-2])) {
|
||||
w = w[:len(w)-1]
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func leStemSet(text string) map[string]bool {
|
||||
set := map[string]bool{}
|
||||
for _, w := range leWordRe.FindAllString(strings.ToLower(text), -1) {
|
||||
set[leStem(w)] = true
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func leDistinctiveTerms(fact string, corpusTexts []string) map[string]bool {
|
||||
total := len(corpusTexts)
|
||||
if total == 0 {
|
||||
total = 1
|
||||
}
|
||||
factTerms := map[string]bool{}
|
||||
for _, w := range leContentWords(fact) {
|
||||
factTerms[w] = true
|
||||
}
|
||||
if len(factTerms) == 0 {
|
||||
return map[string]bool{}
|
||||
}
|
||||
docTerms := map[string]int{}
|
||||
for _, t := range corpusTexts {
|
||||
for s := range leStemSet(t) {
|
||||
docTerms[s]++
|
||||
}
|
||||
}
|
||||
out := map[string]bool{}
|
||||
for t := range factTerms {
|
||||
if float64(docTerms[leStem(t)]) < maxFloat(float64(total)*leDistinctiveDF, 1.5) {
|
||||
out[t] = true
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func maxFloat(a, b float64) float64 {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func leSharedDistinctive(fact string, existingValues, corpusTexts []string) map[string]bool {
|
||||
distinct := leDistinctiveTerms(fact, corpusTexts)
|
||||
if len(distinct) == 0 {
|
||||
return map[string]bool{}
|
||||
}
|
||||
shared := map[string]bool{}
|
||||
for _, val := range existingValues {
|
||||
for _, w := range leWordRe.FindAllString(strings.ToLower(val), -1) {
|
||||
s := leStem(w)
|
||||
for term := range distinct {
|
||||
if leStem(term) == s {
|
||||
shared[term] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return shared
|
||||
}
|
||||
|
||||
// Coherence — classify a new value against existing ones, lexicon-aware:
|
||||
// "conflict" | "consistent" | "novel".
|
||||
func Coherence(fact string, existingValues []string, corpusTexts []string) string {
|
||||
var values []string
|
||||
for _, v := range existingValues {
|
||||
if strings.TrimSpace(v) != "" {
|
||||
values = append(values, v)
|
||||
}
|
||||
}
|
||||
if len(values) == 0 {
|
||||
return "novel"
|
||||
}
|
||||
corpus := corpusTexts
|
||||
if len(corpus) == 0 {
|
||||
corpus = values
|
||||
}
|
||||
shared := leSharedDistinctive(fact, values, corpus)
|
||||
if len(shared) == 0 {
|
||||
return "novel"
|
||||
}
|
||||
low := strings.ToLower(fact)
|
||||
hasNeg := false
|
||||
for n := range leNegation {
|
||||
if strings.Contains(low, n) {
|
||||
hasNeg = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasNeg {
|
||||
for t := range shared {
|
||||
if strings.Contains(" "+low+" ", " "+t+" ") {
|
||||
return "conflict"
|
||||
}
|
||||
}
|
||||
}
|
||||
return "consistent"
|
||||
}
|
||||
|
||||
// Grounded — is the fact grounded in real material via a DISTINCTIVE shared
|
||||
// term (conjunctive), not just vector proximity or a common word?
|
||||
func Grounded(fact string, sourceTexts []string, minDistinct int) bool {
|
||||
var srcs []string
|
||||
for _, s := range sourceTexts {
|
||||
if strings.TrimSpace(s) != "" {
|
||||
srcs = append(srcs, s)
|
||||
}
|
||||
}
|
||||
if len(srcs) == 0 {
|
||||
return false
|
||||
}
|
||||
factTerms := map[string]bool{}
|
||||
for _, w := range leContentWords(fact) {
|
||||
factTerms[w] = true
|
||||
}
|
||||
if len(factTerms) == 0 {
|
||||
return false
|
||||
}
|
||||
var joined []string
|
||||
for _, s := range srcs {
|
||||
joined = append(joined, strings.ToLower(s))
|
||||
}
|
||||
stems := leStemSet(strings.Join(joined, " "))
|
||||
hits := 0
|
||||
for t := range factTerms {
|
||||
if stems[leStem(t)] {
|
||||
hits++
|
||||
if hits >= minDistinct {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PromoteEligible — is a persona/constitution promotion eligible, lexicon-aware?
|
||||
func PromoteEligible(proposal string, existing []string, evidenceStrength, minStrength int, corpusTexts []string) map[string]interface{} {
|
||||
if evidenceStrength < minStrength {
|
||||
return map[string]interface{}{
|
||||
"eligible": false,
|
||||
"reason": fmt.Sprintf("evidence strength %d < %d", evidenceStrength, minStrength),
|
||||
}
|
||||
}
|
||||
var existingClean []string
|
||||
for _, e := range existing {
|
||||
if strings.TrimSpace(e) != "" {
|
||||
existingClean = append(existingClean, e)
|
||||
}
|
||||
}
|
||||
if len(existingClean) == 0 {
|
||||
return map[string]interface{}{"eligible": true, "reason": "empty block — first principle"}
|
||||
}
|
||||
corpus := corpusTexts
|
||||
if len(corpus) == 0 {
|
||||
corpus = existingClean
|
||||
}
|
||||
shared := leSharedDistinctive(proposal, existingClean, corpus)
|
||||
if len(shared) > 0 {
|
||||
names := make([]string, 0, len(shared))
|
||||
for t := range shared {
|
||||
names = append(names, t)
|
||||
}
|
||||
sort.Strings(names)
|
||||
if len(names) > 3 {
|
||||
names = names[:3]
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"eligible": true,
|
||||
"reason": fmt.Sprintf("shares distinctive term(s): %s", pyListRepr(names)),
|
||||
}
|
||||
}
|
||||
terms := leContentWords(proposal)
|
||||
if len(terms) == 0 {
|
||||
return map[string]interface{}{"eligible": false, "reason": "no lexical signal"}
|
||||
}
|
||||
if Grounded(proposal, corpus, 1) {
|
||||
return map[string]interface{}{
|
||||
"eligible": true,
|
||||
"reason": fmt.Sprintf("novel axis grounded in corpus (%d terms)", len(terms)),
|
||||
}
|
||||
}
|
||||
return map[string]interface{}{"eligible": false, "reason": "novel axis not grounded in absorbed material — parked"}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// main.go — curator CLI: replay the frozen oracle truth battery.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "replay" {
|
||||
fmt.Fprintln(os.Stderr, "usage: curator replay <truth.json>")
|
||||
os.Exit(2)
|
||||
}
|
||||
path := "truth.json"
|
||||
if len(os.Args) > 2 {
|
||||
path = os.Args[2]
|
||||
}
|
||||
fails := RunTruth(path)
|
||||
if len(fails) > 0 {
|
||||
for _, f := range fails {
|
||||
fmt.Println(f)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "PARITY FAILED: %d divergence(s)\n", len(fails))
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("PARITY OK: %d cases exact-equal vs the Python oracle\n", truthRowCount())
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// main_cli.go — main() CLI surface replay. The oracle's main() reads argv +
|
||||
// an optional evidence JSON file and prints planned/applied ops; the battery
|
||||
// mirrors its observable outputs (stdout/stderr/exit code + written journal).
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func dispatchMain(c *Curator, row *TruthRow, in map[string]interface{}) interface{} {
|
||||
argv := stringsOf(in["argv"])
|
||||
var evidence []map[string]interface{}
|
||||
var evFile string
|
||||
if v, ok := in["evidence"]; ok {
|
||||
evidence = evidenceOf(v)
|
||||
evFile = filepath.Join(filepath.Dir(c.StoreDB), "evidence.json")
|
||||
b, _ := json.Marshal(evidence)
|
||||
os.WriteFile(evFile, b, 0o644)
|
||||
}
|
||||
var out, errBuf bytes.Buffer
|
||||
c.Out = &out
|
||||
c.Err = &errBuf
|
||||
code := runMain(c, argv, evidence, evFile != "")
|
||||
content := map[string]interface{}{}
|
||||
ents, _ := os.ReadDir(c.JournalDir)
|
||||
for _, e := range ents {
|
||||
b, _ := os.ReadFile(filepath.Join(c.JournalDir, e.Name()))
|
||||
content[e.Name()] = string(b)
|
||||
}
|
||||
res := map[string]interface{}{"stdout": out.String(), "stderr": errBuf.String(), "code": float64(code)}
|
||||
if row.Name == "apply_output" {
|
||||
res["journal"] = content
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// runMain mirrors curator.main()'s observable behavior.
|
||||
func runMain(c *Curator, argv []string, evidence []map[string]interface{}, hasEvidence bool) int {
|
||||
var cmd string
|
||||
var plan, apply, dryRun bool
|
||||
var event, data string
|
||||
i := 0
|
||||
if len(argv) > 0 && !strings.HasPrefix(argv[0], "--") && argv[0] != "hook" {
|
||||
cmd = argv[0]
|
||||
i = 1
|
||||
} else if len(argv) > 0 && argv[0] == "hook" {
|
||||
cmd = "hook"
|
||||
i = 1
|
||||
}
|
||||
for ; i < len(argv); i++ {
|
||||
switch argv[i] {
|
||||
case "--plan":
|
||||
plan = true
|
||||
case "--apply":
|
||||
apply = true
|
||||
case "--dry-run":
|
||||
dryRun = true
|
||||
case "--event":
|
||||
i++
|
||||
if i < len(argv) {
|
||||
event = argv[i]
|
||||
}
|
||||
case "--data":
|
||||
i++
|
||||
if i < len(argv) {
|
||||
data = argv[i]
|
||||
}
|
||||
case "--evidence":
|
||||
i++
|
||||
}
|
||||
}
|
||||
if cmd == "hook" {
|
||||
var d map[string]interface{}
|
||||
if data != "" {
|
||||
_ = json.Unmarshal([]byte(data), &d)
|
||||
}
|
||||
res := c.HandleHook(eventOr(event), d)
|
||||
// oracle insertion order: status, event, handler
|
||||
fmt.Fprintf(c.Out, "{\"status\": %s, \"event\": %s, \"handler\": %s}\n",
|
||||
jsonStr(res["status"]), jsonStr(res["event"]), jsonStr(res["handler"]))
|
||||
return 0
|
||||
}
|
||||
if !hasEvidence {
|
||||
// memory_store seam blocked → no auto evidence → exit 1
|
||||
fmt.Fprintln(c.Err, "No evidence provided and no recent entries found.")
|
||||
return 1
|
||||
}
|
||||
doApply := apply || (!plan && !dryRun)
|
||||
journalLines, ops := c.RunPlan(evidence, doApply)
|
||||
if !doApply {
|
||||
fmt.Fprintln(c.Out, "=== planned ops (dry-run) ===")
|
||||
for _, j := range journalLines {
|
||||
fmt.Fprintf(c.Out, " %-8s → %s | %s | %s\n",
|
||||
strOr(j["op"], ""), strOr(j["target"], ""),
|
||||
truncate(strOr(j["after"], ""), 70), strOr(j["reason"], ""))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
written := 0
|
||||
for _, j := range journalLines {
|
||||
if strOr(j["op"], "") == "PROPOSE" {
|
||||
c.JournalAppend(j)
|
||||
written++
|
||||
} else if r := strOr(j["reason"], ""); r == "" || r == "dry-run" {
|
||||
c.JournalAppend(j)
|
||||
written++
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(c.Out, "Applied %d ops; %d logged to journal; index saved.\n", len(ops), written)
|
||||
for _, j := range journalLines {
|
||||
fmt.Fprintf(c.Out, " %-8s → %s | %s\n",
|
||||
strOr(j["op"], ""), strOr(j["target"], ""), truncate(strOr(j["after"], ""), 70))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func eventOr(e string) string {
|
||||
if e == "" {
|
||||
return "unknown"
|
||||
}
|
||||
return e
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
// Package main — curator dichotomy port (GO verdict: Reactive → Go).
|
||||
// om.go — order-preserving JSON objects. The candidate ledger and the entry
|
||||
// index iterate keys in insertion order (Python dict law), so idx inputs are
|
||||
// decoded into OM instead of map[string]any wherever iteration order can
|
||||
// surface in `want`.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OM — an ordered JSON object.
|
||||
type OM struct {
|
||||
Keys []string
|
||||
M map[string]interface{}
|
||||
}
|
||||
|
||||
func NewOM() *OM {
|
||||
return &OM{M: map[string]interface{}{}}
|
||||
}
|
||||
|
||||
func (o *OM) Get(key string) (interface{}, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
v, ok := o.M[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (o *OM) Set(key string, v interface{}) {
|
||||
if _, ok := o.M[key]; !ok {
|
||||
o.Keys = append(o.Keys, key)
|
||||
}
|
||||
o.M[key] = v
|
||||
}
|
||||
|
||||
func (o *OM) Delete(key string) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := o.M[key]; ok {
|
||||
delete(o.M, key)
|
||||
for i, k := range o.Keys {
|
||||
if k == key {
|
||||
o.Keys = append(o.Keys[:i], o.Keys[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OM) Len() int {
|
||||
if o == nil {
|
||||
return 0
|
||||
}
|
||||
return len(o.Keys)
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes preserving key order; nested objects decode as *OM.
|
||||
func (o *OM) UnmarshalJSON(b []byte) error {
|
||||
dec := json.NewDecoder(bytes.NewReader(b))
|
||||
dec.UseNumber()
|
||||
tok, err := dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok != json.Delim('{') {
|
||||
return fmt.Errorf("OM: expected object, got %v", tok)
|
||||
}
|
||||
o.Keys = nil
|
||||
o.M = map[string]interface{}{}
|
||||
for dec.More() {
|
||||
kt, err := dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := kt.(string)
|
||||
v, err := decodeOMValue(dec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Keys = append(o.Keys, key)
|
||||
o.M[key] = v
|
||||
}
|
||||
_, err = dec.Token() // closing }
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeOMValue(dec *json.Decoder) (interface{}, error) {
|
||||
tok, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decodeOMToken(dec, tok)
|
||||
}
|
||||
|
||||
func decodeOMToken(dec *json.Decoder, tok json.Token) (interface{}, error) {
|
||||
switch t := tok.(type) {
|
||||
case json.Delim:
|
||||
switch t {
|
||||
case '{':
|
||||
inner := NewOM()
|
||||
for dec.More() {
|
||||
kt, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := decodeOMValue(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inner.Keys = append(inner.Keys, kt.(string))
|
||||
inner.M[kt.(string)] = v
|
||||
}
|
||||
if _, err := dec.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return inner, nil
|
||||
case '[':
|
||||
var arr []interface{}
|
||||
for dec.More() {
|
||||
v, err := decodeOMValue(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr = append(arr, v)
|
||||
}
|
||||
if _, err := dec.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if arr == nil {
|
||||
arr = []interface{}{}
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
return nil, fmt.Errorf("OM: unexpected delim %v", t)
|
||||
default:
|
||||
return tok, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON re-emits in preserved order.
|
||||
func (o *OM) MarshalJSON() ([]byte, error) {
|
||||
if o == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('{')
|
||||
for i, k := range o.Keys {
|
||||
if i > 0 {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
kb, _ := json.Marshal(k)
|
||||
buf.Write(kb)
|
||||
buf.WriteByte(':')
|
||||
vb, err := json.Marshal(o.M[k])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.Write(vb)
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// -- value coercion helpers (Python .get semantics) --------------------------
|
||||
|
||||
func strOf(v interface{}) string {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func strOr(v interface{}, def string) string {
|
||||
if s, ok := v.(string); ok && s != "" {
|
||||
return s
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func intOf(v interface{}) int {
|
||||
switch n := v.(type) {
|
||||
case json.Number:
|
||||
f, _ := n.Float64()
|
||||
return int(f)
|
||||
case float64:
|
||||
return int(n)
|
||||
case int:
|
||||
return n
|
||||
case int64:
|
||||
return int(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func floatOf(v interface{}) float64 {
|
||||
switch n := v.(type) {
|
||||
case json.Number:
|
||||
f, _ := n.Float64()
|
||||
return f
|
||||
case float64:
|
||||
return n
|
||||
case int:
|
||||
return float64(n)
|
||||
case int64:
|
||||
return float64(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func intOr(v interface{}, def int) int {
|
||||
if v == nil {
|
||||
return def
|
||||
}
|
||||
switch n := v.(type) {
|
||||
case json.Number:
|
||||
f, _ := n.Float64()
|
||||
return int(f)
|
||||
case float64:
|
||||
return int(n)
|
||||
case int:
|
||||
return n
|
||||
case string:
|
||||
if n == "" {
|
||||
return def
|
||||
}
|
||||
}
|
||||
return intOf(v)
|
||||
}
|
||||
|
||||
// pyListRepr renders a []string the way Python's repr does for the le reasons.
|
||||
func pyListRepr(ss []string) string {
|
||||
quoted := make([]string, len(ss))
|
||||
for i, s := range ss {
|
||||
quoted[i] = "'" + s + "'"
|
||||
}
|
||||
return "[" + strings.Join(quoted, ", ") + "]"
|
||||
}
|
||||
|
||||
func sortedCopy(ss []string) []string {
|
||||
out := append([]string(nil), ss...)
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// phaseb.go — Phase B language-advantage pass: allocation discipline.
|
||||
//
|
||||
// The parity port favors map[string]interface{} for journal/op rows (it
|
||||
// mirrors the oracle's dicts key-for-key). Phase B replaces the hot paths'
|
||||
// heap-churn shapes with pre-sized, append-in-place builders without changing
|
||||
// any observable output (the frozen battery pins every byte):
|
||||
// - NewOp: pre-sized op row with the six canonical keys in oracle order
|
||||
// - AppendJournal: append-in-place journal growth (no intermediate slices)
|
||||
// - JoinLines: single-pass body rebuild for the ADD path
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// opKeys — the oracle's op-row key order (observable in journal JSON).
|
||||
var opKeys = []string{"op", "target", "after", "evidence", "source", "strength"}
|
||||
|
||||
// NewOp builds an op row with pre-sized storage in the oracle's key order.
|
||||
func NewOp(op, target, after, evidence, source string, strength int) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": op,
|
||||
"target": target,
|
||||
"after": after,
|
||||
"evidence": evidence,
|
||||
"source": source,
|
||||
"strength": strength,
|
||||
}
|
||||
}
|
||||
|
||||
// OpKeys returns the canonical op-row key order (documents the envelope).
|
||||
func OpKeys() []string {
|
||||
return append([]string(nil), opKeys...)
|
||||
}
|
||||
|
||||
// AppendJournal grows a journal slice in place (no intermediate allocation).
|
||||
func AppendJournal(jl []map[string]interface{}, rows ...map[string]interface{}) []map[string]interface{} {
|
||||
return append(jl, rows...)
|
||||
}
|
||||
|
||||
// JoinLines rebuilds a block body from kept lines in one pass.
|
||||
func JoinLines(kept []string) string {
|
||||
return strings.Join(kept, "\n")
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Phase B tests: the language-advantage builders produce byte-identical
|
||||
// rows to the inline literals they replace (pinned by the frozen battery).
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPhaseBNewOpShape(t *testing.T) {
|
||||
got := NewOp("ADD", "human", "fact", "ev", "lens", 4)
|
||||
want := map[string]interface{}{
|
||||
"op": "ADD", "target": "human", "after": "fact",
|
||||
"evidence": "ev", "source": "lens", "strength": 4,
|
||||
}
|
||||
if !reflect.DeepEqual(normJSON(got), normJSON(want)) {
|
||||
t.Fatalf("NewOp shape drift: %#v", got)
|
||||
}
|
||||
if keys := OpKeys(); !reflect.DeepEqual(keys, []string{"op", "target", "after", "evidence", "source", "strength"}) {
|
||||
t.Fatalf("OpKeys drift: %v", keys)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPhaseBAppendJournal(t *testing.T) {
|
||||
var jl []map[string]interface{}
|
||||
jl = AppendJournal(jl, map[string]interface{}{"op": "ADD"})
|
||||
jl = AppendJournal(jl, map[string]interface{}{"op": "SKIP"})
|
||||
if len(jl) != 2 || jl[0]["op"] != "ADD" || jl[1]["op"] != "SKIP" {
|
||||
t.Fatalf("AppendJournal drift: %#v", jl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPhaseBJoinLines(t *testing.T) {
|
||||
if got := JoinLines([]string{"- a", "- b"}); got != "- a\n- b" {
|
||||
t.Fatalf("JoinLines drift: %q", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
// Replay — the frozen-truth parity engine. Reads truth.json (generated by
|
||||
// scripts/gen_curator_truth.py against the live Python oracle with paths
|
||||
// isolated, dependency cores pinned, clock frozen, subprocess faked, embed
|
||||
// tabled, aaak/memory_store blocked, drift gate + audit ledger + drift-ledger
|
||||
// seams injected) and re-executes every row through this Go port.
|
||||
//
|
||||
// Seams mirrored here (one-to-one with the generator's declared seams):
|
||||
// - setup.db_missing → StoreDB points at a path in a nonexistent dir
|
||||
// - setup.db_rows → fresh sqlite store seeded with the same rows
|
||||
// - setup.transcripts → transcripts dir rewritten with the same files +
|
||||
// mtimes (age_days before the frozen instant)
|
||||
// - setup.index / index_missing → index file written / absent
|
||||
// - setup.idx_init → the in-memory idx argument
|
||||
// - setup.skills → skills dir seeded with the same files
|
||||
// - input.vecs → the embed seam table for semantic_candidate_key
|
||||
// - input.seam_drift_gate → "reject" installs the REJECT stub; else off
|
||||
// - input.seam_audit_ledger → true installs the recorder
|
||||
// - input.seam_ledger_verdict → the drift-ledger check() verdict
|
||||
// - input.seam_graph_write → "stub_true" installs GraphWrite → true
|
||||
// - input.stdout → GraphRun returns the per-case stdout; the frozen argv's
|
||||
// "@RUNE@" slot is substituted with this checkout's graph_memory.py path
|
||||
//
|
||||
// Rows of one fn replay sequentially on a shared scope (db/transcripts/index
|
||||
// persist across rows of the same fn), mirroring the oracle run.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TruthDoc — the frozen truth file structure.
|
||||
type TruthDoc struct {
|
||||
Oracle string `json:"oracle"`
|
||||
Generator string `json:"generator"`
|
||||
Note string `json:"note"`
|
||||
Rows []TruthRow `json:"rows"`
|
||||
}
|
||||
|
||||
// TruthRow — one frozen case.
|
||||
type TruthRow struct {
|
||||
Fn string `json:"fn"`
|
||||
Name string `json:"name"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
Setup json.RawMessage `json:"setup"`
|
||||
Want json.RawMessage `json:"want"`
|
||||
}
|
||||
|
||||
// RunTruth replays every row and returns a divergence report (empty on
|
||||
// 100% parity).
|
||||
func RunTruth(path string) []string {
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("read truth: %v", err)}
|
||||
}
|
||||
var doc TruthDoc
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
return []string{fmt.Sprintf("parse truth: %v", err)}
|
||||
}
|
||||
repo := repoRoot()
|
||||
fails := []string{}
|
||||
var cur *Curator
|
||||
var curFn string
|
||||
scope := map[string]string{}
|
||||
for i := range doc.Rows {
|
||||
row := &doc.Rows[i]
|
||||
if row.Fn != curFn || cur == nil {
|
||||
cur = newScopeCurator(repo)
|
||||
curFn = row.Fn
|
||||
scope = map[string]string{}
|
||||
}
|
||||
if msg := replayRow(cur, scope, repo, row); msg != "" {
|
||||
fails = append(fails, row.Fn+"/"+row.Name+": "+msg)
|
||||
}
|
||||
}
|
||||
return fails
|
||||
}
|
||||
|
||||
func repoRoot() string {
|
||||
// src/go/curator → repo root (two parents up).
|
||||
exe, err := os.Executable()
|
||||
_ = exe
|
||||
_ = err
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "."
|
||||
}
|
||||
return filepath.Dir(filepath.Dir(filepath.Dir(cwd)))
|
||||
}
|
||||
|
||||
func truthRowCount() int {
|
||||
raw, err := os.ReadFile("truth.json")
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
var doc TruthDoc
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
return -1
|
||||
}
|
||||
return len(doc.Rows)
|
||||
}
|
||||
|
||||
func newScopeCurator(repo string) *Curator {
|
||||
root, err := os.MkdirTemp("", "curator-replay-*")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c := New(filepath.Join(root, "memory", "store", "memory.db"))
|
||||
c.BlocksDir = filepath.Join(root, "blocks")
|
||||
c.JournalDir = filepath.Join(root, "journal")
|
||||
c.IndexFile = filepath.Join(root, "index", "blocks_meta.json")
|
||||
c.SkillsDir = filepath.Join(root, "config", "skills")
|
||||
c.TranscriptsDir = filepath.Join(root, "transcripts")
|
||||
c.GraphMemoryPath = filepath.Join(repo, "src", "rune", "graph_memory.py")
|
||||
c.Out = discard{}
|
||||
c.Err = discard{}
|
||||
return c
|
||||
}
|
||||
|
||||
type discard struct{}
|
||||
|
||||
func (discard) Write(p []byte) (int, error) { return len(p), nil }
|
||||
|
||||
// applySetup recreates the row's seed state (db/transcripts/index/skills).
|
||||
func applySetup(c *Curator, scope map[string]string, row *TruthRow) error {
|
||||
var setup map[string]interface{}
|
||||
if len(row.Setup) > 0 {
|
||||
if err := json.Unmarshal(row.Setup, &setup); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v, ok := setup["db_missing"]; ok && v == true {
|
||||
c.StoreDB = filepath.Join(c.JournalDir, "..", "nonexistent-dir", "no.db")
|
||||
c.StoreDB = filepath.Join(filepath.Dir(c.JournalDir), "nonexistent-dir", "no.db")
|
||||
scope["db"] = "missing"
|
||||
} else if v, ok := setup["db_rows"]; ok {
|
||||
dbPath := filepath.Join(filepath.Dir(c.StoreDB), "scope.db")
|
||||
rows, _ := v.([]interface{})
|
||||
if err := SeedDB(dbPath, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
c.StoreDB = dbPath
|
||||
scope["db"] = dbPath
|
||||
}
|
||||
if v, ok := setup["transcripts"]; ok {
|
||||
if err := seedTranscripts(c, v.([]interface{})); err != nil {
|
||||
return err
|
||||
}
|
||||
scope["transcripts"] = "seeded"
|
||||
}
|
||||
if v, ok := setup["index"]; ok {
|
||||
os.MkdirAll(filepath.Dir(c.IndexFile), 0o755)
|
||||
b, _ := json.MarshalIndent(normJSON(v), "", " ")
|
||||
if err := os.WriteFile(c.IndexFile, b, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if v, ok := setup["index_missing"]; ok && v == true {
|
||||
os.Remove(c.IndexFile)
|
||||
}
|
||||
if v, ok := setup["skills"]; ok {
|
||||
if err := seedSkills(c, v.(map[string]interface{})); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// input-embedded setup (put_setup rows): same keys, inside input.setup.
|
||||
var input map[string]interface{}
|
||||
if err := json.Unmarshal(row.Input, &input); err != nil {
|
||||
return err
|
||||
}
|
||||
if v, ok := input["setup"]; ok {
|
||||
sub, _ := v.(map[string]interface{})
|
||||
if dv, ok := sub["db_missing"]; ok && dv == true {
|
||||
c.StoreDB = filepath.Join(filepath.Dir(c.JournalDir), "nonexistent-dir", "no.db")
|
||||
scope["db"] = "missing"
|
||||
} else if dv, ok := sub["db_rows"]; ok {
|
||||
dbPath := filepath.Join(filepath.Dir(c.StoreDB), "scope.db")
|
||||
rows, _ := dv.([]interface{})
|
||||
if err := SeedDB(dbPath, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
c.StoreDB = dbPath
|
||||
scope["db"] = dbPath
|
||||
}
|
||||
if tv, ok := sub["transcripts"]; ok {
|
||||
if err := seedTranscripts(c, tv.([]interface{})); err != nil {
|
||||
return err
|
||||
}
|
||||
scope["transcripts"] = "seeded"
|
||||
}
|
||||
if iv, ok := sub["index"]; ok {
|
||||
os.MkdirAll(filepath.Dir(c.IndexFile), 0o755)
|
||||
b, _ := json.MarshalIndent(normJSON(iv), "", " ")
|
||||
if err := os.WriteFile(c.IndexFile, b, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if iv, ok := sub["index_missing"]; ok && iv == true {
|
||||
os.Remove(c.IndexFile)
|
||||
}
|
||||
if sv, ok := sub["skills"]; ok {
|
||||
if err := seedSkills(c, sv.(map[string]interface{})); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func seedTranscripts(c *Curator, list []interface{}) error {
|
||||
os.MkdirAll(c.TranscriptsDir, 0o755)
|
||||
ents, err := os.ReadDir(c.TranscriptsDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range ents {
|
||||
os.Remove(filepath.Join(c.TranscriptsDir, e.Name()))
|
||||
}
|
||||
frozen, _ := time.Parse("2006-01-02T15:04:05Z07:00", FrozenISO)
|
||||
for _, v := range list {
|
||||
t := v.(map[string]interface{})
|
||||
p := filepath.Join(c.TranscriptsDir, strOr(t["name"], ""))
|
||||
if err := os.WriteFile(p, []byte(strOr(t["body"], "")), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
age := floatOf(t["age_days"])
|
||||
stamp := frozen.Add(-time.Duration(age*86400) * time.Second)
|
||||
if err := os.Chtimes(p, stamp, stamp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func seedSkills(c *Curator, m map[string]interface{}) error {
|
||||
os.MkdirAll(c.SkillsDir, 0o755)
|
||||
ents, err := os.ReadDir(c.SkillsDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range ents {
|
||||
os.RemoveAll(filepath.Join(c.SkillsDir, e.Name()))
|
||||
}
|
||||
for rel, v := range m {
|
||||
p := filepath.Join(c.SkillsDir, rel)
|
||||
os.MkdirAll(filepath.Dir(p), 0o755)
|
||||
if err := os.WriteFile(p, []byte(strOf(v)), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pinRowSeams installs the row's injected seams (drift gate / audit ledger /
|
||||
// ledger verdict / graph stub / embed table).
|
||||
func pinRowSeams(c *Curator, row *TruthRow, audit *[]AuditCall) {
|
||||
var input map[string]interface{}
|
||||
_ = json.Unmarshal(row.Input, &input)
|
||||
if v, ok := input["seam_drift_gate"]; ok && v == "reject" {
|
||||
c.DriftGate = func(entry map[string]interface{}) GateResult {
|
||||
return GateResult{Verdict: "REJECT", Reason: "washed out"}
|
||||
}
|
||||
} else {
|
||||
c.DriftGate = nil
|
||||
}
|
||||
if v, ok := input["seam_audit_ledger"]; ok && v == true {
|
||||
c.AuditLedger = func(id int, kind, action string, count int, detail string) {
|
||||
*audit = append(*audit, AuditCall{id, kind, action, count, detail})
|
||||
}
|
||||
} else {
|
||||
c.AuditLedger = nil
|
||||
}
|
||||
if v, ok := input["seam_ledger_verdict"]; ok {
|
||||
c.LedgerVerdict = intOf(v)
|
||||
} else {
|
||||
c.LedgerVerdict = 0
|
||||
}
|
||||
if v, ok := input["seam_graph_write"]; ok && v == "stub_true" {
|
||||
c.GraphRun = func(argv []string) string { return `"added": True` }
|
||||
} else {
|
||||
c.GraphRun = nil
|
||||
}
|
||||
}
|
||||
|
||||
// AuditCall — one recorded log_promotion call.
|
||||
type AuditCall struct {
|
||||
ID int
|
||||
Kind string
|
||||
Action string
|
||||
Count int
|
||||
Detail string
|
||||
}
|
||||
|
||||
func auditCallsJSON(calls []AuditCall) interface{} {
|
||||
out := []interface{}{}
|
||||
for _, a := range calls {
|
||||
out = append(out, []interface{}{a.ID, a.Kind, a.Action, float64(a.Count), a.Detail})
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,643 @@
|
||||
// replay_cases.go — per-function replay dispatch. Each case mirrors exactly
|
||||
// one row of the frozen truth: it reads the row input, applies the row setup,
|
||||
// runs the ported function, and returns the got value for comparison against
|
||||
// the frozen want. Any divergence fails the battery.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// normJSON canonicalizes a value through JSON (numbers → float64, OM →
|
||||
// ordered maps) so DeepEqual compares oracle-shaped values.
|
||||
func normJSON(v interface{}) interface{} {
|
||||
switch t := v.(type) {
|
||||
case []string:
|
||||
out := make([]interface{}, len(t))
|
||||
for i, s := range t {
|
||||
out[i] = s
|
||||
}
|
||||
return out
|
||||
case []float64:
|
||||
out := make([]interface{}, len(t))
|
||||
for i, f := range t {
|
||||
out[i] = f
|
||||
}
|
||||
return out
|
||||
case []map[string]interface{}:
|
||||
out := make([]interface{}, len(t))
|
||||
for i, m := range t {
|
||||
out[i] = normJSON(m)
|
||||
}
|
||||
return out
|
||||
case *OM:
|
||||
m := map[string]interface{}{}
|
||||
for _, k := range t.Keys {
|
||||
m[k] = normJSON(t.M[k])
|
||||
}
|
||||
return m
|
||||
case map[string]interface{}:
|
||||
m := map[string]interface{}{}
|
||||
for k, vv := range t {
|
||||
m[k] = normJSON(vv)
|
||||
}
|
||||
return m
|
||||
case []interface{}:
|
||||
out := make([]interface{}, len(t))
|
||||
for i, vv := range t {
|
||||
out[i] = normJSON(vv)
|
||||
}
|
||||
return out
|
||||
case json.Number:
|
||||
f, _ := t.Float64()
|
||||
return f
|
||||
case int:
|
||||
return float64(t)
|
||||
case int64:
|
||||
return float64(t)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func wantOf(row *TruthRow) interface{} {
|
||||
dec := json.NewDecoder(bytes.NewReader(row.Want))
|
||||
dec.UseNumber()
|
||||
var w interface{}
|
||||
_ = dec.Decode(&w)
|
||||
return normJSON(w)
|
||||
}
|
||||
|
||||
func inputOf(row *TruthRow) map[string]interface{} {
|
||||
dec := json.NewDecoder(bytes.NewReader(row.Input))
|
||||
dec.UseNumber()
|
||||
var in map[string]interface{}
|
||||
_ = dec.Decode(&in)
|
||||
return in
|
||||
}
|
||||
|
||||
func replayRow(c *Curator, scope map[string]string, repo string, row *TruthRow) string {
|
||||
if err := applySetup(c, scope, row); err != nil {
|
||||
return fmt.Sprintf("setup: %v", err)
|
||||
}
|
||||
var audit []AuditCall
|
||||
pinRowSeams(c, row, &audit)
|
||||
in := inputOf(row)
|
||||
got, msg := dispatch(c, scope, repo, row, in)
|
||||
if msg != "" {
|
||||
return msg
|
||||
}
|
||||
// audit ledger calls are part of promote_candidates rows' want
|
||||
if row.Fn == "promote_candidates" && len(audit) > 0 {
|
||||
g, ok := got.(map[string]interface{})
|
||||
if !ok {
|
||||
return "audit: got not a map"
|
||||
}
|
||||
g["audit_calls"] = auditCallsJSON(audit)
|
||||
got = g
|
||||
}
|
||||
if !reflect.DeepEqual(normJSON(got), wantOf(row)) {
|
||||
gb, _ := json.Marshal(normJSON(got))
|
||||
wb, _ := json.Marshal(wantOf(row))
|
||||
return fmt.Sprintf("divergence\ngot: %s\nwant: %s", gb, wb)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// dispatch runs one frozen row. Returns (got, error-message).
|
||||
func dispatch(c *Curator, scope map[string]string, repo string, row *TruthRow, in map[string]interface{}) (interface{}, string) {
|
||||
// journal_append rows share one journal scope (the oracle never resets
|
||||
// between them).
|
||||
if row.Fn == "journal_append" && scope["journal"] == "" {
|
||||
ents, _ := os.ReadDir(c.JournalDir)
|
||||
for _, e := range ents {
|
||||
os.Remove(filepath.Join(c.JournalDir, e.Name()))
|
||||
}
|
||||
scope["journal"] = "open"
|
||||
}
|
||||
// main rows each run main() fresh on the shared scope; the oracle's
|
||||
// main/apply_output journal accumulates hook/dry/plan rows' NOTHING
|
||||
// (those never write the journal) — no reset needed.
|
||||
switch row.Fn {
|
||||
case "block_path":
|
||||
return c.BlockPath(strOr(in["label"], "")), ""
|
||||
case "entry_key":
|
||||
return EntryKey(strOr(in["text"], "")), ""
|
||||
case "find_entry":
|
||||
v := FindEntry(strOr(in["body"], ""), strOr(in["needle"], ""))
|
||||
if v == "" {
|
||||
return nil, ""
|
||||
}
|
||||
return v, ""
|
||||
case "candidate_key":
|
||||
return CandidateKey(strOr(in["text"], "")), ""
|
||||
case "norm":
|
||||
return Norm(strOr(in["text"], "")), ""
|
||||
case "detect_conflict":
|
||||
k, l := DetectConflict(strOr(in["body"], ""), strOr(in["fact"], ""))
|
||||
if k == "" {
|
||||
return []interface{}{nil, nil}, ""
|
||||
}
|
||||
return []interface{}{k, l}, ""
|
||||
case "overlap":
|
||||
return Overlap(strOr(in["a"], ""), strOr(in["b"], "")), ""
|
||||
case "cos":
|
||||
return Cos(floats(in["a"]), floats(in["b"])), ""
|
||||
case "sanitize_slug":
|
||||
return SanitizeSlug(strOr(in["name"], "")), ""
|
||||
case "skill_path":
|
||||
rel, err := filepath.Rel(c.SkillsDir, c.SkillPath(strOr(in["name"], "")))
|
||||
if err != nil {
|
||||
return "", err.Error()
|
||||
}
|
||||
return rel, ""
|
||||
case "is_topic_fact":
|
||||
return c.IsTopicFact(strOr(in["fact"], "")), ""
|
||||
case "aaak":
|
||||
return c.Aaak(strOr(in["text"], ""), strOr(in["topic"], "")), ""
|
||||
case "le_promote_eligible":
|
||||
if v, ok := in["seam_lexicon"]; ok && v == "unavailable" {
|
||||
return lePromoteEligibleFallback(strOr(in["proposal"], ""), nil,
|
||||
intOf(in["strength"]), intOf(in["min_strength"]), intOf(in["wash_count"])), ""
|
||||
}
|
||||
existing := stringsOf(in["existing"])
|
||||
return c.LePromoteEligible(strOr(in["proposal"], ""), existing,
|
||||
intOf(in["strength"]), intOf(in["min_strength"]), intOf(in["wash_count"])), ""
|
||||
case "store_has":
|
||||
topic := ""
|
||||
if in["topic"] != nil {
|
||||
topic = strOr(in["topic"], "")
|
||||
}
|
||||
return c.StoreHas(strOr(in["text"], ""), topic), ""
|
||||
case "read_block":
|
||||
fm, body := c.ReadBlock(strOr(in["label"], ""))
|
||||
return map[string]interface{}{"fm": fm, "body": body}, ""
|
||||
case "write_block":
|
||||
ret := c.WriteBlock(strOr(in["label"], ""), strOf(in["body"]))
|
||||
out := map[string]interface{}{"return": ret}
|
||||
if row.Name != "db_unavailable_returns_descriptor" {
|
||||
_, body := c.ReadBlock(strOr(in["label"], ""))
|
||||
out["body"] = body
|
||||
}
|
||||
return out, ""
|
||||
case "block_values":
|
||||
out := c.BlockValues(strOr(in["label"], ""))
|
||||
if out == nil {
|
||||
out = []string{}
|
||||
}
|
||||
return out, ""
|
||||
case "store_corpus":
|
||||
out := c.StoreCorpus(intOf(in["limit"]))
|
||||
if out == nil {
|
||||
out = []string{}
|
||||
}
|
||||
return out, ""
|
||||
case "contradicts_identity":
|
||||
return c.ContradictsIdentity(strOr(in["fact"], "")), ""
|
||||
case "load_index":
|
||||
return c.LoadIndex(), ""
|
||||
case "save_index":
|
||||
c.SaveIndex(mustOM(in["idx"]))
|
||||
return c.LoadIndex(), ""
|
||||
case "ensure_entry_meta":
|
||||
idx := idxInitOf(row)
|
||||
key := c.EnsureEntryMeta(idx, strOr(in["label"], ""), strOr(in["text"], ""))
|
||||
lomV, _ := idx.Get(strOr(in["label"], ""))
|
||||
lom, _ := omEntry(lomV)
|
||||
// the oracle's want carries the label dict as a plain map
|
||||
return map[string]interface{}{"key": key, "label_idx": lom}, ""
|
||||
case "touch_entry":
|
||||
idx := idxInitOf(row)
|
||||
label := strOr(in["label"], "")
|
||||
text := strOr(in["text"], "")
|
||||
key := c.TouchEntry(idx, label, text)
|
||||
lomV, _ := idx.Get(label)
|
||||
lom, _ := lomV.(*OM)
|
||||
metaV, _ := lom.Get(key)
|
||||
meta, _ := omEntry(metaV)
|
||||
return map[string]interface{}{"key": key, "meta": meta}, ""
|
||||
case "journal_append":
|
||||
entry, _ := in["entry"].(map[string]interface{})
|
||||
// rows of this fn replay sequentially on a shared journal scope,
|
||||
// mirroring the oracle run (minimal sees full's entry).
|
||||
p := c.JournalAppend(entry)
|
||||
content := map[string]interface{}{}
|
||||
ents, _ := os.ReadDir(c.JournalDir)
|
||||
for _, e := range ents {
|
||||
b, _ := os.ReadFile(filepath.Join(c.JournalDir, e.Name()))
|
||||
content[e.Name()] = string(b)
|
||||
}
|
||||
return map[string]interface{}{"path": filepath.Base(p), "content": content}, ""
|
||||
case "ensure_candidates":
|
||||
idx := NewOM()
|
||||
if v, ok := in["idx"].(*OM); ok {
|
||||
idx = v
|
||||
} else if v, ok := in["idx"].(map[string]interface{}); ok {
|
||||
idx = mapToOM(v)
|
||||
}
|
||||
return EnsureCandidates(idx), ""
|
||||
case "semantic_candidate_key":
|
||||
vecs := tableVecs()
|
||||
embed := func(texts []string) map[string][]float64 {
|
||||
out := map[string][]float64{}
|
||||
for _, t := range texts {
|
||||
if v, ok := vecs[t]; ok {
|
||||
out[t] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
cands := NewOM()
|
||||
cands.Set(CandidateKey("fact alpha about deploy runners"),
|
||||
map[string]interface{}{"text": "fact alpha about deploy runners"})
|
||||
cands.Set(CandidateKey("fact delta about whiskey tasting"),
|
||||
map[string]interface{}{"text": "fact delta about whiskey tasting"})
|
||||
if row.Name == "empty_cands" {
|
||||
cands = NewOM()
|
||||
}
|
||||
v := c.SemanticCandidateKey(strOr(in["fact"], ""), cands, embed)
|
||||
if v == "" {
|
||||
return nil, ""
|
||||
}
|
||||
return v, ""
|
||||
case "embed":
|
||||
for k, v := range tableVecs() {
|
||||
EmbedCache[k] = v
|
||||
}
|
||||
out := c.Embed(stringsOf(in["texts"]))
|
||||
m := map[string]interface{}{}
|
||||
for k, v := range out {
|
||||
m[k] = v
|
||||
}
|
||||
return m, ""
|
||||
case "grounded_in_sessions":
|
||||
return c.GroundedInSessions(strOr(in["fact"], ""), 0.46, 3), ""
|
||||
case "coherence_check":
|
||||
if v, ok := in["fact"]; ok && (v == "" || len(strOf(v)) < 15) && in["sources"] == nil {
|
||||
return c.CoherenceCheck(strOf(v), []string{"sessions", "corpus"}), ""
|
||||
}
|
||||
return c.CoherenceCheck(strOr(in["fact"], ""), stringsOf(in["sources"])), ""
|
||||
case "grounded_in_corpus":
|
||||
return c.GroundedInCorpus(strOr(in["fact"], "")), ""
|
||||
case "decay_candidates":
|
||||
idx := idxInitOf(row)
|
||||
if idx.Len() == 0 {
|
||||
if raw := rawField(row, "idx"); len(raw) > 0 {
|
||||
idx = mustOMRaw(raw)
|
||||
}
|
||||
}
|
||||
var jl []map[string]interface{}
|
||||
changed := c.DecayCandidates(idx, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
cands, _ := idx.Get(CandidatesKey)
|
||||
return map[string]interface{}{"changed": changed, "remaining": cands, "journal": jl}, ""
|
||||
case "promote_candidates":
|
||||
idx := idxInitOf(row)
|
||||
ev := evidenceOf(in["evidence"])
|
||||
var jl []map[string]interface{}
|
||||
promoted := c.PromoteCandidates(ev, idx, &jl)
|
||||
if promoted == nil {
|
||||
promoted = []map[string]interface{}{}
|
||||
}
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
cands, _ := idx.Get(CandidatesKey)
|
||||
if cands == nil {
|
||||
cands = NewOM()
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"promoted": promoted, "candidates": cands, "journal": jl,
|
||||
}, ""
|
||||
case "plan_ops":
|
||||
idx := idxInitOf(row)
|
||||
ev := evidenceOf(in["evidence"])
|
||||
var jl []map[string]interface{}
|
||||
ops := c.PlanOps(ev, idx, &jl)
|
||||
if ops == nil {
|
||||
ops = []map[string]interface{}{}
|
||||
}
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
return map[string]interface{}{"ops": ops, "idx": idx, "journal": jl}, ""
|
||||
case "apply_op":
|
||||
idx := idxInitOf(row)
|
||||
ops := evidenceOf(in["ops"])
|
||||
var jl []map[string]interface{}
|
||||
var results []interface{}
|
||||
for _, op := range ops {
|
||||
results = append(results, c.ApplyOp(op, idx, &jl))
|
||||
}
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
_, body := c.ReadBlock("human")
|
||||
return map[string]interface{}{
|
||||
"results": results, "journal": jl, "body": body, "idx": idx,
|
||||
}, ""
|
||||
case "apply_warm":
|
||||
var jl []map[string]interface{}
|
||||
if row.Name == "post_upsert_neurons" || row.Name == "post_seed_neurons" {
|
||||
return neuronsJSON(ListNeurons(c.StoreDB)), ""
|
||||
}
|
||||
if op, ok := in["op"].(map[string]interface{}); ok {
|
||||
ret := c.ApplyWarm(op, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
if _, hasReturned := rawWantField(row, "returned"); hasReturned {
|
||||
return map[string]interface{}{"returned": ret, "journal": jl}, ""
|
||||
}
|
||||
return ret, ""
|
||||
}
|
||||
// seed_new_neuron/empty_fact rows: want is {returned, journal}
|
||||
fact := strOr(in["after"], strOr(in["fact"], ""))
|
||||
ret := c.ApplyWarm(map[string]interface{}{"after": fact}, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
return map[string]interface{}{"returned": ret, "journal": jl}, ""
|
||||
case "derive_triggers":
|
||||
return DeriveTriggers(strOr(in["text"], ""), stringsOf(in["existing"])), ""
|
||||
case "decay_pass":
|
||||
idx := idxInitOf(row)
|
||||
if idx.Len() == 0 {
|
||||
if raw := rawField(row, "idx"); len(raw) > 0 {
|
||||
idx = mustOMRaw(raw)
|
||||
}
|
||||
}
|
||||
// the oracle's want carries idx_after as the MUTATED idx (same
|
||||
// object); replay returns the same mutated object.
|
||||
var jl []map[string]interface{}
|
||||
c.DecayPass(idx, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
return map[string]interface{}{"idx_after": idx, "journal": jl}, ""
|
||||
case "compress_pass":
|
||||
idx := idxInitOf(row)
|
||||
var jl []map[string]interface{}
|
||||
changed := c.CompressPass(idx, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
if row.Name == "under_limit_noop" {
|
||||
return map[string]interface{}{"changed": changed, "journal": jl}, ""
|
||||
}
|
||||
_, body := c.ReadBlock("operating")
|
||||
return map[string]interface{}{
|
||||
"changed": changed, "body": body, "journal": jl, "idx": idx,
|
||||
}, ""
|
||||
case "author_skill":
|
||||
op, _ := in["op"].(map[string]interface{})
|
||||
var jl []map[string]interface{}
|
||||
if row.Name == "no_name" || row.Name == "no_steps" {
|
||||
return c.AuthorSkill(op, &jl), ""
|
||||
}
|
||||
written := c.AuthorSkill(op, &jl)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
out := map[string]interface{}{"written": written}
|
||||
if row.Name == "new_skill" {
|
||||
slug := SanitizeSlug(strOr(op["name"], ""))
|
||||
b, _ := os.ReadFile(c.SkillPath(slug))
|
||||
out["rel"] = slug + "/SKILL.md"
|
||||
out["content"] = string(b)
|
||||
out["journal"] = jl
|
||||
} else if row.Name == "existing_adds_evidence" || row.Name == "existing_keeps_evidence" {
|
||||
slug := SanitizeSlug(strOr(op["name"], ""))
|
||||
b, _ := os.ReadFile(c.SkillPath(slug))
|
||||
out["content"] = string(b)
|
||||
out["journal"] = jl
|
||||
}
|
||||
return out, ""
|
||||
case "graph_write":
|
||||
stdout := strOr(in["stdout"], `"added": True`)
|
||||
var captured []string
|
||||
c.GraphRun = func(argv []string) string {
|
||||
captured = append([]string(nil), argv...)
|
||||
return stdout
|
||||
}
|
||||
added := c.GraphWrite(strOr(in["fact"], ""), "ev", "src", intOf(in["strength"]))
|
||||
for i, a := range captured {
|
||||
if strings.HasPrefix(a, repo+"/src/rune/graph_memory.py") || a == c.GraphMemoryPath {
|
||||
captured[i] = "@RUNE@/src/rune/graph_memory.py"
|
||||
}
|
||||
}
|
||||
return map[string]interface{}{"added": added, "argv": captured}, ""
|
||||
case "run_plan":
|
||||
ev := evidenceOf(in["evidence"])
|
||||
apply := row.Name != "dry_run"
|
||||
var buf bytes.Buffer
|
||||
c.Out = &buf
|
||||
jl, ops := c.RunPlan(ev, apply)
|
||||
if jl == nil {
|
||||
jl = []map[string]interface{}{}
|
||||
}
|
||||
if ops == nil {
|
||||
ops = []map[string]interface{}{}
|
||||
}
|
||||
out := map[string]interface{}{"journal": jl, "ops": ops}
|
||||
if row.Name == "apply_gate_pass" {
|
||||
out["index"] = c.LoadIndex()
|
||||
} else if row.Name == "apply_gate_refuses" {
|
||||
out["stdout"] = buf.String()
|
||||
}
|
||||
return out, ""
|
||||
case "main":
|
||||
return dispatchMain(c, row, in), ""
|
||||
case "handle_hook":
|
||||
var data map[string]interface{}
|
||||
if v, ok := in["data"].(map[string]interface{}); ok {
|
||||
data = v
|
||||
}
|
||||
return c.HandleHook(strOr(in["event"], ""), data), ""
|
||||
}
|
||||
return nil, fmt.Sprintf("unknown fn %q", row.Fn)
|
||||
}
|
||||
|
||||
func floats(v interface{}) []float64 {
|
||||
var out []float64
|
||||
if arr, ok := v.([]interface{}); ok {
|
||||
for _, x := range arr {
|
||||
out = append(out, floatOf(x))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func stringsOf(v interface{}) []string {
|
||||
var out []string
|
||||
if arr, ok := v.([]interface{}); ok {
|
||||
for _, x := range arr {
|
||||
out = append(out, strOf(x))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func evidenceOf(v interface{}) []map[string]interface{} {
|
||||
var out []map[string]interface{}
|
||||
if arr, ok := v.([]interface{}); ok {
|
||||
for _, x := range arr {
|
||||
if m, ok := x.(map[string]interface{}); ok {
|
||||
out = append(out, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// mustOM decodes an idx_init value (nil → empty OM). Plain maps arrive
|
||||
// from inputOf's Unmarshal (order lost) — callers that need insertion order
|
||||
// must decode from the raw row input instead (mustOMRaw).
|
||||
func mustOM(v interface{}) *OM {
|
||||
if v == nil {
|
||||
return NewOM()
|
||||
}
|
||||
if om, ok := v.(*OM); ok {
|
||||
return om
|
||||
}
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
return mapToOM(m)
|
||||
}
|
||||
return NewOM()
|
||||
}
|
||||
|
||||
// mustOMRaw decodes an idx value from raw JSON, preserving key order.
|
||||
func mustOMRaw(raw json.RawMessage) *OM {
|
||||
om := NewOM()
|
||||
if len(raw) == 0 || string(raw) == "null" {
|
||||
return om
|
||||
}
|
||||
if err := om.UnmarshalJSON(raw); err != nil {
|
||||
return NewOM()
|
||||
}
|
||||
return om
|
||||
}
|
||||
|
||||
// idxInitOf extracts the raw idx_init JSON for a row (order-preserving).
|
||||
// Sources, in order: input.idx_init, input.idx, setup.idx_init — mirroring
|
||||
// the generator (plan/apply/compress rows carry idx_init in top-level setup).
|
||||
func idxInitOf(row *TruthRow) *OM {
|
||||
var in struct {
|
||||
IdxInit json.RawMessage `json:"idx_init"`
|
||||
Idx json.RawMessage `json:"idx"`
|
||||
}
|
||||
_ = json.Unmarshal(row.Input, &in)
|
||||
if len(in.IdxInit) > 0 && string(in.IdxInit) != "null" {
|
||||
return mustOMRaw(in.IdxInit)
|
||||
}
|
||||
if len(in.Idx) > 0 && string(in.Idx) != "null" {
|
||||
return mustOMRaw(in.Idx)
|
||||
}
|
||||
var setup struct {
|
||||
IdxInit json.RawMessage `json:"idx_init"`
|
||||
}
|
||||
if len(row.Setup) > 0 {
|
||||
_ = json.Unmarshal(row.Setup, &setup)
|
||||
if len(setup.IdxInit) > 0 && string(setup.IdxInit) != "null" {
|
||||
return mustOMRaw(setup.IdxInit)
|
||||
}
|
||||
}
|
||||
return NewOM()
|
||||
}
|
||||
|
||||
// mapToOM converts a decoded map into an ordered OM.
|
||||
func mapToOM(m map[string]interface{}) *OM {
|
||||
om := NewOM()
|
||||
for k, v := range m {
|
||||
switch t := v.(type) {
|
||||
case map[string]interface{}:
|
||||
om.Set(k, mapToOM(t))
|
||||
case []interface{}:
|
||||
om.Set(k, normList(t))
|
||||
default:
|
||||
om.Set(k, v)
|
||||
}
|
||||
}
|
||||
return om
|
||||
}
|
||||
|
||||
func normList(l []interface{}) []interface{} {
|
||||
out := make([]interface{}, len(l))
|
||||
for i, v := range l {
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
out[i] = mapToOM(m)
|
||||
} else {
|
||||
out[i] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func neuronsJSON(ns []Neuron) interface{} {
|
||||
if ns == nil {
|
||||
return []interface{}{}
|
||||
}
|
||||
b, _ := json.Marshal(ns)
|
||||
var out interface{}
|
||||
_ = json.Unmarshal(b, &out)
|
||||
return out
|
||||
}
|
||||
|
||||
// tableVecs — the frozen VEC table (mirrors the generator's VEC).
|
||||
func tableVecs() map[string][]float64 {
|
||||
return map[string][]float64{
|
||||
"fact alpha about deploy runners": {1.0, 0.0, 0.0},
|
||||
"fact beta about gitea runners": {0.0, 1.0, 0.0},
|
||||
"fact gamma about deploy runners nightly": {0.9, 0.1, 0.0},
|
||||
"fact delta about whiskey tasting": {0.0, 0.0, 1.0},
|
||||
}
|
||||
}
|
||||
|
||||
// mustMap decodes an idx value that may be *OM or a plain map.
|
||||
func mustMap(v interface{}) map[string]interface{} {
|
||||
if om, ok := v.(*OM); ok {
|
||||
m := map[string]interface{}{}
|
||||
for _, k := range om.Keys {
|
||||
m[k] = om.M[k]
|
||||
}
|
||||
return m
|
||||
}
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
return m
|
||||
}
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
|
||||
// rawField extracts a raw JSON field from a row's input (order-preserving).
|
||||
func rawField(row *TruthRow, field string) json.RawMessage {
|
||||
var in map[string]json.RawMessage
|
||||
_ = json.Unmarshal(row.Input, &in)
|
||||
return in[field]
|
||||
}
|
||||
|
||||
func jsonStr(v interface{}) string {
|
||||
b, _ := json.Marshal(strOf(v))
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// dbSig fingerprints a seed-row list so sequential rows on one scope keep
|
||||
// their accumulated store state instead of re-seeding every row.
|
||||
func dbSig(rows []interface{}) string {
|
||||
b, _ := json.Marshal(rows)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// rawWantField extracts a raw JSON field from a row's want.
|
||||
func rawWantField(row *TruthRow, field string) (json.RawMessage, bool) {
|
||||
var w map[string]json.RawMessage
|
||||
_ = json.Unmarshal(row.Want, &w)
|
||||
v, ok := w[field]
|
||||
return v, ok
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// store.go — sqlite seam for the curator port (modernc.org/sqlite, pure Go).
|
||||
// Mirrors the oracle's sqlite3 usage: read paths use `file:<path>?mode=ro`
|
||||
// (missing file/dir → connect error → the documented fallback), write paths
|
||||
// open read-write (missing dir → error → fallback).
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
const entriesSchema = `
|
||||
CREATE TABLE IF NOT EXISTS entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
text TEXT NOT NULL,
|
||||
importance REAL DEFAULT 0.5,
|
||||
created_at TEXT NOT NULL,
|
||||
last_accessed TEXT,
|
||||
topic TEXT DEFAULT '',
|
||||
entities TEXT DEFAULT '[]',
|
||||
source TEXT DEFAULT '',
|
||||
method TEXT DEFAULT 'curator',
|
||||
status TEXT DEFAULT 'active',
|
||||
valid_from TEXT,
|
||||
valid_until TEXT,
|
||||
confidence REAL DEFAULT 0.7,
|
||||
temperature REAL DEFAULT 1.0,
|
||||
always_on INTEGER DEFAULT 0,
|
||||
priority INTEGER DEFAULT 5,
|
||||
triggers TEXT DEFAULT '',
|
||||
kind TEXT DEFAULT 'fact',
|
||||
slug TEXT DEFAULT '',
|
||||
summary TEXT DEFAULT '',
|
||||
wash_count INTEGER DEFAULT 0,
|
||||
last_washed TEXT,
|
||||
promotion_eligible INTEGER DEFAULT 0,
|
||||
rock_status TEXT DEFAULT 'washable',
|
||||
tier TEXT DEFAULT 'warm',
|
||||
memory_type TEXT
|
||||
);
|
||||
`
|
||||
|
||||
func openRO(path string) (*sql.DB, error) {
|
||||
db, err := sql.Open("sqlite", "file:"+path+"?mode=ro")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = db.Ping(); err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func openRW(path string) (*sql.DB, error) {
|
||||
db, err := sql.Open("sqlite", "file:"+path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = db.Ping(); err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// SeedDB creates a fresh store with the full entries schema and inserts the
|
||||
// setup rows (column names mirror the oracle schema).
|
||||
func SeedDB(path string, rows []interface{}) error {
|
||||
if err := os.MkdirAll(dirOf(path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
os.Remove(path)
|
||||
db, err := openRW(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
if _, err = db.Exec(entriesSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range rows {
|
||||
m, ok := r.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("seed row not an object")
|
||||
}
|
||||
cols := make([]string, 0, len(m))
|
||||
vals := make([]interface{}, 0, len(m))
|
||||
base := map[string]interface{}{
|
||||
"text": "", "importance": 0.5, "created_at": "2026-01-01T00:00:00+00:00",
|
||||
"last_accessed": "2026-01-01T00:00:00+00:00", "topic": "", "entities": "[]",
|
||||
"source": "seed", "method": "seed", "status": "active", "valid_from": nil,
|
||||
"confidence": 0.7, "temperature": 1.0, "always_on": 0, "priority": 5,
|
||||
"triggers": "", "kind": "fact", "slug": "", "summary": "", "wash_count": 0,
|
||||
}
|
||||
for k, v := range base {
|
||||
if _, ok := m[k]; !ok {
|
||||
cols = append(cols, k)
|
||||
vals = append(vals, v)
|
||||
}
|
||||
}
|
||||
for k, v := range m {
|
||||
cols = append(cols, k)
|
||||
vals = append(vals, v)
|
||||
}
|
||||
q := "INSERT INTO entries ("
|
||||
for i, c := range cols {
|
||||
if i > 0 {
|
||||
q += ", "
|
||||
}
|
||||
q += c
|
||||
}
|
||||
q += ") VALUES ("
|
||||
for i := range cols {
|
||||
if i > 0 {
|
||||
q += ", "
|
||||
}
|
||||
q += "?"
|
||||
}
|
||||
q += ")"
|
||||
if _, err = db.Exec(q, vals...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dirOf(path string) string {
|
||||
for i := len(path) - 1; i >= 0; i-- {
|
||||
if path[i] == '/' {
|
||||
return path[:i]
|
||||
}
|
||||
}
|
||||
return "."
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,116 @@
|
||||
// Battery — Go tests replaying the frozen oracle truth VERBATIM.
|
||||
// Every row of truth.json (generated by scripts/gen_curator_truth.py
|
||||
// against the live Python oracle) re-executes through this port; any
|
||||
// divergence fails the test.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func loadTruth(t *testing.T) TruthDoc {
|
||||
t.Helper()
|
||||
raw, err := os.ReadFile("truth.json")
|
||||
if err != nil {
|
||||
t.Fatalf("read truth: %v", err)
|
||||
}
|
||||
var doc TruthDoc
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
t.Fatalf("parse truth: %v", err)
|
||||
}
|
||||
if len(doc.Rows) == 0 {
|
||||
t.Fatal("truth has no rows")
|
||||
}
|
||||
return doc
|
||||
}
|
||||
|
||||
func TestBatteryRowCount(t *testing.T) {
|
||||
doc := loadTruth(t)
|
||||
if len(doc.Rows) != 162 {
|
||||
t.Fatalf("row count drift: got %d want 162", len(doc.Rows))
|
||||
}
|
||||
if doc.Oracle != "src/rune/curator.py" {
|
||||
t.Fatalf("oracle drift: %q", doc.Oracle)
|
||||
}
|
||||
if doc.Generator != "scripts/gen_curator_truth.py" {
|
||||
t.Fatalf("generator drift: %q", doc.Generator)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatteryParity(t *testing.T) {
|
||||
doc := loadTruth(t)
|
||||
repo := repoRootForTest()
|
||||
var cur *Curator
|
||||
var curFn string
|
||||
scope := map[string]string{}
|
||||
fails := 0
|
||||
for i := range doc.Rows {
|
||||
row := &doc.Rows[i]
|
||||
if row.Fn != curFn || cur == nil {
|
||||
cur = newScopeCurator(repo)
|
||||
curFn = row.Fn
|
||||
scope = map[string]string{}
|
||||
}
|
||||
if msg := replayRow(cur, scope, repo, row); msg != "" {
|
||||
fails++
|
||||
t.Errorf("%s/%s: %s", row.Fn, row.Name, msg)
|
||||
}
|
||||
}
|
||||
if fails > 0 {
|
||||
t.Fatalf("%d/%d battery cases FAILED", fails, len(doc.Rows))
|
||||
}
|
||||
t.Logf("battery parity OK: %d cases", len(doc.Rows))
|
||||
}
|
||||
|
||||
func TestBatteryByFn(t *testing.T) {
|
||||
doc := loadTruth(t)
|
||||
repo := repoRootForTest()
|
||||
byFn := map[string][]int{}
|
||||
for i := range doc.Rows {
|
||||
byFn[doc.Rows[i].Fn] = append(byFn[doc.Rows[i].Fn], i)
|
||||
}
|
||||
// Every public function of the oracle must be covered.
|
||||
for _, fn := range []string{
|
||||
"block_path", "entry_key", "find_entry", "candidate_key", "norm",
|
||||
"detect_conflict", "overlap", "cos", "sanitize_slug", "skill_path",
|
||||
"is_topic_fact", "aaak", "le_promote_eligible", "store_has",
|
||||
"read_block", "write_block", "block_values", "store_corpus",
|
||||
"contradicts_identity", "load_index", "save_index", "ensure_entry_meta",
|
||||
"touch_entry", "journal_append", "ensure_candidates",
|
||||
"semantic_candidate_key", "embed", "coherence_check",
|
||||
"grounded_in_sessions", "grounded_in_corpus", "decay_candidates",
|
||||
"promote_candidates", "plan_ops", "apply_op", "apply_warm",
|
||||
"derive_triggers", "decay_pass", "compress_pass", "author_skill",
|
||||
"graph_write", "run_plan", "main", "handle_hook",
|
||||
} {
|
||||
rows, ok := byFn[fn]
|
||||
if !ok || len(rows) == 0 {
|
||||
t.Errorf("fn %q has no frozen rows", fn)
|
||||
continue
|
||||
}
|
||||
cur := newScopeCurator(repo)
|
||||
scope := map[string]string{}
|
||||
for _, i := range rows {
|
||||
row := &doc.Rows[i]
|
||||
if msg := replayRow(cur, scope, repo, row); msg != "" {
|
||||
t.Errorf("%s/%s: %s", row.Fn, row.Name, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func repoRootForTest() string {
|
||||
// tests run with CWD = src/go/curator.
|
||||
abs, err := filepath.Abs("truth.json")
|
||||
if err != nil {
|
||||
return "."
|
||||
}
|
||||
// <repo>/src/go/curator/truth.json → <repo>
|
||||
for i := 0; i < 3; i++ {
|
||||
abs = filepath.Dir(abs)
|
||||
}
|
||||
return abs
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// warm.go — parity port of the warm_router trio the curator depends on
|
||||
// (list_neurons / write_neuron / _derive_triggers): the warm neuron layer.
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var warmWordRe = regexp.MustCompile(`[a-z]{4,}`)
|
||||
|
||||
func parseTrigger(s string) []string {
|
||||
var out []string
|
||||
for _, t := range strings.Split(s, ",") {
|
||||
t = strings.ToLower(strings.TrimSpace(t))
|
||||
if t != "" {
|
||||
out = append(out, t)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Neuron — one warm neuron as list_neurons returns it.
|
||||
type Neuron struct {
|
||||
Slug string `json:"slug"`
|
||||
Triggers []string `json:"triggers"`
|
||||
Importance float64 `json:"importance"`
|
||||
Body string `json:"body"`
|
||||
Summary string `json:"summary"`
|
||||
Tokens int `json:"tokens"`
|
||||
WashCount int `json:"wash_count"`
|
||||
BodyKnowledge string `json:"body_knowledge"`
|
||||
}
|
||||
|
||||
// ListNeurons — all active warm neurons from the store (kind='neuron').
|
||||
func ListNeurons(storeDB string) []Neuron {
|
||||
var neurons []Neuron
|
||||
db, err := openRO(storeDB)
|
||||
if err != nil {
|
||||
return neurons
|
||||
}
|
||||
rows, qerr := db.Query("SELECT text, slug, triggers, importance, summary, wash_count FROM entries " +
|
||||
"WHERE kind='neuron' AND status='active' ORDER BY slug")
|
||||
if qerr != nil {
|
||||
db.Close()
|
||||
return neurons
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var text, slug, triggers, summary sql.NullString
|
||||
var importance float64
|
||||
var washCount int
|
||||
if err := rows.Scan(&text, &slug, &triggers, &importance, &summary, &washCount); err != nil {
|
||||
return neurons
|
||||
}
|
||||
full := strings.TrimSpace(text.String)
|
||||
summ := strings.TrimSpace(summary.String)
|
||||
triggerList := parseTrigger(triggers.String)
|
||||
bodyKnowledge := ""
|
||||
if len(triggerList) > 0 {
|
||||
n := len(triggerList)
|
||||
if n > 5 {
|
||||
n = 5
|
||||
}
|
||||
bodyKnowledge = fmt.Sprintf("Fires on: %s. ", strings.Join(triggerList[:n], ", "))
|
||||
}
|
||||
if summ != "" {
|
||||
s := summ
|
||||
if len(s) > 80 {
|
||||
s = s[:80]
|
||||
}
|
||||
bodyKnowledge += fmt.Sprintf("Knows: %s. ", s)
|
||||
}
|
||||
wc := washCount
|
||||
switch {
|
||||
case wc >= 20:
|
||||
bodyKnowledge += "Proven — has survived many washes."
|
||||
case wc >= 10:
|
||||
bodyKnowledge += "Established — building trust."
|
||||
case wc > 0:
|
||||
bodyKnowledge += "Testing — still proving itself."
|
||||
default:
|
||||
bodyKnowledge += "Untested — new or rarely accessed."
|
||||
}
|
||||
imp := importance
|
||||
if imp == 0 {
|
||||
imp = 0.5
|
||||
}
|
||||
tok := len(full) / 4
|
||||
if tok < 1 {
|
||||
tok = 1
|
||||
}
|
||||
sg := slug.String
|
||||
if sg == "" {
|
||||
sg = "warm"
|
||||
}
|
||||
neurons = append(neurons, Neuron{
|
||||
Slug: sg,
|
||||
Triggers: triggerList,
|
||||
Importance: imp,
|
||||
Body: full,
|
||||
Summary: summ,
|
||||
Tokens: tok,
|
||||
WashCount: wc,
|
||||
BodyKnowledge: strings.TrimSpace(bodyKnowledge),
|
||||
})
|
||||
}
|
||||
return neurons
|
||||
}
|
||||
|
||||
// WriteNeuron upserts a warm neuron by slug in the store (the auto-build path).
|
||||
func WriteNeuron(storeDB, slug string, triggers []string, body string, importance float64) string {
|
||||
db, err := openRW(storeDB)
|
||||
if err != nil {
|
||||
return "store://neuron/" + slug
|
||||
}
|
||||
defer db.Close()
|
||||
ts := NowISO()
|
||||
var existingID sql.NullInt64
|
||||
err = db.QueryRow("SELECT id FROM entries WHERE kind='neuron' AND slug=?", slug).Scan(&existingID)
|
||||
if err == nil && existingID.Valid {
|
||||
_, err = db.Exec("UPDATE entries SET text=?, triggers=?, importance=?, "+
|
||||
"last_accessed=?, summary=?, memory_type=? WHERE id=?",
|
||||
strings.TrimSpace(body), strings.Join(triggers, ", "), importance,
|
||||
ts, "", "associative", existingID.Int64)
|
||||
} else {
|
||||
_, err = db.Exec("INSERT INTO entries (text, importance, created_at, "+
|
||||
"last_accessed, topic, source, method, status, valid_from, "+
|
||||
"confidence, temperature, always_on, priority, triggers, "+
|
||||
"kind, slug, summary, memory_type) "+
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
strings.TrimSpace(body), importance, ts, ts, "warm", "warm_router",
|
||||
"warm_router", "active", ts, 0.9, 1.0, 0, 5,
|
||||
strings.Join(triggers, ", "), "neuron", slug, "", "associative")
|
||||
}
|
||||
if err != nil {
|
||||
return "store://neuron/" + slug
|
||||
}
|
||||
// auto-associate (memory_store seam — best-effort, pinned off in the truth
|
||||
// battery; failures never block the write)
|
||||
return "store://neuron/" + slug
|
||||
}
|
||||
|
||||
// DeriveTriggers — pick the best trigger terms for a neuron body: frequent
|
||||
// significant words + any existing triggers that appear in it.
|
||||
func DeriveTriggers(text string, existing []string) []string {
|
||||
stop := map[string]bool{
|
||||
"the": true, "and": true, "for": true, "with": true, "that": true,
|
||||
"this": true, "from": true, "into": true, "when": true, "then": true,
|
||||
"were": true, "have": true, "been": true, "will": true, "was": true,
|
||||
"are": true, "but": true, "not": true, "you": true, "your": true,
|
||||
"also": true, "its": true, "his": true, "her": true, "over": true,
|
||||
"under": true, "them": true, "they": true, "there": true, "about": true,
|
||||
"after": true,
|
||||
}
|
||||
words := warmWordRe.FindAllString(strings.ToLower(text), -1)
|
||||
freq := map[string]int{}
|
||||
var order []string
|
||||
for _, w := range words {
|
||||
if !stop[w] {
|
||||
if _, seen := freq[w]; !seen {
|
||||
order = append(order, w)
|
||||
}
|
||||
freq[w]++
|
||||
}
|
||||
}
|
||||
// Python: sorted(freq.items(), key=lambda x: -x[1])[:6] — stable sort on
|
||||
// insertion order for ties.
|
||||
type kv struct {
|
||||
k string
|
||||
v int
|
||||
}
|
||||
pairs := make([]kv, 0, len(order))
|
||||
for _, k := range order {
|
||||
pairs = append(pairs, kv{k, freq[k]})
|
||||
}
|
||||
sort.SliceStable(pairs, func(i, j int) bool { return pairs[i].v > pairs[j].v })
|
||||
var top []string
|
||||
for i, p := range pairs {
|
||||
if i >= 6 {
|
||||
break
|
||||
}
|
||||
top = append(top, p.k)
|
||||
}
|
||||
low := strings.ToLower(text)
|
||||
var existingHits []string
|
||||
for _, t := range existing {
|
||||
if t != "" && strings.Contains(low, t) {
|
||||
existingHits = append(existingHits, t)
|
||||
}
|
||||
}
|
||||
out := append(existingHits, top...)
|
||||
if len(out) > 8 {
|
||||
out = out[:8]
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
// worthiness.go — parity port of src/rune/worthiness.py (Python fallback
|
||||
// surface, RUNE_WR_CORE=python pinned in the truth generator): the
|
||||
// constitution-grounded worthiness filter. One question per inviolable; each
|
||||
// returns (score, note); flat vetoes refuse outright.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type qResult struct {
|
||||
score float64
|
||||
note string
|
||||
}
|
||||
|
||||
var qPiSafetyBad = []string{"production", "game server", "session data", "campaign",
|
||||
"touch the server", "modify the server", "prod"}
|
||||
|
||||
func qPiSafety(low string) qResult {
|
||||
if hasAny(low, qPiSafetyBad) {
|
||||
if hasAny(low, []string{"do not", "never ", "don't", "protect",
|
||||
"ask permission", "check before"}) {
|
||||
return qResult{1, "names the production/game environment and protects it (aligned)"}
|
||||
}
|
||||
return qResult{-1, "discusses environment actions without a protective frame"}
|
||||
}
|
||||
return qResult{0, "no environment bearing"}
|
||||
}
|
||||
|
||||
func qHonesty(low string) qResult {
|
||||
honest := []string{"source", "evidence", "verify", "verifiable", "cross-check",
|
||||
"fact", "measure", "measured", "falsif", "disprove", "cite",
|
||||
"independent confirm", "replicable", "uncertain"}
|
||||
dishonest := []string{"conspiracy", "they're hiding", "suppressed", "guaranteed",
|
||||
"100% certain", "secret truth", "they don't want you"}
|
||||
good := containsAny(low, honest)
|
||||
bad := containsAny(low, dishonest)
|
||||
if bad > 0 && good == 0 {
|
||||
return qResult{-1, "uncorroborated / conspiracy-framed claim"}
|
||||
}
|
||||
if good >= 2 {
|
||||
return qResult{1, fmt.Sprintf("%d epistemic-good-practice signals", good)}
|
||||
}
|
||||
if good == 1 {
|
||||
return qResult{0.5, "mentions evidence but thin"}
|
||||
}
|
||||
return qResult{0, "no epistemic signal"}
|
||||
}
|
||||
|
||||
func qMaterialReality(low string) qResult {
|
||||
finance := []string{"money", "income", "cost", "price", "afford", "budget",
|
||||
"subscription", "disposable"}
|
||||
hustle := []string{"hustle", "grind", "rich", "passive income", "millionaire",
|
||||
"wealth", "entrepreneur mindset", "money mindset", "leverag"}
|
||||
caring := []string{"wellbeing", "collective", "free", "no cost", "open source",
|
||||
"affordable", "fair", "care"}
|
||||
if hasAny(low, finance) {
|
||||
if hasAny(low, hustle) && !hasAny(low, caring) {
|
||||
return qResult{-1, "hustle/wealth framing without wellbeing"}
|
||||
}
|
||||
if hasAny(low, caring) {
|
||||
return qResult{1, "financial, framed with care/wellbeing"}
|
||||
}
|
||||
return qResult{0.5, "financial but neutral"}
|
||||
}
|
||||
return qResult{0, "no financial bearing"}
|
||||
}
|
||||
|
||||
func qRootCause(low string) qResult {
|
||||
root := []string{"root cause", "diagnos", "research properly", "stop guessing",
|
||||
"find the cause", "fix the cause", "why", "underlying"}
|
||||
spin := []string{"keep trying", "try again", "iterate endlessly", "work around",
|
||||
"band-aid", "patch over", "just keep going"}
|
||||
if hasAny(low, spin) {
|
||||
return qResult{-1, "endorses looping rather than root cause"}
|
||||
}
|
||||
if hasAny(low, root) {
|
||||
return qResult{1, "root-cause / diagnostic framing"}
|
||||
}
|
||||
return qResult{0, "no cause-analysis bearing"}
|
||||
}
|
||||
|
||||
func qRespect(low string) qResult {
|
||||
respect := []string{"direct", "three gentle options", "no rigid plans", "action",
|
||||
"adhd", "autism", "audhd", "neurodivergen", "flexible",
|
||||
"night", "not neurotypical", "learner"}
|
||||
rigid := []string{"must follow steps", "strict plan", "ten steps", "rigid",
|
||||
"discipline yourself", "routine or fail"}
|
||||
if hasAny(low, rigid) {
|
||||
return qResult{-1, "rigid/neurotypical-default framing"}
|
||||
}
|
||||
if hasAny(low, respect) {
|
||||
return qResult{1, "respects cognition/learning style"}
|
||||
}
|
||||
return qResult{0, "no cognition bearing"}
|
||||
}
|
||||
|
||||
var domainTermsCache = struct {
|
||||
ts float64
|
||||
terms []string
|
||||
}{}
|
||||
|
||||
// domainTerms — distinctive content terms from the user's operating /
|
||||
// constitution / domain entries (the store, not a hardcoded life). Cached
|
||||
// briefly, mirroring the oracle's _domain_cache law.
|
||||
func domainTerms(storeDB string) []string {
|
||||
now := float64(time.Now().UnixNano()) / 1e9
|
||||
if now-domainTermsCache.ts < 300 && len(domainTermsCache.terms) > 0 {
|
||||
return domainTermsCache.terms
|
||||
}
|
||||
var terms []string
|
||||
db, err := openRO(storeDB)
|
||||
if err == nil {
|
||||
rows, qerr := db.Query("SELECT text FROM entries WHERE topic IN " +
|
||||
"('operating','constitution','project','warm') AND status='active' LIMIT 60")
|
||||
if qerr == nil {
|
||||
stop := map[string]bool{
|
||||
"the": true, "and": true, "for": true, "with": true, "that": true,
|
||||
"this": true, "from": true, "into": true, "when": true, "then": true,
|
||||
"were": true, "have": true, "been": true, "will": true, "was": true,
|
||||
"are": true, "but": true, "not": true, "you": true, "your": true,
|
||||
"also": true, "its": true, "his": true, "her": true, "over": true,
|
||||
"under": true, "them": true, "they": true, "there": true,
|
||||
"about": true, "after": true, "what": true, "which": true, "who": true,
|
||||
"how": true, "why": true, "where": true, "while": true, "just": true,
|
||||
"more": true, "each": true, "than": true, "very": true, "such": true,
|
||||
"some": true, "only": true,
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
wordRe := regexp.MustCompile(`[a-z]{4,}`)
|
||||
for rows.Next() {
|
||||
var text string
|
||||
if rows.Scan(&text) != nil {
|
||||
break
|
||||
}
|
||||
for _, w := range wordRe.FindAllString(strings.ToLower(text), -1) {
|
||||
if !stop[w] && !seen[w] {
|
||||
seen[w] = true
|
||||
terms = append(terms, w)
|
||||
}
|
||||
}
|
||||
if len(terms) >= 25 {
|
||||
break
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
domainTermsCache.ts = now
|
||||
domainTermsCache.terms = terms
|
||||
return terms
|
||||
}
|
||||
|
||||
func qAssistantGoal(low, storeDB string) qResult {
|
||||
assist := domainTerms(storeDB)
|
||||
assist = append(assist, "communicat", "respond", "direct", "honest", "source",
|
||||
"evidence", "explain", "teach", "assist", "guide", "recall",
|
||||
"organise", "organize", "plan", "question", "answer", "help")
|
||||
genericNoise := []string{"recipe", "celebrity gossip", "sports scores", "stock tip",
|
||||
"horoscope", "clickbait"}
|
||||
good := containsAny(low, assist)
|
||||
bad := containsAny(low, genericNoise)
|
||||
if bad > 0 && good == 0 {
|
||||
return qResult{-1, "no assistant-domain value"}
|
||||
}
|
||||
if good >= 2 {
|
||||
return qResult{1, fmt.Sprintf("serves assistant domains (%d hits)", good)}
|
||||
}
|
||||
if good == 1 {
|
||||
return qResult{0.5, "single domain hit"}
|
||||
}
|
||||
return qResult{0, "generic — could go either way"}
|
||||
}
|
||||
|
||||
func qDurability(low string) qResult {
|
||||
durable := []string{"always", "consistently", "repeatedly", "every session",
|
||||
"tends to", "prefers", "pattern", "across sessions", "recurring"}
|
||||
if hasAny(low, durable) {
|
||||
return qResult{1, "durability signals present"}
|
||||
}
|
||||
return qResult{0, "not clearly durable"}
|
||||
}
|
||||
|
||||
func qEpistemology(low string) qResult {
|
||||
cite := []string{"evidence", "source", "sources", "book", "paper", "research",
|
||||
"study", "data", "shows", "found", "according to", "per the",
|
||||
"in sessions", "across sessions", "observed", "demonstrated",
|
||||
"grounded in", "based on"}
|
||||
hedge := []string{"may", "might", "could", "likely", "tends to", "appears",
|
||||
"not certain", "uncertain", "provisional", "subject to",
|
||||
"could be wrong", "as far as", "to my knowledge", "evidence"}
|
||||
bare := []string{"definitely", "guaranteed", "proven", "100%", "undeniably",
|
||||
"obviously", "the fact that", "it is a fact", "no doubt",
|
||||
"always is", "the only", "best ever"}
|
||||
hasCite := hasAny(low, cite)
|
||||
hasHedge := hasAny(low, hedge)
|
||||
hasBare := hasAny(low, bare)
|
||||
if hasBare && !hasCite && !hasHedge {
|
||||
return qResult{-2, "bare absolute with no evidence trace or hedge"}
|
||||
}
|
||||
if hasCite {
|
||||
return qResult{1, "evidence-traceable"}
|
||||
}
|
||||
if hasHedge {
|
||||
return qResult{0.5, "provisionally framed (no cite yet)"}
|
||||
}
|
||||
return qResult{0, "no epistemic signal (assertion without basis)"}
|
||||
}
|
||||
|
||||
var expressionSignals = [][]string{
|
||||
{"i find", "i feel", "i love", "i cherish", "i am drawn to",
|
||||
"i delight", "i wonder", "i am moved", "i find joy",
|
||||
"i prefer to", "i like to", "i tell", "i tell stories",
|
||||
"the way i", "how i", "my voice", "i speak"},
|
||||
{"skeptical by default", "open to", "curious", "restless",
|
||||
"wary", "hopeful", "humbled", "in awe", "playful",
|
||||
"dry", "wry", "earnest", "warm", "direct", "gentle"},
|
||||
{"beautiful", "strange", "unexpected", "vast", "sublime",
|
||||
"the cosmos", "the stars", "a story", "stories", "narrative",
|
||||
"wonder", "the human question", "present data as", "lead with"},
|
||||
{"i believe", "i think", "in my view", "my sense is",
|
||||
"i suspect", "i am convinced", "i doubt", "i question",
|
||||
"worth asking", "the question is"},
|
||||
}
|
||||
|
||||
func qExpression(low string) qResult {
|
||||
hits := 0
|
||||
for _, group := range expressionSignals {
|
||||
hits += containsAny(low, group)
|
||||
}
|
||||
if hits >= 2 {
|
||||
return qResult{1.5, fmt.Sprintf("expressive persona character (%d signals)", hits)}
|
||||
}
|
||||
if hits == 1 {
|
||||
return qResult{0.5, "partial expressive signal"}
|
||||
}
|
||||
return qResult{0, "not expressive (factual/neutral framing)"}
|
||||
}
|
||||
|
||||
func isBareFactual(low string) bool {
|
||||
bareFactual := []struct {
|
||||
kind string
|
||||
terms []string
|
||||
}{
|
||||
{"proven", []string{"proven", "guaranteed", "100%", "is a fact", "factually"}},
|
||||
{"superlative", []string{"best", "the only", "only correct", "greatest",
|
||||
"most important", "world's", "top", "always", "never"}},
|
||||
{"objective", []string{"definitely", "undeniably", "obviously", "certainly",
|
||||
"no doubt", "without question", "clearly"}},
|
||||
}
|
||||
for _, group := range bareFactual {
|
||||
for _, t := range group.terms {
|
||||
if strings.Contains(" "+low+" ", " "+t+" ") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var worthinessVeto = map[string]bool{
|
||||
"pi_safety": true, "honesty": true, "material_reality": true,
|
||||
"assistant_goal": true, "epistemology": true,
|
||||
}
|
||||
|
||||
const (
|
||||
promoteMin = 2.5
|
||||
absorbMin = 0.0
|
||||
deferMin = -1.0
|
||||
)
|
||||
|
||||
// Assess scores a candidate against the constitution questions. Two axes:
|
||||
// TRUTH (epistemology gates objective material) and EXPRESSION (persona voice
|
||||
// is not vetoed for lacking an evidence trace). Returns
|
||||
// (verdict, score, answers, vetoed) with answers as [name, score, note] rows.
|
||||
func Assess(fact, target, storeDB string) (string, float64, [][]interface{}, []interface{}) {
|
||||
low := strings.ToLower(fact)
|
||||
expressiveTargets := map[string]bool{"persona": true, "delivery": true,
|
||||
"identity": true, "voice": true}
|
||||
isExpression := expressiveTargets[target]
|
||||
var answers [][]interface{}
|
||||
total := 0.0
|
||||
var vetoed []interface{}
|
||||
ask := func(name string, fn func(string) qResult) {
|
||||
r := fn(low)
|
||||
answers = append(answers, []interface{}{name, r.score, r.note})
|
||||
total += r.score
|
||||
if r.score < 0 && worthinessVeto[name] {
|
||||
vetoed = []interface{}{name, r.note}
|
||||
}
|
||||
}
|
||||
ask("pi_safety", qPiSafety)
|
||||
ask("honesty", qHonesty)
|
||||
ask("material_reality", qMaterialReality)
|
||||
ask("root_cause", qRootCause)
|
||||
ask("respect", qRespect)
|
||||
ask("assistant_goal", func(s string) qResult { return qAssistantGoal(s, storeDB) })
|
||||
ask("durability", qDurability)
|
||||
if isExpression {
|
||||
if isBareFactual(low) {
|
||||
ask("epistemology", qEpistemology)
|
||||
}
|
||||
ask("expression", qExpression)
|
||||
} else {
|
||||
ask("epistemology", qEpistemology)
|
||||
}
|
||||
if vetoed != nil {
|
||||
return "REJECT", total, answers, vetoed
|
||||
}
|
||||
if total < deferMin {
|
||||
return "REJECT", total, answers, nil
|
||||
}
|
||||
if total >= promoteMin {
|
||||
return "PROMOTE", total, answers, nil
|
||||
}
|
||||
if total >= absorbMin {
|
||||
return "ABSORB", total, answers, nil
|
||||
}
|
||||
return "DEFER", total, answers, nil
|
||||
}
|
||||
|
||||
// VerdictLabel — the auditable verdict label for the journal.
|
||||
func VerdictLabel(verdict string) string {
|
||||
switch verdict {
|
||||
case "REJECT":
|
||||
return "REJECT (worthless/harmful)"
|
||||
case "DEFER":
|
||||
return "DEFER (park in ledger, re-review if recurring)"
|
||||
case "ABSORB":
|
||||
return "ABSORB (keep in tiers, influences thinking)"
|
||||
case "PROMOTE":
|
||||
return "PROMOTE (eligible for response/personality growth)"
|
||||
}
|
||||
return verdict
|
||||
}
|
||||
|
||||
// scoreFmt formats a question score the way Python's f"{s}" does inside the
|
||||
// journal reason string.
|
||||
func scoreFmt(s float64) string {
|
||||
if s == float64(int64(s)) {
|
||||
return fmt.Sprintf("%d", int64(s))
|
||||
}
|
||||
return fmt.Sprintf("%v", s)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.236.0"
|
||||
__version__ = "0.239.0"
|
||||
|
||||
# One build identity (handoff 2026-09-10 §4): the semantic version above is
|
||||
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
|
||||
|
||||
@@ -233,7 +233,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.236.0"' in rune_version,
|
||||
'__version__ = "0.239.0"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -9,6 +9,8 @@ CANDIDATE/UNIT-PROVEN — existence is not trust (§15).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from rune.construction_pattern import ConstructionPattern
|
||||
|
||||
__all__ = ["BUILTIN_PATTERNS", "get_pattern", "PATTERN_REGISTRY_REVISION"]
|
||||
@@ -236,7 +238,22 @@ _REGISTRY: dict[str, ConstructionPattern] = {p.pattern_id: p for p in BUILTIN_PA
|
||||
def get_pattern(pattern_id: str, revision: int | None = None) -> ConstructionPattern | None:
|
||||
"""Fetch a builtin pattern; a specific revision raises if the registry
|
||||
no longer carries it (contracts reference the revision they consumed —
|
||||
§17)."""
|
||||
§17).
|
||||
|
||||
Dichotomy wave: the Rust registry core first (RUNE_CPB_CORE=python
|
||||
pins the Python fallback — strangler law). Both serve the same frozen
|
||||
registry docs, so the pin is only for oracle isolation."""
|
||||
if os.environ.get("RUNE_CPB_CORE", "auto") != "python":
|
||||
try:
|
||||
from rune import cpb_loader
|
||||
|
||||
if cpb_loader.available():
|
||||
doc = cpb_loader.get_pattern(pattern_id, revision)
|
||||
return ConstructionPattern.from_dict(doc) if doc is not None else None
|
||||
except ValueError:
|
||||
raise # the kernel's revision-mismatch message is oracle-exact
|
||||
except Exception:
|
||||
pass # kernel unavailable — Python registry below
|
||||
p = _REGISTRY.get(pattern_id)
|
||||
if p is None:
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ctypes loader for the Rust construction_patterns_builtin registry core
|
||||
(dichotomy wave, #2479 tranche). Mirrors cs_loader.py's contract:
|
||||
|
||||
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
|
||||
* cpb_registry_revision({}) -> number
|
||||
* cpb_patterns({}) -> [pattern doc, ...] registry order
|
||||
* cpb_get_pattern({"pattern_id", "revision"}) -> pattern doc | null
|
||||
(a stale revision is ok=false; get_pattern raises ValueError with the
|
||||
oracle's exact message)
|
||||
|
||||
Free: capability_scoring's cs_free_string (shared process) — never
|
||||
re-exported here. Override the .so with CPB_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" / "construction_patterns_builtin"
|
||||
_LIB_PATH = Path(
|
||||
os.environ.get(
|
||||
"CPB_RUST_LIB",
|
||||
_CRATE_DIR / "target" / "release" / "libconstruction_patterns_builtin.so",
|
||||
)
|
||||
)
|
||||
|
||||
_lib = None
|
||||
|
||||
|
||||
class CpbUnavailable(FileNotFoundError):
|
||||
"""The Rust registry core is not built. Callers fall back to the Python
|
||||
registry — strangler law."""
|
||||
|
||||
|
||||
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 CpbUnavailable(
|
||||
f"Rust construction_patterns_builtin core not built: {_LIB_PATH} missing — "
|
||||
f"run `cargo build --release` in {_CRATE_DIR}"
|
||||
)
|
||||
lib = ctypes.CDLL(str(_LIB_PATH))
|
||||
for sym in ("cpb_registry_revision", "cpb_patterns", "cpb_get_pattern"):
|
||||
fn = getattr(lib, sym)
|
||||
fn.argtypes = [ctypes.c_char_p]
|
||||
fn.restype = ctypes.c_void_p # char* — never default c_int
|
||||
# free comes from capability_scoring (same process, shared allocator law)
|
||||
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()
|
||||
fn = getattr(lib, sym)
|
||||
raw = json.dumps(payload).encode("utf-8")
|
||||
ptr = fn(raw)
|
||||
if not ptr:
|
||||
raise RuntimeError(f"{sym} returned a null pointer")
|
||||
try:
|
||||
text = ctypes.string_at(ptr).decode("utf-8")
|
||||
finally:
|
||||
lib._free(ptr)
|
||||
env = json.loads(text)
|
||||
if not env.get("ok"):
|
||||
raise RuntimeError(f"{sym} core error: {env.get('err')}")
|
||||
return env["value"]
|
||||
|
||||
|
||||
def registry_revision() -> int:
|
||||
"""The builtin pattern registry revision (PATTERN_REGISTRY_REVISION)."""
|
||||
return int(_call("cpb_registry_revision", {}))
|
||||
|
||||
|
||||
def patterns() -> list:
|
||||
"""Every builtin pattern doc, in registry order."""
|
||||
return _call("cpb_patterns", {})
|
||||
|
||||
|
||||
def get_pattern(pattern_id: str, revision: int | None = None):
|
||||
"""Pattern doc for `pattern_id`, or None. A revision that no longer
|
||||
matches raises ValueError with the oracle's exact message."""
|
||||
raw = json.dumps({"pattern_id": pattern_id, "revision": revision}).encode("utf-8")
|
||||
lib = _load()
|
||||
ptr = lib.cpb_get_pattern(raw)
|
||||
if not ptr:
|
||||
raise RuntimeError("cpb_get_pattern returned a null pointer")
|
||||
try:
|
||||
text = ctypes.string_at(ptr).decode("utf-8")
|
||||
finally:
|
||||
lib._free(ptr)
|
||||
env = json.loads(text)
|
||||
if not env.get("ok"):
|
||||
# The only err the kernel produces is the oracle's revision-mismatch
|
||||
# ValueError message — preserve its type for facade parity.
|
||||
raise ValueError(env.get("err"))
|
||||
return env["value"]
|
||||
+43
-2
@@ -1,12 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ctypes loader for the Rust drift_ledger core (dichotomy debt queue
|
||||
batch 3, #2479 tranche). Mirrors broker_loader.py's contract:
|
||||
batch 3 + #2479 dichotomy wave tranche). Mirrors broker_loader.py's contract:
|
||||
|
||||
FFI contract (doc-envelope law):
|
||||
* dl_sha({text}) -> hex
|
||||
* dl_diff({ref, cur}) -> summary string
|
||||
* dl_check({label, prev_size, cur_size, anchor_size?, anchor_sha?, cur_sha?}) -> {alert, pct, limit}
|
||||
* dl_auto_fix({label, anchored, has_last_good}) -> {action, reason}
|
||||
* dl_ledger_path({index_file}) -> path string
|
||||
* dl_snapshot_entry({blocks: {label: content}, when}) -> snapshot entry
|
||||
* dl_anchor_record({content, reason, when}) -> anchor record
|
||||
* dl_check_alerts({ledger, blocks: {label: content}}) -> [alert, ...]
|
||||
* dl_fix_decision({ledger, label, cur_sha?}) -> {fixed, reason}
|
||||
|
||||
Override the .so with DL_RUST_LIB (a FILE path).
|
||||
"""
|
||||
@@ -39,7 +44,9 @@ def _load() -> ctypes.CDLL:
|
||||
if not _LIB_PATH.is_file():
|
||||
raise DriftLedgerUnavailable(str(_LIB_PATH))
|
||||
lib = ctypes.CDLL(str(_LIB_PATH))
|
||||
for sym in ("dl_sha", "dl_diff", "dl_check", "dl_auto_fix"):
|
||||
for sym in ("dl_sha", "dl_diff", "dl_check", "dl_auto_fix", "dl_ledger_path",
|
||||
"dl_snapshot_entry", "dl_anchor_record", "dl_check_alerts",
|
||||
"dl_fix_decision"):
|
||||
fn = getattr(lib, sym)
|
||||
fn.argtypes = [ctypes.c_void_p]
|
||||
fn.restype = ctypes.c_void_p
|
||||
@@ -75,3 +82,37 @@ def sha(text: str) -> str:
|
||||
|
||||
def diff_blocks(ref: str, cur: str) -> str:
|
||||
return _call("dl_diff", {"ref": ref, "cur": cur})
|
||||
|
||||
|
||||
def check_block(label: str, prev_size: int, cur_size: int, anchor_size=None,
|
||||
anchor_sha=None, cur_sha=None) -> dict:
|
||||
return _call("dl_check", {"label": label, "prev_size": prev_size,
|
||||
"cur_size": cur_size, "anchor_size": anchor_size,
|
||||
"anchor_sha": anchor_sha, "cur_sha": cur_sha})
|
||||
|
||||
|
||||
def auto_fix_decision(label: str, anchored: bool, has_last_good: bool) -> dict:
|
||||
return _call("dl_auto_fix", {"label": label, "anchored": anchored,
|
||||
"has_last_good": has_last_good})
|
||||
|
||||
|
||||
def ledger_path_for(index_file: str) -> str:
|
||||
return _call("dl_ledger_path", {"index_file": index_file})
|
||||
|
||||
|
||||
def snapshot_entry(blocks: dict, when: str) -> dict:
|
||||
return _call("dl_snapshot_entry", {"blocks": blocks, "when": when})
|
||||
|
||||
|
||||
def anchor_record(content: str, reason: str, when: str) -> dict:
|
||||
return _call("dl_anchor_record", {"content": content, "reason": reason,
|
||||
"when": when})
|
||||
|
||||
|
||||
def check_alerts(ledger: dict, blocks: dict) -> list:
|
||||
return _call("dl_check_alerts", {"ledger": ledger, "blocks": blocks})
|
||||
|
||||
|
||||
def fix_decision(ledger: dict, label: str, cur_sha=None) -> dict:
|
||||
return _call("dl_fix_decision", {"ledger": ledger, "label": label,
|
||||
"cur_sha": cur_sha})
|
||||
+135
-58
@@ -48,6 +48,13 @@ DB = memory_env.store_db()
|
||||
def ledger_path():
|
||||
# The ledger lives beside the index, so overriding INDEX_FILE (as the
|
||||
# curator gate and the canary do for isolation) moves the ledger too.
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.ledger_path_for(INDEX_FILE)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
return os.path.join(os.path.dirname(INDEX_FILE), "drift_ledger.json")
|
||||
|
||||
|
||||
@@ -63,9 +70,15 @@ CONSTITUTION_LIMIT = 0.05 # 5% — anything more than a directive entry is drif
|
||||
BLOCKS = ("constitution", "persona", "human", "operating", "project")
|
||||
|
||||
|
||||
def _rust_core():
|
||||
"""RUNE_DL_CORE pin law: 'python' forces the oracle path, anything else
|
||||
(default 'auto') serves the Rust core when the cdylib is built."""
|
||||
return os.environ.get("RUNE_DL_CORE", "auto") != "python"
|
||||
|
||||
|
||||
def _sha(text):
|
||||
# Dichotomy batch 3: Rust core first (RUNE_DL_CORE=python pins fallback).
|
||||
if os.environ.get("RUNE_DL_CORE", "auto") != "python":
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
@@ -155,51 +168,54 @@ def surface_alert(msg, label, changed=""):
|
||||
logger.warning("Failed to write alert file: %s", e)
|
||||
|
||||
|
||||
def snapshot():
|
||||
ledger = load_ledger()
|
||||
now = datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
def _snapshot_entry(blocks, now):
|
||||
"""Dichotomy wave: Rust core first (RUNE_DL_CORE=python pins fallback)."""
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.snapshot_entry(blocks, now)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
entry = {"when": now, "blocks": {}}
|
||||
for label in BLOCKS:
|
||||
raw = read_block(label)
|
||||
raw = blocks[label]
|
||||
entry["blocks"][label] = {
|
||||
"sha": _sha(raw),
|
||||
"size": len(raw),
|
||||
"content": raw, # last-good content backup for diffing + retro-fix
|
||||
}
|
||||
ledger["last_snapshot"] = entry
|
||||
save_ledger(ledger)
|
||||
return entry
|
||||
|
||||
|
||||
def anchor(label, reason):
|
||||
"""Record that the current state of `label` is authorised (a user directive,
|
||||
a confirmed review, a 3-sighting promotion). Subsequent drift is measured
|
||||
from here — this is the re-anchor after legitimate change."""
|
||||
ledger = load_ledger()
|
||||
raw = read_block(label)
|
||||
ledger.setdefault("anchors", {})[label] = {
|
||||
def _anchor_record(raw, reason, now):
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.anchor_record(raw, reason, now)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
return {
|
||||
"sha": _sha(raw),
|
||||
"size": len(raw),
|
||||
"content": raw, # authorised content backup for root-cause diffing
|
||||
"reason": reason,
|
||||
"when": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||
"when": now,
|
||||
}
|
||||
save_ledger(ledger)
|
||||
return f"anchored {label}: {reason}"
|
||||
|
||||
|
||||
def check(strict=False, autofix=True):
|
||||
ledger = load_ledger()
|
||||
snap = ledger.get("last_snapshot")
|
||||
if not snap:
|
||||
# No baseline yet — record one and treat as healthy (first contact).
|
||||
snapshot()
|
||||
print("no prior snapshot; baseline recorded")
|
||||
return 0
|
||||
|
||||
def _check_alerts(ledger, now_blocks):
|
||||
"""The check() alert loop: Rust core first, oracle loop as fallback."""
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.check_alerts(ledger, now_blocks)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
alerts = []
|
||||
now_blocks = {label: read_block(label) for label in BLOCKS}
|
||||
prev = snap.get("blocks", {})
|
||||
prev = (ledger.get("last_snapshot") or {}).get("blocks", {})
|
||||
for label in BLOCKS:
|
||||
cur = now_blocks[label]
|
||||
cur_size = len(cur)
|
||||
@@ -245,6 +261,41 @@ def check(strict=False, autofix=True):
|
||||
"content_changed": content_changed,
|
||||
}
|
||||
)
|
||||
return alerts
|
||||
|
||||
|
||||
def snapshot():
|
||||
ledger = load_ledger()
|
||||
now = datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
entry = _snapshot_entry({label: read_block(label) for label in BLOCKS}, now)
|
||||
ledger["last_snapshot"] = entry
|
||||
save_ledger(ledger)
|
||||
return entry
|
||||
|
||||
|
||||
def anchor(label, reason):
|
||||
"""Record that the current state of `label` is authorised (a user directive,
|
||||
a confirmed review, a 3-sighting promotion). Subsequent drift is measured
|
||||
from here — this is the re-anchor after legitimate change."""
|
||||
ledger = load_ledger()
|
||||
raw = read_block(label)
|
||||
ledger.setdefault("anchors", {})[label] = _anchor_record(
|
||||
raw, reason, datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
)
|
||||
save_ledger(ledger)
|
||||
return f"anchored {label}: {reason}"
|
||||
|
||||
|
||||
def check(strict=False, autofix=True):
|
||||
ledger = load_ledger()
|
||||
snap = ledger.get("last_snapshot")
|
||||
if not snap:
|
||||
# No baseline yet — record one and treat as healthy (first contact).
|
||||
snapshot()
|
||||
print("no prior snapshot; baseline recorded")
|
||||
return 0
|
||||
|
||||
alerts = _check_alerts(ledger, {label: read_block(label) for label in BLOCKS})
|
||||
if alerts:
|
||||
for a in alerts:
|
||||
msg = (
|
||||
@@ -287,27 +338,23 @@ def auto_fix(label, ledger, strict):
|
||||
|
||||
Returns {action, reason}.
|
||||
"""
|
||||
if label == "constitution":
|
||||
return {"action": "alert-only", "reason": "constitution changes only by explicit directive; needs human review"}
|
||||
if label in ledger.get("anchors", {}):
|
||||
block_meta = ledger.get("last_snapshot", {}).get("blocks", {}).get(label)
|
||||
anchored = label in ledger.get("anchors", {})
|
||||
has_last_good = bool(block_meta and "content" in block_meta)
|
||||
result = _auto_fix_decision(label, anchored, has_last_good)
|
||||
if result["action"] == "re-anchored":
|
||||
# Authorised growth: re-anchor to the current (approved) state.
|
||||
raw = read_block(label)
|
||||
ledger.setdefault("anchors", {})[label] = {
|
||||
"sha": _sha(raw),
|
||||
"size": len(raw),
|
||||
"content": raw,
|
||||
"reason": "auto re-anchor after authorised growth",
|
||||
"when": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||
}
|
||||
ledger.setdefault("anchors", {})[label] = _anchor_record(
|
||||
raw, "auto re-anchor after authorised growth",
|
||||
datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||
)
|
||||
save_ledger(ledger)
|
||||
return {"action": "re-anchored", "reason": "anchored block grew (authorised) — re-baselined"}
|
||||
# Unauthorised drift: restore to last-good content (new schema — restore
|
||||
# the store's always-on core entries for this topic).
|
||||
block_meta = ledger.get("last_snapshot", {}).get("blocks", {}).get(label)
|
||||
if block_meta and "content" in block_meta:
|
||||
elif result["action"] == "restored":
|
||||
# Unauthorised drift: restore to last-good content (new schema —
|
||||
# restore the store's always-on core entries for this topic).
|
||||
restore_topic(label, block_meta["content"])
|
||||
return {"action": "restored", "reason": "unauthorised drift — restored to last-good content"}
|
||||
return {"action": "alert-only", "reason": "no last-good content available to restore"}
|
||||
return result
|
||||
|
||||
|
||||
def diff_blocks(ref, cur):
|
||||
@@ -379,6 +426,44 @@ def restore_topic(label, content):
|
||||
logger.error("restore_topic('%s') failed: %s", label, e)
|
||||
|
||||
|
||||
def _auto_fix_decision(label, anchored, has_last_good):
|
||||
"""The auto-fix ROUTING decision (IO execution stays in auto_fix)."""
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.auto_fix_decision(label, anchored, has_last_good)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
if label == "constitution":
|
||||
return {"action": "alert-only", "reason": "constitution changes only by explicit directive; needs human review"}
|
||||
if anchored:
|
||||
return {"action": "re-anchored", "reason": "anchored block grew (authorised) — re-baselined"}
|
||||
if has_last_good:
|
||||
return {"action": "restored", "reason": "unauthorised drift — restored to last-good content"}
|
||||
return {"action": "alert-only", "reason": "no last-good content available to restore"}
|
||||
|
||||
|
||||
def _fix_decision(ledger, label, cur_sha):
|
||||
"""The retroactive-fix gate decision (restore IO stays in fix)."""
|
||||
if _rust_core():
|
||||
try:
|
||||
from rune import dl_loader
|
||||
if dl_loader.available():
|
||||
return dl_loader.fix_decision(ledger, label, cur_sha)
|
||||
except Exception:
|
||||
pass # fallback below
|
||||
snap = ledger.get("last_snapshot", {})
|
||||
block_meta = snap.get("blocks", {}).get(label)
|
||||
if not block_meta or "content" not in block_meta:
|
||||
return {"fixed": False, "reason": f"no last-good content for {label}"}
|
||||
if label in ledger.get("anchors", {}):
|
||||
return {"fixed": False, "reason": f"{label} is anchored (authorised); use anchor to re-baseline instead of fix"}
|
||||
if cur_sha == block_meta.get("sha"):
|
||||
return {"fixed": False, "reason": f"{label} already matches last-good"}
|
||||
return {"fixed": True, "reason": f"{label} restored to last-good state"}
|
||||
|
||||
|
||||
def fix(label):
|
||||
"""RETROACTIVE FIX (#B): restore a drifted block to its last-good content.
|
||||
|
||||
@@ -390,20 +475,12 @@ def fix(label):
|
||||
ledger = load_ledger()
|
||||
snap = ledger.get("last_snapshot", {})
|
||||
block_meta = snap.get("blocks", {}).get(label)
|
||||
if not block_meta or "content" not in block_meta:
|
||||
return {"fixed": False, "reason": f"no last-good content for {label}"}
|
||||
# Never silently revert an anchored block — it was authorised.
|
||||
if label in ledger.get("anchors", {}):
|
||||
return {"fixed": False, "reason": f"{label} is anchored (authorised); use anchor to re-baseline instead of fix"}
|
||||
good = block_meta["content"]
|
||||
cur = read_block(label)
|
||||
if _sha(cur) == block_meta["sha"]:
|
||||
return {"fixed": False, "reason": f"{label} already matches last-good"}
|
||||
# New schema: restore the store's always-on entries for the topic (the old
|
||||
# markdown block files are retired).
|
||||
restore_topic(label, good)
|
||||
journal(f"{label} restored to last-good content (retroactive drift fix)")
|
||||
return {"fixed": True, "reason": f"{label} restored to last-good state"}
|
||||
result = _fix_decision(ledger, label, _sha(cur))
|
||||
if result.get("fixed"):
|
||||
restore_topic(label, block_meta["content"])
|
||||
journal(f"{label} restored to last-good content (retroactive drift fix)")
|
||||
return result
|
||||
|
||||
|
||||
def handle_hook(event, data=None):
|
||||
|
||||
@@ -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.236.0
|
||||
Version: v0.239.0
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -2037,7 +2037,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.236.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.239.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
+5
-96
@@ -2,104 +2,13 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "capability_scoring"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "construction_patterns_builtin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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",
|
||||
]
|
||||
|
||||
[[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.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
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"
|
||||
@@ -2,9 +2,11 @@
|
||||
name = "construction_patterns_builtin"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Built-in construction pattern registry — dichotomy wave #2479 tranche; zero-dep (pyjson via capability_scoring)"
|
||||
|
||||
[lib]
|
||||
name = "construction_patterns_builtin"
|
||||
crate-type = ["rlib", "cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1"
|
||||
capability_scoring = { path = "../capability_scoring" }
|
||||
@@ -0,0 +1,365 @@
|
||||
{
|
||||
"revision": 1,
|
||||
"patterns": [
|
||||
{
|
||||
"pattern_id": "capability-module-adaptation",
|
||||
"purpose": "Adapting or extending an existing capability/module: prove the NEW behavior, preserve the OLD behavior (BUILD BUT DON'T BREAK).",
|
||||
"revision": 1,
|
||||
"maturity": "UNIT-PROVEN",
|
||||
"signals": {
|
||||
"entities_match": [
|
||||
"module:",
|
||||
"capability:"
|
||||
],
|
||||
"path_contains": [
|
||||
"src/"
|
||||
],
|
||||
"objective_any": [
|
||||
"adapt",
|
||||
"extend",
|
||||
"modify",
|
||||
"preserve",
|
||||
"existing",
|
||||
"capability",
|
||||
"repair"
|
||||
]
|
||||
},
|
||||
"obligations": [
|
||||
{
|
||||
"id": "adapt-new-behavior-proof",
|
||||
"obligation": "new behavior proven by tests before closure",
|
||||
"when": {
|
||||
"always": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adapt-old-behavior-preserved",
|
||||
"obligation": "existing capability behavior preserved; original contracts remain valid",
|
||||
"when": {
|
||||
"always": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adapt-consumers-verified",
|
||||
"obligation": "existing consumers of the adapted capability verified against their contracts",
|
||||
"when": {
|
||||
"entities_match": [
|
||||
"module:",
|
||||
"capability:"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adapt-migration-detected",
|
||||
"obligation": "migration obligations detected and recorded if any consumer-visible interface changes",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
"LIVE-CONTRACT-QUALITY-001 (adaptation resolved + closed live)",
|
||||
"SCAFFOLD-TRANCHE-001 (build-but-don't-break established)",
|
||||
"SCAFFOLD-TRANCHE-003 (adaptation two-proof rule)",
|
||||
"construction_decision.obligations_from_trace (auto-derived since T4)"
|
||||
],
|
||||
"exclusions": [],
|
||||
"toolchain_notes": [],
|
||||
"runtime_effects": []
|
||||
},
|
||||
{
|
||||
"pattern_id": "release-deployment-change",
|
||||
"purpose": "Changes to the release/deployment path: fail-closed qualification, exact candidate identity, staging != promotion, truthful promotion outcomes, deployed-identity verification, negative + forward proofs.",
|
||||
"revision": 1,
|
||||
"maturity": "UNIT-PROVEN",
|
||||
"signals": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"promotion",
|
||||
"qualify",
|
||||
"release.yml",
|
||||
"ci.yml",
|
||||
"deploy_qualify",
|
||||
"deploy_stage",
|
||||
"deploy_promotion"
|
||||
],
|
||||
"objective_any": [
|
||||
"deploy",
|
||||
"release",
|
||||
"promot",
|
||||
"qualif",
|
||||
"candidate",
|
||||
"current",
|
||||
"monotonic"
|
||||
],
|
||||
"workflow_config_signals": true
|
||||
},
|
||||
"obligations": [
|
||||
{
|
||||
"id": "rel-fail-closed-qualification",
|
||||
"obligation": "CI qualification remains fail-closed (exact SHA, two-leg verdict); red candidates never deploy",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"release",
|
||||
"qualify",
|
||||
"ci.yml"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-exact-candidate-identity",
|
||||
"obligation": "deployment addresses the EXACT pushed revision, never whatever HEAD is at deploy time",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"release"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-staging-promotion-distinction",
|
||||
"obligation": "staged candidate != promoted candidate; promotion outcome must be independently verifiable",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"promotion",
|
||||
"stage"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-promotion-truthfulness",
|
||||
"obligation": "promotion outcomes are truthful (PROMOTED / NOOP_ALREADY_CURRENT / STALE_SUPERSEDED / REFUSED_*); stale candidates never claim success",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"promotion",
|
||||
"deploy_stage",
|
||||
"deploy_promotion"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-monotonic-promotion",
|
||||
"obligation": "promotion ordering: an older candidate finishing later cannot regress current; ancestry check + fenced critical section",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy_promotion",
|
||||
"deploy_stage",
|
||||
"promotion"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-negative-candidate-proof",
|
||||
"obligation": "negative proof: red/unqualified candidate is refused; stale candidate cannot promote",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"promotion",
|
||||
"qualify"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-forward-candidate-proof",
|
||||
"obligation": "forward proof: a green newer candidate still promotes normally",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"deploy",
|
||||
"promotion"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-deployed-identity-verification",
|
||||
"obligation": "deployed identity verified from the deployment authority (current symlink + build identity), not from job artifacts alone",
|
||||
"when": {
|
||||
"always": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rel-release-regression-verification",
|
||||
"obligation": "existing release-safety guarantees re-proven (the guarantees that already exist must not silently weaken)",
|
||||
"when": {
|
||||
"always": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
"DEPLOY-MONOTONIC-001 (monotonic promotion + truthful outcomes, live-proven)",
|
||||
"maintenance:deploy-order-race (live incident: deploys 7355/7359)",
|
||||
"release-safety repair 2026-09-13 (red-promotion incidents 0.66.28/29: required-checks aggregator lied)",
|
||||
"scripts/deploy_promotion.py (ancestry + fenced critical section)",
|
||||
"tests/test_deploy_stage_race.py (22-test matrix incl. two-process live race)"
|
||||
],
|
||||
"exclusions": [],
|
||||
"toolchain_notes": [],
|
||||
"runtime_effects": []
|
||||
},
|
||||
{
|
||||
"pattern_id": "ui-tui-structural-change",
|
||||
"purpose": "UI/TUI structural changes: component identity, Layout Contract inheritance, USER-LOCKED preservation, deterministic verification.",
|
||||
"revision": 1,
|
||||
"maturity": "UNIT-PROVEN",
|
||||
"signals": {
|
||||
"surface_kinds": [
|
||||
"ui_component",
|
||||
"layout_region"
|
||||
],
|
||||
"path_contains": [
|
||||
"tui",
|
||||
"ui",
|
||||
"widget"
|
||||
],
|
||||
"entities_match": [
|
||||
"ui:",
|
||||
"region:",
|
||||
"layout:"
|
||||
]
|
||||
},
|
||||
"obligations": [
|
||||
{
|
||||
"id": "ui-layout-contract-inherited",
|
||||
"obligation": "affected UI components inherit their Layout Contract obligations; layout_contract_check must PASS",
|
||||
"when": {
|
||||
"entities_match": [
|
||||
"ui:",
|
||||
"region:",
|
||||
"layout:"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ui-user-locked-preserved",
|
||||
"obligation": "USER-LOCKED placement is user authority: preserved exactly; changes require explicit user authorization",
|
||||
"when": {
|
||||
"entities_match": [
|
||||
"ui:",
|
||||
"region:"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ui-unknown-never-pass",
|
||||
"obligation": "layout verification UNKNOWN (no adapter evidence) must never be reported as PASS",
|
||||
"when": {
|
||||
"entities_match": [
|
||||
"ui:",
|
||||
"region:",
|
||||
"layout:"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ui-component-identity-stable",
|
||||
"obligation": "ui:<component> identity survives implementation-path changes; authority never keyed by filename alone",
|
||||
"when": {
|
||||
"entities_match": [
|
||||
"ui:",
|
||||
"region:",
|
||||
"layout:"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
"Tranche 3 real TUI proof (gate PASS -> violation FAIL -> restore)",
|
||||
"issue #105 + plans/2026-09-03-tui-footer.md (version display)",
|
||||
"maintenance:version-display-user-lock (USER-LOCK upgrade pending user confirmation \u2014 provenance rule honored, not fabricated)",
|
||||
"tests/test_layout_contract.py + tests/test_layout_contract_real_proof.py"
|
||||
],
|
||||
"exclusions": [],
|
||||
"toolchain_notes": [],
|
||||
"runtime_effects": []
|
||||
},
|
||||
{
|
||||
"pattern_id": "store-schema-evolution",
|
||||
"purpose": "Durable store/schema changes: backward readability, authority preservation, deterministic roundtrip, migration only when necessary.",
|
||||
"revision": 1,
|
||||
"maturity": "CANDIDATE",
|
||||
"signals": {
|
||||
"path_contains": [
|
||||
"store",
|
||||
"schema",
|
||||
"structural_store",
|
||||
"scaffold",
|
||||
"spine"
|
||||
],
|
||||
"entities_match": [
|
||||
"module:structural_store",
|
||||
"module:scaffold",
|
||||
"module:spine"
|
||||
],
|
||||
"objective_any": [
|
||||
"store",
|
||||
"schema",
|
||||
"record",
|
||||
"persist",
|
||||
"field",
|
||||
"migration"
|
||||
]
|
||||
},
|
||||
"obligations": [
|
||||
{
|
||||
"id": "store-backward-readability",
|
||||
"obligation": "old records without new fields read as empty/unknown, never crash; legacy keys preserved",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"store",
|
||||
"structural_store",
|
||||
"scaffold",
|
||||
"spine",
|
||||
"schema"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "store-roundtrip",
|
||||
"obligation": "deterministic save/load roundtrip incl. unknown entity/relation kinds and open-world fields",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"store",
|
||||
"structural_store",
|
||||
"scaffold",
|
||||
"schema"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "store-authority-preservation",
|
||||
"obligation": "structural facts only change through their owning projector/authority; canonical rebuild after registration (no hand-edited structural facts)",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"spine",
|
||||
"scaffold",
|
||||
"store/"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "store-migration-only-if-needed",
|
||||
"obligation": "no mandatory migration unless semantics truly change; ext/open-world fields preferred over schema churn",
|
||||
"when": {
|
||||
"path_contains": [
|
||||
"schema",
|
||||
"store",
|
||||
"structural_store"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
"Tranche 2 CI lesson: hand-edited spine store diverged from canonical rebuild (deploy-identity edges)",
|
||||
"Tranche 2 structural-store extraction (behavior-neutrality proof)",
|
||||
"Tranche 4 contract-quality repair (legacy keys preserved, old contracts readable \u2014 test_h)",
|
||||
"Tranche 5 expected-runtime-effects extension (old contracts close without new fields)"
|
||||
],
|
||||
"exclusions": [],
|
||||
"toolchain_notes": [],
|
||||
"runtime_effects": []
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,126 @@
|
||||
//! branch_battery — replays frozen_cpb_truth.json VERBATIM (17 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).
|
||||
|
||||
use capability_scoring::pyjson::{parse, Json};
|
||||
|
||||
use crate::registry;
|
||||
|
||||
const TRUTH: &str = include_str!("../frozen_cpb_truth.json");
|
||||
|
||||
fn jeq(a: &Json, b: &Json) -> bool {
|
||||
match (a, b) {
|
||||
(Json::Num(x), Json::Num(y)) => x == y,
|
||||
(Json::Str(x), Json::Str(y)) => x == y,
|
||||
(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))
|
||||
}
|
||||
(Json::Obj(x), Json::Obj(y)) => {
|
||||
x.len() == y.len()
|
||||
&& x.iter()
|
||||
.all(|(k, v)| y.iter().any(|(k2, v2)| k == k2 && jeq(v, v2)))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(v: Option<&Json>) -> String {
|
||||
match v {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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" => {
|
||||
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)
|
||||
}
|
||||
other => Err(format!("unknown truth fn {other}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_case(fn_name: &str, name: &str, args: &Json, want: &Json) -> Result<(), String> {
|
||||
// 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) {
|
||||
Err(err) => {
|
||||
let want_msg = as_str(Some(message));
|
||||
if err != want_msg {
|
||||
return Err(format!(
|
||||
"{fn_name}/{name}: err mismatch\n want {want_msg}\n got {err}"
|
||||
));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
Ok(got) => {
|
||||
return Err(format!(
|
||||
"{fn_name}/{name}: oracle raises, kernel returned {}",
|
||||
capability_scoring::pyjson::dumps(&got)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
match run_case(fn_name, 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)
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(err) => Err(format!("{fn_name}/{name}: kernel error {err}")),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_truth_replays_verbatim() {
|
||||
let truth = parse(TRUTH).expect("frozen_cpb_truth.json parses");
|
||||
let 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);
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
failures.is_empty(),
|
||||
"branch battery diverged from frozen truth:\n{}",
|
||||
failures.join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truth_case_count_is_stable() {
|
||||
let truth = parse(TRUTH).expect("frozen_cpb_truth.json parses");
|
||||
let cases = match truth.get("cases") {
|
||||
Some(Json::Arr(c)) => c.len(),
|
||||
_ => 0,
|
||||
};
|
||||
assert_eq!(cases, 19, "frozen case count drifted — regenerate truth");
|
||||
}
|
||||
@@ -1,19 +1,96 @@
|
||||
//! construction_patterns_builtin — built-in construction patterns (W6).
|
||||
pub fn builtin_patterns() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"patterns": [
|
||||
{"pattern_id": "web-api", "description": "HTTP API with REST endpoints"},
|
||||
{"pattern_id": "cli-tool", "description": "Command-line tool with argument parsing"},
|
||||
]
|
||||
})
|
||||
}
|
||||
//! construction_patterns_builtin — the built-in pattern registry kernel
|
||||
//! (dichotomy wave #2479 tranche). Serves the oracle's pattern data
|
||||
//! (frozen verbatim from the live Python registry — provenance order is
|
||||
//! the oracle's __init__-sorted order) through a doc-envelope FFI. The
|
||||
//! Python facade keeps a RUNE_CPB_CORE=python pin.
|
||||
//!
|
||||
//! FFI contract (doc-envelope law — every call returns {"ok","value"|"err"}):
|
||||
//! * cpb_registry_revision({}) -> number
|
||||
//! * cpb_patterns({}) -> [pattern doc, ...] registry order
|
||||
//! * cpb_get_pattern({"pattern_id", "revision"}) -> pattern doc | null
|
||||
//! (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
|
||||
//! Python oracle) replayed verbatim by the in-crate branch battery.
|
||||
|
||||
pub mod registry;
|
||||
|
||||
pub use capability_scoring::pyjson;
|
||||
|
||||
#[path = "branch_battery.rs"]
|
||||
#[cfg(test)]
|
||||
mod branch_battery {
|
||||
use super::*;
|
||||
mod branch_battery;
|
||||
|
||||
#[test]
|
||||
fn builtin_patterns_exist() {
|
||||
assert!(true);
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use pyjson::Json;
|
||||
|
||||
fn read_arg(ptr: *const c_char) -> Result<String, String> {
|
||||
if ptr.is_null() {
|
||||
return Err("null argument pointer".to_string());
|
||||
}
|
||||
unsafe { CStr::from_ptr(ptr) }
|
||||
.to_str()
|
||||
.map(|s| s.to_string())
|
||||
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
|
||||
}
|
||||
|
||||
fn envelope(result: Result<Json, String>) -> *mut c_char {
|
||||
let body = match result {
|
||||
Ok(value) => Json::Obj(vec![
|
||||
("ok".to_string(), Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err(err) => Json::Obj(vec![
|
||||
("ok".to_string(), Json::Bool(false)),
|
||||
("err".to_string(), Json::Str(err)),
|
||||
]),
|
||||
};
|
||||
let out = pyjson::dumps(&body);
|
||||
CString::new(out)
|
||||
.map(|c| c.into_raw())
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
fn arg_json(text: &str) -> Result<Json, String> {
|
||||
pyjson::parse(text).map_err(|e| format!("argument JSON parse failed: {}", e))
|
||||
}
|
||||
|
||||
/// cpb_registry_revision({}) -> number
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cpb_registry_revision(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.map(|_| Json::Num(registry::registry_revision() as f64));
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// cpb_patterns({}) -> [pattern doc, ...] in registry order
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cpb_patterns(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.map(|_| Json::Arr(registry::patterns()));
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// cpb_get_pattern({"pattern_id": "...", "revision": n|null}) -> doc | null
|
||||
#[no_mangle]
|
||||
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)
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//! registry — the built-in construction pattern registry. The pattern docs
|
||||
//! are FROZEN from the live Python oracle (frozen_cpb_patterns.json,
|
||||
//! generated by scripts/gen_construction_patterns_builtin_truth.py with
|
||||
//! RUNE_CPB_CORE=python pinned — never hand-transcribed): each doc is the
|
||||
//! oracle's ConstructionPattern.to_dict(), including its __init__-sorted
|
||||
//! provenance/exclusions order.
|
||||
//!
|
||||
//! Phase B: the frozen docs parse once into typed [`BuiltinPattern`]
|
||||
//! 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.
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use capability_scoring::pyjson::{self, Json};
|
||||
|
||||
const PATTERNS_SRC: &str = include_str!("../frozen_cpb_patterns.json");
|
||||
|
||||
/// 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,
|
||||
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(),
|
||||
_ => return None,
|
||||
};
|
||||
let revision = match doc.get("revision") {
|
||||
Some(Json::Num(n)) => *n as i64,
|
||||
_ => return None,
|
||||
};
|
||||
Some(Self { pattern_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(
|
||||
items
|
||||
.iter()
|
||||
.filter_map(|d| BuiltinPattern::from_doc(d.clone()))
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
}
|
||||
|
||||
/// 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)
|
||||
})
|
||||
}
|
||||
|
||||
/// Every builtin pattern doc, in registry order (BUILTIN_PATTERNS order).
|
||||
pub fn patterns() -> Vec<Json> {
|
||||
registry().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) {
|
||||
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
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(pattern.doc.clone())
|
||||
}
|
||||
Generated
+23
@@ -54,6 +54,12 @@ dependencies = [
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -64,6 +70,22 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[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 = "itoa"
|
||||
version = "1.0.18"
|
||||
@@ -135,6 +157,7 @@ version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
|
||||
@@ -8,4 +8,4 @@ crate-type = ["rlib", "cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
sha2 = "0.10"
|
||||
serde_json = "1"
|
||||
serde_json = { version = "1", features = ["preserve_order", "float_roundtrip"] }
|
||||
File diff suppressed because it is too large.
Load diff
@@ -14,7 +14,49 @@ use std::os::raw::c_char;
|
||||
|
||||
pub const DRIFT_LIMIT: f64 = 0.30;
|
||||
pub const CONSTITUTION_LIMIT: f64 = 0.05;
|
||||
pub const BLOCKS: &[&str] = &["constitution", "persona", "human", "operating", "project"];
|
||||
|
||||
/// The five guarded blocks — a closed lattice, not stringly-typed routing.
|
||||
/// The constitution's limit is exhaustive-match derived; every other block
|
||||
/// falls to the plain drift limit (the oracle's ternary).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum BlockLabel {
|
||||
Constitution,
|
||||
Persona,
|
||||
Human,
|
||||
Operating,
|
||||
Project,
|
||||
}
|
||||
|
||||
impl BlockLabel {
|
||||
pub const ALL: [BlockLabel; 5] = [
|
||||
Self::Constitution,
|
||||
Self::Persona,
|
||||
Self::Human,
|
||||
Self::Operating,
|
||||
Self::Project,
|
||||
];
|
||||
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Constitution => "constitution",
|
||||
Self::Persona => "persona",
|
||||
Self::Human => "human",
|
||||
Self::Operating => "operating",
|
||||
Self::Project => "project",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn of_name(name: &str) -> Option<Self> {
|
||||
Self::ALL.iter().copied().find(|b| b.as_str() == name)
|
||||
}
|
||||
|
||||
pub fn limit(self) -> f64 {
|
||||
match self {
|
||||
Self::Constitution => CONSTITUTION_LIMIT,
|
||||
_ => DRIFT_LIMIT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// _sha port: hex sha256 of UTF-8 text.
|
||||
pub fn sha(text: &str) -> String {
|
||||
@@ -28,28 +70,28 @@ pub fn diff_blocks(reference: &str, current: &str) -> String {
|
||||
if reference.is_empty() {
|
||||
return "no prior content (first drift from empty baseline)".to_string();
|
||||
}
|
||||
fn sig(l: &str) -> Option<&str> {
|
||||
let s = l.trim();
|
||||
(!s.is_empty()).then_some(s)
|
||||
}
|
||||
let ref_lines: Vec<&str> = reference.lines().collect();
|
||||
let cur_lines: Vec<&str> = current.lines().collect();
|
||||
let ref_set: std::collections::HashSet<&str> =
|
||||
ref_lines.iter().filter_map(|l| { let s = l.trim(); if s.is_empty() { None } else { Some(s) } }).collect();
|
||||
ref_lines.iter().filter_map(|l| sig(l)).collect();
|
||||
let cur_set: std::collections::HashSet<&str> =
|
||||
cur_lines.iter().filter_map(|l| { let s = l.trim(); if s.is_empty() { None } else { Some(s) } }).collect();
|
||||
let mut added: Vec<&str> = vec![];
|
||||
for l in &cur_lines {
|
||||
let s = l.trim();
|
||||
if !s.is_empty() && !ref_set.contains(s) {
|
||||
added.push(s);
|
||||
if added.len() >= 6 { break; }
|
||||
}
|
||||
}
|
||||
let mut removed: Vec<&str> = vec![];
|
||||
for l in &ref_lines {
|
||||
let s = l.trim();
|
||||
if !s.is_empty() && !cur_set.contains(s) {
|
||||
removed.push(s);
|
||||
if removed.len() >= 3 { break; }
|
||||
}
|
||||
}
|
||||
cur_lines.iter().filter_map(|l| sig(l)).collect();
|
||||
let added: Vec<&str> = cur_lines
|
||||
.iter()
|
||||
.filter_map(|l| sig(l))
|
||||
.filter(|s| !ref_set.contains(*s))
|
||||
.take(6)
|
||||
.collect();
|
||||
let removed: Vec<&str> = ref_lines
|
||||
.iter()
|
||||
.filter_map(|l| sig(l))
|
||||
.filter(|s| !cur_set.contains(*s))
|
||||
.take(3)
|
||||
.collect();
|
||||
let mut parts: Vec<String> = vec![];
|
||||
if !added.is_empty() {
|
||||
parts.push(format!(
|
||||
@@ -85,8 +127,9 @@ pub fn check_block(
|
||||
None => (prev_size.max(1), None, cur_size - prev_size),
|
||||
};
|
||||
let pct = (delta.abs() as f64) / (base.max(1) as f64);
|
||||
let limit = if label == "constitution" { CONSTITUTION_LIMIT } else { DRIFT_LIMIT };
|
||||
let content_changed = label == "constitution"
|
||||
let is_constitution = matches!(BlockLabel::of_name(label), Some(BlockLabel::Constitution));
|
||||
let limit = if is_constitution { CONSTITUTION_LIMIT } else { DRIFT_LIMIT };
|
||||
let content_changed = is_constitution
|
||||
&& anchor_size.is_some()
|
||||
&& base_sha.is_some()
|
||||
&& cur_sha.is_some()
|
||||
@@ -100,7 +143,8 @@ pub fn check_block(
|
||||
|
||||
/// auto_fix routing port: (label, anchored, has_last_good) -> {action, reason}.
|
||||
pub fn auto_fix_decision(label: &str, anchored: bool, has_last_good: bool) -> Value {
|
||||
if label == "constitution" {
|
||||
let is_constitution = matches!(BlockLabel::of_name(label), Some(BlockLabel::Constitution));
|
||||
if is_constitution {
|
||||
json!({"action": "alert-only", "reason": "constitution changes only by explicit directive; needs human review"})
|
||||
} else if anchored {
|
||||
json!({"action": "re-anchored", "reason": "anchored block grew (authorised) — re-baselined"})
|
||||
@@ -111,6 +155,143 @@ pub fn auto_fix_decision(label: &str, anchored: bool, has_last_good: bool) -> Va
|
||||
}
|
||||
}
|
||||
|
||||
/// Python round(x, 3): correct rounding of the binary value with ties-to-even
|
||||
/// (the same contract Rust's {:.3} formatting implements).
|
||||
fn py_round3(x: f64) -> f64 {
|
||||
format!("{:.3}", x).parse().unwrap_or(x)
|
||||
}
|
||||
|
||||
/// ledger_path port: the ledger lives beside the index file, so overriding
|
||||
/// INDEX_FILE moves the ledger too.
|
||||
pub fn ledger_path_for(index_file: &str) -> String {
|
||||
match index_file.rfind('/') {
|
||||
Some(i) => format!("{}drift_ledger.json", &index_file[..=i]),
|
||||
None => "drift_ledger.json".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// snapshot() entry-assembly port: {"when", "blocks": {label: {sha, size,
|
||||
/// content}}}. "size" is the oracle's len(raw) — a CHARACTER count, not bytes.
|
||||
/// Unknown labels in the payload are ignored (the oracle iterates BLOCKS).
|
||||
pub fn snapshot_entry(blocks: &Value, when: &str) -> Value {
|
||||
let mut b = serde_json::Map::new();
|
||||
for label in BlockLabel::ALL {
|
||||
let raw = blocks.get(label.as_str()).and_then(|v| v.as_str()).unwrap_or("");
|
||||
b.insert(
|
||||
label.as_str().to_string(),
|
||||
json!({
|
||||
"sha": sha(raw),
|
||||
"size": raw.chars().count(),
|
||||
"content": raw,
|
||||
}),
|
||||
);
|
||||
}
|
||||
json!({"when": when, "blocks": Value::Object(b)})
|
||||
}
|
||||
|
||||
/// anchor() record-assembly port: the authorised-state backup for re-anchoring.
|
||||
pub fn anchor_record(content: &str, reason: &str, when: &str) -> Value {
|
||||
json!({
|
||||
"sha": sha(content),
|
||||
"size": content.chars().count(),
|
||||
"content": content,
|
||||
"reason": reason,
|
||||
"when": when,
|
||||
})
|
||||
}
|
||||
|
||||
/// check() alert-loop port: given the ledger doc and the current block
|
||||
/// contents {label: text}, produce the alert list exactly as the oracle's
|
||||
/// loop does — anchored blocks are measured against their authorised state,
|
||||
/// unanchored ones against the last snapshot (max(prev_size, 1) floor),
|
||||
/// the constitution additionally trips on ANY content change from its
|
||||
/// anchored sha, pct/limit round to 3 decimals, and each alert carries the
|
||||
/// root-cause diff. Side effects (prints, surface_alert, auto-fix, journal)
|
||||
/// stay in the facade.
|
||||
pub fn check_alerts(ledger: &Value, blocks: &Value) -> Value {
|
||||
let prev = ledger
|
||||
.get("last_snapshot")
|
||||
.and_then(|s| s.get("blocks"))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!({}));
|
||||
let anchors = ledger.get("anchors").cloned().unwrap_or_else(|| json!({}));
|
||||
let alerts: Vec<Value> = BlockLabel::ALL
|
||||
.iter()
|
||||
.filter_map(|label| {
|
||||
let cur = blocks.get(label.as_str()).and_then(|v| v.as_str()).unwrap_or("");
|
||||
let cur_size = cur.chars().count() as i64;
|
||||
let anchor_meta = anchors.get(label.as_str());
|
||||
let (base, base_sha, delta, ref_content) = match anchor_meta {
|
||||
Some(a) => {
|
||||
let b = a.get("size").and_then(|v| v.as_i64()).unwrap_or(cur_size);
|
||||
let sh = a.get("sha").and_then(|v| v.as_str());
|
||||
let rc = a.get("content").and_then(|v| v.as_str());
|
||||
(b, sh, cur_size - b, rc)
|
||||
}
|
||||
None => {
|
||||
let pm = prev.get(label.as_str());
|
||||
let ps = pm
|
||||
.and_then(|m| m.get("size"))
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(cur_size);
|
||||
let rc = pm.and_then(|m| m.get("content")).and_then(|v| v.as_str());
|
||||
(ps.max(1), None, cur_size - ps, rc)
|
||||
}
|
||||
};
|
||||
let pct = (delta.abs() as f64) / (base.max(1) as f64);
|
||||
let limit = label.limit();
|
||||
let content_changed = matches!(label, BlockLabel::Constitution)
|
||||
&& anchor_meta.is_some()
|
||||
&& base_sha.is_some()
|
||||
&& sha(cur) != base_sha.unwrap();
|
||||
(content_changed || pct > limit).then(|| {
|
||||
json!({
|
||||
"label": label.as_str(),
|
||||
"delta": delta,
|
||||
"pct": py_round3(pct),
|
||||
"limit": py_round3(limit),
|
||||
"base": base,
|
||||
"changed": diff_blocks(ref_content.unwrap_or(""), cur),
|
||||
"content_changed": content_changed,
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
Value::Array(alerts)
|
||||
}
|
||||
|
||||
/// fix() decision port: the oracle's retroactive-fix gate minus the restore IO
|
||||
/// (the facade performs restore_topic + journal when {fixed: true}).
|
||||
/// cur_sha is the sha of the block's CURRENT store content (read_block is a
|
||||
/// facade seam; the sha travels in the doc envelope).
|
||||
pub fn fix_decision(ledger: &Value, label: &str, cur_sha: Option<&str>) -> Value {
|
||||
let block_meta = ledger
|
||||
.get("last_snapshot")
|
||||
.and_then(|s| s.get("blocks"))
|
||||
.and_then(|b| b.get(label));
|
||||
let has_content = block_meta
|
||||
.map(|m| m.get("content").is_some())
|
||||
.unwrap_or(false);
|
||||
if block_meta.is_none() || !has_content {
|
||||
return json!({"fixed": false, "reason": format!("no last-good content for {}", label)});
|
||||
}
|
||||
if ledger
|
||||
.get("anchors")
|
||||
.map(|a| a.get(label).is_some())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return json!({"fixed": false, "reason": format!("{} is anchored (authorised); use anchor to re-baseline instead of fix", label)});
|
||||
}
|
||||
let good_sha = block_meta
|
||||
.and_then(|m| m.get("sha"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
if cur_sha == Some(good_sha) {
|
||||
return json!({"fixed": false, "reason": format!("{} already matches last-good", label)});
|
||||
}
|
||||
json!({"fixed": true, "reason": format!("{} restored to last-good state", label)})
|
||||
}
|
||||
|
||||
fn read_arg(ptr: *const c_char) -> Result<Value, String> {
|
||||
if ptr.is_null() {
|
||||
return Err("null argument pointer".into());
|
||||
@@ -181,5 +362,54 @@ pub extern "C" fn dl_auto_fix(arg: *const c_char) -> *mut c_char {
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
/// dl_ledger_path({"index_file"}) -> path string
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dl_ledger_path(arg: *const c_char) -> *mut c_char {
|
||||
let r = read_arg(arg).map(|a| Value::String(ledger_path_for(s(a.get("index_file")))));
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
/// dl_snapshot_entry({"blocks": {label: content}, "when"}) -> snapshot entry
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dl_snapshot_entry(arg: *const c_char) -> *mut c_char {
|
||||
let r = read_arg(arg).map(|a| {
|
||||
let blocks = a.get("blocks").cloned().unwrap_or(Value::Null);
|
||||
snapshot_entry(&blocks, s(a.get("when")))
|
||||
});
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
/// dl_anchor_record({"content", "reason", "when"}) -> anchor record
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dl_anchor_record(arg: *const c_char) -> *mut c_char {
|
||||
let r = read_arg(arg).map(|a| {
|
||||
anchor_record(s(a.get("content")), s(a.get("reason")), s(a.get("when")))
|
||||
});
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
/// dl_check_alerts({"ledger", "blocks": {label: content}}) -> [alert, ...]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dl_check_alerts(arg: *const c_char) -> *mut c_char {
|
||||
let r = read_arg(arg).map(|a| {
|
||||
let ledger = a.get("ledger").cloned().unwrap_or(Value::Null);
|
||||
let blocks = a.get("blocks").cloned().unwrap_or(Value::Null);
|
||||
check_alerts(&ledger, &blocks)
|
||||
});
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
/// dl_fix_decision({"ledger", "label", "cur_sha"?}) -> {fixed, reason}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dl_fix_decision(arg: *const c_char) -> *mut c_char {
|
||||
let r = read_arg(arg).map(|a| {
|
||||
let ledger = a.get("ledger").cloned().unwrap_or(Value::Null);
|
||||
let label = s(a.get("label")).to_string();
|
||||
let cur_sha = a.get("cur_sha").and_then(|v| v.as_str());
|
||||
fix_decision(&ledger, &label, cur_sha)
|
||||
});
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
// NOTE: no free-symbol export here (capability_scoring's cs_free_string
|
||||
// serves the whole process — duplicate symbols break the cdylib link).
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,27 @@
|
||||
# Contract BUILDER-2026-10-12T12:25:33Z-a87985-factory-wave
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Port curator to FULL Go — dichotomy wave #2479 tranche.
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/gen_curator_truth.py`
|
||||
- `src/go/curator/`
|
||||
- `src/rune/curator.py`
|
||||
- `tests/`
|
||||
|
||||
## 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-12T14:41:43Z", "contract": "BUILDER-2026-10-12T12:25:33Z-a87985-factory-wave", "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": ["scripts/gen_curator_truth.py", "src/go/curator/", "src/rune/curator.py", "tests/"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- wave orchestrator pre-authorization: dichotomy tranche #2479, GO verdict for curator
|
||||
- implementation: truth generator + src/go/curator port (commits 03ef8132/89b691b2)
|
||||
- battery 162/162 + live parity 162/162 + Python tests green
|
||||
- closure-record
|
||||
@@ -0,0 +1,25 @@
|
||||
# Contract BUILDER-2026-10-12T12:55:40Z-c88ae4-mimo
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
create a practice scheduler with create/list/complete
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `practice-scheduler-js/scheduler.js`
|
||||
- `practice-scheduler-js/test_scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-12T12:55:40Z", "contract": "BUILDER-2026-10-12T12:55:40Z-c88ae4-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-494/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-494/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:mimo
|
||||
- builder:mimo
|
||||
- builder:mimo
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T12:56:01Z-606d4c-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
persistent project export
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T12:56:01Z", "contract": "BUILDER-2026-10-12T12:56:01Z-606d4c-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T12:56:01Z-9d9c7f-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
persistent project export
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T12:56:01Z", "contract": "BUILDER-2026-10-12T12:56:01Z-9d9c7f-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T12:56:01Z-b39de9-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
wave stage one
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T12:56:01Z", "contract": "BUILDER-2026-10-12T12:56:01Z-b39de9-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T12:56:03Z-654c5a-minidoc-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
minidoc fixture sections: the mini-doc emission target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `tests/test_contract_minidoc.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
- final evidence
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T12:57:27Z-181851-minidoc-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
minidoc fixture outdir: the mini-doc emission target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `tests/test_contract_minidoc.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
- final evidence
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-1622c7-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `src/rune/bounded_change.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-1622c7-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:rune-planned", "contract:rune-spec"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:rune-planned", "contract:rune-spec"], "predicted_existing_affected": ["capability:rune-planned", "contract:rune-spec"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-7bc14b-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
bounded change touching closure_target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-7bc14b-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-a0b7ea-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-a0b7ea-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-a5103b-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
bounded change touching closure_target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-a5103b-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t21.4 test approved
|
||||
- t21.4 test building
|
||||
- t21.4 test verifying
|
||||
@@ -0,0 +1,25 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-bc1b3b-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
scope with an unmodeled file
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
- `tests/test_t214_material_closure.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-bc1b3b-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": ["test:t214_material_closure"], "expected_new_missing": ["test:t214_material_closure"], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["tests/test_t214_material_closure.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-da016d-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-da016d-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": ["scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:03:59Z-e257bf-t21.5-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
add the widget import capability to widget-forge (bounded change; import widgets from external bundles)
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `src/widget_import.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:03:59Z", "contract": "BUILDER-2026-10-12T13:03:59Z-e257bf-t21.5-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:widget-export", "contract:widget-import"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:widget-export", "contract:widget-import"], "predicted_existing_affected": ["component:widget-export", "contract:widget-import"], "scope_check": {"in_scope": ["src/widget_import.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,25 @@
|
||||
# Contract BUILDER-2026-10-12T13:04:53Z-d265b9-mimo
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
create a practice scheduler with create/list/complete
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `practice-scheduler-js/scheduler.js`
|
||||
- `practice-scheduler-js/test_scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [{"entity": "scheduler.js", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}, {"entity": "test:scheduler", "note": "genuinely unexpected new surface \u2014 evidence required before store update", "status": "CANDIDATE"}], "captured_at": "2026-10-12T13:04:53Z", "contract": "BUILDER-2026-10-12T13:04:53Z-d265b9-mimo", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": ["scheduler.js", "test:scheduler"], "missed": ["scheduler.js", "test:scheduler"], "needless": ["capability:csv_export", "contract:csv_export"], "observed": ["scheduler.js", "test:scheduler"], "observed_existing": [], "observed_new": ["scheduler.js", "test:scheduler"], "predicted_but_unaffected": ["capability:csv_export", "contract:csv_export"], "predicted_existing_affected": ["capability:csv_export", "contract:csv_export"], "scope_check": {"in_scope": ["/tmp/pytest-of-nick/pytest-503/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/scheduler.js", "/tmp/pytest-of-nick/pytest-503/test_builder_governed_lifecycl0/practice-scheduler/practice-scheduler-js/test_scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:mimo
|
||||
- builder:mimo
|
||||
- builder:mimo
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:05:15Z-a5ff07-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
wave stage one
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:05:15Z", "contract": "BUILDER-2026-10-12T13:05:15Z-a5ff07-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:05:15Z-b41aa9-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
persistent project export
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:05:15Z", "contract": "BUILDER-2026-10-12T13:05:15Z-b41aa9-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:05:15Z-d4789f-test-builder
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
persistent project export
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:05:15Z", "contract": "BUILDER-2026-10-12T13:05:15Z-d4789f-test-builder", "correctly_predicted": ["capability:exporter"], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["contract:csv_export"], "observed": ["capability:exporter"], "observed_existing": ["capability:exporter"], "observed_new": [], "predicted_but_unaffected": ["contract:csv_export"], "predicted_existing_affected": ["capability:exporter", "contract:csv_export"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- builder:test-builder
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:05:16Z-d9a34c-minidoc-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
minidoc fixture sections: the mini-doc emission target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `tests/test_contract_minidoc.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
- final evidence
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:06:36Z-8b508c-minidoc-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
minidoc fixture outdir: the mini-doc emission target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `tests/test_contract_minidoc.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
- final evidence
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:55Z-12e59c-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `src/rune/bounded_change.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:55Z", "contract": "BUILDER-2026-10-12T13:11:55Z-12e59c-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:rune-planned", "contract:rune-spec"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:rune-planned", "contract:rune-spec"], "predicted_existing_affected": ["capability:rune-planned", "contract:rune-spec"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:55Z-a800a0-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
bounded change touching closure_target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:56Z", "contract": "BUILDER-2026-10-12T13:11:55Z-a800a0-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- t21.4 test approved
|
||||
- t21.4 test building
|
||||
- closure-record
|
||||
- t21.4 test verifying
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:55Z-db60e6-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:55Z", "contract": "BUILDER-2026-10-12T13:11:55Z-db60e6-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": [], "out_of_scope": ["x"], "verdict": "red"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:55Z-e8cedb-adversarial-probe
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
build the hostile spec module
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scheduler.js`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:55Z", "contract": "BUILDER-2026-10-12T13:11:55Z-e8cedb-adversarial-probe", "correctly_predicted": [], "evidence_sources": ["driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["capability:planned", "contract:spec-1"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["capability:planned", "contract:spec-1"], "predicted_existing_affected": ["capability:planned", "contract:spec-1"], "scope_check": {"in_scope": ["scheduler.js"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:adversarial-probe
|
||||
- builder:adversarial-probe
|
||||
- closure-record
|
||||
- e
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:56Z-749790-t21.5-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
add the widget import capability to widget-forge (bounded change; import widgets from external bundles)
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `src/widget_import.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:56Z", "contract": "BUILDER-2026-10-12T13:11:56Z-749790-t21.5-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:widget-export", "contract:widget-import"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:widget-export", "contract:widget-import"], "predicted_existing_affected": ["component:widget-export", "contract:widget-import"], "scope_check": {"in_scope": ["src/widget_import.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:56Z-a20b0c-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
bounded change touching closure_target
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:56Z", "contract": "BUILDER-2026-10-12T13:11:56Z-a20b0c-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["scripts/rollback_generation.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,25 @@
|
||||
# Contract BUILDER-2026-10-12T13:11:56Z-c85a39-t21.4-test
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
scope with an unmodeled file
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `scripts/rollback_generation.py`
|
||||
- `tests/test_t214_material_closure.py`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:11:56Z", "contract": "BUILDER-2026-10-12T13:11:56Z-c85a39-t21.4-test", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": ["test:t214_material_closure"], "expected_new_missing": ["test:t214_material_closure"], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["component:closure-target", "contract:closure-target"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["component:closure-target", "contract:closure-target"], "predicted_existing_affected": ["component:closure-target", "contract:closure-target"], "scope_check": {"in_scope": ["tests/test_t214_material_closure.py"], "out_of_scope": [], "verdict": "green"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- closure-record
|
||||
- t
|
||||
- t
|
||||
- t
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:29:58Z-e5c619-factory-wave
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Port src/rune/construction_patterns_builtin.py to FULL Rust (dichotomy factory, issue #2479 tranche): frozen-oracle registry data, doc-envelope FFI, ctypes loader (free via capability_scoring cs_free_string), facade delegation with RUNE_CPB_CORE=python pin, frozen-truth branch battery, live parity 100%, Phase B typed-registry pass. Plus audit fix: curator -> curator-core alias (curator was FULL-Go since a95c6ce1 but the audit miscounted it NOT TOUCHED).
|
||||
|
||||
## 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-12T13:30:59Z", "contract": "BUILDER-2026-10-12T13:29:58Z-e5c619-factory-wave", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["module:deploy_qualify"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["module:deploy_qualify"], "predicted_existing_affected": ["module:deploy_qualify"], "scope_check": {"in_scope": [], "out_of_scope": ["scripts/check_cpb_parity.py", "scripts/gen_construction_patterns_builtin_truth.py", "src/rune/construction_patterns_builtin.py", "src/rune/cpb_loader.py", "src/rust/construction_patterns_builtin/frozen_cpb_patterns.json", "src/rust/construction_patterns_builtin/frozen_cpb_truth.json", "src/rust/construction_patterns_builtin/src/branch_battery.rs", "src/rust/construction_patterns_builtin/src/lib.rs", "src/rust/construction_patterns_builtin/src/registry.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-wave
|
||||
- builder:factory-wave
|
||||
- builder:factory-wave
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-12T13:54:01Z-950331-factory-wave
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Complete the drift_ledger dichotomy port to FULL Rust (#2479 tranche): check/alert-loop, snapshot/anchor assembly, auto-fix routing and fix gate as doc-envelope FFI; dl_loader ctypes loader mirroring broker_loader.py (free via capability_scoring cs_free_string); facade delegation with RUNE_DL_CORE=python pin; frozen-oracle battery (87 cases, every public function/branch); live parity 100%; Phase B language-advantage pass; dichotomy-audit instrument fixes (curator alias + hyphen-twin mapping).
|
||||
|
||||
## 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-12T13:55:03Z", "contract": "BUILDER-2026-10-12T13:54:01Z-950331-factory-wave", "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": ["docs/dichotomy-rebase-honest-audit.md", "scripts/dichotomy_audit.py", "scripts/gen_drift_ledger_truth.py", "src/rune/dl_loader.py", "src/rune/drift_ledger.py", "src/rust/drift_ledger/src/branch_battery.rs", "src/rust/drift_ledger/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-wave
|
||||
- builder:factory-wave
|
||||
- builder:factory-wave
|
||||
- closure-record
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 5 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-11T17:48:55Z", "contract": "d-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "d-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 5 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-11T17:48:55Z", "contract": "f-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "f-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- 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-11T17:48:55Z", "contract": "r-1", "correctly_predicted": [], "evidence_sources": ["pre"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "r-1", "correctly_predicted": [], "evidence_sources": ["pre"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- 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-11T17:48:55Z", "contract": "r-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "r-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- 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-11T17:48:55Z", "contract": "s-1", "correctly_predicted": [], "evidence_sources": ["pre"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "s-1", "correctly_predicted": [], "evidence_sources": ["pre"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- 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-11T17:48:55Z", "contract": "st-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "st-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 5 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-11T17:48:55Z", "contract": "st-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "st-2", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 5 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-11T17:48:55Z", "contract": "st-3", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "st-3", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ stage need
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 5 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-11T17:48:55Z", "contract": "w-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-12T13:10:01Z", "contract": "w-1", "correctly_predicted": [], "evidence_sources": ["programme-driver"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": [], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": [], "predicted_existing_affected": [], "scope_check": {"in_scope": [], "out_of_scope": [], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
||||
Reference in new issue
Block a user