Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
405dcc78e0 | ||
|
|
2597b58b88 | ||
|
|
49bd788442 | ||
|
|
7d20ef9b64 | ||
|
|
bc66b33ebf | ||
|
|
885f52ee22 | ||
|
|
cfb50b7576 | ||
|
|
80249a0ac5 | ||
|
|
69083f1970 | ||
|
|
50039ed83b | ||
|
|
28f5ed5ee1 | ||
|
|
2bc95aca8d | ||
|
|
290ed7341e | ||
|
|
70f8775838 | ||
|
|
060daaa44c | ||
|
|
32533500ed | ||
|
|
e34a3fb1cd | ||
|
|
45598be00d | ||
|
|
d7412f0855 | ||
|
|
b2adffbbbd | ||
|
|
a1ecd59d10 | ||
|
|
373891985e | ||
|
|
15aeb9a890 | ||
|
|
0b7e89b4f5 | ||
|
|
32c16c544d | ||
|
|
0569a2e599 | ||
|
|
192c63b36e | ||
|
|
b433be3e33 | ||
|
|
60eec844ed | ||
|
|
8f9835fb9b | ||
|
|
11e4bd20d5 | ||
|
|
59866dc8a7 | ||
|
|
cd51159660 | ||
|
|
53cc9618cf | ||
|
|
0771ca5f86 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.288.0**
|
||||
**Current release: v0.293.2**
|
||||
|
||||
**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,16 +2,16 @@
|
||||
|
||||
_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._
|
||||
|
||||
**FULL completion: 41%** (79/192 runtime modules at FULL)
|
||||
**FULL completion: 43%** (82/192 runtime modules at FULL)
|
||||
|
||||
Function-level detail: 62% (1403/2278 runtime functions matched) — secondary; includes in-flight work
|
||||
Function-level detail: 63% (1440/2278 runtime functions matched) — secondary; includes in-flight work
|
||||
|
||||
| Status | Modules | Lines | Meaning |
|
||||
|---|---|---|---|
|
||||
| FULL | 79 | 31836 | 80%+ of functions ported |
|
||||
| PARTIAL | 73 | 30782 | 20–80% — real logic exists, gaps named below |
|
||||
| FULL | 82 | 34347 | 80%+ of functions ported |
|
||||
| PARTIAL | 70 | 28304 | 20–80% — real logic exists, gaps named below |
|
||||
| NOT TOUCHED | 40 | 11513 | no name-preserving implementation |
|
||||
| Total runtime | 192 | 74131 | |
|
||||
| Total runtime | 192 | 74164 | |
|
||||
|
||||
## NOT TOUCHED — the port queue, in priority order (largest first)
|
||||
|
||||
@@ -64,7 +64,6 @@ Function-level detail: 62% (1403/2278 runtime functions matched) — secondary;
|
||||
|---|---|---|---|
|
||||
| rune_operator | 2746 | 25/68 | _build_model_router, _sorted_tool_names, _filter_safety_noise, _wire_auto_filer, _reconcile_guarded, get_operator |
|
||||
| memory_store | 2333 | 30/68 | _ctx_budget, now_iso, ensure_memory_type_column, _embed, _temp_json, _entities_to_json |
|
||||
| construction_interface | 1193 | 6/27 | _to_stage_check, _guard_specs_from_obligations, t_layout, _obligations_projection, _obligation_scope_files, main |
|
||||
| provider_registry | 679 | 11/28 | _ctx_budget, _format_tools_openai, _execute_tool_calls, _execute_tool_calls_anthropic, get_registry, connect_provider |
|
||||
| warm_router | 1518 | 17/33 | _ensure_use_history_table, record_outcome, record_neuron_fire, base_level_activation, _db, _aaak |
|
||||
| cron_engine | 440 | 13/27 | get_cron_engine, run_task, start_engine, stop_engine, to_dict, fire_on_task_complete |
|
||||
@@ -79,9 +78,7 @@ Function-level detail: 62% (1403/2278 runtime functions matched) — secondary;
|
||||
| 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 |
|
||||
| drift_core | 471 | 3/11 | _ms_core, _now_iso, promote_entry, compute_fama, compute_drift_velocity, compute_drift_direction |
|
||||
| identity_anchors | 542 | 6/14 | show_anchors, show_rules, show_pronouns, _announcement_patterns, _pronoun_patterns, _hedge_patterns |
|
||||
| time_awareness | 402 | 12/20 | _clock_args, _ta_core, get_time_awareness, to_dict, _to_state, _apply_state |
|
||||
| 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 | 284 | 6/13 | _now, _raise_core_err, to_dict, from_dict, save, _ledger_state |
|
||||
| voice_hybrid | 427 | 3/10 | _connect, _load_growth, _save_growth, source_profiles, always, grow |
|
||||
@@ -142,6 +139,7 @@ Function-level detail: 62% (1403/2278 runtime functions matched) — secondary;
|
||||
|---|---|---|---|
|
||||
| curator | 1838 | 43/43 | GO |
|
||||
| construction_decision | 1211 | 21/24 | RUST |
|
||||
| construction_interface | 1193 | 27/27 | RUST |
|
||||
| sleep_time | 1056 | 26/26 | GO |
|
||||
| spine | 975 | 25/25 | RUST |
|
||||
| structural_store | 921 | 34/41 | RUST |
|
||||
@@ -151,6 +149,7 @@ Function-level detail: 62% (1403/2278 runtime functions matched) — secondary;
|
||||
| local_tool_runtime | 809 | 30/30 | GO |
|
||||
| elastic_cognition | 774 | 14/14 | GO |
|
||||
| memory_consolidation | 770 | 22/22 | GO |
|
||||
| contracts | 743 | 11/11 | RUST |
|
||||
| persona_gate | 724 | 23/23 | GO |
|
||||
| abstraction | 656 | 16/16 | GO |
|
||||
| safety_override | 649 | 20/20 | RUST |
|
||||
@@ -159,12 +158,13 @@ Function-level detail: 62% (1403/2278 runtime functions matched) — secondary;
|
||||
| system_registry | 603 | 14/16 | RUST |
|
||||
| work_manager | 594 | 25/25 | GO |
|
||||
| construction_intent | 580 | 13/16 | RUST |
|
||||
| identity_anchors | 575 | 14/14 | RUST |
|
||||
| capability_ledger | 571 | 18/18 | RUST |
|
||||
| drift_ledger | 548 | 20/21 | RUST |
|
||||
| construction_pattern | 547 | 13/13 | RUST |
|
||||
| failure_auto_filer | 527 | 24/24 | GO |
|
||||
| build_mode | 521 | 33/33 | GO |
|
||||
| growth_delta | 520 | 16/18 | GO |
|
||||
| growth_delta | 520 | 17/18 | GO |
|
||||
| event_wait | 518 | 14/14 | GO |
|
||||
| worthiness | 469 | 12/13 | unclassified |
|
||||
| tool_protocol | 461 | 22/27 | GO |
|
||||
|
||||
+51
-12
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"landed": [
|
||||
"abstraction",
|
||||
"abstraction_ladder",
|
||||
"adaptive_router",
|
||||
"attention_capsule",
|
||||
"auto_context",
|
||||
"auto_tasks",
|
||||
@@ -9,32 +11,51 @@
|
||||
"build_mode",
|
||||
"capability_ledger",
|
||||
"concept_topology",
|
||||
"connection_pool",
|
||||
"construction_decision",
|
||||
"construction_depth",
|
||||
"construction_intent",
|
||||
"construction_interface",
|
||||
"construction_pattern",
|
||||
"construction_patterns_builtin",
|
||||
"context_broker",
|
||||
"contracts",
|
||||
"curator",
|
||||
"drift-ledger",
|
||||
"drift_cache",
|
||||
"drift_ledger",
|
||||
"drift_observability",
|
||||
"drift_resume",
|
||||
"elastic_cognition",
|
||||
"event_wait",
|
||||
"evidence_probe",
|
||||
"execution_trace",
|
||||
"experience_encoding",
|
||||
"failure_auto_filer",
|
||||
"failure_recovery",
|
||||
"forge",
|
||||
"forge_client",
|
||||
"goal",
|
||||
"grading",
|
||||
"growth_delta",
|
||||
"growth_pipeline",
|
||||
"hook_engine",
|
||||
"identity_anchors",
|
||||
"impact_preview",
|
||||
"inference_paths",
|
||||
"intent_continuity",
|
||||
"iteration",
|
||||
"lexicon_evolution",
|
||||
"local_tool_runtime",
|
||||
"meaningful_events",
|
||||
"memory_consolidation",
|
||||
"memory_selector",
|
||||
"memory_types",
|
||||
"message_graph",
|
||||
"message_queue",
|
||||
"model_connect",
|
||||
"model_routing",
|
||||
"mutation_guards",
|
||||
"night_mode",
|
||||
"openai_compat_transport",
|
||||
"outcome_ledger",
|
||||
@@ -45,46 +66,64 @@
|
||||
"programme_continuation",
|
||||
"programme_gates",
|
||||
"project_registry",
|
||||
"prompt_sync",
|
||||
"provider_budget",
|
||||
"provider_context",
|
||||
"recall_uplift",
|
||||
"release_notes",
|
||||
"research_budget",
|
||||
"route_risk_flags",
|
||||
"rune_profiler",
|
||||
"rune_spinner",
|
||||
"safety_override",
|
||||
"scaffold",
|
||||
"self_model",
|
||||
"self_modify",
|
||||
"shard_manager",
|
||||
"skill_compiler",
|
||||
"sleep_time",
|
||||
"spine",
|
||||
"spine_language",
|
||||
"state_checkpoint",
|
||||
"structural_store",
|
||||
"subconscious_pass",
|
||||
"subsystem_health",
|
||||
"system_registry",
|
||||
"task_gate",
|
||||
"testing_mode",
|
||||
"time_awareness",
|
||||
"token_optimizer",
|
||||
"tool_protocol",
|
||||
"toolchain",
|
||||
"verification_layer",
|
||||
"wait_guard",
|
||||
"witness",
|
||||
"work_manager",
|
||||
"worthiness"
|
||||
],
|
||||
"in_flight": {
|
||||
"memory_types": "rune-wave-bd",
|
||||
"wait_guard_corpus": "rune-wave-be",
|
||||
"research_budget": "rune-wave-be",
|
||||
"evidence_capsule": "rune-wave-be",
|
||||
"builder_bridge_cli": "rune-wave-be",
|
||||
"safety_override": "rune-wave-bn",
|
||||
"construction_decision": "rune-wave-bo",
|
||||
"provider_registry": "rune-wave-bq",
|
||||
"construction_interface": "rune-wave-bu",
|
||||
"spine": "rune-wave-bv",
|
||||
"elastic_cognition": "rune-wave-bx",
|
||||
"contracts": "rune-wave-by",
|
||||
"adaptive_router": "rune-wave-bz",
|
||||
"memory_selector": "rune-wave-ca",
|
||||
"capability_broker": "rune-wave-cd",
|
||||
"identity_anchors": "rune-wave-ce",
|
||||
"construction_pattern": "rune-wave-cb [agent: naming-artifact claim UNPROVEN \u2014 audit reads PARTIAL 7/14; awaiting per-fn proof or re-port]"
|
||||
"behavior": "rune-wave-cf",
|
||||
"cache": "rune-wave-ch",
|
||||
"claim_audit": "rune-wave-cj",
|
||||
"graph_memory": "rune-wave-ck",
|
||||
"drift_core": "rune-wave-cm",
|
||||
"cron_engine": "rune-wave-co",
|
||||
"model_profiles": "rune-wave-cp",
|
||||
"microkernel": "rune-wave-cq",
|
||||
"voice_hybrid": "rune-wave-cr",
|
||||
"parallel_processor": "rune-wave-cs",
|
||||
"structural_model": "rune-wave-ct",
|
||||
"construction_mode": "rune-wave-cu",
|
||||
"layout_contract": "rune-wave-cv",
|
||||
"builder_bridge": "rune-wave-cw",
|
||||
"drift_compression": "rune-wave-cx",
|
||||
"event_envelope": "rune-wave-cy",
|
||||
"stage_guards": "rune-wave-cz"
|
||||
},
|
||||
"excluded": [
|
||||
"TUI-LAST modules",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.288.0"
|
||||
version = "0.293.2"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Live parity: construction_interface Rust kernels vs the frozen oracle
|
||||
truth (dichotomy wave, contract factory-gap-ci). Layers:
|
||||
|
||||
1. FROZEN — the frozen truth corpora (frozen_ci_truth.json 85 cases +
|
||||
frozen_ci_truth_hash.json 5 shape-pinned cases, generated by
|
||||
scripts/gen_construction_interface_truth.py against the LIVE Python
|
||||
oracle through the scripts/ci_freeze_seams rig) replayed through
|
||||
the ci_replay ctypes FFI entry of the built cdylib, case by case.
|
||||
2. LIVE — a fresh re-freeze of the oracle through the same rig in a
|
||||
subprocess; the regenerated corpora must be byte-identical to the
|
||||
committed files (the oracle is still the parity authority while the
|
||||
strangler runs).
|
||||
|
||||
Exit 0 only at 100% parity (85 verbatim + 5 shape-pinned + byte-identical
|
||||
re-freeze).
|
||||
"""
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
CRATE = REPO / "src" / "rust" / "construction_interface"
|
||||
LIB = CRATE / "target" / "release" / "libconstruction_interface.so"
|
||||
FROZEN = CRATE / "frozen_ci_truth.json"
|
||||
FROZEN_HASH = CRATE / "frozen_ci_truth_hash.json"
|
||||
|
||||
HASH_ID_PREFIXES = (
|
||||
"contract:", "regression:", "verification:",
|
||||
"composition:", "acquisition:",
|
||||
)
|
||||
|
||||
|
||||
def normalize_hash_ids(obj):
|
||||
if isinstance(obj, str):
|
||||
kind, _, digits = obj.partition(":")
|
||||
if (f"{kind}:" in HASH_ID_PREFIXES and digits
|
||||
and len(digits) <= 8 and digits.isdigit()):
|
||||
return f"{kind}:#"
|
||||
return obj
|
||||
if isinstance(obj, list):
|
||||
return [normalize_hash_ids(v) for v in obj]
|
||||
if isinstance(obj, dict):
|
||||
return {k: normalize_hash_ids(v) for k, v in obj.items()}
|
||||
return obj
|
||||
|
||||
|
||||
def replay(lib, case):
|
||||
payload = json.dumps(case, separators=(",", ":")).encode()
|
||||
ptr = lib.ci_replay(payload, len(payload))
|
||||
if not ptr:
|
||||
raise RuntimeError("ci_replay returned NULL")
|
||||
text = ctypes.c_char_p(ptr).value.decode()
|
||||
lib.ci_free_string(ptr)
|
||||
return json.loads(text)
|
||||
|
||||
|
||||
def frozen_layer():
|
||||
lib = ctypes.CDLL(str(LIB))
|
||||
lib.ci_replay.argtypes = [ctypes.c_char_p, ctypes.c_size_t]
|
||||
lib.ci_replay.restype = ctypes.c_void_p
|
||||
lib.ci_free_string.argtypes = [ctypes.c_void_p]
|
||||
lib.ci_free_string.restype = None
|
||||
ok = 0
|
||||
cases = json.loads(FROZEN.read_text())
|
||||
for case in cases:
|
||||
got = replay(lib, case)
|
||||
assert got == case["expected"], (
|
||||
f"FROZEN divergence: {case['fn']} "
|
||||
f"{case['args'][0] if case['args'] else '?'}")
|
||||
ok += 1
|
||||
hash_ok = 0
|
||||
for case in json.loads(FROZEN_HASH.read_text()):
|
||||
got = normalize_hash_ids(replay(lib, case))
|
||||
want = normalize_hash_ids(case["expected"])
|
||||
assert got == want, (
|
||||
f"HASH divergence: {case['fn']} "
|
||||
f"{case['args'][0] if case['args'] else '?'}")
|
||||
hash_ok += 1
|
||||
print(f"FROZEN: PARITY OK {ok}/{len(cases)} verbatim "
|
||||
f"+ {hash_ok} hash-shape cases")
|
||||
return ok, hash_ok
|
||||
|
||||
|
||||
def main() -> int:
|
||||
committed_main = FROZEN.read_bytes()
|
||||
committed_hash = FROZEN_HASH.read_bytes()
|
||||
n_main, n_hash = frozen_layer()
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="ci_gap_parity_") as _scratch:
|
||||
# the re-freeze must run at the CANONICAL rig home — the mini-doc
|
||||
# paths are embedded in the frozen truth, so a different
|
||||
# CI_FREEZE_HOME changes the bytes without changing behavior
|
||||
home = "/tmp/ci_gap_freeze_home"
|
||||
subprocess.run(["rm", "-rf", home], check=True)
|
||||
env = dict(
|
||||
os.environ,
|
||||
CI_FREEZE_HOME=home,
|
||||
PYTHONPATH="scripts/ci_freeze_seams:src",
|
||||
CS_RUST_LIB="/mnt/workdrive/rune/src/rust/capability_scoring/"
|
||||
"target/release/libcapability_scoring.so",
|
||||
)
|
||||
r = subprocess.run(
|
||||
[sys.executable, "scripts/gen_construction_interface_truth.py"],
|
||||
cwd=str(REPO), env=env, capture_output=True, text=True, timeout=600)
|
||||
if r.returncode != 0:
|
||||
print(r.stdout[-2000:])
|
||||
print(r.stderr[-2000:])
|
||||
print("LIVE: re-freeze FAILED")
|
||||
return 1
|
||||
same_main = FROZEN.read_bytes() == committed_main
|
||||
same_hash = FROZEN_HASH.read_bytes() == committed_hash
|
||||
if not (same_main and same_hash):
|
||||
print(f"LIVE: re-freeze NOT byte-identical "
|
||||
f"(main={same_main} hash={same_hash})")
|
||||
return 1
|
||||
print(f"LIVE: fresh re-freeze byte-identical "
|
||||
f"({n_main}+{n_hash} cases, oracle authority held)")
|
||||
print("PARITY OK construction_interface")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
"""check_model_connect_parity.py — live oracle-vs-Go parity sweep for the
|
||||
model_connect gap closure (#2479, contract factory-gap-mconn).
|
||||
|
||||
The frozen envelope (truth.json) pins the ported surface byte-identically.
|
||||
THIS script drives the LIVE Python oracle and the Go binary (stdin op
|
||||
dispatch) across every op family — clean, moe, route, ctx_budget, now
|
||||
(clock pinned on both sides), hook, and the cloud-model config sweep
|
||||
(per-fixture hermetic HOME shared by oracle and binary) — comparing
|
||||
sort_keys JSON. Exit 0 on 100% parity, 1 with the first divergences.
|
||||
|
||||
Usage: python3 scripts/check_model_connect_parity.py
|
||||
[--bin src/go/model-connect/model-connect]
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
import rune.model_connect as mc # noqa: E402
|
||||
|
||||
FROZEN_NOW = "2026-10-14T08:00:00+00:00"
|
||||
|
||||
CLEAN = [
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"hf.co/org/Llama-3-8B-Instruct:latest",
|
||||
"hf.co/short/gemma-2-9b",
|
||||
"hf.co/user/nano-model",
|
||||
"hf.co/user/ab",
|
||||
"qwen2.5:3b",
|
||||
"mimo-v2.5-pro",
|
||||
"llava:7b",
|
||||
"huggingface.co/x/y/Llama-3-8B",
|
||||
]
|
||||
|
||||
MOE = [
|
||||
"mixtral:8x7b", "qwen2.5:3b", "deepseek-moe-16b", "My-Mixture-Model",
|
||||
"expert-v1", "4x22b-tiny", "plain-conversational", "GPT-XL",
|
||||
]
|
||||
|
||||
MODELS_ALL = [
|
||||
"qwen2.5:3b", "qwen2.5:7b", "qwen3:14b", "qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0", "qwen2.5vl:3b", "llava:7b",
|
||||
"qwen3-embedding:0.6b", "nomic-embed-text:latest", "mxbai-embed-large:latest",
|
||||
]
|
||||
|
||||
ROUTE = [
|
||||
("coding", MODELS_ALL), ("research", MODELS_ALL), ("conversation", MODELS_ALL),
|
||||
("unrestricted", MODELS_ALL), ("unknown-type", MODELS_ALL),
|
||||
("coding", ["mystery-model:x"]), ("coding", []),
|
||||
]
|
||||
|
||||
CTX = ["deterministic", "qwen2.5:3b", "qwen3:14b", "qwen3.6:27b",
|
||||
"mimo-v2.5-pro", "totally-unknown-model", ""]
|
||||
|
||||
HOOKS = [
|
||||
("pre_tool_use", {"tool": "bash", "dry": False}),
|
||||
("", None),
|
||||
("post_response", {"ok": True}),
|
||||
("unicode-évent", {}),
|
||||
]
|
||||
|
||||
FIXTURES = {
|
||||
"main": """{
|
||||
// MiMoCode config — JSONC: comments and trailing commas allowed
|
||||
"provider": {
|
||||
"ollama": { // skipped: local models handled by list_models
|
||||
"models": {
|
||||
"qwen3:14b": {},
|
||||
},
|
||||
},
|
||||
"openai": {
|
||||
"models": {
|
||||
"gpt-5.2": {"contextLength": 400000},
|
||||
"o4-mini": "not-even-a-dict",
|
||||
},
|
||||
},
|
||||
"kimi": {
|
||||
"models": {
|
||||
"kimi-for-coding": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
""",
|
||||
"only_ollama": '{\n "provider": {\n "ollama": {"models": {"qwen2.5:3b": {}}},\n },\n}\n',
|
||||
"no_models_key": '{\n "provider": {\n "anthropic": {"apiKey": "sk-test"},\n },\n}\n',
|
||||
"no_provider_key": '{\n "theme": "dark",\n}\n',
|
||||
"broken_late": '{\n "provider": {\n "a": {"models": {"m1": {}}},\n "b": {"models": "not-a-dict"},\n },\n}\n',
|
||||
"null_models": '{\n "provider": {\n "z": {"models": null},\n },\n}\n',
|
||||
"url_corruption": '{\n "provider": {\n "gateway": {\n "baseUrl": "http://api.example.com/v1",\n "models": {"gw-model": {}},\n },\n },\n}\n',
|
||||
}
|
||||
|
||||
|
||||
def run_go(binpath, req, env=None):
|
||||
e = dict(os.environ)
|
||||
if env:
|
||||
e.update(env)
|
||||
p = subprocess.run([str(binpath)], input=json.dumps(req), capture_output=True,
|
||||
text=True, env=e)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError(f"go op {req.get('op')} exited {p.returncode}: {p.stdout} {p.stderr}")
|
||||
return json.loads(p.stdout)
|
||||
|
||||
|
||||
def frozen_clock():
|
||||
base = datetime.fromisoformat(FROZEN_NOW)
|
||||
|
||||
class FrozenDatetime(datetime):
|
||||
@classmethod
|
||||
def now(cls, tz=None):
|
||||
return base if tz is not None else base.replace(tzinfo=None)
|
||||
|
||||
return FrozenDatetime
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--bin", default=str(REPO / "src/go/model-connect/model-connect"))
|
||||
args = ap.parse_args()
|
||||
binpath = Path(args.bin)
|
||||
if not binpath.exists():
|
||||
subprocess.run(["go", "build", "-o", str(binpath), str(binpath.parent)],
|
||||
check=True, cwd=binpath.parent)
|
||||
|
||||
fails = total = 0
|
||||
|
||||
def check(name, oracle_val, go_val):
|
||||
nonlocal fails, total
|
||||
total += 1
|
||||
if json.dumps(oracle_val, sort_keys=True) != json.dumps(go_val, sort_keys=True):
|
||||
fails += 1
|
||||
print(f"DIVERGE {name}:\n oracle: {json.dumps(oracle_val)[:300]}\n go: {json.dumps(go_val)[:300]}")
|
||||
|
||||
for name in CLEAN:
|
||||
g = run_go(binpath, {"op": "clean", "name": name})
|
||||
check(f"clean:{name[:40]}", {"result": mc._clean_model_name(name)}, g)
|
||||
|
||||
for name in MOE:
|
||||
g = run_go(binpath, {"op": "moe", "name": name})
|
||||
check(f"moe:{name}", {"result": mc.is_moe_model(name)}, g)
|
||||
|
||||
for task, models in ROUTE:
|
||||
g = run_go(binpath, {"op": "route", "task": task, "models": models})
|
||||
check(f"route:{task}", mc.route_model(task, models), g)
|
||||
|
||||
for mid in CTX:
|
||||
g = run_go(binpath, {"op": "ctx_budget", "model": mid})
|
||||
check(f"ctx_budget:{mid}", {"result": mc._ctx_budget(mid)}, g)
|
||||
|
||||
saved_dt = mc.datetime
|
||||
mc.datetime = frozen_clock()
|
||||
try:
|
||||
g = run_go(binpath, {"op": "now"}, env={"MCONN_CLOCK": FROZEN_NOW})
|
||||
check("now", {"result": mc._now()}, g)
|
||||
finally:
|
||||
mc.datetime = saved_dt
|
||||
|
||||
for event, data in HOOKS:
|
||||
g = run_go(binpath, {"op": "hook", "event": event, "data": data})
|
||||
check(f"hook:{event}", {"result": mc.handle_hook(event, data)}, g)
|
||||
|
||||
saved_home = os.environ.get("HOME")
|
||||
try:
|
||||
for label, fixture in FIXTURES.items():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
cfg = os.path.join(td, ".config", "mimocode")
|
||||
os.makedirs(cfg)
|
||||
with open(os.path.join(cfg, "mimocode.jsonc"), "w") as f:
|
||||
f.write(fixture)
|
||||
os.environ["HOME"] = td
|
||||
oracle_val = mc._get_cloud_models()
|
||||
g = run_go(binpath, {"op": "cloud_models"}, env={"HOME": td})
|
||||
check(f"cloud:{label}", {"result": oracle_val}, g)
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
os.environ["HOME"] = td
|
||||
oracle_val = mc._get_cloud_models()
|
||||
g = run_go(binpath, {"op": "cloud_models"}, env={"HOME": td})
|
||||
check("cloud:missing", {"result": oracle_val}, g)
|
||||
finally:
|
||||
if saved_home is not None:
|
||||
os.environ["HOME"] = saved_home
|
||||
|
||||
print(f"parity: {total - fails}/{total} match")
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
"""check_witness_parity.py — live oracle-vs-Go parity sweep for the
|
||||
witness gap closure (#2479, contract factory-gap-wi).
|
||||
|
||||
The frozen envelope (truth.json, 58 cases) pins the JSON-native surface
|
||||
byte-identically. THIS script drives the LIVE Python oracle (kernel
|
||||
delegation on — the Rust cognition_core is the authority) and the Go
|
||||
binary (`op` mode) across the same branches plus the seams the harness
|
||||
cannot freeze: the full log round-trip with BYTE-COMPARED log files
|
||||
(frozen clock → identical jsonl bytes incl. ", "/": " separators,
|
||||
insertion order, ensure_ascii), read_log deque semantics against
|
||||
hand-seeded blank/malformed lines, log_stats shapes incl. list-shaped
|
||||
signals and skip_rate half-even rounding, the missing-file branches, and
|
||||
_now under the pinned clock.
|
||||
|
||||
Usage: PYTHONPATH=src python3 scripts/check_witness_parity.py
|
||||
[--bin src/go/witness/witness]
|
||||
Exit 0 on 100% parity, 1 with the first divergence.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "scripts"))
|
||||
|
||||
FROZEN_NOW = "2026-10-14T09:15:00.123456+00:00"
|
||||
SCRATCH_P = Path("/tmp/witness_parity_py/memory")
|
||||
SCRATCH_G = Path("/tmp/witness_parity_go/memory")
|
||||
|
||||
os.environ["RUNE_MEMORY_DIR"] = str(SCRATCH_P)
|
||||
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
|
||||
|
||||
from freeze_truth import _pin_clock # noqa: E402
|
||||
|
||||
import rune.witness as wt # noqa: E402
|
||||
|
||||
_pin_clock(wt) # module-global datetime pinned → _now() frozen both sides
|
||||
|
||||
IS_CORRECTION = [
|
||||
"no, that's wrong, fix it",
|
||||
"Actually, you misunderstood the requirement",
|
||||
"that answer is wrong",
|
||||
"incorrect output",
|
||||
"not right either",
|
||||
"please try again",
|
||||
"nope",
|
||||
"stop doing that",
|
||||
"we already did the migration",
|
||||
"that's not what I asked for", # hits via the lowercase that'?s? not (correct|right|what)
|
||||
"I meant the left column", # capital-I quirk → False
|
||||
"I already told you", # capital-I quirk → False
|
||||
"wrongly spelled", # \b boundary → False
|
||||
"looks good to me",
|
||||
"",
|
||||
"don't do that",
|
||||
"I told you the column",
|
||||
]
|
||||
|
||||
EXTRACT_TOPIC = [
|
||||
"the deployment runner needs repair now",
|
||||
"fix this now",
|
||||
"",
|
||||
"café résumé matters",
|
||||
"the fix_it_loop crashed again",
|
||||
"alpha beta gamma delta epsilon zeta eta theta",
|
||||
"WHY DOES THIS matter",
|
||||
"why does the memory keep drifting",
|
||||
]
|
||||
|
||||
DETECT_SIGNALS = [
|
||||
("", None, None, None),
|
||||
("hello", "boom", None, None),
|
||||
("hello", "é" * 250, None, None),
|
||||
("hello", None, "done", None),
|
||||
("hello", None, "completed", None),
|
||||
("hello", None, "abandoned", None),
|
||||
("hello", None, "failed", None),
|
||||
("hello", None, "running", None),
|
||||
("no, that's wrong, try again", None, None, None),
|
||||
("i need to check that", None, None, None),
|
||||
("we already did the migration", None, None, None),
|
||||
("I'll send the report", None, None, None),
|
||||
("anyway moving on to budgets", None, None, ["budget"]),
|
||||
("the deployment runner needs repair", None, None, ["deployment", "runner"]),
|
||||
("urgent! I prefer rust, but actually wait", None, None, None),
|
||||
("why does the memory keep drifting", None, None, None),
|
||||
]
|
||||
|
||||
LOG_ENTRIES = [
|
||||
({"correction": True, "corrected_topic": ["budgets"]}, "user corrected the budget", "sess-1"),
|
||||
({"urgency_detected": True}, "", "sess-2"),
|
||||
({"correction": True}, "r2", ""),
|
||||
({"learning_opportunity": True}, "noted — café", "s4"),
|
||||
({"completion": "done"}, "", "s5"),
|
||||
({"error": True}, "logged", "s6"),
|
||||
({"error": True}, "", "s7"),
|
||||
({"commitment_detected": True}, "planned", "s8"),
|
||||
]
|
||||
|
||||
|
||||
def run_go(binpath, env, req):
|
||||
p = subprocess.run([str(binpath), "op"], input=json.dumps(req),
|
||||
capture_output=True, text=True, env=env)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError(f"go op {req.get('op')} exited {p.returncode}: {p.stdout} {p.stderr}")
|
||||
out = json.loads(p.stdout)
|
||||
return out.get("result")
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--bin", default=str(REPO / "src/go/witness/witness"))
|
||||
args = ap.parse_args()
|
||||
binpath = Path(args.bin)
|
||||
if not binpath.exists():
|
||||
print(f"Go binary missing: {binpath} (go build -o witness . in src/go/witness)")
|
||||
return 1
|
||||
|
||||
for scratch in (SCRATCH_P, SCRATCH_G):
|
||||
base = scratch.parent
|
||||
if base.exists():
|
||||
shutil.rmtree(base)
|
||||
scratch.mkdir(parents=True)
|
||||
|
||||
go_env = dict(os.environ)
|
||||
go_env["RUNE_MEMORY_DIR"] = str(SCRATCH_G)
|
||||
go_env["WITNESS_FROZEN_NOW"] = FROZEN_NOW
|
||||
|
||||
fails = total = 0
|
||||
|
||||
def check(name, oracle_val, go_val):
|
||||
nonlocal fails, total
|
||||
total += 1
|
||||
# log_stats may carry INT signal_types keys (list-shaped signals —
|
||||
# Python dicts accept them; json.dumps coerces to "1"/"2" on dump
|
||||
# but sort_keys chokes first). Normalize the way dumps coerces.
|
||||
if isinstance(oracle_val, dict) and "signal_types" in oracle_val:
|
||||
oracle_val = dict(oracle_val)
|
||||
oracle_val["signal_types"] = {
|
||||
str(k): v for k, v in oracle_val["signal_types"].items()}
|
||||
if json.dumps(oracle_val, sort_keys=True) != json.dumps(go_val, sort_keys=True):
|
||||
fails += 1
|
||||
print(f"DIVERGE {name}:\n oracle: {json.dumps(oracle_val)[:300]}\n"
|
||||
f" go: {json.dumps(go_val)[:300]}")
|
||||
|
||||
# _now under the pinned clock
|
||||
check("now", wt._now(), run_go(binpath, go_env, {"op": "now"}))
|
||||
|
||||
# is_correction — live public fn (capital-letter quirk included)
|
||||
for text in IS_CORRECTION:
|
||||
check(f"is_correction:{text[:30]!r}", wt.is_correction(text),
|
||||
run_go(binpath, go_env, {"op": "is_correction", "text": text}))
|
||||
|
||||
# extract_topic — live kernel delegation
|
||||
for text in EXTRACT_TOPIC:
|
||||
check(f"extract_topic:{text[:30]!r}", wt.extract_topic(text),
|
||||
run_go(binpath, go_env, {"op": "extract_topic", "text": text}))
|
||||
|
||||
# detect_signals — live kernel delegation, full dicts
|
||||
for msg, te, ts, rt in DETECT_SIGNALS:
|
||||
check(f"detect_signals:{msg[:30]!r}",
|
||||
wt.detect_signals(msg, tool_error=te, task_status=ts, recent_topics=rt),
|
||||
run_go(binpath, go_env, {"op": "detect_signals", "message": msg,
|
||||
"tool_error": te, "task_status": ts,
|
||||
"recent_topics": rt}))
|
||||
|
||||
# gather seams
|
||||
check("stopwords", wt._stopwords(), run_go(binpath, go_env, {"op": "stopwords"}))
|
||||
check("tables", wt._tables(), run_go(binpath, go_env, {"op": "tables"}))
|
||||
|
||||
# log family — read/stats on missing files
|
||||
check("read_log:missing", wt.read_log(20),
|
||||
run_go(binpath, go_env, {"op": "read_log", "limit": 20}))
|
||||
check("log_stats:missing", wt.log_stats(), run_go(binpath, go_env, {"op": "log_stats"}))
|
||||
|
||||
# log_entry sequence — then BYTE-COMPARE the two jsonl files
|
||||
for signals, reflection, session in LOG_ENTRIES:
|
||||
wt.log_entry(signals, reflection, session)
|
||||
run_go(binpath, go_env, {"op": "log_entry", "signals": signals,
|
||||
"reflection": reflection, "session_id": session})
|
||||
py_log = Path(wt.LOG_PATH).read_bytes()
|
||||
go_log = (SCRATCH_G / "index" / "witness_log.jsonl").read_bytes()
|
||||
total += 1
|
||||
if py_log != go_log:
|
||||
fails += 1
|
||||
print(f"DIVERGE log-file-bytes:\n oracle: {py_log[:200]!r}\n go: {go_log[:200]!r}")
|
||||
|
||||
# read_log limits (deque semantics) + log_stats (skip_rate half-even)
|
||||
for limit in (0, 1, 2, 3, 20, 99):
|
||||
check(f"read_log:{limit}", wt.read_log(limit),
|
||||
run_go(binpath, go_env, {"op": "read_log", "limit": limit}))
|
||||
check("log_stats:full", wt.log_stats(), run_go(binpath, go_env, {"op": "log_stats"}))
|
||||
|
||||
# hand-seeded blank + malformed lines land on BOTH files identically
|
||||
seed = b'{bad json\n\n{"signals": [1, 2, 2], "reflection": "x"}\n'
|
||||
with open(wt.LOG_PATH, "ab") as f:
|
||||
f.write(seed)
|
||||
with open(SCRATCH_G / "index" / "witness_log.jsonl", "ab") as f:
|
||||
f.write(seed)
|
||||
for limit in (3, 20):
|
||||
check(f"read_log:seeded:{limit}", wt.read_log(limit),
|
||||
run_go(binpath, go_env, {"op": "read_log", "limit": limit}))
|
||||
check("log_stats:seeded", wt.log_stats(), run_go(binpath, go_env, {"op": "log_stats"}))
|
||||
|
||||
# missing-file branches again after wipe
|
||||
os.remove(wt.LOG_PATH)
|
||||
os.remove(SCRATCH_G / "index" / "witness_log.jsonl")
|
||||
check("read_log:removed", wt.read_log(5),
|
||||
run_go(binpath, go_env, {"op": "read_log", "limit": 5}))
|
||||
check("log_stats:removed", wt.log_stats(), run_go(binpath, go_env, {"op": "log_stats"}))
|
||||
|
||||
print(f"parity: {total - fails}/{total} match")
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,562 @@
|
||||
# Freeze rig for the construction_interface dichotomy gap-closing (dichotomy
|
||||
# wave #2479 gap port). Auto-imported on interpreter start
|
||||
# (PYTHONPATH=scripts/ci_freeze_seams:src) by BOTH the truth generator
|
||||
# (scripts/gen_construction_interface_truth.py) and the shared harness's
|
||||
# --verify mode, so frozen truth is byte-reproducible in any process:
|
||||
#
|
||||
# * EVERY RUNE_*_CORE gate is pinned to "python" — the oracle runs its
|
||||
# pure-Python floors end to end (construction_interface, scaffold,
|
||||
# structural_store, construction_decision, construction_mode, capability
|
||||
# ledger, programme continuation, layout contract, ...). The shared
|
||||
# harness's _pin_oracle_cores cannot reach the transitive gates; this
|
||||
# blanket pin is the poisoned-truth law for the whole dependency cone.
|
||||
# * The wall clocks are FROZEN: rune.structural_store.now and
|
||||
# rune.scaffold.now (bound import) report CI_FROZEN_NOW. The oracle
|
||||
# stamps need ids, observed_at, checkpoints and closure records through
|
||||
# these two seams; the frozen truth carries the constant instant.
|
||||
# * uuid.uuid4 is a deterministic counter (submit_need mints contract ids
|
||||
# from uuid4().hex[:6]); the counter RESETS per rig helper call so a
|
||||
# case's ids depend only on how many mints happen inside it.
|
||||
# * CI_FREEZE_HOME (default /tmp/ci_gap_freeze_home) roots every per-case
|
||||
# hermetic store: cases/<case>/proj/.rune/scaffold — deterministic
|
||||
# per-case dirs, because envelopes that carry paths (mini_doc) must
|
||||
# replay byte-identically.
|
||||
# * DOC-CARRYING SEAMS: the Rust kernel is a pure doc-in/doc-out membrane
|
||||
# (the store stays with the facade), so every stateful seam below takes
|
||||
# the FULL input doc as an argument — the frozen args replay in the Rust
|
||||
# battery without any store. The input docs are built by the deterministic
|
||||
# builder helpers (build_doc/submit_doc/walk_doc) that the GENERATOR
|
||||
# calls; the seam injects the doc into a fresh hermetic store, runs the
|
||||
# ORACLE method, and returns the envelope (plus oracle-derived doc
|
||||
# outputs where the kernel's contract includes them).
|
||||
# * write_mini_doc is redirected into the case dir (the oracle's default
|
||||
# routes through the SOURCE TREE — a repo-dependent absolute path).
|
||||
#
|
||||
# KNOWN-NONDETERMINISTIC SEAM (memory_consolidation precedent): the
|
||||
# obligation ids in _obligations_projection carry Python's
|
||||
# process-randomized str hash. Cases whose output carries those ids live
|
||||
# in the SEPARATE frozen_ci_truth_hash.json battery (captured + verified
|
||||
# with PYTHONHASHSEED=0) and are SHAPE-pinned in the Rust battery and the
|
||||
# parity check — never value-frozen in the hash-free battery.
|
||||
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import uuid as _uuid
|
||||
from pathlib import Path
|
||||
|
||||
for _k in list(os.environ):
|
||||
if _k.startswith("RUNE_") and _k.endswith("_CORE"):
|
||||
os.environ[_k] = "python"
|
||||
|
||||
CI_FREEZE_HOME = os.environ.get("CI_FREEZE_HOME") or "/tmp/ci_gap_freeze_home"
|
||||
FROZEN_NOW = "2026-10-13T09:41:23Z"
|
||||
|
||||
import rune.structural_store as ss # noqa: E402
|
||||
import rune.scaffold as _sc # noqa: E402
|
||||
|
||||
ss.now = lambda: FROZEN_NOW
|
||||
_sc.now = lambda: FROZEN_NOW
|
||||
|
||||
# programme_continuation stamps saved_at/at through time.strftime directly
|
||||
# (not ss.now) — pin the time module floor for it.
|
||||
import rune.capability_ledger as _cl_mod # noqa: E402
|
||||
import rune.programme_continuation as _pc_mod # noqa: E402
|
||||
import time as _time_mod # noqa: E402
|
||||
|
||||
_cl_mod._now = lambda: FROZEN_NOW
|
||||
_pc_mod.time = type("_T", (), {
|
||||
"strftime": staticmethod(lambda f, _t: FROZEN_NOW),
|
||||
"gmtime": staticmethod(lambda *_a: None),
|
||||
"time": staticmethod(lambda: 0.0),
|
||||
"monotonic": staticmethod(lambda: 0.0),
|
||||
})()
|
||||
|
||||
_MINT = itertools.count(1)
|
||||
|
||||
|
||||
class _DetUUID:
|
||||
def __init__(self, n: int):
|
||||
self.hex = f"{n:06x}" + "0" * 26
|
||||
|
||||
|
||||
def _reset_mint():
|
||||
global _MINT
|
||||
_MINT = itertools.count(1)
|
||||
|
||||
|
||||
_uuid.uuid4 = lambda: _DetUUID(next(_MINT)) # type: ignore[assignment]
|
||||
|
||||
import rune.construction_interface as ci # noqa: E402
|
||||
|
||||
# write_mini_doc redirect (source-tree default → per-case dir)
|
||||
import rune.construction_projection as _cp_mod # noqa: E402
|
||||
|
||||
_orig_mini_doc = _cp_mod.write_mini_doc
|
||||
|
||||
|
||||
def _hermetic_mini_doc(scaffold, contract_id, out_dir=None):
|
||||
case = os.environ.get("CI_ACTIVE_CASE", "mini-doc")
|
||||
out = Path(CI_FREEZE_HOME) / "cases" / case / "docs"
|
||||
return _orig_mini_doc(scaffold, contract_id, out_dir=out)
|
||||
|
||||
|
||||
_cp_mod.write_mini_doc = _hermetic_mini_doc
|
||||
|
||||
# Originals captured BEFORE the seam bindings below shadow the module
|
||||
# globals the oracle itself calls internally (envelope assembly etc.) —
|
||||
# the wrappers must call the captured originals, never the shadowed name.
|
||||
_ORIG = {name: getattr(ci, name) for name in (
|
||||
"_envelope", "_to_stage_check", "_guard_specs_from_obligations",
|
||||
"t_layout", "_obligations_projection", "_obligation_scope_files",
|
||||
"main")}
|
||||
|
||||
FIXTURE_ENTITIES = [
|
||||
{"id": "capability:exporter", "kind": "capability", "identities": {},
|
||||
"maturity": "WIRED", "evidence_refs": ["f"], "relationships": [],
|
||||
"observations": []},
|
||||
{"id": "contract:csv_export", "kind": "contract", "identities": {},
|
||||
"maturity": "SEED", "evidence_refs": ["f"], "relationships": [],
|
||||
"observations": []},
|
||||
]
|
||||
FIXTURE_RELATIONSHIPS = [
|
||||
{"type": "implements", "from": "capability:exporter",
|
||||
"to": "contract:csv_export", "evidence_refs": ["f"], "observations": []},
|
||||
]
|
||||
|
||||
|
||||
def _case_dir(case: str) -> Path:
|
||||
os.environ["CI_ACTIVE_CASE"] = case
|
||||
d = Path(CI_FREEZE_HOME) / "cases" / case
|
||||
shutil.rmtree(d, ignore_errors=True)
|
||||
(d / "proj" / ".rune").mkdir(parents=True, exist_ok=True)
|
||||
return d
|
||||
|
||||
|
||||
def _iface(case: str, project_id: str = "gap-ci-proj"):
|
||||
_reset_mint()
|
||||
d = _case_dir(case)
|
||||
store = str(d / "proj" / ".rune" / "scaffold")
|
||||
iface = ci.ConstructionInterface(
|
||||
builder="factory-gap-ci", project_store=store, project_id=project_id)
|
||||
iface.scaffold.init(purpose="fixture")
|
||||
doc = iface.scaffold.load()
|
||||
for e in FIXTURE_ENTITIES:
|
||||
doc["entities"].append(json.loads(json.dumps(e)))
|
||||
for r in FIXTURE_RELATIONSHIPS:
|
||||
doc["relationships"].append(json.loads(json.dumps(r)))
|
||||
iface.scaffold.save(doc)
|
||||
return iface
|
||||
|
||||
|
||||
def _iface_with_doc(case: str, doc: dict, project_id: str = "gap-ci-proj"):
|
||||
"""Fresh hermetic store with `doc` injected — the seam entry point."""
|
||||
_reset_mint()
|
||||
d = _case_dir(case)
|
||||
store = str(d / "proj" / ".rune" / "scaffold")
|
||||
iface = ci.ConstructionInterface(
|
||||
builder="factory-gap-ci", project_store=store, project_id=project_id)
|
||||
iface.scaffold.init(purpose="fixture")
|
||||
iface.scaffold.save(json.loads(json.dumps(doc)))
|
||||
return iface
|
||||
|
||||
|
||||
def build_doc() -> dict:
|
||||
"""The fixture authority document (pure dict, no store IO)."""
|
||||
doc = ss.new_doc()
|
||||
for e in FIXTURE_ENTITIES:
|
||||
doc["entities"].append(json.loads(json.dumps(e)))
|
||||
for r in FIXTURE_RELATIONSHIPS:
|
||||
doc["relationships"].append(json.loads(json.dumps(r)))
|
||||
return doc
|
||||
|
||||
|
||||
def submit_doc(case: str, doc: dict, objective: str = "persistent project export",
|
||||
**kw) -> dict:
|
||||
"""Builder helper (NOT a frozen fn): run oracle submit_need over a
|
||||
hermetic store seeded with `doc`; return the updated doc."""
|
||||
payload = dict(
|
||||
constraints={"contracts": ["contract:csv_export"]},
|
||||
affected_surface=[],
|
||||
evidence_refs=["x"],
|
||||
approval_context="covered by fixture authority",
|
||||
)
|
||||
payload.update(kw)
|
||||
iface = _iface_with_doc(case, doc)
|
||||
r = iface.submit_need(objective, **payload)
|
||||
assert r["success"] or not payload.get("generate", True), r
|
||||
return iface.scaffold.load()
|
||||
|
||||
|
||||
def walk_doc(case: str, doc: dict, objective: str = "persistent project export",
|
||||
phases=("approved", "building", "verifying"), **kw) -> dict:
|
||||
"""Builder helper: submit + walk the legal ladder in ONE process."""
|
||||
iface = _iface_with_doc(case, doc)
|
||||
payload = dict(
|
||||
constraints={"contracts": ["contract:csv_export"]},
|
||||
affected_surface=[],
|
||||
evidence_refs=["x"],
|
||||
approval_context="covered by fixture authority",
|
||||
)
|
||||
payload.update(kw)
|
||||
r = iface.submit_need(objective, **payload)
|
||||
assert r["success"], r
|
||||
cid = r["ids"]["contract_id"]
|
||||
for ph in phases:
|
||||
t = iface.transition(cid, ph)
|
||||
assert t["success"], t
|
||||
return iface.scaffold.load()
|
||||
|
||||
|
||||
def contract_of(doc: dict, contract_id: str):
|
||||
for e in doc.get("entities", []):
|
||||
if e.get("kind") == "construction_contract" and \
|
||||
e.get("id") == f"contract:{contract_id}":
|
||||
return e
|
||||
return None
|
||||
|
||||
|
||||
def build_ledger_caps() -> dict:
|
||||
"""A valid capability-ledger doc via the ledger's own define API
|
||||
(builder helper; frozen clock keeps it deterministic)."""
|
||||
from rune.capability_ledger import CapabilityLedger
|
||||
|
||||
ledger = CapabilityLedger(Path(CI_FREEZE_HOME) / "cases" / "b-ledger")
|
||||
ledger.define(capability_id="capability:exporter", name="exporter",
|
||||
purpose="export fixtures", owning_project="gap-ci-proj",
|
||||
component="exporter", source_locations=["src/export.py"])
|
||||
return json.loads(json.dumps(ledger.doc))
|
||||
|
||||
|
||||
def _discover_doc(contract_id: str, observed_at: str, project: str) -> dict:
|
||||
"""A minimal store doc carrying ONE construction contract (builder
|
||||
helper for the discover_active_contract seam)."""
|
||||
doc = ss.new_doc()
|
||||
ss.add_entity(doc, id=f"contract:{contract_id}",
|
||||
kind="construction_contract",
|
||||
identities={"project": project, "scope": [],
|
||||
"affected_entities": []},
|
||||
evidence_refs=["f"])
|
||||
doc["entities"][-1]["observed_at"] = observed_at
|
||||
return doc
|
||||
|
||||
|
||||
def _submitted_cid(doc: dict) -> str:
|
||||
for e in doc.get("entities", []):
|
||||
if e.get("kind") == "construction_contract":
|
||||
return e["id"].split(":", 1)[1]
|
||||
raise AssertionError("no contract in doc")
|
||||
|
||||
|
||||
# ── pure module-level seams ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _envelope(operation, *, success, ids=None, state=None, evidence=None,
|
||||
errors=None, warnings=None, extra=None):
|
||||
return _ORIG["_envelope"](operation, success=success, ids=ids, state=state,
|
||||
evidence=evidence, errors=errors,
|
||||
warnings=warnings, **(extra or {}))
|
||||
|
||||
|
||||
def _to_stage_check(spec):
|
||||
from rune import stage_guards as _sg
|
||||
|
||||
c = _sg.StageCheck(
|
||||
name=str(spec.get("name", "guard")),
|
||||
kind=str(spec.get("kind", "assert")),
|
||||
argv=spec.get("argv"),
|
||||
output_pattern=str(spec.get("output_pattern", "")),
|
||||
path=str(spec.get("path", "")),
|
||||
check=spec.get("check"),
|
||||
description=str(spec.get("description", "")),
|
||||
)
|
||||
return {"name": c.name, "kind": c.kind, "argv": c.argv,
|
||||
"output_pattern": c.output_pattern, "path": c.path,
|
||||
"check": c.check.__name__ if callable(c.check) else None,
|
||||
"description": c.description}
|
||||
|
||||
|
||||
def _guard_specs_from_obligations(c):
|
||||
return _ORIG["_guard_specs_from_obligations"](c)
|
||||
|
||||
|
||||
def t_layout(ext):
|
||||
return _ORIG["t_layout"](ext)
|
||||
|
||||
|
||||
def _obligations_projection(c):
|
||||
return _ORIG["_obligations_projection"](c)
|
||||
|
||||
|
||||
def _obligation_scope_files(obligations):
|
||||
return _ORIG["_obligation_scope_files"](obligations)
|
||||
|
||||
|
||||
def main(case, argv):
|
||||
"""The JSON CLI transport over the hermetic rune-internal store."""
|
||||
_reset_mint()
|
||||
d = _case_dir(case)
|
||||
(d / "store" / "scaffold").mkdir(parents=True, exist_ok=True)
|
||||
prev = os.getcwd()
|
||||
os.chdir(d)
|
||||
try:
|
||||
inner = ci.ConstructionInterface(builder="factory-gap-ci")
|
||||
inner.scaffold.init(purpose="fixture")
|
||||
return _ORIG["main"](list(argv))
|
||||
finally:
|
||||
os.chdir(prev)
|
||||
|
||||
|
||||
# ── authority access ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _authorities(scaffold_doc, spine_doc=None, mode="external_project"):
|
||||
"""The oracle's authority assembly given the loaded docs (doc-carrying:
|
||||
the loads stay with the caller)."""
|
||||
auth = {"project_scaffold": scaffold_doc}
|
||||
if mode == "rune_internal" and spine_doc is not None:
|
||||
auth["rune_spine"] = spine_doc
|
||||
return auth
|
||||
|
||||
|
||||
def _record_session(doc, operation, detail, builder="factory-gap-ci",
|
||||
mode="external_project", now=None):
|
||||
iface = _iface("rec-session")
|
||||
d = json.loads(json.dumps(doc))
|
||||
iface._record_session(d, operation, detail)
|
||||
return d
|
||||
|
||||
|
||||
# ── classify / context / capabilities ───────────────────────────────────────
|
||||
|
||||
|
||||
def classify(decision, builder="factory-gap-ci"):
|
||||
"""Envelope assembly over the canonical classifier's result (the
|
||||
classifier itself is construction_mode's port surface)."""
|
||||
iface = _iface("classify")
|
||||
d = dict(decision)
|
||||
env = _ORIG["_envelope"]("classify", success=d.get("mode") != "UNKNOWN",
|
||||
state={**d, "builder": builder})
|
||||
return env
|
||||
|
||||
|
||||
def construction_context(case, doc, contract_id=None,
|
||||
builder="factory-gap-ci", project="gap-ci-proj"):
|
||||
iface = _iface_with_doc(case, doc, project_id=project)
|
||||
return iface.construction_context(contract_id)
|
||||
|
||||
|
||||
def capabilities(mode="external_project", project="gap-ci-proj"):
|
||||
iface = _iface("caps")
|
||||
iface.mode = mode
|
||||
iface.scaffold.project_id = project
|
||||
return iface.capabilities()
|
||||
|
||||
|
||||
# ── submit_need ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def submit_need(case, doc, objective, origin="builder", constraints=None,
|
||||
affected_surface=None, evidence_refs=None,
|
||||
approval_context="", task_ref="", generate=True,
|
||||
contract_id=None):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
kw = dict(origin=origin, generate=generate)
|
||||
if constraints is not None:
|
||||
kw["constraints"] = constraints
|
||||
if affected_surface is not None:
|
||||
kw["affected_surface"] = affected_surface
|
||||
if evidence_refs is not None:
|
||||
kw["evidence_refs"] = evidence_refs
|
||||
kw["approval_context"] = approval_context
|
||||
kw["task_ref"] = task_ref
|
||||
if contract_id is not None:
|
||||
kw["contract_id"] = contract_id
|
||||
return iface.submit_need(objective, **kw)
|
||||
|
||||
|
||||
# ── read projections + evidence + verification ──────────────────────────────
|
||||
|
||||
|
||||
def inspect_decision(case, doc, contract_id):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.inspect_decision(contract_id)
|
||||
|
||||
|
||||
def get_scope(case, doc, contract_id):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.get_scope(contract_id)
|
||||
|
||||
|
||||
def get_obligations(case, doc, contract_id):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.get_obligations(contract_id)
|
||||
|
||||
|
||||
def report_observation(case, doc, contract_id, observations):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.report_observation(contract_id, observations)
|
||||
|
||||
|
||||
def verify(case, doc, contract_id, changed_files=None,
|
||||
layout_observations=None):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.verify(contract_id, changed_files=changed_files,
|
||||
layout_observations=layout_observations)
|
||||
|
||||
|
||||
def transition(case, doc, contract_id, phase, evidence_ref="",
|
||||
guard_checks=None):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.transition(contract_id, phase, evidence_ref=evidence_ref,
|
||||
guard_checks=guard_checks)
|
||||
|
||||
|
||||
def close(case, doc, contract_id, observed_evidence, scope_files=None):
|
||||
"""`doc` must already carry the contract at verifying (walk_doc)."""
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.close(contract_id, observed_evidence=observed_evidence,
|
||||
scope_files=scope_files)
|
||||
|
||||
|
||||
def _programme_continuation(case, doc, contract_id, programmes=None):
|
||||
"""programmes: list of programme DOCS (generator-built via the pc API);
|
||||
the seam persists them into the case's programme area, runs the oracle,
|
||||
and returns the continuation plus the persisted-after docs."""
|
||||
from rune import programme_continuation as pc
|
||||
|
||||
iface = _iface_with_doc(case, doc)
|
||||
base = Path(iface.scaffold.current).parent / pc.DEFAULT_PROGRAMME_AREA
|
||||
if programmes is not None:
|
||||
base.mkdir(parents=True, exist_ok=True)
|
||||
for pd in programmes:
|
||||
prog = pc.Programme(
|
||||
programme_id=pd["programme_id"], objective=pd["objective"],
|
||||
stages=[pc.ProgrammeStage(**s) for s in pd["stages"]])
|
||||
prog.save(base)
|
||||
out = iface._programme_continuation(contract_id)
|
||||
after = None
|
||||
if base.is_dir():
|
||||
after = []
|
||||
for f in sorted(base.glob("*.json")):
|
||||
after.append(json.loads(f.read_text()))
|
||||
return {"continuation": out, "programmes_after": after}
|
||||
|
||||
|
||||
def _auto_material_change(case, doc, scope_files, capabilities=None):
|
||||
"""capabilities: the ledger DOC (kernel input); the seam persists it as
|
||||
the project rune_model ledger, runs the oracle, and returns the oracle
|
||||
result plus the ledger doc after the oracle's material_change/save."""
|
||||
from rune.capability_ledger import CapabilityLedger
|
||||
|
||||
iface = _iface_with_doc(case, doc)
|
||||
if capabilities is not None:
|
||||
ledger_dir = Path(iface.scaffold.store_dir).parent / "rune_model"
|
||||
ledger_dir.mkdir(parents=True, exist_ok=True)
|
||||
(ledger_dir / "capability_ledger.json").write_text(
|
||||
json.dumps(capabilities))
|
||||
out = iface._auto_material_change(
|
||||
list(scope_files), note="contract closed (material change)")
|
||||
after = None
|
||||
led = Path(iface.scaffold.store_dir).parent / "rune_model" / \
|
||||
"capability_ledger.json"
|
||||
if led.is_file():
|
||||
after = json.loads(led.read_text())
|
||||
return {"result": out, "ledger_after": after}
|
||||
|
||||
|
||||
def discover_active_contract(case, candidates, root_name="store"):
|
||||
"""candidates: [{project: str|null, doc: {...}}] — the seam persists
|
||||
each doc at projects/<p>/current.json (or the root current.json) inside
|
||||
the case dir and runs the oracle over that store root."""
|
||||
d = _case_dir(case)
|
||||
for cand in candidates:
|
||||
proj, doc = cand["project"], cand["doc"]
|
||||
if proj is None:
|
||||
(d / "current.json").write_text(json.dumps(doc))
|
||||
else:
|
||||
p = d / "projects" / proj
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
(p / "current.json").write_text(json.dumps(doc))
|
||||
return ci.ConstructionInterface.discover_active_contract(str(d))
|
||||
|
||||
|
||||
def resume(case, doc, contract_id):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
return iface.resume(contract_id)
|
||||
|
||||
|
||||
def amend_scope(case, doc, contract_id, add_paths, reason, authority="user"):
|
||||
iface = _iface_with_doc(case, doc)
|
||||
env = iface.amend_scope(contract_id, add_paths, reason=reason,
|
||||
authority=authority)
|
||||
return {"envelope": env,
|
||||
"contract_after": contract_of(iface.scaffold.load(), contract_id)}
|
||||
|
||||
|
||||
def ladder_walk(case, objective="persistent project export"):
|
||||
"""The FULL ladder in ONE process (the shared-store clobber law):
|
||||
submit_need → approved → building → verifying → close, with the read
|
||||
projections riding the walk."""
|
||||
iface = _iface(case)
|
||||
out = []
|
||||
r = iface.submit_need(
|
||||
objective,
|
||||
constraints={"contracts": ["contract:csv_export"]},
|
||||
affected_surface=[], evidence_refs=["x"],
|
||||
approval_context="covered by fixture authority")
|
||||
out.append({"step": "submit_need", "envelope": r})
|
||||
if not r["success"]:
|
||||
return out
|
||||
cid = r["ids"]["contract_id"]
|
||||
out.append({"step": "inspect_decision", "envelope": iface.inspect_decision(cid)})
|
||||
out.append({"step": "get_scope", "envelope": iface.get_scope(cid)})
|
||||
out.append({"step": "verify", "envelope": iface.verify(cid)})
|
||||
for ph in ("approved", "building", "verifying"):
|
||||
t = iface.transition(cid, ph)
|
||||
out.append({"step": f"transition:{ph}", "envelope": t})
|
||||
if not t["success"]:
|
||||
return out
|
||||
c = iface.close(cid, observed_evidence=[
|
||||
{"kind": "port_evidence", "detail": "gap closed with proof"}])
|
||||
out.append({"step": "close", "envelope": c})
|
||||
return out
|
||||
|
||||
|
||||
# Bind the seams onto the oracle module so the shared harness's
|
||||
# getattr(module, fn) resolves every frozen fn name.
|
||||
ci.ladder_walk = ladder_walk
|
||||
ci.submit_need = submit_need
|
||||
ci.classify = classify
|
||||
ci.construction_context = construction_context
|
||||
ci.capabilities = capabilities
|
||||
ci.inspect_decision = inspect_decision
|
||||
ci.get_scope = get_scope
|
||||
ci.get_obligations = get_obligations
|
||||
ci.report_observation = report_observation
|
||||
ci.verify = verify
|
||||
ci.transition = transition
|
||||
ci.close = close
|
||||
ci._programme_continuation = _programme_continuation
|
||||
ci._auto_material_change = _auto_material_change
|
||||
ci.discover_active_contract = discover_active_contract
|
||||
ci.resume = resume
|
||||
ci.amend_scope = amend_scope
|
||||
ci._authorities = _authorities
|
||||
ci._record_session = _record_session
|
||||
ci.t_layout = t_layout
|
||||
ci._obligations_projection = _obligations_projection
|
||||
ci._obligation_scope_files = _obligation_scope_files
|
||||
ci._guard_specs_from_obligations = _guard_specs_from_obligations
|
||||
ci.ci_to_stage_check = _to_stage_check
|
||||
ci._envelope = _envelope
|
||||
ci.main = main
|
||||
# NOTE: ci._to_stage_check is deliberately NOT rebound — the oracle's
|
||||
# transition() calls the module-global _to_stage_check internally and needs
|
||||
# real StageCheck objects for the readiness canary. The rig's JSON-safe
|
||||
# _to_stage_check is exposed as the ci_to_stage_check seam instead (same
|
||||
# logic, JSON-safe projection).
|
||||
# ci._obligations_projection IS rebound to the identity wrapper above
|
||||
# (pure dict in → dict out through the captured original) — internal
|
||||
# oracle calls with live contract dicts pass through unharmed.
|
||||
@@ -17,14 +17,14 @@ from rune.construction_interface import ConstructionInterface
|
||||
cid = sys.argv[1]
|
||||
iface = ConstructionInterface(builder="factory-gap-cp")
|
||||
|
||||
t = iface.transition(cid, "verifying", evidence_ref="feat 0fb08c63 — battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins")
|
||||
t = iface.transition(cid, "verifying", evidence_ref="feat 1ad658cf — battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins")
|
||||
print("transition->verifying:", json.dumps(t)[:300])
|
||||
if not t.get("success"):
|
||||
print("TRANSITION FAILED — aborting"); sys.exit(1)
|
||||
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": "construction_pattern dichotomy completion — feat 0fb08c63 "
|
||||
"detail": "construction_pattern dichotomy completion — feat 1ad658cf "
|
||||
"'feat(construction_pattern): close PARTIAL gaps — dichotomy "
|
||||
"wave'. Audit PARTIAL 7/13 -> FULL 13/13 (headline 74/192, "
|
||||
"fn 1358/2278). Ported _need_dict (FFI need envelope, wired "
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Close the #2479 dichotomy-wave model_connect gap contract (GO port).
|
||||
Full lifecycle walk in ONE process (shared-store clobber hazard; segment
|
||||
transitions take ~60s each — do NOT split across processes). Carries the
|
||||
already-pushed parity SHA as evidence:
|
||||
feat 1f2fe468 close PARTIAL gaps — dichotomy wave (7/11 -> 11/11)
|
||||
|
||||
Usage: close_contract_model_connect.py
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
os.environ.setdefault(
|
||||
"CS_RUST_LIB",
|
||||
"/mnt/workdrive/rune/src/rust/capability_scoring/target/release/libcapability_scoring.so",
|
||||
)
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rune.construction_interface import ConstructionInterface
|
||||
|
||||
PARITY_SHA = "1f2fe468"
|
||||
EVIDENCE = f"parity {PARITY_SHA}"
|
||||
|
||||
iface = ConstructionInterface(builder="factory-gap-mconn")
|
||||
|
||||
r = iface.submit_need(
|
||||
"model_connect dichotomy gap-close (GO): name-preserving port of "
|
||||
"the 4 audit-missing functions (_ctx_budget, _now, "
|
||||
"_get_cloud_models, handle_hook) into src/go/model-connect as "
|
||||
"CtxBudget / Now / GetCloudModels / HandleHook, wall clock behind "
|
||||
"the injectable MCONN_CLOCK seam, hermetic HOME via "
|
||||
"scripts/mconn_freeze_seams, frozen-truth battery (truth.json, "
|
||||
"40-case envelope) generated against the live Python oracle and "
|
||||
"verified byte-identical via freeze_truth.py, embedded VERBATIM in "
|
||||
"truth_test.go TestFrozenTruthReplay (3/3); CI replay binary 40/40; "
|
||||
"live parity sweep 44/44 "
|
||||
"(scripts/check_model_connect_parity.py), gofmt/vet/go build clean, "
|
||||
"Python oracle smoke green both pins. Oracle quirks preserved and "
|
||||
"frozen: string-blind JSONC // strip (URL corruption -> []), "
|
||||
"partial cloud list on mid-provider shape errors, "
|
||||
"insertion-order provider/model iteration, live model_registry "
|
||||
"constants (OUTPUT_RESERVE default 2048 / TOOL_RESULT_RESERVE "
|
||||
"1024). Dichotomy audit 7/11 PARTIAL -> 11/11 FULL. Delivered on "
|
||||
"gitea/master: feat " + PARITY_SHA + ".",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:300])
|
||||
if not r.get("success"):
|
||||
print("NEED FAILED — aborting")
|
||||
sys.exit(1)
|
||||
c = r["ids"]["contract_id"]
|
||||
print("contract_id:", c)
|
||||
|
||||
for phase in ("approved", "building", "verifying", "closed"):
|
||||
t = iface.transition(c, phase, evidence_ref=EVIDENCE)
|
||||
ok = t.get("success")
|
||||
print(f"transition->{phase}:", "ok" if ok else json.dumps(t)[:300])
|
||||
if not ok:
|
||||
sys.exit(1)
|
||||
|
||||
doc = iface.scaffold.load()
|
||||
e = iface.scaffold.contract(doc, c)
|
||||
print("FINAL PHASE:", e.get("phase") if e else "MISSING")
|
||||
if not e or e.get("phase") != "closed":
|
||||
sys.exit(1)
|
||||
print("CLOSED", c)
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Close the #2479 dichotomy-wave witness gap contract (GO port).
|
||||
Full lifecycle walk in ONE process (shared-store clobber hazard; segment
|
||||
transitions can take ~60s each — do NOT split across processes). Carries
|
||||
the already-pushed parity SHA as evidence:
|
||||
feat cc51b181 close PARTIAL gaps — dichotomy wave
|
||||
|
||||
Usage: close_contract_witness.py
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
os.environ.setdefault(
|
||||
"CS_RUST_LIB",
|
||||
"/mnt/workdrive/rune/src/rust/capability_scoring/target/release/libcapability_scoring.so",
|
||||
)
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rune.construction_interface import ConstructionInterface
|
||||
|
||||
PARITY_SHA = "cc51b181"
|
||||
EVIDENCE = f"parity {PARITY_SHA}"
|
||||
|
||||
iface = ConstructionInterface(builder="factory-gap-wi")
|
||||
|
||||
r = iface.submit_need(
|
||||
"witness dichotomy gap-close (GO): name-preserving port of the 4 "
|
||||
"audit-missing functions (_now, log_entry, read_log, log_stats) into "
|
||||
"src/go/witness as now / logEntry / readLog / logStats with the "
|
||||
"injectable clock + log-path seams, plus parity-driven defect fixes "
|
||||
"to the old-era port: current 20-pattern correction table + family "
|
||||
"tables, kernel-parity extract_topic (ASCII \\w runs, cap 5), "
|
||||
"detect_signals kernel order (error → correction → completion → "
|
||||
"drift → commitment → contradiction → preference → urgency → "
|
||||
"learning) with case-insensitive family matching, rune-safe [:200] "
|
||||
"error_text and context[-500:], extraction-ordered new_topics, "
|
||||
"num_ctx 30720 via the _ctx_budget seam, and json.dumps byte-parity "
|
||||
"log lines (separators, insertion order, ensure_ascii). Frozen-truth "
|
||||
"battery (truth.json, 58 cases incl. the capital-letter is_correction "
|
||||
"quirk, completion triple, half-even skip_rate 37.5→38%) generated "
|
||||
"against the live oracle and verified byte-identical via "
|
||||
"freeze_truth.py, embedded VERBATIM in truth_test.go "
|
||||
"TestFrozenTruthReplay + seam units (deque read semantics, malformed/"
|
||||
"blank lines, list-shaped signal_types, log-line bytes, rune "
|
||||
"truncation); live parity sweep 59/59 with byte-compared log files "
|
||||
"(scripts/check_witness_parity.py); gofmt/vet/go build clean; Python "
|
||||
"oracle battery green both pins (16 live + 9 under "
|
||||
"RUNE_COGNITION_CORE=python). Dichotomy audit 11/15 PARTIAL -> "
|
||||
"15/15 FULL. Delivered on gitea/master: feat " + PARITY_SHA + ".",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:300])
|
||||
if not r.get("success"):
|
||||
print("NEED FAILED — aborting")
|
||||
sys.exit(1)
|
||||
c = r["ids"]["contract_id"]
|
||||
print("contract_id:", c)
|
||||
|
||||
for phase in ("approved", "building", "verifying", "closed"):
|
||||
t = iface.transition(c, phase, evidence_ref=EVIDENCE)
|
||||
ok = t.get("success")
|
||||
print(f"transition->{phase}:", "ok" if ok else json.dumps(t)[:300])
|
||||
if not ok:
|
||||
sys.exit(1)
|
||||
|
||||
doc = iface.scaffold.load()
|
||||
e = iface.scaffold.contract(doc, c)
|
||||
print("FINAL PHASE:", e.get("phase") if e else "MISSING")
|
||||
if not e or e.get("phase") != "closed":
|
||||
sys.exit(1)
|
||||
print("CLOSED", c)
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ct_rig.py — deterministic fixture modules for the contracts gap-close
|
||||
frozen truth (dichotomy wave, #2479 tranche).
|
||||
|
||||
The contracts oracle resolves modules with a bare ``__import__``; two of
|
||||
its branches need modules no stdlib provides:
|
||||
|
||||
* import-time crash (``except Exception -> crash`` on import): see
|
||||
``ct_rig_badimport.py`` (raises RuntimeError at import).
|
||||
* projection-time crash (``_project`` raising on a hostile result):
|
||||
``make_bad_len`` returns an object whose ``__len__`` raises, so
|
||||
``hasattr(result, "__len__")`` is True but ``len(result)`` explodes.
|
||||
|
||||
``make_ok`` / ``ATTR_VALUE`` cover the plain found paths without depending
|
||||
on any third-party module. Everything here is pure and deterministic —
|
||||
safe to import from both the freeze generator and ``--verify`` (both run
|
||||
with ``scripts/`` on ``sys.path``).
|
||||
"""
|
||||
|
||||
ATTR_VALUE = "ct-rig-stable-value"
|
||||
|
||||
|
||||
class _BadLen:
|
||||
def __len__(self):
|
||||
raise RuntimeError("boom")
|
||||
|
||||
|
||||
def make_bad_len():
|
||||
"""Return an object that breaks ``_project``'s ``len()`` call."""
|
||||
return _BadLen()
|
||||
|
||||
|
||||
def make_ok():
|
||||
"""Return a plain JSON-safe dict (the found-path control case)."""
|
||||
return {"ok": True, "n": 3}
|
||||
|
||||
|
||||
def make_none():
|
||||
"""Return None (the expect_not_none-fail control case)."""
|
||||
return None
|
||||
|
||||
|
||||
def raise_on_call():
|
||||
"""Raise on call (the call-crash control case)."""
|
||||
raise ValueError("rig call failure")
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ct_rig_badimport.py — import-crash fixture for the contracts gap-close
|
||||
frozen truth (dichotomy wave, #2479 tranche).
|
||||
|
||||
Importing this module raises a non-ImportError, exercising the oracle's
|
||||
``except Exception -> crash`` import branch in ``_resolve_and_project``
|
||||
(and ``_run_contract_python``'s outer catch). Deterministic by
|
||||
construction. See ``ct_rig.py`` for the companion fixtures.
|
||||
"""
|
||||
|
||||
raise RuntimeError("rig import failure")
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# factory_status.sh — the factory at a glance. Run directly, or in a
|
||||
# second terminal: watch -n 30 --color bash /mnt/workdrive/rune/scripts/factory_status.sh
|
||||
# Everything here is READ-ONLY (git + file mtimes + claims + audit).
|
||||
|
||||
REPO=/mnt/workdrive/rune
|
||||
cd "$REPO" || exit 1
|
||||
|
||||
B='\033[1m'; D='\033[2m'; G='\033[32m'; Y='\033[33m'; R='\033[31m'; C='\033[36m'; N='\033[0m'
|
||||
|
||||
now_epoch=$(date +%s)
|
||||
|
||||
echo -e "${B}═════════════════ RUNE FACTORY — LIVE STATUS ═════════════════${N} $(date '+%H:%M:%S')"
|
||||
|
||||
# ── headline ────────────────────────────────────────────────────────────
|
||||
git fetch gitea -q 2>/dev/null
|
||||
HEADLINE=$(python3 scripts/dichotomy_audit.py 2>/dev/null | head -1)
|
||||
GATE=$(bash scripts/factory_spawn_gate.sh 2>/dev/null | head -1)
|
||||
ACTIVE=$(echo "$GATE" | grep -oE 'active=[0-9]+' | cut -d= -f2)
|
||||
UNVER=$(echo "$GATE" | grep -oE 'unverified=[0-9]+' | cut -d= -f2)
|
||||
LAND=$(python3 -c "import json; c=json.load(open('docs/factory-claims.json')); print(len(c['landed']))")
|
||||
INFL=$(python3 -c "import json; c=json.load(open('docs/factory-claims.json')); print(len(c['in_flight']))")
|
||||
LAST_CLOSE=$(git log gitea/master --format='%cr — %s' --grep='chore(store): close' -1 2>/dev/null | head -c 100)
|
||||
|
||||
echo -e " ${C}$HEADLINE${N}"
|
||||
echo -e " ${GATE} claims: ${G}${LAND} landed${N} / ${Y}${INFL} in-flight${N}"
|
||||
echo -e " last landing: ${D}${LAST_CLOSE}${N}"
|
||||
|
||||
# ── lanes: one line per worktree ────────────────────────────────────────
|
||||
echo -e "\n${B}── LANES ──${N}"
|
||||
printf " ${B}%-16s %-24s %-10s %-9s %-8s %s${N}\n" "WORKTREE" "MODULE" "ACTIVITY" "DIRTY" "AHEAD" "HEAD"
|
||||
for wt in /mnt/workdrive/rune-wave-*; do
|
||||
[ -d "$wt" ] || continue
|
||||
name=$(basename "$wt" | sed 's/rune-wave-//')
|
||||
wname=$(basename "$wt")
|
||||
mod=$(python3 -c "
|
||||
import json
|
||||
c = json.load(open('docs/factory-claims.json'))
|
||||
for m, w in c['in_flight'].items():
|
||||
if w.split()[0] in ('$wt', '$wname'): print(m); break
|
||||
" 2>/dev/null)
|
||||
[ -z "$mod" ] && mod="-"
|
||||
# newest file mtime = work signal
|
||||
newest=$(find "$wt/src" "$wt/scripts" -type f -newer "$wt/go.mod" -printf '%T@\n' 2>/dev/null | sort -rn | head -1 | cut -d. -f1)
|
||||
if [ -n "$newest" ] && [ "$((now_epoch - newest))" -lt 300 ]; then
|
||||
act="${G}● writing${N}"
|
||||
elif [ -n "$newest" ] && [ "$((now_epoch - newest))" -lt 3600 ]; then
|
||||
act="${Y}● $(( (now_epoch - newest) / 60 ))m ago${N}"
|
||||
else
|
||||
act="${D}○ idle${N}"
|
||||
fi
|
||||
dirty=$(git -C "$wt" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
||||
ahead=$(git -C "$wt" rev-list --count gitea/master..HEAD 2>/dev/null)
|
||||
hsha=$(git -C "$wt" log --oneline -1 --format='%h' 2>/dev/null)
|
||||
printf " %-16s %-24s %-20b %-9s %-8s %s\n" "$name" "$mod" "$act" "$dirty" "$ahead" "$hsha"
|
||||
done
|
||||
|
||||
# ── recent master movement ─────────────────────────────────────────────
|
||||
echo -e "\n${B}── MASTER (last 5) ──${N}"
|
||||
git log gitea/master --oneline -5 2>/dev/null | while read -r line; do echo -e " ${D}${line}${N}"; done
|
||||
|
||||
# ── landings awaiting verification ──────────────────────────────────────
|
||||
PENDING=$(python3 - <<'EOF' 2>/dev/null
|
||||
import json, subprocess
|
||||
c = json.load(open('docs/factory-claims.json'))
|
||||
landed = set(c['landed'])
|
||||
out = subprocess.run(['git','log','gitea/master','--format','%s','-200'],capture_output=True,text=True).stdout
|
||||
import re
|
||||
pend = []
|
||||
for line in out.splitlines():
|
||||
m = re.search(r'chore\(store\): close ([a-z_]+) dichotomy contract', line)
|
||||
if m and m.group(1) not in landed:
|
||||
pend.append(m.group(1))
|
||||
print(', '.join(dict.fromkeys(pend)) if pend else '')
|
||||
EOF
|
||||
)
|
||||
if [ -n "$PENDING" ]; then
|
||||
echo -e "\n${Y}── CLOSES AWAITING VERIFICATION: $PENDING ──${N}"
|
||||
fi
|
||||
echo
|
||||
@@ -11,6 +11,7 @@ set -u
|
||||
SHA="$1"
|
||||
CRATE="$2"
|
||||
LANG_="${3:-rust}"
|
||||
FACADE_OVERRIDE="${4:-}"
|
||||
REPO=/mnt/workdrive/rune
|
||||
PASS=0; FAIL=0
|
||||
|
||||
@@ -48,7 +49,7 @@ fi
|
||||
|
||||
# Layer 3: truth file exists and is consumed (path made ABSOLUTE here —
|
||||
# later layers run from the repo root, a relative path breaks 7e's read)
|
||||
TRUTH=$(find . \( -name "frozen_*_truth.json" -o -name "frozen_truth.json" -o -name "frozen_*_truth.json" -o -name "truth.json" -o -name "truth_*.json" \) 2>/dev/null | head -1)
|
||||
TRUTH=$(find . \( -name "frozen_*_truth.json" -o -name "frozen_truth.json" -o -name "*_truth.json" -o -name "truth.json" -o -name "truth_*.json" -o -name "ct_*.json" \) 2>/dev/null | head -1)
|
||||
[ -n "$TRUTH" ] && TRUTH="$(pwd)/${TRUTH#./}"
|
||||
if [ -n "$TRUTH" ]; then
|
||||
ROWS=$(python3 -c "import json; d=json.load(open('$TRUTH')); print(len(d) if isinstance(d,list) else sum(len(v) if isinstance(v,list) else 0 for v in d.values()))" 2>/dev/null)
|
||||
@@ -83,6 +84,12 @@ MOD=$(basename "$CRATE" | tr '-' '_') # crate dir -> module stem
|
||||
STEM="${MOD%_loader}"; STEM="${STEM%-loader}"
|
||||
LOADER="src/rune/${STEM}_loader.py"
|
||||
FACADE="src/rune/${STEM}.py"
|
||||
# Shared-kernel crates (cognition_core hosts many modules' kernels) have
|
||||
# NO 1:1 facade — pass it explicitly as $4 (e.g. src/rune/safety_override.py).
|
||||
if [ -n "$FACADE_OVERRIDE" ]; then
|
||||
FACADE="$FACADE_OVERRIDE"
|
||||
echo " [INFO] facade override: $FACADE (shared-kernel crate)"
|
||||
fi
|
||||
# 7a/7b: connection completeness. Language-dependent law:
|
||||
# RUST — facade delegates through a ctypes *_loader.py (doc-envelope FFI).
|
||||
# GO — Go kernels are services/binaries by verdict; the facade keeps
|
||||
@@ -92,17 +99,28 @@ CRATE_DIR="$CRATE"
|
||||
if [ "$LANG_" = "rust" ]; then
|
||||
# 7a: loader exists — discovered from the facade's own import (loader
|
||||
# naming uses abbreviated stems: subsystem_health -> sh_loader).
|
||||
# REPLAY-SURFACE crates (ci_replay-style: the facade consumes the
|
||||
# kernel through battery/CLI evidence, not a ctypes loader) are
|
||||
# legitimate without a loader import — the kernel FFI surface + truth
|
||||
# reference IS the connection proof.
|
||||
LOADER_REF=$(grep -oE "[a-z0-9]+_loader" "$FACADE" 2>/dev/null | head -1)
|
||||
KERNEL_FFI=$(grep -rlE 'pub extern "C" fn' "$CRATE_DIR" --include='*.rs' 2>/dev/null | head -1)
|
||||
if [ -n "$LOADER_REF" ] && [ -f "src/rune/${LOADER_REF}.py" ]; then
|
||||
check "PASS" "7a loader exists: src/rune/${LOADER_REF}.py (per facade import)"
|
||||
elif [ -n "$KERNEL_FFI" ] && grep -qE 'include_str!.*truth|truth[_./-]' "$CRATE_DIR" --include='*.rs' -r 2>/dev/null; then
|
||||
check "PASS" "7a replay-surface crate: kernel FFI + truth battery (no loader by design)"
|
||||
elif [ -f "$FACADE" ] && ! grep -qE "import.*_loader|from.*_loader" "$FACADE"; then
|
||||
check "FAIL" "7a facade imports no loader"
|
||||
check "FAIL" "7a facade imports no loader and crate has no kernel FFI"
|
||||
else
|
||||
check "FAIL" "7a loader referenced as $LOADER_REF but file missing"
|
||||
fi
|
||||
# 7b: facade delegation wired (core-selection seam)
|
||||
# 7b: facade delegation wired (core-selection seam). Replay-surface
|
||||
# crates pass 7a via kernel FFI — their 7b is the same evidence: the
|
||||
# crate's battery replays frozen truth through the kernel surface.
|
||||
if [ -f "$FACADE" ] && grep -qE "RUNE_[A-Z_]+_CORE|_loader" "$FACADE" 2>/dev/null; then
|
||||
check "PASS" "7b facade has core-selection seam"
|
||||
elif [ -n "$KERNEL_FFI" ]; then
|
||||
check "PASS" "7b replay-surface: battery replays truth through kernel FFI"
|
||||
else
|
||||
check "FAIL" "7b facade not wired to implementation"
|
||||
fi
|
||||
@@ -149,7 +167,7 @@ def count(o):
|
||||
return sum(count(v) for v in o.values())
|
||||
return 0
|
||||
total = 0
|
||||
for t in glob.glob('$CRATE_DIR/truth*.json') + glob.glob('$CRATE_DIR/frozen*truth*.json') + glob.glob('$CRATE_DIR/src/frozen*truth*.json') + glob.glob('$CRATE_DIR/src/truth*.json'):
|
||||
for t in glob.glob('$CRATE_DIR/truth*.json') + glob.glob('$CRATE_DIR/frozen*truth*.json') + glob.glob('$CRATE_DIR/*_truth.json') + glob.glob('$CRATE_DIR/ct_*.json') + glob.glob('$CRATE_DIR/src/frozen*truth*.json') + glob.glob('$CRATE_DIR/src/truth*.json') + glob.glob('$CRATE_DIR/src/*_truth.json') + glob.glob('$CRATE_DIR/src/ct_*.json'):
|
||||
try:
|
||||
total += count(json.load(open(t)))
|
||||
except Exception:
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Freeze the dichotomy-wave gap truth for src/rune/construction_interface
|
||||
through the SHARED harness (scripts/freeze_truth.py — one law).
|
||||
|
||||
The oracle is a stateful facade (ConstructionInterface over a Scaffold
|
||||
store) with clock/uuid nondeterminism, so this generator runs under the
|
||||
freeze rig (scripts/ci_freeze_seams/sitecustomize.py):
|
||||
pinned RUNE_*_CORE=python floors, frozen clock, deterministic uuid mint,
|
||||
hermetic per-case stores (deterministic per-case dirs — envelopes that
|
||||
carry paths, like mini_doc, replay byte-identically), and DOC-CARRYING
|
||||
seam bindings the shared harness can getattr: the Rust kernel is a pure
|
||||
doc-in/doc-out membrane, so every stateful case carries the full input
|
||||
doc in its args and replays in the battery with no store.
|
||||
|
||||
Run (from the repo root):
|
||||
rm -rf /tmp/ci_gap_freeze_home
|
||||
CI_FREEZE_HOME=/tmp/ci_gap_freeze_home \
|
||||
PYTHONPATH=scripts/ci_freeze_seams:src \
|
||||
python3 scripts/gen_construction_interface_truth.py
|
||||
|
||||
Verify (byte-identical, same rig):
|
||||
CI_FREEZE_HOME=/tmp/ci_gap_freeze_home \
|
||||
PYTHONPATH=scripts/ci_freeze_seams:src \
|
||||
python3 scripts/freeze_truth.py --verify \
|
||||
src/rust/construction_interface/frozen_ci_truth.json \
|
||||
--module rune.construction_interface
|
||||
|
||||
Every public function and branch is exercised. The obligation-id seam
|
||||
(_obligations_projection carries process-randomized str hash) lives in
|
||||
the SEPARATE frozen_ci_truth_hash.json battery (captured + verified with
|
||||
PYTHONHASHSEED=0) and is SHAPE-pinned downstream — never value-frozen
|
||||
here.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(REPO / "scripts"))
|
||||
|
||||
from freeze_truth import freeze, write # noqa: E402
|
||||
|
||||
import sitecustomize as rig # noqa: E402
|
||||
|
||||
# ── deterministic input docs (builder helpers; NOT frozen fns) ──
|
||||
DOC0 = rig.build_doc() # fixture authority, no contract
|
||||
DOC_SUBMITTED = rig.submit_doc("b-submitted", rig.build_doc())
|
||||
DOC_WALKED = rig.walk_doc("b-walked", rig.build_doc())
|
||||
DOC_WITH_LEDGER_CAPS = rig.build_ledger_caps()
|
||||
PROGRAMMES_BOUND = [{
|
||||
"programme_id": "prog-gap-ci", "objective": "close the gap",
|
||||
"stages": [
|
||||
{"stage_id": rig._submitted_cid(DOC_SUBMITTED),
|
||||
"objective": "the gap stage"},
|
||||
{"stage_id": "next-stage", "objective": "the next stage"},
|
||||
],
|
||||
}]
|
||||
|
||||
GUARD_FAIL = [{"name": "always-fail", "kind": "command", "argv": ["false"]}]
|
||||
GUARD_PASS = [{"name": "always-pass", "kind": "command", "argv": ["true"]}]
|
||||
GUARD_ASSERT = [{"name": "truthy", "kind": "assert",
|
||||
"description": "always true"}]
|
||||
|
||||
cases = [
|
||||
# ── _envelope: success + failure shapes, extra keys ──
|
||||
("_envelope", ("op",), {"success": True}),
|
||||
("_envelope", ("op",), {"success": False,
|
||||
"errors": [{"error": "X"}],
|
||||
"warnings": [{"warning": "W"}],
|
||||
"ids": {"a": "b"}, "state": {"k": 1},
|
||||
"extra": {"extra_key": "extra"}}),
|
||||
# ── _to_stage_check: full spec, defaults ──
|
||||
("ci_to_stage_check", ({"name": "g", "kind": "command",
|
||||
"argv": ["true"], "output_pattern": "ok",
|
||||
"path": "/x", "description": "d"},), {}),
|
||||
("ci_to_stage_check", ({},), {}),
|
||||
# ── _guard_specs_from_obligations: guard rows, junk, bad JSON ──
|
||||
("_guard_specs_from_obligations",
|
||||
({"identities": {"verification_obligations": [
|
||||
'guard:{"name": "g1", "kind": "command", "argv": ["true"]}',
|
||||
"free-text obligation",
|
||||
"guard:not-json{{{",
|
||||
'["not", "a", "dict"]',
|
||||
'guard:{"name": "g2"}',
|
||||
]}},), {}),
|
||||
("_guard_specs_from_obligations", ({},), {}),
|
||||
# ── t_layout: present + absent ──
|
||||
("t_layout", ({"decision_trace": {"layout_obligations": [
|
||||
{"component": "c", "obligation": "o"}]}},), {}),
|
||||
("t_layout", ({},), {}),
|
||||
# ── _obligations_projection: synthetic hash-free fixtures (empty,
|
||||
# pattern-only, layout-only — the contract/structural id branches
|
||||
# carry process-randomized hash → hash battery) ──
|
||||
("_obligations_projection", ({},), {}),
|
||||
("_obligations_projection",
|
||||
({"ext": {"decision_trace": {"obligations": {"pattern": [
|
||||
{"id": "pat-1", "pattern": "seed_loop", "revision": 3,
|
||||
"obligation": "keep the seed loop closed", "verdict": "SATISFIED",
|
||||
"reason": "evidence row 1", "pattern_applicability": "always"}]}}}},),
|
||||
{}),
|
||||
("_obligations_projection",
|
||||
({"ext": {"decision_trace": {"layout_obligations": [
|
||||
{"component": "ui:header", "obligation": "stay in region top",
|
||||
"verification": "adapter observation"}]}}},), {}),
|
||||
# ── _obligation_scope_files: passthrough stub ──
|
||||
("_obligation_scope_files", ([{"id": "x"}],), {}),
|
||||
("_obligation_scope_files", ([],), {}),
|
||||
# ── _authorities: external mode, rune-internal w/ + w/o spine ──
|
||||
("_authorities", (rig.build_doc(),), {}),
|
||||
("_authorities", (rig.build_doc(), {"schema_version": 1,
|
||||
"entities": []}),
|
||||
{"mode": "rune_internal"}),
|
||||
("_authorities", (rig.build_doc(), None), {"mode": "rune_internal"}),
|
||||
# ── _record_session: append + long-detail truncation ──
|
||||
("_record_session", (rig.build_doc(), "submit_need", "short detail"), {}),
|
||||
("_record_session", (rig.build_doc(), "close", "d" * 500), {}),
|
||||
# ── classify: envelope assembly over classifier results ──
|
||||
("classify", ({"mode": "UNKNOWN", "evidence": ["probe: which surface?"],
|
||||
"probe_questions": ["q1"]},), {}),
|
||||
("classify", ({"mode": "EXISTING_PROJECT_CHANGE", "evidence": ["e1"],
|
||||
"probe_questions": []},), {}),
|
||||
("classify", ({"mode": "LOCAL_CHANGE"},),
|
||||
{"builder": "other-builder"}),
|
||||
# ── construction_context: none active, explicit unknown id (the
|
||||
# ACTIVE projection carries obligation ids → hash battery) ──
|
||||
("construction_context", ("cc-none", rig.build_doc()), {}),
|
||||
("construction_context", ("cc-unknown", DOC_SUBMITTED, "NOPE"), {}),
|
||||
# ── capabilities: the full discovery envelope, both modes ──
|
||||
("capabilities", (), {"mode": "external_project"}),
|
||||
("capabilities", (), {"mode": "rune_internal",
|
||||
"project": "issue161-harness"}),
|
||||
# ── submit_need: happy, empty objective, MATERIAL_GAP, approval,
|
||||
# no-generate, custom contract id, task_ref ──
|
||||
("submit_need", ("sn-ok", rig.build_doc(), "persistent project export"), {}),
|
||||
("submit_need", ("sn-empty", rig.build_doc(), ""), {}),
|
||||
("submit_need", ("sn-gap", rig.build_doc(),
|
||||
"change the exporter widget colors"),
|
||||
{"affected_surface": ["capability:exporter"], "constraints": {},
|
||||
"evidence_refs": ["x"]}),
|
||||
("submit_need", ("sn-appr", rig.build_doc(),
|
||||
"start a brand new repository for billing"),
|
||||
{"constraints": {"new_repository": True}, "evidence_refs": ["x"]}),
|
||||
("submit_need", ("sn-nogen", rig.build_doc(), "persistent project export"),
|
||||
{"generate": False}),
|
||||
("submit_need", ("sn-cid", rig.build_doc(), "persistent project export"),
|
||||
{"contract_id": "MY-CID"}),
|
||||
("submit_need", ("sn-task", rig.build_doc(), "persistent project export"),
|
||||
{"task_ref": "task-1"}),
|
||||
# ── inspect_decision: ok + unknown ──
|
||||
("inspect_decision", ("in-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
("inspect_decision", ("in-no", DOC_SUBMITTED, "NOPE"), {}),
|
||||
# ── get_scope: ok + unknown ──
|
||||
("get_scope", ("gs-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
("get_scope", ("gs-no", DOC_SUBMITTED, "NOPE"), {}),
|
||||
# ── get_obligations: unknown (ok carries hash ids → hash battery) ──
|
||||
("get_obligations", ("go-no", DOC_SUBMITTED, "NOPE"), {}),
|
||||
# ── report_observation: ok, bare-dict, missing entity, unknown ──
|
||||
("report_observation", ("ro-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED),
|
||||
[{"entity": "contract:csv_export",
|
||||
"detail": "observed while building"}]), {}),
|
||||
("report_observation", ("ro-bare", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED),
|
||||
{"entity": "x"}), {}),
|
||||
("report_observation", ("ro-noent", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED),
|
||||
[{"detail": "x"}]), {}),
|
||||
("report_observation", ("ro-no", DOC_SUBMITTED, "NOPE",
|
||||
[{"entity": "x"}]), {}),
|
||||
# ── verify: unknown, scope unknown/green/red, layout PASS/FAIL/UNKNOWN,
|
||||
# walked-contract contract-quality projection ──
|
||||
("verify", ("vf-no", DOC_SUBMITTED, "NOPE"), {}),
|
||||
("verify", ("vf-base", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
("verify", ("vf-green", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"changed_files": ["src/allowed.py"]}),
|
||||
("verify", ("vf-red", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"changed_files": ["src/evil.py"]}),
|
||||
("verify", ("vf-pass", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"layout_observations": {"components": []}}),
|
||||
("verify", ("vf-fail", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"layout_observations": {"header": {"region": "bottom"}}}),
|
||||
("verify", ("vf-unk", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"layout_observations": {"header": {"region": "top"}}}),
|
||||
# ── transition: happy edge, illegal edge, unknown, guard block/pass ──
|
||||
("transition", ("tr-appr", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), "approved"), {}),
|
||||
("transition", ("tr-ill", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), "closed"), {}),
|
||||
("transition", ("tr-no", DOC_SUBMITTED, "NOPE", "approved"), {}),
|
||||
("transition", ("tr-block", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), "approved"),
|
||||
{"guard_checks": GUARD_FAIL}),
|
||||
("transition", ("tr-pass", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), "approved"),
|
||||
{"guard_checks": GUARD_PASS}),
|
||||
("transition", ("tr-assert", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), "approved"),
|
||||
{"guard_checks": GUARD_ASSERT}),
|
||||
# ── close: full ladder doc, unknown, custom scope files ──
|
||||
("close", ("cl-ok", DOC_WALKED, rig._submitted_cid(DOC_WALKED),
|
||||
[{"kind": "port_evidence", "detail": "gap closed"}]), {}),
|
||||
("close", ("cl-scope", DOC_WALKED, rig._submitted_cid(DOC_WALKED),
|
||||
[{"kind": "port_evidence", "detail": "gap closed"}]),
|
||||
{"scope_files": ["src/export.py"]}),
|
||||
("close", ("cl-no", DOC_WALKED, "NOPE", [{"entity": "x"}]), {}),
|
||||
# ── _programme_continuation: bound, unbound stage, no programme dir ──
|
||||
("_programme_continuation",
|
||||
("pc-hit", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)),
|
||||
{"programmes": PROGRAMMES_BOUND}),
|
||||
("_programme_continuation",
|
||||
("pc-miss", DOC_SUBMITTED, "other-stage"),
|
||||
{"programmes": PROGRAMMES_BOUND}),
|
||||
("_programme_continuation",
|
||||
("pc-none", DOC_SUBMITTED, rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
# ── _auto_material_change: hit, miss, no ledger ──
|
||||
("_auto_material_change",
|
||||
("mc-hit", DOC_SUBMITTED, ["src/export.py"]),
|
||||
{"capabilities": DOC_WITH_LEDGER_CAPS}),
|
||||
("_auto_material_change",
|
||||
("mc-miss", DOC_SUBMITTED, ["src/zzz.py"]),
|
||||
{"capabilities": DOC_WITH_LEDGER_CAPS}),
|
||||
("_auto_material_change",
|
||||
("mc-nol", DOC_SUBMITTED, ["src/export.py"]), {}),
|
||||
# ── discover_active_contract: seeded store, empty store ──
|
||||
("discover_active_contract", ("dc-seed",
|
||||
[{"project": "alpha", "doc": rig._discover_doc("old", "2026-10-01T00:00:00Z", "alpha")},
|
||||
{"project": None, "doc": rig._discover_doc("main-latest", "2026-10-03T00:00:00Z", "gamma")}]),
|
||||
{}),
|
||||
("discover_active_contract", ("dc-empty", []), {}),
|
||||
# ── resume: unknown (ok carries hash ids → hash battery) ──
|
||||
("resume", ("rs-no", DOC_SUBMITTED, "NOPE"), {}),
|
||||
# ── amend_scope: ok, non-user, unknown ──
|
||||
("amend_scope", ("am-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), ["src/a.py"]),
|
||||
{"reason": "user asked"}),
|
||||
("amend_scope", ("am-nouser", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED), ["src/a.py"]),
|
||||
{"reason": "x", "authority": "builder"}),
|
||||
("amend_scope", ("am-no", DOC_SUBMITTED, "NOPE", ["a"]),
|
||||
{"reason": "x"}),
|
||||
# ── main: every CLI command ──
|
||||
("main", ("m-help",), {"argv": ["--help"]}),
|
||||
("main", ("m-unk",), {"argv": ["frobnicate"]}),
|
||||
("main", ("m-caps",), {"argv": ["capabilities"]}),
|
||||
("main", ("m-cls",), {"argv": ["classify",
|
||||
'{"objective": "fix typo"}']}),
|
||||
("main", ("m-ctx",), {"argv": ["context"]}),
|
||||
("main", ("m-sub",), {"argv": ["submit-need",
|
||||
'{"objective": "x"}']}),
|
||||
("main", ("m-dec",), {"argv": ["decision", "NOPE"]}),
|
||||
("main", ("m-scope",), {"argv": ["scope", "NOPE"]}),
|
||||
("main", ("m-obl",), {"argv": ["obligations", "NOPE"]}),
|
||||
("main", ("m-obs",), {"argv": ["observe", "NOPE", "[]"]}),
|
||||
("main", ("m-ver",), {"argv": ["verify", "NOPE"]}),
|
||||
("main", ("m-tr",), {"argv": ["transition", "NOPE", "approved"]}),
|
||||
("main", ("m-close",), {"argv": ["close", "NOPE", "[]"]}),
|
||||
("main", ("m-res",), {"argv": ["resume", "NOPE"]}),
|
||||
# ── the FULL ladder in ONE process (shared-store clobber law) ──
|
||||
("ladder_walk", ("walk1",), {}),
|
||||
("ladder_walk", ("walk2", "start a brand new repository for billing"), {}),
|
||||
]
|
||||
|
||||
truth = freeze("rune.construction_interface", cases,
|
||||
oracle_module="rune.construction_interface")
|
||||
write(truth, REPO / "src" / "rust" / "construction_interface"
|
||||
/ "frozen_ci_truth.json")
|
||||
print(f"froze {len(truth)} cases")
|
||||
|
||||
# ── §2 hash battery: every envelope carrying obligation ids. Captured +
|
||||
# verified with PYTHONHASHSEED=0 (set at INTERPRETER start — the seed
|
||||
# cannot be changed mid-process, so the main run re-execs itself for
|
||||
# this part); the Rust battery SHAPE-pins these ids (prefix before ":",
|
||||
# stable description/kind/provenance/status) — never value-freezes the
|
||||
# randomized suffix. ──
|
||||
HASH_CASES = [
|
||||
("_obligations_projection", (rig.contract_of(DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)),), {}),
|
||||
("construction_context", ("hc-active", DOC_SUBMITTED), {}),
|
||||
("construction_context", ("hc-explicit", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
("get_obligations", ("ho-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
("resume", ("hr-ok", DOC_SUBMITTED,
|
||||
rig._submitted_cid(DOC_SUBMITTED)), {}),
|
||||
]
|
||||
|
||||
if os.environ.get("CI_GEN_HASH_ONLY") == "1":
|
||||
assert os.environ.get("PYTHONHASHSEED") == "0", \
|
||||
"hash battery requires PYTHONHASHSEED=0 at interpreter start"
|
||||
hash_truth = freeze("rune.construction_interface", HASH_CASES,
|
||||
oracle_module="rune.construction_interface")
|
||||
write(hash_truth, REPO / "src" / "rust" / "construction_interface"
|
||||
/ "frozen_ci_truth_hash.json")
|
||||
print(f"froze {len(hash_truth)} hash cases (PYTHONHASHSEED=0)")
|
||||
else:
|
||||
env = dict(os.environ, PYTHONHASHSEED="0", CI_GEN_HASH_ONLY="1",
|
||||
PYTHONPATH="scripts/ci_freeze_seams:src")
|
||||
subprocess.run([sys.executable, str(Path(__file__).resolve())],
|
||||
check=True, env=env, cwd=str(REPO))
|
||||
@@ -0,0 +1,584 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_contracts_gap_truth.py — freeze/replay parity truth for the contracts
|
||||
gap-close (dichotomy wave, #2479 tranche).
|
||||
|
||||
Freeze mode (default): exercises the LIVE Python oracle
|
||||
(src/rune/contracts.py — the 7 functions the audit names as missing:
|
||||
_ct_core, _resolve_and_project, _run_contract_python, capture_signatures,
|
||||
save_signatures, load_signatures, main, plus run_contract/run_all_contracts
|
||||
companions) and records the truth into
|
||||
src/rust/contracts/src/ct_gap_truth.json.
|
||||
|
||||
The file has two sections:
|
||||
|
||||
* ``cases`` — shared-harness schema, re-verifiable with
|
||||
``PYTHONPATH=src python3 scripts/freeze_truth.py --verify
|
||||
src/rust/contracts/src/ct_gap_truth.json --module rune.contracts``.
|
||||
Contract-taking fns cross via the harness ``recv`` form: the receiver
|
||||
spec rebuilds a live ``Contract`` (cls __new__ + attrs, no IO) and the
|
||||
fn is called as an unbound-style first argument. ``expect_type`` stays
|
||||
None because a type object is not JSON-safe — the type-check branches
|
||||
are covered by the pre-existing 58-case ``ct_truth.json`` battery,
|
||||
replayed through the new ``_run_contract_python`` Rust kernel.
|
||||
``check_signature_drift()`` reads the real signatures file (no args) so
|
||||
it stays out of the harness set (its compare kernel is already frozen
|
||||
in ct_truth.json's drift_cases).
|
||||
* ``extra`` — oracle-derived rows the harness cannot round-trip
|
||||
(``ContractResult`` dataclasses are not JSON-native; ``save/load`` touch
|
||||
the signatures file; ``main`` drives argv/stdout/exit-code):
|
||||
``result_cases`` (run_contract / _run_contract_python asdicts),
|
||||
``run_all`` (42 asdicts), ``probes`` (loader-state -> gate bool),
|
||||
``file_cases`` (per-case deterministic dirs, no paths in expectations),
|
||||
``main_cases`` (argv/stdout/exit-code). Embedded VERBATIM in the
|
||||
``gap_battery`` alongside ``cases``.
|
||||
|
||||
Replay mode (--replay): re-runs the SAME scenarios with the Rust core
|
||||
delegation ACTIVE and asserts facade-level and kernel-level parity.
|
||||
|
||||
Poisoned-truth law: freeze pins RUNE_CONTRACTS_CORE=python BEFORE any
|
||||
oracle import (the shared harness also pins it per module stem).
|
||||
Mutation law: case inputs are deep-copied BEFORE they reach the oracle.
|
||||
Deterministic-dirs law: file/main cases redirect SIGNATURES_FILE into
|
||||
/tmp/ct-gap-freeze/<case>/ (fixed names — identical at freeze, --verify
|
||||
and --replay); expectations never embed the paths.
|
||||
"""
|
||||
import copy
|
||||
import dataclasses
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from contextlib import redirect_stdout
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
TRUTH_PATH = os.path.join(REPO, "src", "rust", "contracts",
|
||||
"src", "ct_gap_truth.json")
|
||||
FREEZE_ROOT = "/tmp/ct-gap-freeze"
|
||||
REPLAY = "--replay" in sys.argv
|
||||
|
||||
sys.path.insert(0, os.path.join(REPO, "scripts"))
|
||||
sys.path.insert(0, os.path.join(REPO, "src"))
|
||||
from freeze_truth import freeze # noqa: E402
|
||||
|
||||
if not REPLAY:
|
||||
os.environ["RUNE_CONTRACTS_CORE"] = "python" # poisoned-truth law
|
||||
else:
|
||||
os.environ.pop("RUNE_CONTRACTS_CORE", None) # live-parity law
|
||||
|
||||
sys.path.insert(0, os.path.join(REPO, "src", "rune"))
|
||||
import contracts as oracle_mod # noqa: E402
|
||||
|
||||
|
||||
def contract_dict(name, module, function, args=(), kwargs=None, **kw):
|
||||
"""A JSON-safe Contract field dict (exact dataclass field set)."""
|
||||
return {
|
||||
"name": name,
|
||||
"module": module,
|
||||
"function": function,
|
||||
"args": list(args),
|
||||
"kwargs": dict(kwargs or {}),
|
||||
"expect_type": None,
|
||||
"expect_keys": kw.get("expect_keys"),
|
||||
"expect_len": kw.get("expect_len"),
|
||||
"expect_not_none": kw.get("expect_not_none", False),
|
||||
"expect_callable": kw.get("expect_callable", False),
|
||||
"skip_on_import_error": kw.get("skip_on_import_error", True),
|
||||
}
|
||||
|
||||
|
||||
def recv_case(fn, contract, args=()):
|
||||
"""Harness case in recv form: {"cls": "Contract", <field>: value}
|
||||
rebuilds a live Contract receiver; the fn is called fn(contract, *args).
|
||||
The harness records the result AND the post-call receiver attrs —
|
||||
contracts are never mutated, so attrs echo the inputs."""
|
||||
recv = {"cls": "Contract"}
|
||||
recv.update(copy.deepcopy(contract))
|
||||
return {"fn": fn, "recv": recv, "args": list(args), "kwargs": {}}
|
||||
|
||||
|
||||
def live_contract(d):
|
||||
"""Rebuild the live Contract from a JSON-safe field dict."""
|
||||
return oracle_mod.Contract(
|
||||
name=d["name"], module=d["module"], function=d["function"],
|
||||
args=tuple(d["args"]), kwargs=dict(d["kwargs"]),
|
||||
expect_type=None, expect_keys=d["expect_keys"],
|
||||
expect_len=d["expect_len"], expect_not_none=d["expect_not_none"],
|
||||
expect_callable=d["expect_callable"],
|
||||
skip_on_import_error=d["skip_on_import_error"],
|
||||
)
|
||||
|
||||
|
||||
# ── branch inventory ───────────────────────────────────────────────────────
|
||||
# _resolve_and_project + run_contract/_run_contract_python share this
|
||||
# inventory: every phase branch (found / import_error / import-crash /
|
||||
# not_found / call-crash / project-crash), the expect_callable
|
||||
# short-circuit (callable and non-callable), the plain-attribute path,
|
||||
# and each expectation branch (not-none, keys ok/missing, len
|
||||
# ok/mismatch). expect_type stays None (JSON law).
|
||||
RESOLVE_CASES = [
|
||||
("rp-found-dict", contract_dict("rp found", "ct_rig", "make_ok")),
|
||||
("rp-found-none-notnone-fail", contract_dict(
|
||||
"rp none", "ct_rig", "make_none", expect_not_none=True)),
|
||||
("rp-found-str-attr", contract_dict(
|
||||
"rp attr", "ct_rig", "ATTR_VALUE")),
|
||||
("rp-call-crash", contract_dict("rp crash", "ct_rig", "raise_on_call")),
|
||||
("rp-project-crash", contract_dict("rp proj", "ct_rig", "make_bad_len")),
|
||||
("rp-import-error", contract_dict(
|
||||
"rp import", "definitely_missing_module_xyz", "whatever")),
|
||||
("rp-import-crash", contract_dict(
|
||||
"rp badimport", "ct_rig_badimport", "whatever")),
|
||||
("rp-not-found", contract_dict(
|
||||
"rp notfound", "ct_rig", "no_such_fn_xyz")),
|
||||
("rp-expect-callable", contract_dict(
|
||||
"rp callable", "ct_rig", "make_ok", expect_callable=True)),
|
||||
("rp-expect-callable-not", contract_dict(
|
||||
"rp notcallable", "ct_rig", "ATTR_VALUE", expect_callable=True)),
|
||||
("rp-keys-ok", contract_dict(
|
||||
"rp keys", "ct_rig", "make_ok", expect_keys=["ok"])),
|
||||
("rp-keys-missing", contract_dict(
|
||||
"rp keys miss", "ct_rig", "make_ok", expect_keys=["nope"])),
|
||||
("rp-len-ok", contract_dict(
|
||||
"rp len", "ct_rig", "make_ok", expect_len=2)),
|
||||
("rp-len-mismatch", contract_dict(
|
||||
"rp len miss", "ct_rig", "make_ok", expect_len=9)),
|
||||
]
|
||||
|
||||
# _project: (contract, JSON-safe result) — every projection branch
|
||||
# (dict/empty-dict/list/str/None/int-unsized/bool). expect_type None →
|
||||
# type_ok is always null here; the True/False branches live in the
|
||||
# 58-case ct_truth.json battery.
|
||||
PROJECT_CASES = [
|
||||
("pj-dict", contract_dict("pj", "ct_rig", "make_ok"),
|
||||
{"ok": True, "n": 3}),
|
||||
("pj-empty-dict", contract_dict("pj", "ct_rig", "make_ok"), {}),
|
||||
("pj-list", contract_dict("pj", "ct_rig", "make_ok"), [1, 2, 3]),
|
||||
("pj-str", contract_dict("pj", "ct_rig", "make_ok"), "hello"),
|
||||
("pj-none", contract_dict("pj", "ct_rig", "make_ok"), None),
|
||||
("pj-int-unsized", contract_dict("pj", "ct_rig", "make_ok"), 42),
|
||||
("pj-true", contract_dict("pj", "ct_rig", "make_ok"), True),
|
||||
]
|
||||
|
||||
|
||||
def freeze_harness_cases():
|
||||
"""Cases for the shared harness (JSON-safe in/out, --verify clean)."""
|
||||
entries = [("_ct_core", [], {})]
|
||||
for _tag, c in RESOLVE_CASES:
|
||||
entries.append(recv_case("_resolve_and_project", c))
|
||||
for _tag, c, result in PROJECT_CASES:
|
||||
entries.append(recv_case("_project", c, [result]))
|
||||
entries.append(("capture_signatures", [], {}))
|
||||
return freeze("rune.contracts", entries, oracle_module="rune.contracts")
|
||||
|
||||
|
||||
def case_dir(name):
|
||||
d = os.path.join(FREEZE_ROOT, name)
|
||||
os.makedirs(d, exist_ok=True)
|
||||
return d
|
||||
|
||||
|
||||
def seed_drifted(d):
|
||||
"""Write a saved-sigs file that drifts from the live capture on
|
||||
exactly one key (the alphabetically first)."""
|
||||
cur = oracle_mod.capture_signatures()
|
||||
key = sorted(cur)[0]
|
||||
saved = {key: "(old_sig)", sorted(cur)[1]: cur[sorted(cur)[1]]}
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "sigs.json")
|
||||
with open(oracle_mod.SIGNATURES_FILE, "w") as f:
|
||||
json.dump(saved, f, indent=2)
|
||||
return key, cur[key]
|
||||
|
||||
|
||||
def freeze_extra():
|
||||
"""Oracle-derived rows the harness cannot round-trip (dataclass
|
||||
returns, file IO, argv/stdout). Per-case deterministic dirs; no paths
|
||||
in expectations."""
|
||||
extra = {}
|
||||
|
||||
# result_cases: run_contract + _run_contract_python asdicts over the
|
||||
# resolve inventory (pinned core: run_contract == oracle path), plus
|
||||
# the skip=False import-error fail branch.
|
||||
result_cases = []
|
||||
for tag, c in RESOLVE_CASES:
|
||||
for fn_name in ("run_contract", "_run_contract_python"):
|
||||
fn = getattr(oracle_mod, fn_name)
|
||||
got = fn(live_contract(copy.deepcopy(c)))
|
||||
result_cases.append({
|
||||
"name": f"{fn_name}:{tag}",
|
||||
"contract": copy.deepcopy(c),
|
||||
"fn": fn_name,
|
||||
"expected": dataclasses.asdict(copy.deepcopy(got)),
|
||||
})
|
||||
noskip = contract_dict("rp import no-skip",
|
||||
"definitely_missing_module_xyz", "whatever",
|
||||
skip_on_import_error=False)
|
||||
for fn_name in ("run_contract", "_run_contract_python"):
|
||||
fn = getattr(oracle_mod, fn_name)
|
||||
got = fn(live_contract(copy.deepcopy(noskip)))
|
||||
result_cases.append({
|
||||
"name": f"{fn_name}:rp-import-noskip-fail",
|
||||
"contract": copy.deepcopy(noskip),
|
||||
"fn": fn_name,
|
||||
"expected": dataclasses.asdict(copy.deepcopy(got)),
|
||||
})
|
||||
extra["result_cases"] = result_cases
|
||||
|
||||
# delegated_cases: the facade's DELEGATED run_contract outputs (Rust
|
||||
# kernel over the resolution). Recorded by calling the loader kernel
|
||||
# directly (the env pin only gates loader.core(), not the FFI). For
|
||||
# every resolve row the kernel verdict is frozen next to the oracle
|
||||
# verdict — one known path divergence: a result whose PROJECTION
|
||||
# raises (rp-project-crash) is a crash on the delegated path (eager
|
||||
# projection) but a PASS on the pure-Python path (lazy checks). Both
|
||||
# behaviors are oracle-shipped; the battery replays both.
|
||||
from rune import contracts_loader # noqa: E402
|
||||
delegated = []
|
||||
delegated_inventory = [(t, c) for t, c in RESOLVE_CASES] + [
|
||||
("rp-import-noskip-fail", noskip)]
|
||||
for tag, c in delegated_inventory:
|
||||
live = live_contract(copy.deepcopy(c))
|
||||
phase, err, call, proj = oracle_mod._resolve_and_project(
|
||||
copy.deepcopy(live))
|
||||
out = contracts_loader.verdict({
|
||||
"name": c["name"], "module": c["module"],
|
||||
"function": c["function"], "expect_type": None,
|
||||
"expect_keys": c["expect_keys"], "expect_len": c["expect_len"],
|
||||
"expect_not_none": c["expect_not_none"],
|
||||
"expect_callable": c["expect_callable"],
|
||||
"skip_on_import_error": c["skip_on_import_error"],
|
||||
"phase": phase, "phase_error": err, "callable": call,
|
||||
"projection": proj})
|
||||
delegated.append({
|
||||
"name": f"run_contract:{tag}",
|
||||
"contract": copy.deepcopy(c),
|
||||
"resolution": [phase, err, call, proj],
|
||||
"expected": out,
|
||||
})
|
||||
extra["delegated_cases"] = delegated
|
||||
|
||||
# run_all: the full 42-result order-preserving run, plus the
|
||||
# resolution inputs (spec fields + _resolve_and_project outcome) that
|
||||
# produced them — the battery replays run_all_contracts over these.
|
||||
# Two rows are env-pinned (sibling crates' .so build state decides
|
||||
# their error text); they are frozen as captured in this checkout.
|
||||
run_all = [
|
||||
dataclasses.asdict(copy.deepcopy(r))
|
||||
for r in oracle_mod.run_all_contracts()
|
||||
]
|
||||
run_all_inputs = []
|
||||
for c in oracle_mod.CONTRACTS:
|
||||
phase, err, call, proj = oracle_mod._resolve_and_project(c)
|
||||
run_all_inputs.append({
|
||||
"name": c.name, "module": c.module, "function": c.function,
|
||||
"expect_type": (c.expect_type.__name__
|
||||
if c.expect_type is not None else None),
|
||||
"expect_keys": c.expect_keys, "expect_len": c.expect_len,
|
||||
"expect_not_none": c.expect_not_none,
|
||||
"expect_callable": c.expect_callable,
|
||||
"skip_on_import_error": c.skip_on_import_error,
|
||||
"phase": phase, "phase_error": err, "callable": call,
|
||||
"projection": proj,
|
||||
})
|
||||
assert len(run_all) == len(run_all_inputs) == len(oracle_mod.CONTRACTS)
|
||||
extra["run_all"] = run_all
|
||||
extra["run_all_inputs"] = run_all_inputs
|
||||
|
||||
# probes: loader states -> gate bool (module objects are not
|
||||
# JSON-safe; the recorded bool is `result is not None` from live calls).
|
||||
real_loader = oracle_mod.contracts_loader
|
||||
|
||||
class _NoCore:
|
||||
def core(self):
|
||||
return None
|
||||
|
||||
class _RaisingCore:
|
||||
def core(self):
|
||||
raise RuntimeError("rig core failure")
|
||||
|
||||
class _LiveCore:
|
||||
def core(self):
|
||||
return object()
|
||||
|
||||
probes = []
|
||||
for tag, loader in (("probe:loader-none", None),
|
||||
("probe:core-none", _NoCore()),
|
||||
("probe:core-raises", _RaisingCore()),
|
||||
("probe:core-live", _LiveCore())):
|
||||
oracle_mod.contracts_loader = loader
|
||||
try:
|
||||
got = oracle_mod._ct_core()
|
||||
probes.append({"name": tag, "expected": got is not None})
|
||||
finally:
|
||||
oracle_mod.contracts_loader = real_loader
|
||||
extra["probes"] = probes
|
||||
|
||||
# file_cases: save/load through per-case dirs (SIGNATURES_FILE seam).
|
||||
real_file = oracle_mod.SIGNATURES_FILE
|
||||
file_cases = []
|
||||
sig_sets = {
|
||||
"sigset:two": {"m.f": "(x)", "n.g": "(a, b=None)"},
|
||||
"sigset:empty": {},
|
||||
"sigset:unicode": {"m.f": "(s='héllo → world')"},
|
||||
}
|
||||
try:
|
||||
for tag, sigs in sig_sets.items():
|
||||
d = case_dir(tag.replace(":", "-"))
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "sigs.json")
|
||||
if os.path.exists(oracle_mod.SIGNATURES_FILE):
|
||||
os.remove(oracle_mod.SIGNATURES_FILE)
|
||||
oracle_mod.save_signatures(copy.deepcopy(sigs))
|
||||
with open(oracle_mod.SIGNATURES_FILE) as f:
|
||||
content = f.read()
|
||||
loaded = oracle_mod.load_signatures()
|
||||
file_cases.append({"name": tag, "sigs": copy.deepcopy(sigs),
|
||||
"content": content,
|
||||
"expected": copy.deepcopy(loaded)})
|
||||
# load-missing -> {} (no file on disk).
|
||||
d = case_dir("sigset-missing")
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "absent.json")
|
||||
if os.path.exists(oracle_mod.SIGNATURES_FILE):
|
||||
os.remove(oracle_mod.SIGNATURES_FILE)
|
||||
file_cases.append({"name": "sigset:missing",
|
||||
"sigs": {},
|
||||
"content": None,
|
||||
"expected": oracle_mod.load_signatures()})
|
||||
# load-corrupt -> {} (suppressed exception branch).
|
||||
d = case_dir("sigset-corrupt")
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "corrupt.json")
|
||||
with open(oracle_mod.SIGNATURES_FILE, "w") as f:
|
||||
f.write("{not json")
|
||||
file_cases.append({"name": "sigset:corrupt",
|
||||
"sigs": {},
|
||||
"content": "{not json",
|
||||
"expected": oracle_mod.load_signatures()})
|
||||
finally:
|
||||
oracle_mod.SIGNATURES_FILE = real_file
|
||||
extra["file_cases"] = file_cases
|
||||
|
||||
# main_cases: argv dispatch (stdout captured, SystemExit caught,
|
||||
# signatures file redirected per case). Call-time prints from live
|
||||
# contract modules interleave into `test` output (deterministic in
|
||||
# this env; Python-side IO — the battery splits at the first result
|
||||
# line). The two -drift variants pre-seed a drifted saved file so the
|
||||
# drift-printing branches are frozen too.
|
||||
real_argv = sys.argv
|
||||
main_cases = []
|
||||
try:
|
||||
for tag, argv in (("main:usage", ["contracts.py"]),
|
||||
("main:test", ["contracts.py", "test"]),
|
||||
("main:signatures", ["contracts.py", "signatures"]),
|
||||
("main:drift", ["contracts.py", "drift"]),
|
||||
("main:bogus", ["contracts.py", "bogus"])):
|
||||
d = case_dir(tag.replace(":", "-"))
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "sigs.json")
|
||||
if os.path.exists(oracle_mod.SIGNATURES_FILE):
|
||||
os.remove(oracle_mod.SIGNATURES_FILE)
|
||||
sys.argv = list(argv)
|
||||
buf = io.StringIO()
|
||||
code = 0
|
||||
with redirect_stdout(buf):
|
||||
try:
|
||||
oracle_mod.main()
|
||||
except SystemExit as e:
|
||||
code = e.code if isinstance(e.code, int) else 1
|
||||
main_cases.append({"name": tag, "argv": list(argv),
|
||||
"exit_code": code,
|
||||
"expected": buf.getvalue()})
|
||||
for tag, argv in (("main:test-drift", ["contracts.py", "test"]),
|
||||
("main:drift-drift", ["contracts.py", "drift"])):
|
||||
d = case_dir(tag.replace(":", "-"))
|
||||
key, cur_sig = seed_drifted(d)
|
||||
sys.argv = list(argv)
|
||||
buf = io.StringIO()
|
||||
code = 0
|
||||
with redirect_stdout(buf):
|
||||
try:
|
||||
oracle_mod.main()
|
||||
except SystemExit as e:
|
||||
code = e.code if isinstance(e.code, int) else 1
|
||||
main_cases.append({
|
||||
"name": tag, "argv": list(argv), "exit_code": code,
|
||||
"drift_key": key, "drift_line": f"{key}: (old_sig) → {cur_sig}",
|
||||
"expected": buf.getvalue()})
|
||||
finally:
|
||||
sys.argv = real_argv
|
||||
oracle_mod.SIGNATURES_FILE = real_file
|
||||
extra["main_cases"] = main_cases
|
||||
return extra
|
||||
|
||||
|
||||
def canon(x):
|
||||
return json.dumps(x, sort_keys=True, default=str)
|
||||
|
||||
|
||||
def replay():
|
||||
"""Live parity: facade (delegation active) + kernel (loader direct)
|
||||
against the frozen file."""
|
||||
with open(TRUTH_PATH) as f:
|
||||
doc = json.load(f)
|
||||
failures = 0
|
||||
|
||||
# Warm import order (mirrors freeze: run_all ran first, so every
|
||||
# contract module is in sys.modules before main_cases capture stdout).
|
||||
oracle_mod.run_all_contracts()
|
||||
|
||||
# Facade replay A: harness-case fns through the live oracle must
|
||||
# reproduce the frozen expectations (recv rebuilt by hand — the
|
||||
# harness does this at --verify time). _ct_core is pin/env-dependent
|
||||
# (the probes section covers its branch logic).
|
||||
for c in doc["cases"]:
|
||||
if c["fn"] == "_ct_core":
|
||||
continue
|
||||
fn = getattr(oracle_mod, c["fn"])
|
||||
if "recv" in c:
|
||||
got = fn(live_contract(c["recv"]), *copy.deepcopy(c["args"]))
|
||||
want = c["expected"]["result"]
|
||||
else:
|
||||
got = fn(*copy.deepcopy(c["args"]), **copy.deepcopy(c["kwargs"]))
|
||||
want = c["expected"]
|
||||
if canon(got) != canon(want):
|
||||
failures += 1
|
||||
print(f"HARNESS DIVERGE {c['fn']} {c['recv'].get('name', c['args'])}"
|
||||
f"\n got: {canon(got)[:300]}\n want: {canon(want)[:300]}")
|
||||
|
||||
# Facade replay B: run_contract/_run_contract_python over the resolve
|
||||
# inventory must reproduce the frozen result_cases (frozen on the
|
||||
# pinned python path — run_contract rows replay with the pin set so
|
||||
# the facade takes the oracle path; the delegated path is replayed
|
||||
# kernel-side below).
|
||||
for rc in doc["extra"]["result_cases"]:
|
||||
fn = getattr(oracle_mod, rc["fn"])
|
||||
if rc["fn"] == "run_contract":
|
||||
os.environ["RUNE_CONTRACTS_CORE"] = "python"
|
||||
try:
|
||||
got = dataclasses.asdict(
|
||||
fn(live_contract(copy.deepcopy(rc["contract"]))))
|
||||
finally:
|
||||
os.environ.pop("RUNE_CONTRACTS_CORE", None)
|
||||
if canon(got) != canon(rc["expected"]):
|
||||
failures += 1
|
||||
print(f"FACADE DIVERGE {rc['name']}"
|
||||
f"\n got: {canon(got)[:300]}"
|
||||
f"\n want: {canon(rc['expected'])[:300]}")
|
||||
|
||||
# Facade replay C: save/load through the per-case dirs (recreated
|
||||
# identically) must reproduce content + loaded maps. The missing and
|
||||
# corrupt rows only exercise load (mirroring freeze).
|
||||
real_file = oracle_mod.SIGNATURES_FILE
|
||||
real_argv = sys.argv
|
||||
try:
|
||||
for fc in doc["extra"]["file_cases"]:
|
||||
d = case_dir(fc["name"].replace(":", "-"))
|
||||
path = os.path.join(d, "sigs.json")
|
||||
if fc["name"] == "sigset:missing":
|
||||
path = os.path.join(d, "absent.json")
|
||||
elif fc["name"] == "sigset:corrupt":
|
||||
path = os.path.join(d, "corrupt.json")
|
||||
oracle_mod.SIGNATURES_FILE = path
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
if fc["name"] == "sigset:corrupt":
|
||||
with open(path, "w") as f:
|
||||
f.write(fc["content"])
|
||||
elif fc["name"] != "sigset:missing":
|
||||
oracle_mod.save_signatures(copy.deepcopy(fc["sigs"]))
|
||||
with open(path) as f:
|
||||
content = f.read()
|
||||
if content != fc["content"]:
|
||||
failures += 1
|
||||
print(f"FILE DIVERGE {fc['name']} content\n"
|
||||
f" got: {content[:200]}"
|
||||
f"\n want: {fc['content'][:200]}")
|
||||
loaded = oracle_mod.load_signatures()
|
||||
if canon(loaded) != canon(fc["expected"]):
|
||||
failures += 1
|
||||
print(f"FILE DIVERGE {fc['name']} loaded")
|
||||
|
||||
# Facade replay D: argv dispatch (stdout + exit code). The -drift
|
||||
# variants re-seed the drifted saved file first (mirroring freeze).
|
||||
for mc in doc["extra"]["main_cases"]:
|
||||
d = case_dir(mc["name"].replace(":", "-"))
|
||||
oracle_mod.SIGNATURES_FILE = os.path.join(d, "sigs.json")
|
||||
if os.path.exists(oracle_mod.SIGNATURES_FILE):
|
||||
os.remove(oracle_mod.SIGNATURES_FILE)
|
||||
if mc["name"].endswith("-drift"):
|
||||
seed_drifted(d)
|
||||
sys.argv = list(mc["argv"])
|
||||
buf = io.StringIO()
|
||||
code = 0
|
||||
with redirect_stdout(buf):
|
||||
try:
|
||||
oracle_mod.main()
|
||||
except SystemExit as e:
|
||||
code = e.code if isinstance(e.code, int) else 1
|
||||
if code != mc["exit_code"] or buf.getvalue() != mc["expected"]:
|
||||
failures += 1
|
||||
print(f"MAIN DIVERGE {mc['name']} exit {code}!= {mc['exit_code']}"
|
||||
f" or stdout drift\n got: {buf.getvalue()[:200]}"
|
||||
f"\n want: {mc['expected'][:200]}")
|
||||
finally:
|
||||
oracle_mod.SIGNATURES_FILE = real_file
|
||||
sys.argv = real_argv
|
||||
|
||||
# Kernel replay: ct_verdict over the frozen resolutions must
|
||||
# reproduce the frozen delegated verdicts (the delegated path's
|
||||
# contract — including the eager-projection crash row).
|
||||
from rune import contracts_loader # noqa: E402
|
||||
if contracts_loader.core() is None:
|
||||
print("REPLAY ABORT: kernel not built")
|
||||
return 2
|
||||
checked = 0
|
||||
for dc in doc["extra"]["delegated_cases"]:
|
||||
c = dc["contract"]
|
||||
phase, err, call, proj = dc["resolution"]
|
||||
out = contracts_loader.verdict({
|
||||
"name": c["name"], "module": c["module"],
|
||||
"function": c["function"], "expect_type": None,
|
||||
"expect_keys": c["expect_keys"], "expect_len": c["expect_len"],
|
||||
"expect_not_none": c["expect_not_none"],
|
||||
"expect_callable": c["expect_callable"],
|
||||
"skip_on_import_error": c["skip_on_import_error"],
|
||||
"phase": phase, "phase_error": err, "callable": call,
|
||||
"projection": proj})
|
||||
checked += 1
|
||||
if canon(out) != canon(dc["expected"]):
|
||||
failures += 1
|
||||
print(f"KERNEL DIVERGE {dc['name']}"
|
||||
f"\n got: {canon(out)[:300]}"
|
||||
f"\n want: {canon(dc['expected'])[:300]}")
|
||||
n_results = len(doc["extra"]["result_cases"])
|
||||
n_delegated = len(doc["extra"]["delegated_cases"])
|
||||
print(f"replay: failures={failures} "
|
||||
f"(facade {n_results}, kernel {n_delegated} checked)")
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
def main():
|
||||
if REPLAY:
|
||||
return replay()
|
||||
cases = freeze_harness_cases()
|
||||
extra = freeze_extra()
|
||||
doc = {"cases": cases, "extra": extra,
|
||||
"note": "Frozen via scripts/gen_contracts_gap_truth.py against "
|
||||
"the live Python oracle (RUNE_CONTRACTS_CORE=python). "
|
||||
"cases: shared-harness schema (--verify clean, recv-form "
|
||||
"Contract receivers). extra: oracle-derived rows "
|
||||
"(dataclass/file/argv surface). Battery embeds this "
|
||||
"VERBATIM."}
|
||||
with open(TRUTH_PATH, "w") as f:
|
||||
json.dump(doc, f, indent=1)
|
||||
f.write("\n")
|
||||
total = (len(cases) + len(extra["result_cases"])
|
||||
+ len(extra["delegated_cases"]) + 1
|
||||
+ len(extra["run_all_inputs"]) + len(extra["probes"])
|
||||
+ len(extra["file_cases"]) + len(extra["main_cases"]))
|
||||
print(f"frozen {total} rows -> {os.path.relpath(TRUTH_PATH, REPO)} "
|
||||
f"({len(cases)} harness + {len(extra['result_cases'])} results + "
|
||||
f"{len(extra['delegated_cases'])} delegated + "
|
||||
f"run_all/{len(extra['run_all'])}+{len(extra['run_all_inputs'])} inputs"
|
||||
f" + {len(extra['probes'])} probes + "
|
||||
f"{len(extra['file_cases'])} file + {len(extra['main_cases'])} main)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_model_connect_truth.py — freeze the model_connect gap-close truth
|
||||
envelope via the shared freeze_truth.py harness (#2479 wave 4).
|
||||
|
||||
Covers the full ported surface, exercising every branch:
|
||||
* _clean_model_name — HF repo paths (family+size / family+version+size /
|
||||
short-part / no-match truncation) and clean names (passthrough)
|
||||
* is_moe_model — every MOE pattern family + negatives
|
||||
* route_model — exact matches per tier, unknown task type, fallback,
|
||||
empty list (null model/tier)
|
||||
* _ctx_budget — every DEFAULT_PROFILES id (incl. deterministic's 0-window
|
||||
→ 8192 floor), the cloud (non-local) tool reserve, unknown + empty ids
|
||||
* _now — the pinned-clock isoformat
|
||||
* handle_hook — constant envelope over varied events/data
|
||||
* _get_cloud_models (seeded/missing seams) — JSONC comments + trailing
|
||||
commas, ollama skip, multi-provider ordering, provider without models,
|
||||
config without provider, the PARTIAL-return mid-loop shape error, the
|
||||
naive comment-strip corrupting URLs, and the missing-file branch
|
||||
|
||||
Usage (from the repo root; the seams dir is mandatory — it pins HOME and
|
||||
binds the cloud seams):
|
||||
PYTHONPATH=scripts/mconn_freeze_seams:src python3 scripts/gen_model_connect_truth.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(os.path.abspath(__file__)).resolve().parents[1]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "scripts"))
|
||||
|
||||
FROZEN_NOW = "2026-10-14T08:00:00+00:00" # microsecond=0: isoformat == the pin
|
||||
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
|
||||
|
||||
import freeze_truth # noqa: E402
|
||||
|
||||
MODELS_ALL = [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest",
|
||||
]
|
||||
|
||||
FIXTURE_MAIN = """{
|
||||
// MiMoCode config — JSONC: comments and trailing commas allowed
|
||||
"provider": {
|
||||
"ollama": { // skipped: local models handled by list_models
|
||||
"models": {
|
||||
"qwen3:14b": {},
|
||||
},
|
||||
},
|
||||
"openai": {
|
||||
"models": {
|
||||
"gpt-5.2": {"contextLength": 400000},
|
||||
"o4-mini": "not-even-a-dict", // model_config is unused by the oracle
|
||||
},
|
||||
},
|
||||
"kimi": {
|
||||
"models": {
|
||||
"kimi-for-coding": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
"""
|
||||
|
||||
FIXTURE_ONLY_OLLAMA = """{
|
||||
"provider": {
|
||||
"ollama": {
|
||||
"models": {"qwen2.5:3b": {}},
|
||||
},
|
||||
},
|
||||
}
|
||||
"""
|
||||
|
||||
FIXTURE_NO_MODELS_KEY = """{
|
||||
"provider": {
|
||||
"anthropic": {
|
||||
"apiKey": "sk-test",
|
||||
},
|
||||
},
|
||||
}
|
||||
"""
|
||||
|
||||
FIXTURE_NO_PROVIDER_KEY = """{
|
||||
// no providers configured
|
||||
"theme": "dark",
|
||||
}
|
||||
"""
|
||||
|
||||
FIXTURE_BROKEN_LATE = """{
|
||||
"provider": {
|
||||
"a": {"models": {"m1": {}}},
|
||||
"b": {"models": "not-a-dict"},
|
||||
},
|
||||
}
|
||||
"""
|
||||
|
||||
FIXTURE_URL_CORRUPTION = """{
|
||||
"provider": {
|
||||
"gateway": {
|
||||
"baseUrl": "http://api.example.com/v1",
|
||||
"models": {"gw-model": {}},
|
||||
},
|
||||
},
|
||||
}
|
||||
"""
|
||||
|
||||
cases = []
|
||||
# _clean_model_name
|
||||
for name in [
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"hf.co/org/Llama-3-8B-Instruct:latest",
|
||||
"hf.co/short/gemma-2-9b",
|
||||
"hf.co/user/nano-model",
|
||||
"hf.co/user/ab",
|
||||
"qwen2.5:3b",
|
||||
"mimo-v2.5-pro",
|
||||
"llava:7b",
|
||||
]:
|
||||
cases.append(("_clean_model_name", (name,), {}))
|
||||
# is_moe_model
|
||||
for name, want in [
|
||||
("mixtral:8x7b", True),
|
||||
("qwen2.5:3b", False),
|
||||
("deepseek-moe-16b", True),
|
||||
("My-Mixture-Model", True),
|
||||
("expert-v1", True),
|
||||
("4x22b-tiny", True),
|
||||
("plain-conversational", False),
|
||||
("GPT-XL", False),
|
||||
]:
|
||||
cases.append(("is_moe_model", (name,), {}))
|
||||
# route_model (available_models always explicit — the None default would
|
||||
# fall through to the networked list_models, which is reactive-side only)
|
||||
for task, models in [
|
||||
("coding", MODELS_ALL),
|
||||
("research", MODELS_ALL),
|
||||
("conversation", MODELS_ALL),
|
||||
("unknown-type", MODELS_ALL),
|
||||
("coding", ["mystery-model:x"]),
|
||||
("coding", []),
|
||||
]:
|
||||
cases.append(("route_model", (task,), {"available_models": models}))
|
||||
# _ctx_budget
|
||||
for mid in ["deterministic", "qwen2.5:3b", "qwen3:14b", "qwen3.6:27b",
|
||||
"mimo-v2.5-pro", "totally-unknown-model", ""]:
|
||||
cases.append(("_ctx_budget", (mid,), {}))
|
||||
# _now (pinned clock)
|
||||
cases.append(("_now", (), {}))
|
||||
# handle_hook
|
||||
cases.append(("handle_hook", ("pre_tool_use", {"tool": "bash", "dry": False}), {}))
|
||||
cases.append(("handle_hook", ("", None), {}))
|
||||
cases.append(("handle_hook", ("post_response", {"ok": True}), {}))
|
||||
# _get_cloud_models via the pinned-HOME seams
|
||||
for fixture in [FIXTURE_MAIN, FIXTURE_ONLY_OLLAMA, FIXTURE_NO_MODELS_KEY,
|
||||
FIXTURE_NO_PROVIDER_KEY, FIXTURE_BROKEN_LATE,
|
||||
FIXTURE_URL_CORRUPTION]:
|
||||
cases.append(("_get_cloud_models_seeded", (fixture,), {}))
|
||||
cases.append(("_get_cloud_models_missing", (), {}))
|
||||
|
||||
truth = freeze_truth.freeze("model_connect", cases, oracle_module="rune.model_connect")
|
||||
out = REPO / "src" / "go" / "model-connect" / "truth.json"
|
||||
freeze_truth.write_envelope(FROZEN_NOW, truth, out)
|
||||
print(f"wrote {len(truth)} cases -> {out}")
|
||||
|
||||
# sanity: the pinned clock must render exactly as the envelope pin
|
||||
now_row = [c for c in truth if c["fn"] == "_now"][0]
|
||||
assert now_row["expected"] == FROZEN_NOW, now_row
|
||||
print("_now pinned-clock row:", now_row["expected"])
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_witness_truth.py — shared-harness truth battery for the witness
|
||||
gap closure (#2479, contract factory-gap-wi).
|
||||
|
||||
Uses scripts/freeze_truth.py (the ONE truth law) to freeze
|
||||
src/rune/witness.py behavior for the Go port at src/go/witness:
|
||||
|
||||
* _now — pinned via the envelope frozen clock (microsecond precision).
|
||||
* is_correction — public pure-Python fn: patterns match AS-IS against
|
||||
LOWERCASED text, so capital-letter patterns (r"\\bI (said|meant|asked)\\b",
|
||||
r"\\bthat'?s? not what I\\b", ...) can never fire — the quirk is
|
||||
frozen, not fixed ("that's not what I asked for" → False).
|
||||
* extract_topic / detect_signals — frozen under the LIVE kernel (the
|
||||
pure-Python oracle retired 2026-10-10): cc_witness_extract_topic's
|
||||
ASCII \\w runs and cc_witness_signals' deterministic order
|
||||
(error → correction → completion → drift → commitment →
|
||||
contradiction → preference → urgency → learning), case-INSENSITIVE
|
||||
family matching (kernel lowercases pattern and text — richer than
|
||||
public is_correction), rune-safe [:200] error_text truncation, and
|
||||
the frozen completion triple ("done"/"abandoned"/"failed" only).
|
||||
* _tables / _stopwords — the gather seams as sorted-list data.
|
||||
* log_entry / read_log / log_stats — the log family. LOG_PATH derives
|
||||
from memory_env at import time, so RUNE_MEMORY_DIR pins it to a
|
||||
scratch dir this script WIPES first; the cases themselves build the
|
||||
log state in order (log_entry creates the file), keeping --verify
|
||||
byte-identical. skip_rate pins Python .0f half-even rounding (37.5 →
|
||||
"38%", 33.33 → "33%").
|
||||
|
||||
Verify (byte-identical law):
|
||||
rm -rf /tmp/witness_gap_freeze && \\
|
||||
RUNE_MEMORY_DIR=/tmp/witness_gap_freeze/memory PYTHONPATH=src \\
|
||||
python3 scripts/freeze_truth.py --verify src/go/witness/truth.json \\
|
||||
--module rune.witness
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
FROZEN_NOW = "2026-10-14T09:15:00.123456+00:00"
|
||||
SCRATCH = Path("/tmp/witness_gap_freeze")
|
||||
|
||||
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
|
||||
os.environ["RUNE_MEMORY_DIR"] = str(SCRATCH / "memory")
|
||||
|
||||
from freeze_truth import freeze, write_envelope # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
if SCRATCH.exists():
|
||||
shutil.rmtree(SCRATCH)
|
||||
|
||||
cases = [
|
||||
# _now — frozen clock
|
||||
("_now", (), {}),
|
||||
# is_correction — hits across the pattern families
|
||||
("is_correction", ("no, that's wrong, fix it",), {}),
|
||||
("is_correction", ("Actually, you misunderstood the requirement",), {}),
|
||||
("is_correction", ("that answer is wrong",), {}),
|
||||
("is_correction", ("incorrect output",), {}),
|
||||
("is_correction", ("not right either",), {}),
|
||||
("is_correction", ("please try again",), {}),
|
||||
("is_correction", ("nope",), {}),
|
||||
("is_correction", ("stop doing that",), {}),
|
||||
("is_correction", ("we already did the migration",), {}),
|
||||
# is_correction — misses incl. the capital-letter quirk and boundaries
|
||||
("is_correction", ("that's not what I asked for",), {}),
|
||||
("is_correction", ("I meant the left column",), {}),
|
||||
("is_correction", ("I already told you",), {}),
|
||||
("is_correction", ("wrongly spelled",), {}),
|
||||
("is_correction", ("looks good to me",), {}),
|
||||
("is_correction", ("",), {}),
|
||||
# extract_topic — kernel ASCII \w runs, stopwords, cap 5
|
||||
("extract_topic", ("the deployment runner needs repair now",), {}),
|
||||
("extract_topic", ("fix this now",), {}),
|
||||
("extract_topic", ("",), {}),
|
||||
("extract_topic", ("café résumé matters",), {}),
|
||||
("extract_topic", ("the fix_it_loop crashed again",), {}),
|
||||
("extract_topic", ("alpha beta gamma delta epsilon zeta eta theta",), {}),
|
||||
("extract_topic", ("WHY DOES THIS matter",), {}),
|
||||
# detect_signals — error family + rune-safe [:200]
|
||||
("detect_signals", ("", None, None, None), {}),
|
||||
("detect_signals", ("hello", "boom", None, None), {}),
|
||||
("detect_signals", ("hello", "é" * 250, None, None), {}),
|
||||
# completion — the frozen triple only
|
||||
("detect_signals", ("hello", None, "done", None), {}),
|
||||
("detect_signals", ("hello", None, "completed", None), {}),
|
||||
("detect_signals", ("hello", None, "abandoned", None), {}),
|
||||
("detect_signals", ("hello", None, "failed", None), {}),
|
||||
("detect_signals", ("hello", None, "running", None), {}),
|
||||
# correction family (kernel: case-insensitive, richer than public)
|
||||
("detect_signals", ("no, that's wrong, try again", None, None, None), {}),
|
||||
("detect_signals", ("i need to check that", None, None, None), {}),
|
||||
("detect_signals", ("we already did the migration", None, None, None), {}),
|
||||
("detect_signals", ("I'll send the report", None, None, None), {}),
|
||||
# topic drift — new-topics order and the overlap ratio both ways
|
||||
("detect_signals", ("anyway moving on to budgets", None, None, ["budget"]), {}),
|
||||
("detect_signals", ("the deployment runner needs repair", None, None,
|
||||
["deployment", "runner"]), {}),
|
||||
# multi-family message — kernel family order pinned
|
||||
("detect_signals", ("urgent! I prefer rust, but actually wait", None, None, None), {}),
|
||||
("detect_signals", ("why does the memory keep drifting", None, None, None), {}),
|
||||
# gather seams
|
||||
("_tables", (), {}),
|
||||
("_stopwords", (), {}),
|
||||
# log family — cases build the scratch log state IN ORDER
|
||||
("read_log", (3,), {}), # missing file → []
|
||||
("log_stats", (), {}), # missing file → 3-key zero shape
|
||||
("log_entry", ({"correction": True, "corrected_topic": ["budgets"]},
|
||||
"user corrected the budget", "sess-1"), {}),
|
||||
("log_entry", ({"urgency_detected": True}, "", "sess-2"), {}),
|
||||
("read_log", (20,), {}),
|
||||
("read_log", (1,), {}),
|
||||
("log_stats", (), {}), # total 2, wr 1 → "50%"
|
||||
("log_entry", ({"correction": True}, "r2", ""), {}),
|
||||
("log_stats", (), {}), # total 3, wr 2 → "33%"
|
||||
("read_log", (0,), {}), # deque maxlen=0 → []
|
||||
("log_entry", ({"learning_opportunity": True}, "noted", "s4"), {}),
|
||||
("log_entry", ({"completion": "done"}, "", "s5"), {}),
|
||||
("log_entry", ({"error": True}, "logged", "s6"), {}),
|
||||
("log_entry", ({"error": True}, "", "s7"), {}),
|
||||
("log_entry", ({"commitment_detected": True}, "planned", "s8"), {}),
|
||||
("log_stats", (), {}), # total 8, wr 5 → 37.5 → "38%" (half-even)
|
||||
("read_log", (99,), {}),
|
||||
]
|
||||
truth = freeze("rune.witness", cases, oracle_module="rune.witness")
|
||||
dest = REPO / "src/go/witness/truth.json"
|
||||
write_envelope(FROZEN_NOW, truth, dest)
|
||||
print(f"wrote {len(truth)} cases -> {dest}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,59 @@
|
||||
# Freeze rig for the model_connect dichotomy gap-closing (dichotomy wave
|
||||
# #2479 gap port, contract factory-gap-mconn). Auto-imported on interpreter
|
||||
# start (PYTHONPATH=scripts/mconn_freeze_seams:src) by BOTH the truth
|
||||
# generator (scripts/gen_model_connect_truth.py), the shared harness's
|
||||
# --verify mode, and the live-parity sweep, so frozen truth is
|
||||
# byte-reproducible in any process:
|
||||
#
|
||||
# * HOME is pinned to a fresh throwaway dir (freeze_rigs.pin_home) —
|
||||
# _get_cloud_models derives ~/.config/mimocode/mimocode.jsonc via
|
||||
# expanduser at call time; hermetic HOME keeps --verify off the real
|
||||
# ~/.config and makes every row deterministic.
|
||||
# * The per-case cloud-model seams (_get_cloud_models_seeded /
|
||||
# _get_cloud_models_missing) are bound onto the oracle module so the
|
||||
# shared harness's getattr(module, fn) can freeze them: seeded writes the
|
||||
# raw JSONC fixture into the pinned HOME then calls the REAL
|
||||
# _get_cloud_models; missing removes the file. The battery reproduces the
|
||||
# same rig from the case args (fixture text rides in the truth rows).
|
||||
# * The clock needs no rig here: the shared harness pins the module-global
|
||||
# datetime from the envelope's frozen_now (RUNE_FROZEN_NOW), which is the
|
||||
# only clock site in the ported surface (_now).
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
_REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.insert(0, os.path.join(_REPO, "scripts"))
|
||||
sys.path.insert(0, os.path.join(_REPO, "src"))
|
||||
|
||||
from freeze_rigs import pin_home # noqa: E402
|
||||
|
||||
pin_home("mconn")
|
||||
|
||||
import rune.model_connect as _mc # noqa: E402 (after the HOME pin)
|
||||
|
||||
|
||||
def _config_path():
|
||||
return os.path.join(os.environ["HOME"], ".config", "mimocode", "mimocode.jsonc")
|
||||
|
||||
|
||||
def _get_cloud_models_seeded(fixture):
|
||||
"""Write the raw JSONC fixture into the pinned HOME, then read it
|
||||
through the oracle's real _get_cloud_models."""
|
||||
path = _config_path()
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, "w") as f:
|
||||
f.write(fixture)
|
||||
return _mc._get_cloud_models()
|
||||
|
||||
|
||||
def _get_cloud_models_missing():
|
||||
"""Remove the config from the pinned HOME (fresh-home error branch)."""
|
||||
path = _config_path()
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
return _mc._get_cloud_models()
|
||||
|
||||
|
||||
_mc._get_cloud_models_seeded = _get_cloud_models_seeded
|
||||
_mc._get_cloud_models_missing = _get_cloud_models_missing
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Open + walk the gap-closing construction contract for contracts (Rust)
|
||||
to closed. Full lifecycle in ONE process (builder=factory-gap-ct) — close-time
|
||||
re-walk law: DRAFT → approved → building → verifying → closed."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
os.environ["CS_RUST_LIB"] = str(
|
||||
ROOT / "src" / "rust" / "capability_scoring" / "target" / "release" / "libcapability_scoring.so")
|
||||
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
from rune.construction_interface import ConstructionInterface
|
||||
|
||||
iface = ConstructionInterface(builder="factory-gap-ct")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Close the PARTIAL gaps in src/rust/contracts against the "
|
||||
"src/rune/contracts.py oracle (dichotomy wave, issue #2479 "
|
||||
"tranche): name-preserving 1:1 port of the 7 unmatched functions "
|
||||
"(_ct_core, _resolve_and_project, _run_contract_python, "
|
||||
"capture_signatures, save_signatures, load_signatures, main), "
|
||||
"IO behind injectable seams, frozen-truth battery generated against "
|
||||
"the live Python oracle via the shared harness "
|
||||
"scripts/freeze_truth.py (RUNE core pinned to python, deep-copied "
|
||||
"inputs), existing tests green + clippy clean, live parity 100% on "
|
||||
"the new functions, Phase B language-advantage pass.",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:300])
|
||||
if not r.get("success"):
|
||||
print("NEED FAILED — aborting")
|
||||
sys.exit(1)
|
||||
cid = r["ids"]["contract_id"]
|
||||
print("contract_id:", cid)
|
||||
for phase in ("approved", "building", "verifying"):
|
||||
t = iface.transition(cid, phase)
|
||||
print(f"transition->{phase}:", json.dumps(t)[:150])
|
||||
if not t.get("success"):
|
||||
sys.exit(1)
|
||||
|
||||
FEAT = os.environ.get("CT_FEAT_SHA", "66de70c7")
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": f"contracts dichotomy gap-close — {FEAT} feat(contracts): "
|
||||
"close PARTIAL gaps — dichotomy wave (rebased onto "
|
||||
"gitea/master and pushed; Phase B BTreeMap import + "
|
||||
"rustfmt folded in). Audit contracts 4/11 -> 11/11 FULL. "
|
||||
"All 7 audit-missing fns ported name-preserving into "
|
||||
"src/rust/contracts (lib.rs) with IO behind injectable "
|
||||
"seams (CoreProbe / Invoker / Signaturer / MainIO): "
|
||||
"_ct_core gate, _resolve_and_project mapping, "
|
||||
"_run_contract_python branch tree, run_all_contracts "
|
||||
"loop, capture_signatures loop, save/load_signatures "
|
||||
"byte-parity content kernels, contracts_main CLI "
|
||||
"dispatch; 8 new FFI doc-envelope kernels (ct_gate, "
|
||||
"ct_resolve, ct_run_python, ct_run_all, ct_capture, "
|
||||
"ct_save, ct_load, ct_main) wired via contracts_loader "
|
||||
"(cs_free_string, never re-exported). Frozen truth "
|
||||
"ct_gap_truth.json 127 rows (23 shared-harness cases "
|
||||
"byte-identical via freeze_truth --verify; extra: 30 "
|
||||
"result rows, 15 delegated rows, run_all 42+42, 4 "
|
||||
"probes, 5 file rows, 7 main rows) embedded VERBATIM in "
|
||||
"gap_battery.rs; battery 19/19 green (12 gap + 7 prior); "
|
||||
"live parity replay failures=0 (facade 30, kernel 15); "
|
||||
"clippy --all-targets -D warnings 0; cargo fmt clean; "
|
||||
"pytest tests/test_contracts_port.py 6/6 BOTH pins "
|
||||
"(live + RUNE_CONTRACTS_CORE=python); full-suite failure "
|
||||
"set byte-identical to base (118 pre-existing, none "
|
||||
"new). One documented eager/lazy divergence "
|
||||
"(projection-crash row): crash delegated vs PASS lazy "
|
||||
"oracle — pinned both ways. Evidence: verification/"
|
||||
"ct-gap-*.log in the worktree (paths in the agent "
|
||||
"report).",
|
||||
}], scope_files=[
|
||||
"src/rune/contracts_loader.py",
|
||||
"src/rust/contracts/src/lib.rs",
|
||||
"src/rust/contracts/src/gap_battery.rs",
|
||||
"src/rust/contracts/src/ct_gap_truth.json",
|
||||
"scripts/ct_rig.py",
|
||||
"scripts/ct_rig_badimport.py",
|
||||
"scripts/gen_contracts_gap_truth.py",
|
||||
"scripts/open_contract_contracts_gap.py",
|
||||
])
|
||||
print("close:", json.dumps(c)[:300])
|
||||
if not c.get("success"):
|
||||
print("CLOSE FAILED")
|
||||
sys.exit(1)
|
||||
print("CONTRACT", cid, "CLOSED")
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Walk + close the #2479 dichotomy-wave contract for memory_selector on the
|
||||
FRESH master store (one process, per the shared-store clobber pattern)."""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rune.construction_interface import ConstructionInterface
|
||||
|
||||
PARITY_SHA = sys.argv[1] if len(sys.argv) > 1 else ""
|
||||
PHASEB_SHA = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||
if not (PARITY_SHA and PHASEB_SHA):
|
||||
sys.exit("usage: walk_close_contract_memory_selector.py <parity_sha> <phaseb_sha>")
|
||||
|
||||
iface = ConstructionInterface(builder="factory-gap-ms")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Close the PARTIAL gaps in src/rust/memory_selector against the "
|
||||
"src/rune/memory_selector.py oracle (dichotomy wave, issue #2479 "
|
||||
"tranche): the three audit-named functions (add_source registry "
|
||||
"kernel — position-preserving replace; _source_store persona-lane "
|
||||
"gate through mse_persona_wanted + merge through mse_store_project; "
|
||||
"_mse_core probe contract frozen under the RUNE_MSE_CORE=python pin), "
|
||||
"frozen-truth battery generated against the live oracle through the "
|
||||
"ms_freeze_seams rig (FTS-seeded hermetic store, byte-identical "
|
||||
"--verify), Rust battery + clippy -D warnings clean, live parity "
|
||||
"536/536 (frozen FFI rows, fuzz registry ops, dual-mode facade), "
|
||||
"Python oracle tests green under both pins, Phase B language-advantage "
|
||||
"pass.",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:200])
|
||||
if not r.get("success"):
|
||||
sys.exit(1)
|
||||
cid = r["ids"]["contract_id"]
|
||||
print("contract_id:", cid)
|
||||
|
||||
for phase in ("approved", "building", "verifying"):
|
||||
t = iface.transition(cid, phase)
|
||||
if not t.get("success"):
|
||||
print(f"transition->{phase} FAILED:", json.dumps(t)[:300])
|
||||
sys.exit(1)
|
||||
print(f"transition->{phase}: ok")
|
||||
print("walked to verifying")
|
||||
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": (
|
||||
f"memory_selector RUST dichotomy gap-close — parity commit {PARITY_SHA}, "
|
||||
f"Phase B commit {PHASEB_SHA}; dichotomy audit fn coverage 11/14 PARTIAL "
|
||||
"-> 14/14 FULL (missing list emptied); 10-row frozen gap truth "
|
||||
"(scripts/gen_memory_selector_truth.py under scripts/ms_freeze_seams — "
|
||||
"byte-identical across generation and --verify runs), Rust battery 9/9 "
|
||||
"with the gap truth embedded via include_str!, live parity 536/536 "
|
||||
"(frozen FFI replay + 522 fuzz registry ops vs the oracle dict + "
|
||||
"dual-mode facade on RUNE_MSE_CORE=python vs live core), cargo clippy "
|
||||
"--all-targets -D warnings 0, Python tests both pins (test_p1_03 66 "
|
||||
"passed + 2 pre-existing worktree-only cached_recall failures verified "
|
||||
"identical on the stashed base; test_context_broker 18/18 both pins)."
|
||||
),
|
||||
}], scope_files=[
|
||||
"src/rune/memory_selector.py",
|
||||
"src/rune/mse_loader.py",
|
||||
"src/rust/memory_selector/src/lib.rs",
|
||||
"src/rust/memory_selector/src/branch_battery.rs",
|
||||
"src/rust/memory_selector/frozen_truth.json",
|
||||
"scripts/gen_memory_selector_truth.py",
|
||||
"scripts/ms_freeze_seams/sitecustomize.py",
|
||||
"scripts/check_memory_selector_parity.py",
|
||||
])
|
||||
print("close:", json.dumps(c)[:300])
|
||||
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Open AND close the #2479 dichotomy-wave construction contract for
|
||||
construction_interface (Rust gap-close) — the FULL lifecycle walk in ONE
|
||||
process (shared-store clobber hazard; transitions can take ~60s each)."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
os.environ["CS_RUST_LIB"] = (
|
||||
"/mnt/workdrive/rune/src/rust/capability_scoring/target/release/"
|
||||
"libcapability_scoring.so")
|
||||
|
||||
from rune.construction_interface import ConstructionInterface # noqa: E402
|
||||
|
||||
iface = ConstructionInterface(builder="factory-gap-ci")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Close the PARTIAL gaps in src/rust/construction_interface against "
|
||||
"the src/rune/construction_interface.py oracle (dichotomy wave, issue "
|
||||
"#2479 tranche): name-preserving 1:1 Rust kernels for the 2 unmatched "
|
||||
"functions (main — the JSON CLI transport dispatch + exit law, and "
|
||||
"_programme_continuation — programme ladder completion with the "
|
||||
"continuation canary) plus the doc-in/doc-out halves the frozen truth "
|
||||
"battery replays (submit_need, verify, transition, close, "
|
||||
"_auto_material_change, ladder_walk over the construction_decision / "
|
||||
"capability_ledger / layout_contract kernels), frozen-truth corpora "
|
||||
"generated against the live Python oracle through the "
|
||||
"scripts/ci_freeze_seams rig (pinned floors, frozen clock, "
|
||||
"deterministic mint, hermetic per-case stores; 85 verbatim + 5 "
|
||||
"hash-shape cases), battery 25/25, clippy -D warnings 0, live parity "
|
||||
"100% (FFI replay + byte-identical fresh re-freeze), pytest 37/37 "
|
||||
"both pins.",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:300])
|
||||
if not r.get("success"):
|
||||
print("NEED FAILED — aborting")
|
||||
sys.exit(1)
|
||||
cid = r["ids"]["contract_id"]
|
||||
print("contract_id:", cid)
|
||||
|
||||
for phase in ("approved", "building", "verifying"):
|
||||
t = iface.transition(cid, phase)
|
||||
print(f"transition->{phase}:", json.dumps(t)[:220])
|
||||
if not t.get("success"):
|
||||
sys.exit(1)
|
||||
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": "construction_interface dichotomy completion — parity "
|
||||
"4706c735 feat(construction_interface): close PARTIAL gaps "
|
||||
"— dichotomy wave; Phase B 65db257e refactor("
|
||||
"construction_interface): Phase B language-advantage pass — "
|
||||
"dichotomy wave; both pushed gitea/master. Rust kernels at "
|
||||
"src/rust/construction_interface close the audit gaps "
|
||||
"name-preserving (main, _programme_continuation) plus the "
|
||||
"doc-carrying stateful surface (submit_need/verify/"
|
||||
"transition/close/_auto_material_change/ladder_walk over "
|
||||
"the construction_decision, capability_ledger, "
|
||||
"layout_contract kernels). Freeze rig scripts/"
|
||||
"ci_freeze_seams + generator: 85-case frozen truth + 5-case "
|
||||
"hash battery regenerate byte-identical (PYTHONHASHSEED=0 "
|
||||
"shape law). Battery 25/25 replay VERBATIM via kernel::"
|
||||
"dispatch; parity scripts/check_construction_interface_"
|
||||
"parity.py FROZEN 85/85 + 5 through the ci_replay ctypes "
|
||||
"FFI + LIVE fresh re-freeze byte-identical; clippy "
|
||||
"--all-targets -D warnings 0; pytest 37/37 both pins "
|
||||
"(floors pinned python + live cores). Audit 25/27 → 27/27 "
|
||||
"FULL.",
|
||||
}], scope_files=[
|
||||
"src/rust/construction_interface/src/kernel.rs",
|
||||
"src/rust/construction_interface/src/projection.rs",
|
||||
"src/rust/construction_interface/src/lib.rs",
|
||||
"src/rust/construction_interface/src/frozen_battery.rs",
|
||||
"src/rust/construction_interface/frozen_ci_truth.json",
|
||||
"src/rust/construction_interface/frozen_ci_truth_hash.json",
|
||||
"src/rust/construction_interface/Cargo.toml",
|
||||
"scripts/ci_freeze_seams/sitecustomize.py",
|
||||
"scripts/gen_construction_interface_truth.py",
|
||||
"scripts/check_construction_interface_parity.py",
|
||||
])
|
||||
print("close:", json.dumps(c)[:400])
|
||||
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
|
||||
sys.exit(0 if c.get("success") else 1)
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Open + walk the gap-closing construction contract for identity_anchors to
|
||||
verifying. Full lifecycle open in ONE process (builder=factory-gap-ia)."""
|
||||
closed. Full lifecycle in ONE process (builder=factory-gap-ia) — close-time
|
||||
re-walk law: DRAFT → approved → building → verifying → closed."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@@ -17,28 +18,29 @@ from rune.construction_interface import ConstructionInterface
|
||||
iface = ConstructionInterface(builder="factory-gap-ia")
|
||||
|
||||
r = iface.submit_need(
|
||||
"Close the identity_anchors dichotomy-port PARTIAL gaps (#2479 wave, "
|
||||
"target >=13/16 fns, ideally 16/16): port the 6 audit-named missing "
|
||||
"functions (show_anchors, show_rules, show_pronouns, "
|
||||
"_announcement_patterns, _pronoun_patterns, _hedge_patterns) plus the "
|
||||
"4 audit-missed stragglers (_sycophancy_patterns, _py_check_drift, "
|
||||
"_cc_core, _py_get_identity_prompt) from the Python oracle "
|
||||
"src/rune/identity_anchors.py into the existing cognition_core Rust "
|
||||
"kernels (src/rust/cognition_core/src/broker.rs — extend, no new "
|
||||
"crate) name-preserving, logic 1:1; behavior lattices (announcement, "
|
||||
"pronoun, hedge, sycophancy, performative) are the core port surface; "
|
||||
"the print/show surface renders behind injectable seams; "
|
||||
"doc-envelope FFI ia_* family (freeing via capability_scoring's "
|
||||
"cs_free_string, never re-exported) + ia_loader.py mirroring "
|
||||
"broker_loader.py + facade delegation with the "
|
||||
"RUNE_IDENTITY_ANCHORS_CORE=python pin (existing RUNE_COGNITION_CORE "
|
||||
"delegation of check_drift/get_identity_prompt stays untouched). "
|
||||
"Freeze shared-harness truth (scripts/freeze_truth.py, "
|
||||
"RUNE_COGNITION_CORE=python pinned via freeze rig, show_* stdout "
|
||||
"captured by the rig wrappers, no absolute paths in truth) embedded "
|
||||
"VERBATIM in the Rust battery; all existing tests green; clippy "
|
||||
"--all-targets -D warnings 0; crate builds; live parity 100% on the "
|
||||
"new fns; Python both-pins green; Phase B language-advantage pass.",
|
||||
"Close the identity_anchors dichotomy-port PARTIAL gaps (#2479 wave): "
|
||||
"port the 8 audit-missing functions (show_anchors, show_rules, "
|
||||
"show_pronouns, _announcement_patterns, _pronoun_patterns, "
|
||||
"_hedge_patterns, _sycophancy_patterns, _cc_core) from the Python "
|
||||
"oracle src/rune/identity_anchors.py into the existing cognition_core "
|
||||
"Rust kernels (src/rust/cognition_core/src/broker.rs — extended, no "
|
||||
"new crate) name-preserving, logic 1:1: the behavior lattices are the "
|
||||
"core port surface (embedded JSON snapshots generated from the frozen "
|
||||
"truth, replay-verified); the show surface renders behind the "
|
||||
"data-injection seam (table as argument, Python data stays the "
|
||||
"runtime authority); _pattern_triples is the real 35-row authority; "
|
||||
"check_genuineness matches over the embedded performative lattice; "
|
||||
"_cc_core is the pin-decision mirror; identity_handle_hook carries the "
|
||||
"'default' envelope. doc-envelope FFI cc_* family via cc_loader "
|
||||
"(freeing via cc_free_string, never re-exported) + facade delegation "
|
||||
"pinned by the existing RUNE_COGNITION_CORE gate. Freeze shared-"
|
||||
"harness truth (scripts/freeze_truth.py, RUNE_COGNITION_CORE=python "
|
||||
"pinned via the ia_freeze_seams rig, show_* stdout captured by the "
|
||||
"rig wrappers, no absolute paths in truth) embedded VERBATIM in the "
|
||||
"Rust battery; clippy --all-targets -D warnings 0; crate builds; live "
|
||||
"parity 100% on the new fns both pins; Python suite both pins green; "
|
||||
"Phase B language-advantage pass (OnceLock lattice caches, prefixed() "
|
||||
"combinator, fmt::Write renderers).",
|
||||
origin="builder",
|
||||
)
|
||||
print("submit_need:", json.dumps(r)[:300])
|
||||
@@ -52,4 +54,31 @@ for phase in ("approved", "building", "verifying"):
|
||||
print(f"transition->{phase}:", json.dumps(t)[:150])
|
||||
if not t.get("success"):
|
||||
sys.exit(1)
|
||||
print("CONTRACT", cid, "verifying")
|
||||
|
||||
FEAT, PHASE_B = "83dc06de", "5cc5440f"
|
||||
c = iface.close(cid, observed_evidence=[{
|
||||
"kind": "port_evidence",
|
||||
"detail": f"identity_anchors dichotomy gap-close — {FEAT} feat("
|
||||
"identity_anchors): close PARTIAL gaps — dichotomy wave + "
|
||||
f"{PHASE_B} refactor(identity_anchors): Phase B language-"
|
||||
"advantage pass (both rebased onto gitea/master and pushed). "
|
||||
"Audit identity_anchors 6/14 -> 14/14 FULL (fn-level +9). All "
|
||||
"8 audit-missing fns ported name-preserving into "
|
||||
"cognition_core broker.rs with doc-envelope FFI cc_* symbols "
|
||||
"via cc_loader (cc_free_string, never re-exported); facade "
|
||||
"delegation behind the existing RUNE_COGNITION_CORE gate. "
|
||||
"Battery identity_battery 3 tests replay the 44-case frozen "
|
||||
"truth VERBATIM (freeze_truth --verify byte-identical, "
|
||||
"ia_freeze_seams rig); live parity 88/88 both pins; cargo "
|
||||
"test 62 green (merged with the concurrent safety_override "
|
||||
"battery); clippy --all-targets -D warnings 0; pytest 48/48 "
|
||||
"both pins (tests/test_rust_core_shims.py + test_spine_"
|
||||
"language.py, sibling .so overrides). Evidence: verification/"
|
||||
"ia-gap-close-*.log + .exit in the worktree (paths in the "
|
||||
"agent report).",
|
||||
}])
|
||||
print("close:", json.dumps(c)[:300])
|
||||
if not c.get("success"):
|
||||
print("CLOSE FAILED")
|
||||
sys.exit(1)
|
||||
print("CONTRACT", cid, "CLOSED")
|
||||
+441
-61
@@ -1,22 +1,33 @@
|
||||
// Package main — model-connect: the GO port of src/rune/model_connect.py's
|
||||
// deterministic cores (batch 113 of the dichotomy tranche, #2479).
|
||||
// deterministic cores (batch 113 of the dichotomy tranche, #2479; gap-close
|
||||
// wave 4).
|
||||
//
|
||||
// Dichotomy verdict: GO (reactive/entry surface). Network I/O (list_models,
|
||||
// health_check, generate) stays on the Python reactive side — only the pure
|
||||
// transforms are ported: _clean_model_name, is_moe_model, route_model.
|
||||
// health_check, generate) stays on the Python reactive side — the ported
|
||||
// surface is the pure/config-derived transforms: _clean_model_name,
|
||||
// is_moe_model, route_model, and (gap-close) _ctx_budget, _now,
|
||||
// _get_cloud_models, handle_hook.
|
||||
//
|
||||
// Parity: truth.json (20 cases) generated oracle-first against the Python
|
||||
// module; replayed hard in CI (non-swallowable step). Parity is the floor —
|
||||
// improvements: none required; oracle verified correct on all probed edges
|
||||
// (empty-list route returns reason "no-models-available" with null model).
|
||||
// Parity: truth.json (shared freeze_truth.py envelope, pinned clock + pinned
|
||||
// HOME) generated oracle-first against the Python module via
|
||||
// scripts/gen_model_connect_truth.py; byte-verified with freeze_truth.py
|
||||
// --verify and embedded VERBATIM in truth_test.go TestFrozenTruthReplay.
|
||||
// Live parity sweep: scripts/check_model_connect_parity.py (op dispatch over
|
||||
// stdin). Known oracle quirks preserved: the JSONC // strip is naive (it
|
||||
// eats URLs), trailing commas are stripped anywhere before } or ], and a
|
||||
// mid-provider shape error returns the PARTIAL model list (the oracle's
|
||||
// try/except wraps the whole loop).
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// moePatterns mirrors MOE_MODEL_PATTERNS.
|
||||
@@ -128,74 +139,443 @@ func routeModel(taskType string, availableModels []string) routeResult {
|
||||
return routeResult{Reason: "no-models-available"}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 && os.Args[1] != "replay" {
|
||||
fmt.Fprintln(os.Stderr, "usage: model-connect [replay [truth.json]]")
|
||||
os.Exit(2)
|
||||
// ── gap-close surface (#2479 wave 4) ────────────────────────────────────────
|
||||
|
||||
// ctxProfile is the projection of model_registry's DEFAULT_PROFILES that
|
||||
// resolve_context_budget reads (the oracle's _ctx_budget imports
|
||||
// model_registry at call time; the values below are the oracle's registry).
|
||||
type ctxProfile struct {
|
||||
ID string
|
||||
ContextWindow int
|
||||
Local bool
|
||||
}
|
||||
|
||||
var ctxBudgetProfiles = []ctxProfile{
|
||||
{ID: "deterministic", ContextWindow: 0, Local: true}, // 0 → 8192 via the `or` floor
|
||||
{ID: "qwen2.5:3b", ContextWindow: 32768, Local: true},
|
||||
{ID: "qwen3:14b", ContextWindow: 32768, Local: true},
|
||||
{ID: "qwen3.6:27b", ContextWindow: 32768, Local: true},
|
||||
{ID: "mimo-v2.5-pro", ContextWindow: 128000, Local: false},
|
||||
}
|
||||
|
||||
const (
|
||||
ctxOutputReserve = 2048 // model_registry.OUTPUT_RESERVE["default"]
|
||||
ctxToolResultReserve = 1024 // model_registry.TOOL_RESULT_RESERVE
|
||||
ctxNumCtxFloor = 1024
|
||||
ctxDefaultWindow = 8192
|
||||
)
|
||||
|
||||
// CtxBudget mirrors _ctx_budget — the num_ctx projection of
|
||||
// model_registry.resolve_context_budget with the default task kind:
|
||||
// max(1024, window − output_reserve − tool_reserve), tool_reserve 0 for
|
||||
// local models.
|
||||
func CtxBudget(modelID string) int {
|
||||
window, local := ctxDefaultWindow, true
|
||||
for _, p := range ctxBudgetProfiles {
|
||||
if p.ID == modelID {
|
||||
window = p.ContextWindow
|
||||
if window == 0 {
|
||||
window = ctxDefaultWindow
|
||||
}
|
||||
local = p.Local
|
||||
break
|
||||
}
|
||||
}
|
||||
toolReserve := 0
|
||||
if !local {
|
||||
toolReserve = ctxToolResultReserve
|
||||
}
|
||||
numCtx := window - ctxOutputReserve - toolReserve
|
||||
if numCtx < ctxNumCtxFloor {
|
||||
numCtx = ctxNumCtxFloor
|
||||
}
|
||||
return numCtx
|
||||
}
|
||||
|
||||
// nowClock is the injectable clock seam behind Now — the no-clock law: the
|
||||
// battery and the live-parity sweep pin it (MCONN_CLOCK / frozen_now), the
|
||||
// unpinned default reads the wall clock like the oracle's
|
||||
// datetime.now(timezone.utc).
|
||||
var nowClock = func() string {
|
||||
if pinned := os.Getenv("MCONN_CLOCK"); pinned != "" {
|
||||
return pinned
|
||||
}
|
||||
return pyIsoformat(time.Now().UTC())
|
||||
}
|
||||
|
||||
// pyIsoformat renders t like Python datetime.isoformat(): +00:00 offset,
|
||||
// microseconds only when nonzero.
|
||||
func pyIsoformat(t time.Time) string {
|
||||
if t.Nanosecond() == 0 {
|
||||
return t.Format("2006-01-02T15:04:05+00:00")
|
||||
}
|
||||
return t.Format("2006-01-02T15:04:05.000000+00:00")
|
||||
}
|
||||
|
||||
// Now mirrors _now — datetime.now(timezone.utc).isoformat().
|
||||
func Now() string { return nowClock() }
|
||||
|
||||
// cloudModel mirrors one _get_cloud_models entry; field order matches the
|
||||
// oracle's dict insertion order (name, size_gb, family, parameters,
|
||||
// capabilities, tier, provider).
|
||||
type cloudModel struct {
|
||||
Name string `json:"name"`
|
||||
SizeGB int `json:"size_gb"`
|
||||
Family string `json:"family"`
|
||||
Parameters string `json:"parameters"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
Tier string `json:"tier"`
|
||||
Provider string `json:"provider"`
|
||||
}
|
||||
|
||||
var cloudCapabilities = []string{"complex-reasoning", "coding", "analysis"}
|
||||
|
||||
// jsonObject is an insertion-ordered JSON object (Python dict semantics —
|
||||
// provider and model iteration order is part of the oracle contract).
|
||||
type jsonObject struct {
|
||||
keys []string
|
||||
values map[string]interface{}
|
||||
}
|
||||
|
||||
func (o *jsonObject) get(key string) (interface{}, bool) {
|
||||
v, ok := o.values[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// parseOrderedValue — json.Decoder token walk preserving object key order.
|
||||
func parseOrderedValue(dec *json.Decoder) (interface{}, error) {
|
||||
tok, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseOrderedFrom(dec, tok)
|
||||
}
|
||||
|
||||
func parseOrderedFrom(dec *json.Decoder, tok json.Token) (interface{}, error) {
|
||||
delim, ok := tok.(json.Delim)
|
||||
if !ok {
|
||||
return tok, nil // nil / bool / float64 / string
|
||||
}
|
||||
switch delim {
|
||||
case '{':
|
||||
obj := &jsonObject{values: map[string]interface{}{}}
|
||||
for dec.More() {
|
||||
keyTok, err := dec.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, ok := keyTok.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("object key is not a string")
|
||||
}
|
||||
val, err := parseOrderedValue(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, dup := obj.values[key]; !dup {
|
||||
obj.keys = append(obj.keys, key)
|
||||
}
|
||||
obj.values[key] = val
|
||||
}
|
||||
if _, err := dec.Token(); err != nil { // consume '}'
|
||||
return nil, err
|
||||
}
|
||||
return obj, nil
|
||||
case '[':
|
||||
arr := []interface{}{}
|
||||
for dec.More() {
|
||||
val, err := parseOrderedValue(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr = append(arr, val)
|
||||
}
|
||||
if _, err := dec.Token(); err != nil { // consume ']'
|
||||
return nil, err
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected delimiter %v", delim)
|
||||
}
|
||||
|
||||
var (
|
||||
jsoncCommentRe = regexp.MustCompile(`(?m)//.*?$`)
|
||||
jsoncTrailingCommaRe = regexp.MustCompile(`,\s*([}\]])`)
|
||||
)
|
||||
|
||||
// stripJsonc mirrors the oracle's naive JSONC → JSON prep. The comment strip
|
||||
// is deliberately string-blind: a "//" inside a quoted URL eats the rest of
|
||||
// the line and the parse then fails — the oracle behaves identically.
|
||||
func stripJsonc(raw string) string {
|
||||
raw = jsoncCommentRe.ReplaceAllString(raw, "")
|
||||
return jsoncTrailingCommaRe.ReplaceAllString(raw, "${1}")
|
||||
}
|
||||
|
||||
// GetCloudModels mirrors _get_cloud_models — read ~/.config/mimocode/
|
||||
// mimocode.jsonc, JSONC-strip, parse, and project every non-ollama provider
|
||||
// model into the fixed cloud shape. Any error mid-loop returns the PARTIAL
|
||||
// list accumulated so far (the oracle's try/except wraps the whole loop);
|
||||
// read/parse errors return an empty list.
|
||||
func GetCloudModels() []cloudModel {
|
||||
out := []cloudModel{}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(home, ".config", "mimocode", "mimocode.jsonc"))
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
v, err := parseOrderedValue(json.NewDecoder(strings.NewReader(stripJsonc(string(raw)))))
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
cfg, ok := v.(*jsonObject)
|
||||
if !ok {
|
||||
return out // config.get on a non-dict raises in the oracle
|
||||
}
|
||||
providersV, ok := cfg.get("provider")
|
||||
if !ok || providersV == nil {
|
||||
return out
|
||||
}
|
||||
providers, ok := providersV.(*jsonObject)
|
||||
if !ok {
|
||||
return out // providers.items() raises in the oracle
|
||||
}
|
||||
for _, pname := range providers.keys {
|
||||
if pname == "ollama" {
|
||||
continue
|
||||
}
|
||||
pcfgV, ok := providers.values[pname]
|
||||
if !ok || pcfgV == nil {
|
||||
return out // provider_config.get raises in the oracle
|
||||
}
|
||||
pcfg, ok := pcfgV.(*jsonObject)
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
modelsV, present := pcfg.get("models")
|
||||
if !present {
|
||||
continue // .get("models", {}) → empty dict, nothing to add
|
||||
}
|
||||
if modelsV == nil {
|
||||
return out // None.items() raises in the oracle
|
||||
}
|
||||
models, ok := modelsV.(*jsonObject)
|
||||
if !ok {
|
||||
return out // models.items() raises in the oracle
|
||||
}
|
||||
for _, mid := range models.keys {
|
||||
out = append(out, cloudModel{
|
||||
Name: pname + "/" + mid,
|
||||
SizeGB: 0,
|
||||
Family: "cloud",
|
||||
Parameters: "cloud",
|
||||
Capabilities: cloudCapabilities,
|
||||
Tier: "cloud",
|
||||
Provider: pname,
|
||||
})
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// hookResult mirrors handle_hook's return dict (insertion order:
|
||||
// status, event, handler).
|
||||
type hookResult struct {
|
||||
Status string `json:"status"`
|
||||
Event string `json:"event"`
|
||||
Handler string `json:"handler"`
|
||||
}
|
||||
|
||||
// HandleHook mirrors handle_hook — the constant ok envelope; data is
|
||||
// accepted and ignored exactly like the oracle.
|
||||
func HandleHook(event string, data interface{}) hookResult {
|
||||
return hookResult{Status: "ok", Event: event, Handler: "model_connect"}
|
||||
}
|
||||
|
||||
// ── replay (frozen truth) + parity (stdin op) entrypoints ───────────────────
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "replay" {
|
||||
os.Exit(replayMain())
|
||||
}
|
||||
os.Exit(parityMain())
|
||||
}
|
||||
|
||||
type frozenCase struct {
|
||||
Fn string `json:"fn"`
|
||||
Args []interface{} `json:"args"`
|
||||
Kwargs map[string]interface{} `json:"kwargs"`
|
||||
Expected json.RawMessage `json:"expected"`
|
||||
}
|
||||
|
||||
// canonical — round-trip a value through JSON so both sides compare as
|
||||
// decoded data (Python None and Go nil decode to the same null).
|
||||
func canonical(v interface{}) (interface{}, error) {
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out interface{}
|
||||
if err := json.Unmarshal(raw, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func replayCase(c frozenCase, seedHome func(fixture string) string, missingHome func() string) (interface{}, error) {
|
||||
switch c.Fn {
|
||||
case "_clean_model_name":
|
||||
return cleanModelName(c.Args[0].(string)), nil
|
||||
case "is_moe_model":
|
||||
return isMoeModel(c.Args[0].(string)), nil
|
||||
case "route_model":
|
||||
var models []string
|
||||
b, _ := json.Marshal(c.Kwargs["available_models"])
|
||||
if err := json.Unmarshal(b, &models); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return routeModel(c.Args[0].(string), models), nil
|
||||
case "_ctx_budget":
|
||||
return CtxBudget(c.Args[0].(string)), nil
|
||||
case "_now":
|
||||
return Now(), nil
|
||||
case "handle_hook":
|
||||
return HandleHook(c.Args[0].(string), c.Args[1]), nil
|
||||
case "_get_cloud_models_seeded":
|
||||
return GetCloudModelsIn(seedHome(c.Args[0].(string))), nil
|
||||
case "_get_cloud_models_missing":
|
||||
return GetCloudModelsIn(missingHome()), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown frozen fn %q", c.Fn)
|
||||
}
|
||||
|
||||
// GetCloudModelsIn — GetCloudModels against an explicit HOME (the battery's
|
||||
// seeded/missing rows rebuild the oracle's pinned-HOME rig).
|
||||
func GetCloudModelsIn(home string) []cloudModel {
|
||||
t := os.Getenv("HOME")
|
||||
os.Setenv("HOME", home)
|
||||
defer os.Setenv("HOME", t)
|
||||
return GetCloudModels()
|
||||
}
|
||||
|
||||
func replayMain() int {
|
||||
path := "truth.json"
|
||||
if len(os.Args) > 2 {
|
||||
path = os.Args[2]
|
||||
}
|
||||
raw, err := os.ReadFile(path)
|
||||
fatal := func(e error) { fmt.Fprintln(os.Stderr, "FATAL:", e); os.Exit(1) }
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
fmt.Fprintln(os.Stderr, "FATAL:", err)
|
||||
return 1
|
||||
}
|
||||
var rows []struct {
|
||||
Op string `json:"op"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
Want json.RawMessage `json:"want"`
|
||||
var env struct {
|
||||
FrozenNow string `json:"frozen_now"`
|
||||
Cases []frozenCase `json:"cases"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &rows); err != nil {
|
||||
fatal(err)
|
||||
if err := json.Unmarshal(raw, &env); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "FATAL:", err)
|
||||
return 1
|
||||
}
|
||||
if len(env.Cases) == 0 {
|
||||
fmt.Fprintln(os.Stderr, "FATAL: no truth cases")
|
||||
return 1
|
||||
}
|
||||
savedClock := nowClock
|
||||
os.Setenv("MCONN_CLOCK", env.FrozenNow)
|
||||
nowClock = func() string { return env.FrozenNow }
|
||||
defer func() {
|
||||
nowClock = savedClock
|
||||
os.Unsetenv("MCONN_CLOCK")
|
||||
}()
|
||||
|
||||
seedHome := func(fixture string) string {
|
||||
home, _ := os.MkdirTemp("", "mconn-replay-")
|
||||
cfgDir := filepath.Join(home, ".config", "mimocode")
|
||||
os.MkdirAll(cfgDir, 0o755)
|
||||
os.WriteFile(filepath.Join(cfgDir, "mimocode.jsonc"), []byte(fixture), 0o644)
|
||||
return home
|
||||
}
|
||||
missingHome := func() string {
|
||||
home, _ := os.MkdirTemp("", "mconn-replay-")
|
||||
return home
|
||||
}
|
||||
|
||||
fails := 0
|
||||
for _, r := range rows {
|
||||
switch r.Op {
|
||||
case "clean":
|
||||
var in, want string
|
||||
json.Unmarshal(r.Input, &in)
|
||||
json.Unmarshal(r.Want, &want)
|
||||
if got := cleanModelName(in); got != want {
|
||||
fails++
|
||||
fmt.Printf("FAIL clean %q: got %q want %q\n", in, got, want)
|
||||
}
|
||||
case "moe":
|
||||
var in string
|
||||
var want bool
|
||||
json.Unmarshal(r.Input, &in)
|
||||
json.Unmarshal(r.Want, &want)
|
||||
if got := isMoeModel(in); got != want {
|
||||
fails++
|
||||
fmt.Printf("FAIL moe %q: got %v want %v\n", in, got, want)
|
||||
}
|
||||
case "route":
|
||||
var in struct {
|
||||
Task string `json:"task"`
|
||||
Models []string `json:"models"`
|
||||
}
|
||||
json.Unmarshal(r.Input, &in)
|
||||
wantRaw, _ := r.Want.MarshalJSON()
|
||||
var wantMap map[string]interface{}
|
||||
json.Unmarshal(wantRaw, &wantMap)
|
||||
got := routeModel(in.Task, in.Models)
|
||||
gotJSON, _ := json.Marshal(got)
|
||||
var gotMap map[string]interface{}
|
||||
json.Unmarshal(gotJSON, &gotMap)
|
||||
if fmt.Sprint(gotMap["model"]) != fmt.Sprint(wantMap["model"]) ||
|
||||
fmt.Sprint(gotMap["tier"]) != fmt.Sprint(wantMap["tier"]) ||
|
||||
gotMap["reason"] != wantMap["reason"] {
|
||||
fails++
|
||||
fmt.Printf("FAIL route %s: got %s want %s\n", in.Task, gotJSON, wantRaw)
|
||||
}
|
||||
default:
|
||||
for _, c := range env.Cases {
|
||||
actual, err := replayCase(c, seedHome, missingHome)
|
||||
if err != nil {
|
||||
fails++
|
||||
fmt.Printf("FAIL unknown op %s\n", r.Op)
|
||||
fmt.Printf("FAIL %s: %v\n", c.Fn, err)
|
||||
continue
|
||||
}
|
||||
got, err := canonical(actual)
|
||||
if err != nil {
|
||||
fails++
|
||||
fmt.Printf("FAIL %s: canonical actual: %v\n", c.Fn, err)
|
||||
continue
|
||||
}
|
||||
var want interface{}
|
||||
if err := json.Unmarshal(c.Expected, &want); err != nil {
|
||||
fails++
|
||||
fmt.Printf("FAIL %s: decode expected: %v\n", c.Fn, err)
|
||||
continue
|
||||
}
|
||||
gj, _ := json.Marshal(got)
|
||||
wj, _ := json.Marshal(want)
|
||||
if string(gj) != string(wj) {
|
||||
fails++
|
||||
fmt.Printf("FAIL %s: got %s want %s\n", c.Fn, gj, wj)
|
||||
}
|
||||
}
|
||||
fmt.Printf("model-connect parity: %d/%d passed\n", len(rows)-fails, len(rows))
|
||||
fmt.Printf("model-connect parity: %d/%d passed\n", len(env.Cases)-fails, len(env.Cases))
|
||||
if fails > 0 {
|
||||
os.Exit(1)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func parityMain() int {
|
||||
var req struct {
|
||||
Op string `json:"op"`
|
||||
Name string `json:"name"`
|
||||
Task string `json:"task"`
|
||||
Model string `json:"model"`
|
||||
Event string `json:"event"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
Models []string `json:"models"`
|
||||
}
|
||||
body, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "FATAL:", err)
|
||||
return 1
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "FATAL:", err)
|
||||
return 1
|
||||
}
|
||||
var result interface{}
|
||||
switch req.Op {
|
||||
case "clean":
|
||||
result = map[string]interface{}{"result": cleanModelName(req.Name)}
|
||||
case "moe":
|
||||
result = map[string]interface{}{"result": isMoeModel(req.Name)}
|
||||
case "route":
|
||||
result = routeModel(req.Task, req.Models)
|
||||
case "ctx_budget":
|
||||
result = map[string]interface{}{"result": CtxBudget(req.Model)}
|
||||
case "now":
|
||||
result = map[string]interface{}{"result": Now()}
|
||||
case "cloud_models":
|
||||
result = map[string]interface{}{"result": GetCloudModels()}
|
||||
case "hook":
|
||||
result = map[string]interface{}{"result": HandleHook(req.Event, req.Data)}
|
||||
default:
|
||||
fmt.Fprintln(os.Stderr, "FATAL: unknown op", req.Op)
|
||||
return 1
|
||||
}
|
||||
out, _ := json.Marshal(result)
|
||||
fmt.Println(string(out))
|
||||
return 0
|
||||
}
|
||||
+481
-194
@@ -1,194 +1,481 @@
|
||||
[
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"want": "Qwen3.6 27B"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "hf.co/org/Llama-3-8B-Instruct:latest",
|
||||
"want": "Llama 3 8B"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "hf.co/short/gemma-2-9b",
|
||||
"want": "gemma 2 9B"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "hf.co/user/nano-model",
|
||||
"want": "nano"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "hf.co/user/ab",
|
||||
"want": "ab"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "qwen2.5:3b",
|
||||
"want": "qwen2.5:3b"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "mimo-v2.5-pro",
|
||||
"want": "mimo-v2.5-pro"
|
||||
},
|
||||
{
|
||||
"op": "clean",
|
||||
"input": "llava:7b",
|
||||
"want": "llava:7b"
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "mixtral:8x7b",
|
||||
"want": true
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "qwen2.5:3b",
|
||||
"want": false
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "deepseek-moe-16b",
|
||||
"want": true
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "My-Mixture-Model",
|
||||
"want": true
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "expert-v1",
|
||||
"want": true
|
||||
},
|
||||
{
|
||||
"op": "moe",
|
||||
"input": "4x22b-tiny",
|
||||
"want": true
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "coding",
|
||||
"models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"model": "qwen2.5-coder:14b",
|
||||
"tier": "local-coder",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "research",
|
||||
"models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"model": "qwen3:14b",
|
||||
"tier": "local-large",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "conversation",
|
||||
"models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"model": "qwen2.5:3b",
|
||||
"tier": "local-light",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "unknown-type",
|
||||
"models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"model": "qwen2.5:3b",
|
||||
"tier": "local-light",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "coding",
|
||||
"models": [
|
||||
"mystery-model:x"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"model": "mystery-model:x",
|
||||
"tier": "fallback",
|
||||
"reason": "no-exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "route",
|
||||
"input": {
|
||||
"task": "coding",
|
||||
"models": []
|
||||
},
|
||||
"want": {
|
||||
"model": null,
|
||||
"tier": null,
|
||||
"reason": "no-models-available"
|
||||
}
|
||||
}
|
||||
]
|
||||
{
|
||||
"frozen_now": "2026-10-14T08:00:00+00:00",
|
||||
"cases": [
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "Qwen3.6 27B"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"hf.co/org/Llama-3-8B-Instruct:latest"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "Llama 3 8B"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"hf.co/short/gemma-2-9b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "gemma 2 9B"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"hf.co/user/nano-model"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "nano"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"hf.co/user/ab"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "ab"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"qwen2.5:3b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "qwen2.5:3b"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"mimo-v2.5-pro"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "mimo-v2.5-pro"
|
||||
},
|
||||
{
|
||||
"fn": "_clean_model_name",
|
||||
"args": [
|
||||
"llava:7b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "llava:7b"
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"mixtral:8x7b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"qwen2.5:3b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"deepseek-moe-16b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"My-Mixture-Model"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"expert-v1"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"4x22b-tiny"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"plain-conversational"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_moe_model",
|
||||
"args": [
|
||||
"GPT-XL"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"coding"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"model": "qwen2.5-coder:14b",
|
||||
"tier": "local-coder",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"research"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"model": "qwen3:14b",
|
||||
"tier": "local-large",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"conversation"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"model": "qwen2.5:3b",
|
||||
"tier": "local-light",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"unknown-type"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": [
|
||||
"qwen2.5:3b",
|
||||
"qwen2.5:7b",
|
||||
"qwen3:14b",
|
||||
"qwen2.5-coder:14b",
|
||||
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF:IQ2_M",
|
||||
"mixtral:8x7b-instruct-v0.1-q4_0",
|
||||
"qwen2.5vl:3b",
|
||||
"llava:7b",
|
||||
"qwen3-embedding:0.6b",
|
||||
"nomic-embed-text:latest",
|
||||
"mxbai-embed-large:latest"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"model": "qwen2.5:3b",
|
||||
"tier": "local-light",
|
||||
"reason": "exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"coding"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": [
|
||||
"mystery-model:x"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"model": "mystery-model:x",
|
||||
"tier": "fallback",
|
||||
"reason": "no-exact-match"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "route_model",
|
||||
"args": [
|
||||
"coding"
|
||||
],
|
||||
"kwargs": {
|
||||
"available_models": []
|
||||
},
|
||||
"expected": {
|
||||
"model": null,
|
||||
"tier": null,
|
||||
"reason": "no-models-available"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"deterministic"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 6144
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"qwen2.5:3b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 30720
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"qwen3:14b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 30720
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"qwen3.6:27b"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 30720
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"mimo-v2.5-pro"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 124928
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
"totally-unknown-model"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 6144
|
||||
},
|
||||
{
|
||||
"fn": "_ctx_budget",
|
||||
"args": [
|
||||
""
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": 6144
|
||||
},
|
||||
{
|
||||
"fn": "_now",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": "2026-10-14T08:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"fn": "handle_hook",
|
||||
"args": [
|
||||
"pre_tool_use",
|
||||
{
|
||||
"tool": "bash",
|
||||
"dry": false
|
||||
}
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"status": "ok",
|
||||
"event": "pre_tool_use",
|
||||
"handler": "model_connect"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "handle_hook",
|
||||
"args": [
|
||||
"",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"status": "ok",
|
||||
"event": "",
|
||||
"handler": "model_connect"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "handle_hook",
|
||||
"args": [
|
||||
"post_response",
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"status": "ok",
|
||||
"event": "post_response",
|
||||
"handler": "model_connect"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n // MiMoCode config — JSONC: comments and trailing commas allowed\n \"provider\": {\n \"ollama\": { // skipped: local models handled by list_models\n \"models\": {\n \"qwen3:14b\": {},\n },\n },\n \"openai\": {\n \"models\": {\n \"gpt-5.2\": {\"contextLength\": 400000},\n \"o4-mini\": \"not-even-a-dict\", // model_config is unused by the oracle\n },\n },\n \"kimi\": {\n \"models\": {\n \"kimi-for-coding\": {},\n },\n },\n },\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"name": "openai/gpt-5.2",
|
||||
"size_gb": 0,
|
||||
"family": "cloud",
|
||||
"parameters": "cloud",
|
||||
"capabilities": [
|
||||
"complex-reasoning",
|
||||
"coding",
|
||||
"analysis"
|
||||
],
|
||||
"tier": "cloud",
|
||||
"provider": "openai"
|
||||
},
|
||||
{
|
||||
"name": "openai/o4-mini",
|
||||
"size_gb": 0,
|
||||
"family": "cloud",
|
||||
"parameters": "cloud",
|
||||
"capabilities": [
|
||||
"complex-reasoning",
|
||||
"coding",
|
||||
"analysis"
|
||||
],
|
||||
"tier": "cloud",
|
||||
"provider": "openai"
|
||||
},
|
||||
{
|
||||
"name": "kimi/kimi-for-coding",
|
||||
"size_gb": 0,
|
||||
"family": "cloud",
|
||||
"parameters": "cloud",
|
||||
"capabilities": [
|
||||
"complex-reasoning",
|
||||
"coding",
|
||||
"analysis"
|
||||
],
|
||||
"tier": "cloud",
|
||||
"provider": "kimi"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n \"provider\": {\n \"ollama\": {\n \"models\": {\"qwen2.5:3b\": {}},\n },\n },\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n \"provider\": {\n \"anthropic\": {\n \"apiKey\": \"sk-test\",\n },\n },\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n // no providers configured\n \"theme\": \"dark\",\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n \"provider\": {\n \"a\": {\"models\": {\"m1\": {}}},\n \"b\": {\"models\": \"not-a-dict\"},\n },\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"name": "a/m1",
|
||||
"size_gb": 0,
|
||||
"family": "cloud",
|
||||
"parameters": "cloud",
|
||||
"capabilities": [
|
||||
"complex-reasoning",
|
||||
"coding",
|
||||
"analysis"
|
||||
],
|
||||
"tier": "cloud",
|
||||
"provider": "a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_seeded",
|
||||
"args": [
|
||||
"{\n \"provider\": {\n \"gateway\": {\n \"baseUrl\": \"http://api.example.com/v1\",\n \"models\": {\"gw-model\": {}},\n },\n },\n}\n"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_get_cloud_models_missing",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
// truth_test.go — the parity gate. Replays every case from truth.json (the
|
||||
// shared freeze_truth.py envelope: pinned clock + pinned HOME + Python
|
||||
// oracle cases WITH inputs, generated by scripts/gen_model_connect_truth.py
|
||||
// against the live oracle under scripts/mconn_freeze_seams) VERBATIM through
|
||||
// the ported Go functions. A divergence fails the port, not the oracle.
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//go:embed truth.json
|
||||
var frozenTruthJSON string
|
||||
|
||||
// TestFrozenTruthReplay — the frozen oracle truth, verbatim, in the recorded
|
||||
// call order, against the ported functions.
|
||||
func TestFrozenTruthReplay(t *testing.T) {
|
||||
var env struct {
|
||||
FrozenNow string `json:"frozen_now"`
|
||||
Cases []frozenCase `json:"cases"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(frozenTruthJSON), &env); err != nil {
|
||||
t.Fatalf("decode truth envelope: %v", err)
|
||||
}
|
||||
if len(env.Cases) == 0 {
|
||||
t.Fatal("no truth cases — the parity gate is empty")
|
||||
}
|
||||
|
||||
savedClock := nowClock
|
||||
t.Setenv("MCONN_CLOCK", env.FrozenNow)
|
||||
nowClock = func() string { return env.FrozenNow }
|
||||
t.Cleanup(func() { nowClock = savedClock })
|
||||
|
||||
seedHome := func(fixture string) string {
|
||||
home := t.TempDir()
|
||||
cfgDir := filepath.Join(home, ".config", "mimocode")
|
||||
if err := os.MkdirAll(cfgDir, 0o755); err != nil {
|
||||
t.Fatalf("seed home: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(cfgDir, "mimocode.jsonc"), []byte(fixture), 0o644); err != nil {
|
||||
t.Fatalf("seed config: %v", err)
|
||||
}
|
||||
return home
|
||||
}
|
||||
missingHome := func() string { return t.TempDir() }
|
||||
|
||||
for i, c := range env.Cases {
|
||||
actual, err := replayCase(c, seedHome, missingHome)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d fn=%s: %v", i, c.Fn, err)
|
||||
}
|
||||
got, err := canonical(actual)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d fn=%s: canonical actual: %v", i, c.Fn, err)
|
||||
}
|
||||
var want interface{}
|
||||
if err := json.Unmarshal(c.Expected, &want); err != nil {
|
||||
t.Fatalf("case %d fn=%s: decode expected: %v", i, c.Fn, err)
|
||||
}
|
||||
gj, _ := json.Marshal(got)
|
||||
wj, _ := json.Marshal(want)
|
||||
if string(gj) != string(wj) {
|
||||
t.Errorf("case %d fn=%s: got %s want %s", i, c.Fn, gj, wj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestStripJsoncPreservesOracleQuirks — the naive JSONC strip: string-blind
|
||||
// comment removal (URLs break the parse downstream) and trailing commas.
|
||||
func TestStripJsoncPreservesOracleQuirks(t *testing.T) {
|
||||
stripped := stripJsonc("{\n // comment\n \"a\": 1, // inline\n \"b\": [1, 2,],\n}\n")
|
||||
want := "{\n \n \"a\": 1, \n \"b\": [1, 2]}\n"
|
||||
if stripped != want {
|
||||
t.Errorf("stripJsonc:\n got %q\nwant %q", stripped, want)
|
||||
}
|
||||
if _, err := parseOrderedValue(jsonDecoder("{ \"u\": \"http://x\" }")); err == nil {
|
||||
// sanity: plain JSON parses
|
||||
} else {
|
||||
t.Fatalf("plain JSON must parse: %v", err)
|
||||
}
|
||||
// the oracle quirk: a URL inside JSONC loses its closing quote
|
||||
broken := stripJsonc("{ \"u\": \"http://x\" }")
|
||||
if _, err := parseOrderedValue(jsonDecoder(broken)); err == nil {
|
||||
t.Errorf("URL-under-JSONC must fail to parse like the oracle, got %q", broken)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetCloudModelsPartialOnLateShapeError — a mid-provider shape error
|
||||
// returns the PARTIAL accumulated list (the oracle's try/except wraps the
|
||||
// whole loop), not an empty one.
|
||||
func TestGetCloudModelsPartialOnLateShapeError(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
cfgDir := filepath.Join(home, ".config", "mimocode")
|
||||
if err := os.MkdirAll(cfgDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fixture := "{\n \"provider\": {\n \"a\": {\"models\": {\"m1\": {}}},\n \"b\": {\"models\": \"not-a-dict\"}\n }\n}\n"
|
||||
if err := os.WriteFile(filepath.Join(cfgDir, "mimocode.jsonc"), []byte(fixture), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := GetCloudModelsIn(home)
|
||||
if len(got) != 1 || got[0].Name != "a/m1" {
|
||||
t.Errorf("partial cloud list: got %+v want [a/m1]", got)
|
||||
}
|
||||
}
|
||||
|
||||
func jsonDecoder(s string) *json.Decoder {
|
||||
return json.NewDecoder(strings.NewReader(s))
|
||||
}
|
||||
+833
-160
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,913 @@
|
||||
{
|
||||
"frozen_now": "2026-10-14T09:15:00.123456+00:00",
|
||||
"cases": [
|
||||
{
|
||||
"fn": "_now",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": "2026-10-14T09:15:00.123456+00:00"
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"no, that's wrong, fix it"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"Actually, you misunderstood the requirement"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"that answer is wrong"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"incorrect output"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"not right either"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"please try again"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"nope"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"stop doing that"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"we already did the migration"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"that's not what I asked for"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": true
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"I meant the left column"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"I already told you"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"wrongly spelled"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
"looks good to me"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "is_correction",
|
||||
"args": [
|
||||
""
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": false
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"the deployment runner needs repair now"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"deployment",
|
||||
"runner",
|
||||
"needs",
|
||||
"repair"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"fix this now"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
""
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"café résumé matters"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"matters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"the fix_it_loop crashed again"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"fix_it_loop",
|
||||
"crashed",
|
||||
"again"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"alpha beta gamma delta epsilon zeta eta theta"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"alpha",
|
||||
"beta",
|
||||
"gamma",
|
||||
"delta",
|
||||
"epsilon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "extract_topic",
|
||||
"args": [
|
||||
"WHY DOES THIS matter"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"matter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
"boom",
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"error": true,
|
||||
"error_text": "boom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
"éééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé",
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"error": true,
|
||||
"error_text": "éééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
null,
|
||||
"done",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"completion": "done"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
null,
|
||||
"completed",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
null,
|
||||
"abandoned",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"completion": "abandoned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
null,
|
||||
"failed",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"completion": "failed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"hello",
|
||||
null,
|
||||
"running",
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"no, that's wrong, try again",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"correction": true,
|
||||
"corrected_topic": [
|
||||
"wrong",
|
||||
"again"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"i need to check that",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"commitment_detected": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"we already did the migration",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"correction": true,
|
||||
"corrected_topic": [
|
||||
"already",
|
||||
"migration"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"I'll send the report",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"commitment_detected": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"anyway moving on to budgets",
|
||||
null,
|
||||
null,
|
||||
[
|
||||
"budget"
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"topic_drift": true,
|
||||
"new_topics": [
|
||||
"anyway",
|
||||
"moving",
|
||||
"budgets"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"the deployment runner needs repair",
|
||||
null,
|
||||
null,
|
||||
[
|
||||
"deployment",
|
||||
"runner"
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"urgent! I prefer rust, but actually wait",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"possible_contradiction": true,
|
||||
"preference_detected": true,
|
||||
"urgency_detected": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "detect_signals",
|
||||
"args": [
|
||||
"why does the memory keep drifting",
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"learning_opportunity": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "_tables",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"stopwords": [
|
||||
"a",
|
||||
"after",
|
||||
"an",
|
||||
"and",
|
||||
"are",
|
||||
"as",
|
||||
"at",
|
||||
"be",
|
||||
"been",
|
||||
"before",
|
||||
"being",
|
||||
"but",
|
||||
"by",
|
||||
"can",
|
||||
"could",
|
||||
"did",
|
||||
"do",
|
||||
"does",
|
||||
"during",
|
||||
"for",
|
||||
"from",
|
||||
"had",
|
||||
"has",
|
||||
"have",
|
||||
"how",
|
||||
"in",
|
||||
"into",
|
||||
"is",
|
||||
"it",
|
||||
"its",
|
||||
"may",
|
||||
"might",
|
||||
"no",
|
||||
"not",
|
||||
"of",
|
||||
"on",
|
||||
"or",
|
||||
"shall",
|
||||
"should",
|
||||
"that",
|
||||
"the",
|
||||
"these",
|
||||
"this",
|
||||
"those",
|
||||
"through",
|
||||
"to",
|
||||
"was",
|
||||
"were",
|
||||
"what",
|
||||
"when",
|
||||
"where",
|
||||
"which",
|
||||
"who",
|
||||
"why",
|
||||
"will",
|
||||
"with",
|
||||
"would"
|
||||
],
|
||||
"correction": [
|
||||
"\\b(don'?t|do not) (do|say|use) (that|this|it)\\b",
|
||||
"\\bI (already|already told you)\\b",
|
||||
"\\bI (don'?t|do not) (want|need|mean)\\b",
|
||||
"\\bI (said|meant|asked)\\b",
|
||||
"\\bI (told|asked|mentioned) (you|this|that)\\b",
|
||||
"\\bactually[,.]?\\s*(it'?s?|that'?s?|you)\\b",
|
||||
"\\bfix (this|that|it)\\b",
|
||||
"\\bincorrect\\b",
|
||||
"\\bno[,.]?\\s*(that'?s?|that is|it'?s?|it is)\\s+(wrong|incorrect|not right)\\b",
|
||||
"\\bnope\\b",
|
||||
"\\bnot right\\b",
|
||||
"\\bnot what I\\b",
|
||||
"\\bstop (doing|saying|that)\\b",
|
||||
"\\bthat'?s? (not|n'?t) (what|how|why)\\b",
|
||||
"\\bthat'?s? not (correct|right|what)\\b",
|
||||
"\\bthat'?s? not what I\\b",
|
||||
"\\btry again\\b",
|
||||
"\\bwe (already|already did)\\b",
|
||||
"\\bwhy (did|are|is) (you|it|that)\\b",
|
||||
"\\bwrong\\b"
|
||||
],
|
||||
"commitment": [
|
||||
"\\bI need to\\b",
|
||||
"\\bI promise\\b",
|
||||
"\\bI will\\s+(send|do|fix|build|check|update|create|write)\\b",
|
||||
"\\bI'?ll\\s+(send|do|fix|build|check|update|create|write)\\b",
|
||||
"\\blet me\\s+(send|do|fix|build|check|update|create|write)\\b",
|
||||
"\\bremind me\\b"
|
||||
],
|
||||
"contradiction": [
|
||||
"\\b(but|however|actually|wait|that contradicts)\\b"
|
||||
],
|
||||
"preference": [
|
||||
"\\b(always|never) (use|do|say)\\b",
|
||||
"\\b(don'?t|do not) (like|want|need)\\b",
|
||||
"\\bI (prefer|like|love|hate|dislike)\\b",
|
||||
"\\bI'?m (not )?(a fan of|into|interested in)\\b"
|
||||
],
|
||||
"urgency": [
|
||||
"\\b(deadline|due|overdue|late)\\b",
|
||||
"\\b(important|critical|crucial|vital)\\b",
|
||||
"\\b(urgent|asap|immediately|now|quick|hurry)\\b"
|
||||
],
|
||||
"learning": [
|
||||
"\\b(I don'?t (understand|know|get))\\b",
|
||||
"\\b(how (does|do|did)|why (does|do|did)|what (is|are|was|were))\\b",
|
||||
"\\b(learn|understand|explain|teach|show me)\\b"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "_stopwords",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
"a",
|
||||
"after",
|
||||
"an",
|
||||
"and",
|
||||
"are",
|
||||
"as",
|
||||
"at",
|
||||
"be",
|
||||
"been",
|
||||
"before",
|
||||
"being",
|
||||
"but",
|
||||
"by",
|
||||
"can",
|
||||
"could",
|
||||
"did",
|
||||
"do",
|
||||
"does",
|
||||
"during",
|
||||
"for",
|
||||
"from",
|
||||
"had",
|
||||
"has",
|
||||
"have",
|
||||
"how",
|
||||
"in",
|
||||
"into",
|
||||
"is",
|
||||
"it",
|
||||
"its",
|
||||
"may",
|
||||
"might",
|
||||
"no",
|
||||
"not",
|
||||
"of",
|
||||
"on",
|
||||
"or",
|
||||
"shall",
|
||||
"should",
|
||||
"that",
|
||||
"the",
|
||||
"these",
|
||||
"this",
|
||||
"those",
|
||||
"through",
|
||||
"to",
|
||||
"was",
|
||||
"were",
|
||||
"what",
|
||||
"when",
|
||||
"where",
|
||||
"which",
|
||||
"who",
|
||||
"why",
|
||||
"will",
|
||||
"with",
|
||||
"would"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "read_log",
|
||||
"args": [
|
||||
3
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "log_stats",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"total": 0,
|
||||
"with_reflection": 0,
|
||||
"signal_types": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"correction": true,
|
||||
"corrected_topic": [
|
||||
"budgets"
|
||||
]
|
||||
},
|
||||
"user corrected the budget",
|
||||
"sess-1"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"urgency_detected": true
|
||||
},
|
||||
"",
|
||||
"sess-2"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "read_log",
|
||||
"args": [
|
||||
20
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "sess-1",
|
||||
"signals": {
|
||||
"correction": true,
|
||||
"corrected_topic": [
|
||||
"budgets"
|
||||
]
|
||||
},
|
||||
"reflection": "user corrected the budget",
|
||||
"signal_count": 2
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "sess-2",
|
||||
"signals": {
|
||||
"urgency_detected": true
|
||||
},
|
||||
"reflection": "",
|
||||
"signal_count": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "read_log",
|
||||
"args": [
|
||||
1
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "sess-2",
|
||||
"signals": {
|
||||
"urgency_detected": true
|
||||
},
|
||||
"reflection": "",
|
||||
"signal_count": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "log_stats",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"total": 2,
|
||||
"with_reflection": 1,
|
||||
"skip_rate": "50%",
|
||||
"signal_types": {
|
||||
"correction": 1,
|
||||
"corrected_topic": 1,
|
||||
"urgency_detected": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"correction": true
|
||||
},
|
||||
"r2",
|
||||
""
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_stats",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"total": 3,
|
||||
"with_reflection": 2,
|
||||
"skip_rate": "33%",
|
||||
"signal_types": {
|
||||
"correction": 2,
|
||||
"corrected_topic": 1,
|
||||
"urgency_detected": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "read_log",
|
||||
"args": [
|
||||
0
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"learning_opportunity": true
|
||||
},
|
||||
"noted",
|
||||
"s4"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"completion": "done"
|
||||
},
|
||||
"",
|
||||
"s5"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"error": true
|
||||
},
|
||||
"logged",
|
||||
"s6"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"error": true
|
||||
},
|
||||
"",
|
||||
"s7"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_entry",
|
||||
"args": [
|
||||
{
|
||||
"commitment_detected": true
|
||||
},
|
||||
"planned",
|
||||
"s8"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": null
|
||||
},
|
||||
{
|
||||
"fn": "log_stats",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"expected": {
|
||||
"total": 8,
|
||||
"with_reflection": 5,
|
||||
"skip_rate": "38%",
|
||||
"signal_types": {
|
||||
"correction": 2,
|
||||
"corrected_topic": 1,
|
||||
"urgency_detected": 1,
|
||||
"learning_opportunity": 1,
|
||||
"completion": 1,
|
||||
"error": 2,
|
||||
"commitment_detected": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fn": "read_log",
|
||||
"args": [
|
||||
99
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "sess-1",
|
||||
"signals": {
|
||||
"correction": true,
|
||||
"corrected_topic": [
|
||||
"budgets"
|
||||
]
|
||||
},
|
||||
"reflection": "user corrected the budget",
|
||||
"signal_count": 2
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "sess-2",
|
||||
"signals": {
|
||||
"urgency_detected": true
|
||||
},
|
||||
"reflection": "",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "",
|
||||
"signals": {
|
||||
"correction": true
|
||||
},
|
||||
"reflection": "r2",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "s4",
|
||||
"signals": {
|
||||
"learning_opportunity": true
|
||||
},
|
||||
"reflection": "noted",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "s5",
|
||||
"signals": {
|
||||
"completion": "done"
|
||||
},
|
||||
"reflection": "",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "s6",
|
||||
"signals": {
|
||||
"error": true
|
||||
},
|
||||
"reflection": "logged",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "s7",
|
||||
"signals": {
|
||||
"error": true
|
||||
},
|
||||
"reflection": "",
|
||||
"signal_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-10-14T09:15:00.123456+00:00",
|
||||
"session_id": "s8",
|
||||
"signals": {
|
||||
"commitment_detected": true
|
||||
},
|
||||
"reflection": "planned",
|
||||
"signal_count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package main
|
||||
|
||||
// truth_test.go — the parity gate. Replays every case from truth.json
|
||||
// (the shared freeze_truth.py envelope: frozen clock + 58 Python-oracle
|
||||
// cases WITH inputs, generated by scripts/gen_witness_truth.py) VERBATIM
|
||||
// through the ported Go functions: _now, is_correction (capital-letter
|
||||
// quirk), extract_topic + detect_signals (kernel parity: ASCII \w runs,
|
||||
// deterministic signal order, case-insensitive families, rune-safe
|
||||
// truncation, frozen completion triple), _tables/_stopwords gather seams,
|
||||
// and the log family (log_entry / read_log / log_stats with skip_rate
|
||||
// half-even rounding). The log cases build the scratch log state IN
|
||||
// ORDER against an isolated log-path seam — replays are order-sensitive
|
||||
// by design, mirroring the oracle's append-only log. A divergence fails
|
||||
// the port, not the oracle.
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//go:embed truth.json
|
||||
var frozenTruthJSON string
|
||||
|
||||
type frozenCase struct {
|
||||
Fn string `json:"fn"`
|
||||
Args []any `json:"args"`
|
||||
Kwargs map[string]any `json:"kwargs"`
|
||||
Expected json.RawMessage `json:"expected"`
|
||||
}
|
||||
|
||||
// canonical — render through the Python-parity serializer, then decode, so
|
||||
// both sides compare as decoded data (Python None and Go nil → null).
|
||||
func canonical(t *testing.T, v any) any {
|
||||
t.Helper()
|
||||
var out any
|
||||
if err := json.Unmarshal([]byte(pyDumps(v)), &out); err != nil {
|
||||
t.Fatalf("decode actual: %v", err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func argStr(v any) string {
|
||||
s, _ := v.(string)
|
||||
return s
|
||||
}
|
||||
|
||||
func argInt(t *testing.T, v any) int {
|
||||
t.Helper()
|
||||
f, ok := v.(float64)
|
||||
if !ok {
|
||||
t.Fatalf("expected number arg, got %v (%T)", v, v)
|
||||
}
|
||||
return int(f)
|
||||
}
|
||||
|
||||
func argStrSlice(t *testing.T, v any) []string {
|
||||
t.Helper()
|
||||
if v == nil {
|
||||
return []string{} // the facade converts None → recent_topics or []
|
||||
}
|
||||
l, ok := v.([]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected list arg, got %v (%T)", v, v)
|
||||
}
|
||||
out := []string{}
|
||||
for _, e := range l {
|
||||
out = append(out, argStr(e))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func argOrd(t *testing.T, v any) *ordObj {
|
||||
t.Helper()
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal signals arg: %v", err)
|
||||
}
|
||||
o, err := decodeOrdObj(string(raw))
|
||||
if err != nil {
|
||||
t.Fatalf("decode signals arg: %v", err)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func TestFrozenTruthReplay(t *testing.T) {
|
||||
var env struct {
|
||||
FrozenNow string `json:"frozen_now"`
|
||||
Cases []frozenCase `json:"cases"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(frozenTruthJSON), &env); err != nil {
|
||||
t.Fatalf("decode truth envelope: %v", err)
|
||||
}
|
||||
if len(env.Cases) == 0 {
|
||||
t.Fatal("no truth cases — the parity gate is empty")
|
||||
}
|
||||
if env.FrozenNow != "2026-10-14T09:15:00.123456+00:00" {
|
||||
t.Fatalf("frozen clock moved: %q", env.FrozenNow)
|
||||
}
|
||||
savedClock := clock
|
||||
clock = func() string { return env.FrozenNow }
|
||||
t.Cleanup(func() { clock = savedClock })
|
||||
dir := t.TempDir()
|
||||
savedLog := logPathFunc
|
||||
logPathFunc = func() string { return filepath.Join(dir, "witness_log.jsonl") }
|
||||
t.Cleanup(func() { logPathFunc = savedLog })
|
||||
|
||||
for i, c := range env.Cases {
|
||||
var actual any
|
||||
switch c.Fn {
|
||||
case "_now":
|
||||
actual = now()
|
||||
case "is_correction":
|
||||
actual = isCorrection(argStr(c.Args[0]))
|
||||
case "extract_topic":
|
||||
actual = extractTopic(argStr(c.Args[0]))
|
||||
case "detect_signals":
|
||||
actual = detectSignals(argStr(c.Args[0]), argStr(c.Args[1]),
|
||||
argStr(c.Args[2]), argStrSlice(t, c.Args[3]))
|
||||
case "_tables":
|
||||
actual = tables()
|
||||
case "_stopwords":
|
||||
actual = stopwordsSorted()
|
||||
case "log_entry":
|
||||
if err := logEntry(argOrd(t, c.Args[0]), argStr(c.Args[1]), argStr(c.Args[2])); err != nil {
|
||||
t.Fatalf("case %d (log_entry): %v", i, err)
|
||||
}
|
||||
actual = nil
|
||||
case "read_log":
|
||||
actual = readLog(argInt(t, c.Args[0]))
|
||||
case "log_stats":
|
||||
actual = logStats()
|
||||
default:
|
||||
t.Fatalf("case %d: unknown fn %q", i, c.Fn)
|
||||
}
|
||||
var want any
|
||||
if err := json.Unmarshal(c.Expected, &want); err != nil {
|
||||
t.Fatalf("case %d (%s): decode expected: %v", i, c.Fn, err)
|
||||
}
|
||||
if got := canonical(t, actual); !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("case %d (%s): got %v want %v", i, c.Fn, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestLogEntryLineBytes — the JSONL line is byte-identical to Python
|
||||
// json.dumps: ", "/": " separators, insertion order (timestamp,
|
||||
// session_id, signals, reflection, signal_count), ensure_ascii.
|
||||
func TestLogEntryLineBytes(t *testing.T) {
|
||||
clockSave := clock
|
||||
clock = func() string { return "2026-10-14T09:15:00.123456+00:00" }
|
||||
defer func() { clock = clockSave }()
|
||||
dir := t.TempDir()
|
||||
p := filepath.Join(dir, "witness_log.jsonl")
|
||||
logSave := logPathFunc
|
||||
logPathFunc = func() string { return p }
|
||||
defer func() { logPathFunc = logSave }()
|
||||
|
||||
sig := newOrd()
|
||||
sig.Set("correction", true)
|
||||
sig.Set("corrected_topic", []string{"budgets"})
|
||||
if err := logEntry(sig, "user corrected the budget", "sess-1"); err != nil {
|
||||
t.Fatalf("logEntry: %v", err)
|
||||
}
|
||||
want := `{"timestamp": "2026-10-14T09:15:00.123456+00:00", "session_id": "sess-1", "signals": {"correction": true, "corrected_topic": ["budgets"]}, "reflection": "user corrected the budget", "signal_count": 2}` + "\n"
|
||||
raw, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
t.Fatalf("read log: %v", err)
|
||||
}
|
||||
if string(raw) != want {
|
||||
t.Errorf("log line bytes:\n got %q\nwant %q", string(raw), want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadLogSeams — deque semantics (limit counts LINES), blank-line and
|
||||
// malformed-line skipping, trailing line without newline.
|
||||
func TestReadLogSeams(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
p := filepath.Join(dir, "witness_log.jsonl")
|
||||
save := logPathFunc
|
||||
logPathFunc = func() string { return p }
|
||||
defer func() { logPathFunc = save }()
|
||||
|
||||
content := `{"a": 1}` + "\n" +
|
||||
`{bad json` + "\n" +
|
||||
"\n" +
|
||||
`{"b": 2}` + "\n" +
|
||||
`{"c": 3}` // no trailing newline
|
||||
if err := os.WriteFile(p, []byte(content), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 5 lines total (a, bad, blank, b, c) — limit counts LINES:
|
||||
// limit 10 → all 3 valid; limit 2 → last two lines (b, c) → 2 valid;
|
||||
// limit 3 → blank, b, c → 2 valid.
|
||||
if got := readLog(10); len(got) != 3 {
|
||||
t.Errorf("limit 10: got %d entries, want 3", len(got))
|
||||
}
|
||||
if got := readLog(2); len(got) != 2 {
|
||||
t.Errorf("limit 2: got %d entries, want 2", len(got))
|
||||
}
|
||||
if got := readLog(3); len(got) != 2 {
|
||||
t.Errorf("limit 3 (blank line consumed): got %d entries, want 2", len(got))
|
||||
}
|
||||
if got := readLog(0); len(got) != 0 {
|
||||
t.Errorf("limit 0: got %d entries, want 0", len(got))
|
||||
}
|
||||
// missing file → []
|
||||
os.Remove(p)
|
||||
if got := readLog(5); len(got) != 0 {
|
||||
t.Errorf("missing file: got %d entries, want 0", len(got))
|
||||
}
|
||||
}
|
||||
|
||||
// TestLogStatsSeams — list-shaped signals counting, missing-file shape
|
||||
// (no skip_rate key), skip_rate half-even pins.
|
||||
func TestLogStatsSeams(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
p := filepath.Join(dir, "witness_log.jsonl")
|
||||
save := logPathFunc
|
||||
logPathFunc = func() string { return p }
|
||||
defer func() { logPathFunc = save }()
|
||||
|
||||
// signals as a LIST: elements become signal_types keys (oracle parity)
|
||||
line1 := `{"signals": [1, 2, 2], "reflection": ""}` + "\n"
|
||||
line2 := `{"signals": {"x": true}, "reflection": "kept"}` + "\n"
|
||||
if err := os.WriteFile(p, []byte(line1+line2), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := logStats()
|
||||
if got := s.GetInt("total"); got != 2 {
|
||||
t.Errorf("total: %d", got)
|
||||
}
|
||||
if got := s.GetInt("with_reflection"); got != 1 {
|
||||
t.Errorf("with_reflection: %d", got)
|
||||
}
|
||||
st, _ := s.Get("signal_types")
|
||||
sto := st.(*ordObj)
|
||||
for k, want := range map[string]int{"1": 1, "2": 2, "x": 1} {
|
||||
if got := sto.GetInt(k); got != want {
|
||||
t.Errorf("signal_types[%q]: got %d want %d", k, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// skip_rate half-even — Python f"{x:.0f}%" on the exact binary double
|
||||
for _, tc := range []struct {
|
||||
total, wr int
|
||||
want string
|
||||
}{
|
||||
{1, 1, "0%"}, {2, 1, "50%"}, {3, 2, "33%"},
|
||||
{8, 5, "38%"}, // 37.5 → half-even → 38
|
||||
{8, 3, "62%"}, // 62.5 → half-even → 62
|
||||
{8, 7, "12%"}, // 12.5 → half-even → 12
|
||||
} {
|
||||
if got := skipRate(tc.total, tc.wr); got != tc.want {
|
||||
t.Errorf("skipRate(%d,%d): got %s want %s", tc.total, tc.wr, got, tc.want)
|
||||
}
|
||||
}
|
||||
|
||||
// missing file: 3-key zero shape, NO skip_rate key
|
||||
os.Remove(p)
|
||||
s2 := logStats()
|
||||
if _, has := s2.Get("skip_rate"); has {
|
||||
t.Error("missing-file shape must not carry skip_rate")
|
||||
}
|
||||
if s2.GetInt("total") != 0 || s2.GetInt("with_reflection") != 0 {
|
||||
t.Errorf("missing-file zeros: %+v", s2)
|
||||
}
|
||||
if st, _ := s2.Get("signal_types"); st.(*ordObj).Len() != 0 {
|
||||
t.Errorf("missing-file signal_types: %+v", st)
|
||||
}
|
||||
}
|
||||
|
||||
// TestErrorTextRuneTruncation — Python str[:200] / kernel chars().take(200)
|
||||
// are char-based; multibyte error text must not split a rune.
|
||||
func TestErrorTextRuneTruncation(t *testing.T) {
|
||||
sig := detectSignals("hello", strings.Repeat("é", 250), "", nil)
|
||||
v, _ := sig.Get("error_text")
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
t.Fatalf("error_text: %v", v)
|
||||
}
|
||||
if len([]rune(s)) != 200 {
|
||||
t.Errorf("rune length: %d", len([]rune(s)))
|
||||
}
|
||||
}
|
||||
|
||||
// TestLiveNowShape — the live clock renders datetime.now(timezone.utc)
|
||||
// .isoformat() shape: microseconds always 6 digits when present, +00:00.
|
||||
func TestLiveNowShape(t *testing.T) {
|
||||
re := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?\+00:00$`)
|
||||
if !re.MatchString(liveNow()) {
|
||||
t.Errorf("liveNow shape: %q", liveNow())
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewTopicsOrder — drift's new_topics keep EXTRACTION order (the
|
||||
// kernel's cur-set iteration), never map order.
|
||||
func TestNewTopicsOrder(t *testing.T) {
|
||||
sig := detectSignals("anyway moving on to budgets", "", "", []string{"budget"})
|
||||
v, _ := sig.Get("new_topics")
|
||||
got, _ := v.([]string)
|
||||
want := []string{"anyway", "moving", "budgets"}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("new_topics: %v", got)
|
||||
}
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Errorf("new_topics[%d]: got %q want %q", i, got[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.288.0"
|
||||
__version__ = "0.293.2"
|
||||
|
||||
# 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.288.0"' in rune_version,
|
||||
'__version__ = "0.293.2"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -7,11 +7,20 @@ FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
|
||||
phase, phase_error, callable, projection}) -> ContractResult fields
|
||||
* ct_drift({current, saved}) -> drift lines
|
||||
* ct_registry() -> the 42 frozen contract specs
|
||||
* ct_gate({available|error}) -> bool (gap-close: _ct_core gate)
|
||||
* ct_resolve({spec..., outcome}) -> [phase, error, callable, projection]
|
||||
* ct_run_python(spec) -> ContractResult fields
|
||||
* ct_run_all([specs]) -> [ContractResult fields]
|
||||
* ct_capture({table, specs}) -> sigs map
|
||||
* ct_save(sigs) -> the signatures file content
|
||||
* ct_load(content|null) -> sigs map
|
||||
* ct_main({argv, run_all, sigs, saved}) -> {exit_code, stdout}
|
||||
|
||||
The IO (dynamic module import + call, signature capture via inspect, the
|
||||
signatures file) stays in contracts.py; this core owns the verdict branch
|
||||
tree and the drift compare. Override the .so with CONTRACTS_RUST_LIB (a
|
||||
FILE path).
|
||||
tree, the drift compare, and — gap-close tranche — the resolution mapping,
|
||||
the signature map/capture loop, the file content/parse kernels and the
|
||||
CLI dispatch. Override the .so with CONTRACTS_RUST_LIB (a FILE path).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -30,6 +39,14 @@ _SYMBOLS = (
|
||||
"ct_verdict",
|
||||
"ct_drift",
|
||||
"ct_registry",
|
||||
"ct_gate",
|
||||
"ct_resolve",
|
||||
"ct_run_python",
|
||||
"ct_run_all",
|
||||
"ct_capture",
|
||||
"ct_save",
|
||||
"ct_load",
|
||||
"ct_main",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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.288.0
|
||||
Version: v0.293.2
|
||||
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.288.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.293.2 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -486,6 +486,21 @@ class Scaffold:
|
||||
raise IllegalPhaseTransition(
|
||||
f"illegal transition: {current} → {phase} (legal: {sorted(LEGAL_TRANSITIONS.get(current, set()))})"
|
||||
)
|
||||
# QUALITY-GATE LAW (2026-10-13): entering `closed` via raw transition
|
||||
# bypassed the predicted-vs-observed computation entirely — two wave
|
||||
# landings (hook_engine, adaptive_router 2026-10-13) closed with a
|
||||
# 'closed' phase and NO contract_quality, silently. The designed
|
||||
# entry is close() (computes quality + material-change). Raw
|
||||
# transition to closed now requires the quality to ALREADY be
|
||||
# recorded (e.g. close_contract ran in this process); otherwise it
|
||||
# refuses — the quality gate is mechanical, not advisory.
|
||||
if phase == "closed":
|
||||
if not e.get("ext", {}).get("contract_quality"):
|
||||
raise IllegalPhaseTransition(
|
||||
f"transition to 'closed' requires contract_quality evidence — "
|
||||
f"close the contract via close() (predicted-vs-observed), "
|
||||
f"not a raw transition ({contract_id})"
|
||||
)
|
||||
e["phase"] = phase
|
||||
if phase == "closed":
|
||||
e["status"] = "closed"
|
||||
@@ -615,6 +630,18 @@ class Scaffold:
|
||||
# independent observed impact (§17): evidence items only
|
||||
obs = record_observed_impact(doc, contract_id, observed_evidence or [])
|
||||
|
||||
# KERNEL-REBUILD TRAP (2026-10-13, found via salvage-close KeyError):
|
||||
# record_observed_impact delegates to the Rust core when live — and
|
||||
# the core rebuilds doc["entities"] with FRESH objects (doc.clear()/
|
||||
# update semantics). The `e` captured above is then an orphaned
|
||||
# reference no longer in the doc; mutations land on the orphan and
|
||||
# silently never persist (observed: contract_quality absent after
|
||||
# close → construction_interface.close() KeyError on re-read).
|
||||
# Law: RE-RESOLVE the entity after any kernel-delegating call.
|
||||
e = entity(doc, f"contract:{contract_id}")
|
||||
if e is None:
|
||||
raise ValueError(f"contract vanished during impact recording: {contract_id}")
|
||||
|
||||
# R2 Wave 1: the bucket math is factored out so the Rust engine
|
||||
# (scaffold_core.close_quality) computes from the SAME gathered
|
||||
# inputs — the production ledger replay is the parity oracle.
|
||||
|
||||
+101
-1
@@ -3,19 +3,107 @@
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "construction_interface"
|
||||
name = "capability_fit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capability_ledger"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capability_scoring"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "construction_decision"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"capability_fit",
|
||||
"capability_scoring",
|
||||
"construction_mode",
|
||||
"construction_pattern",
|
||||
"construction_patterns_builtin",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toolchain",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "construction_interface"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"capability_ledger",
|
||||
"construction_decision",
|
||||
"construction_mode",
|
||||
"layout_contract",
|
||||
"scaffold_core",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "construction_mode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "construction_pattern"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "construction_patterns_builtin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"capability_scoring",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "layout_contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
@@ -40,6 +128,10 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scaffold_core"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
@@ -76,6 +168,7 @@ version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
@@ -94,6 +187,13 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toolchain"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.26"
|
||||
|
||||
@@ -8,4 +8,9 @@ crate-type = ["rlib", "cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_json = { version = "1", features = ["preserve_order"] }
|
||||
construction_decision = { path = "../construction_decision" }
|
||||
construction_mode = { path = "../construction_mode" }
|
||||
capability_ledger = { path = "../capability_ledger" }
|
||||
layout_contract = { path = "../layout_contract" }
|
||||
scaffold_core = { path = "../scaffold_core" }
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,125 @@
|
||||
//! frozen_battery — replay the FROZEN oracle truth VERBATIM
|
||||
//! (frozen_ci_truth.json + frozen_ci_truth_hash.json, generated by
|
||||
//! scripts/gen_construction_interface_truth.py against the LIVE Python
|
||||
//! oracle through the scripts/ci_freeze_seams rig: pinned
|
||||
//! RUNE_*_CORE=python floors, frozen clock, deterministic uuid mint,
|
||||
//! hermetic per-case stores).
|
||||
//!
|
||||
//! The battery never imports the Python oracle — parity stays provable
|
||||
//! after the strangler exits. The main corpus (85 cases) replays
|
||||
//! byte-exact; the hash corpus (5 cases) replays SHAPE-pinned: Python's
|
||||
//! str-hash obligation ids are process-randomized, so both sides are
|
||||
//! normalized (kind:<digits> → kind:#) before compare — the memory_
|
||||
//! consolidation hash-id law.
|
||||
|
||||
use crate::kernel;
|
||||
use serde_json::Value;
|
||||
|
||||
const TRUTH: &str = include_str!("../frozen_ci_truth.json");
|
||||
const HASH_TRUTH: &str = include_str!("../frozen_ci_truth_hash.json");
|
||||
|
||||
fn cases(text: &str) -> Vec<Value> {
|
||||
serde_json::from_str(text).expect("frozen truth parses")
|
||||
}
|
||||
|
||||
fn case_id(c: &Value) -> String {
|
||||
c.get("args")
|
||||
.and_then(|a| a.as_array())
|
||||
.and_then(|a| a.first())
|
||||
.and_then(|x| x.as_str())
|
||||
.unwrap_or("?")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_truth_replays_verbatim() {
|
||||
let mut n = 0;
|
||||
for case in cases(TRUTH) {
|
||||
let got = kernel::dispatch(&case);
|
||||
assert_eq!(
|
||||
got,
|
||||
case.get("expected").cloned().unwrap_or(Value::Null),
|
||||
"case {} ({}) diverged",
|
||||
case.get("fn").and_then(|f| f.as_str()).unwrap_or("?"),
|
||||
case_id(&case),
|
||||
);
|
||||
n += 1;
|
||||
}
|
||||
assert_eq!(n, 85, "the frozen corpus carries 85 cases");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_truth_replays_shape_pinned() {
|
||||
let mut n = 0;
|
||||
for case in cases(HASH_TRUTH) {
|
||||
let got = kernel::dispatch(&case);
|
||||
let expected = case.get("expected").cloned().unwrap_or(Value::Null);
|
||||
assert_eq!(
|
||||
normalize_hash_ids(got),
|
||||
normalize_hash_ids(expected),
|
||||
"hash case {} ({}) diverged beyond the id shape",
|
||||
case.get("fn").and_then(|f| f.as_str()).unwrap_or("?"),
|
||||
case_id(&case),
|
||||
);
|
||||
n += 1;
|
||||
}
|
||||
assert_eq!(n, 5, "the hash corpus carries 5 cases");
|
||||
}
|
||||
|
||||
/// kind:<up-to-8 digits> → kind:# — the obligation-id seam (Python
|
||||
/// str-hash ids are process-randomized; the shape is the contract).
|
||||
fn normalize_hash_ids(v: Value) -> Value {
|
||||
match v {
|
||||
Value::String(s) => {
|
||||
if let Some((kind, digits)) = s.split_once(':') {
|
||||
if matches!(
|
||||
kind,
|
||||
"contract" | "regression" | "verification" | "composition" | "acquisition"
|
||||
) && !digits.is_empty()
|
||||
&& digits.len() <= 8
|
||||
&& digits.chars().all(|c| c.is_ascii_digit())
|
||||
{
|
||||
return Value::String(format!("{}:#", kind));
|
||||
}
|
||||
}
|
||||
Value::String(s)
|
||||
}
|
||||
Value::Array(a) => Value::Array(a.into_iter().map(normalize_hash_ids).collect()),
|
||||
Value::Object(o) => Value::Object(
|
||||
o.into_iter()
|
||||
.map(|(k, v)| (k, normalize_hash_ids(v)))
|
||||
.collect(),
|
||||
),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audit_missing_fns_are_real_ports() {
|
||||
// the two audit-named gap fns exist as name-preserving kernels with
|
||||
// exercised behavior (not stubs): main (CLI transport) and
|
||||
// _programme_continuation (programme ladder completion).
|
||||
let argv: Vec<String> = vec!["--help".to_string()];
|
||||
let d = kernel::main_dispatch(&argv);
|
||||
assert_eq!(d["exit"], serde_json::json!(0));
|
||||
let progs = vec![serde_json::json!({
|
||||
"programme_id": "p1", "objective": "o",
|
||||
"stages": [
|
||||
{"stage_id": "S1", "objective": "a", "state": "PENDING",
|
||||
"depends_on": [], "priority": 0},
|
||||
{"stage_id": "S2", "objective": "b", "state": "PENDING",
|
||||
"depends_on": [], "priority": 0},
|
||||
],
|
||||
"fallbacks": [],
|
||||
})];
|
||||
let (cont, after) = kernel::programme_continuation(&progs, "S1", "2026-10-13T09:41:23Z");
|
||||
assert_eq!(cont["stage_marked_complete"], serde_json::json!("S1"));
|
||||
assert_eq!(cont["canary"]["verdict"], serde_json::json!("PROGRAMME_OPEN"));
|
||||
assert_eq!(cont["canary"]["next_action"], serde_json::json!(["start", "S2"]));
|
||||
assert_eq!(cont["canary"]["reason"], serde_json::json!("1/2 complete; 1 eligible — continue immediately"));
|
||||
let after = after.as_array().unwrap();
|
||||
assert_eq!(after[0]["stages"][0]["state"], serde_json::json!("COMPLETE"));
|
||||
// save drops the in-memory result — the persisted shape is 5-key stages
|
||||
assert!(after[0]["stages"][0].get("result").is_none());
|
||||
assert_eq!(after[0]["saved_at"], serde_json::json!("2026-10-13T09:41:23Z"));
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -7,6 +7,18 @@
|
||||
//! IllegalPhaseTransition legality map. The 16-edge matrix truth battery
|
||||
//! lives in tests (8 legal, 8 illegal — verified against the Python
|
||||
//! scaffold authority 2026-10-07).
|
||||
//!
|
||||
//! kernel.rs + projection.rs carry the gap-closing doc-in/doc-out kernels
|
||||
//! (dichotomy wave #2479): the envelope-assembly and doc-mutation halves of
|
||||
//! the ConstructionInterface methods whose inputs are fully carried by the
|
||||
//! contract doc + caller args. Stores/clocks/guard subprocesses stay behind
|
||||
//! the facade's injectable seams.
|
||||
|
||||
pub mod kernel;
|
||||
pub mod projection;
|
||||
|
||||
#[cfg(test)]
|
||||
mod frozen_battery;
|
||||
|
||||
/// The legal phase transitions. This map IS the scaffold authority's
|
||||
/// twin — changing one side without the other fails the parity battery.
|
||||
@@ -285,6 +297,32 @@ fn to_cstring(s: String) -> *mut u8 {
|
||||
ptr
|
||||
}
|
||||
|
||||
/// ci_replay(case_json) -> result_json — the FFI replay surface over the
|
||||
/// frozen truth rows ({fn, args, kwargs}); the parity script and the Rust
|
||||
/// battery share kernel::dispatch, so both prove the same computation.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)] // pinned: extern "C" ABI — the Survivor loader requires this signature
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ci_replay(arg: *const u8, arg_len: usize) -> *mut u8 {
|
||||
unsafe {
|
||||
let slice = std::slice::from_raw_parts(arg, arg_len);
|
||||
let text = std::str::from_utf8(slice).unwrap_or("{}");
|
||||
let case: serde_json::Value =
|
||||
serde_json::from_str(text).unwrap_or(serde_json::json!({}));
|
||||
let result = kernel::dispatch(&case);
|
||||
to_cstring(result.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// ci_free_string(ptr) — release a string returned by ci_replay.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ci_free_string(ptr: *mut u8) {
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
drop(std::ffi::CString::from_raw(ptr as *mut i8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ffi_battery {
|
||||
use super::*;
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
//! projection.rs — the pure projection helpers of the construction
|
||||
//! interface (dichotomy wave #2479 gap port). Name-preserving 1:1 ports
|
||||
//! of construction_interface.py's module-level helpers; the contract doc
|
||||
//! travels across the boundary (kernel is pure, the facade owns stores).
|
||||
|
||||
use serde_json::{json, Map, Value};
|
||||
|
||||
/// Python `str()` over a JSON value (the common frozen-case shapes).
|
||||
pub fn py_str(v: &Value) -> String {
|
||||
match v {
|
||||
Value::String(s) => s.clone(),
|
||||
Value::Null => "None".to_string(),
|
||||
Value::Bool(b) => (if *b { "True" } else { "False" }).to_string(),
|
||||
Value::Number(n) => n.to_string(),
|
||||
other => other.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Python slice `s[:n]` semantics for a string.
|
||||
pub fn py_truncate(s: &str, n: usize) -> String {
|
||||
if s.chars().count() <= n {
|
||||
s.to_string()
|
||||
} else {
|
||||
s.chars().take(n).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// `_to_stage_check(spec)` — one guard spec → the StageCheck wire dict
|
||||
/// (name/kind defaults "guard"/"assert", path/output_pattern/description
|
||||
/// default ""). The callable `check` rides as JSON null across the FFI.
|
||||
pub fn to_stage_check(spec: &Value) -> Value {
|
||||
let get = |k: &str, d: &str| -> String {
|
||||
match spec.get(k) {
|
||||
Some(v) if !v.is_null() => py_str(v),
|
||||
_ => d.to_string(),
|
||||
}
|
||||
};
|
||||
json!({
|
||||
"name": get("name", "guard"),
|
||||
"kind": get("kind", "assert"),
|
||||
"argv": spec.get("argv").cloned().unwrap_or(Value::Null),
|
||||
"output_pattern": get("output_pattern", ""),
|
||||
"path": get("path", ""),
|
||||
"check": spec.get("check").cloned().unwrap_or(Value::Null),
|
||||
"description": get("description", ""),
|
||||
})
|
||||
}
|
||||
|
||||
/// `_guard_specs_from_obligations(c)` — the contract's guard declarations:
|
||||
/// identities.verification_obligations rows shaped `guard:<json-spec>`.
|
||||
/// JSON-decode failures and non-dict payloads are skipped — no invented
|
||||
/// facts.
|
||||
pub fn guard_specs_from_obligations(c: &Value) -> Vec<Value> {
|
||||
let mut specs = Vec::new();
|
||||
let Some(rows) = c
|
||||
.get("identities")
|
||||
.filter(|i| !i.is_null())
|
||||
.and_then(|i| i.get("verification_obligations"))
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|a| a.as_slice())
|
||||
else {
|
||||
return specs;
|
||||
};
|
||||
for item in rows {
|
||||
let Some(text) = item.as_str() else {
|
||||
continue;
|
||||
};
|
||||
if !text.starts_with("guard:") {
|
||||
continue;
|
||||
}
|
||||
if let Ok(Value::Object(spec)) = serde_json::from_str::<Value>(&text[6..]) {
|
||||
specs.push(Value::Object(spec));
|
||||
}
|
||||
}
|
||||
specs
|
||||
}
|
||||
|
||||
/// `t_layout(ext)` — layout obligations from a contract's decision trace.
|
||||
pub fn t_layout(ext: &Value) -> Value {
|
||||
ext.get("decision_trace")
|
||||
.and_then(|t| t.get("layout_obligations"))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!([]))
|
||||
}
|
||||
|
||||
/// The obligation-id seam. Python mints
|
||||
/// `f"{kind}:{abs(hash(str(item))) % 10**8}"` — str hash is
|
||||
/// process-randomized (PYTHONHASHSEED), so the value is NOT portable; the
|
||||
/// battery and parity check pin the SHAPE (`kind:` + up-to-8 digits),
|
||||
/// mirroring the memory_consolidation hash-id law. The kernel computes a
|
||||
/// deterministic stand-in id of the identical shape.
|
||||
pub fn obligation_id(kind: &str, item: &str) -> String {
|
||||
// FNV-1a 64 — deterministic stand-in, same shape as the Python hash id
|
||||
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
|
||||
for b in item.as_bytes() {
|
||||
h ^= u64::from(*b);
|
||||
h = h.wrapping_mul(0x0000_0100_0000_01b3);
|
||||
}
|
||||
format!("{}:{}", kind, (h % 100_000_000))
|
||||
}
|
||||
|
||||
/// `_obligations_projection(c)` — the builder-facing obligations list:
|
||||
/// CONTRACT rows (identities.verification/regression_obligations),
|
||||
/// STRUCTURAL rows (trace obligations regression/verification/composition/
|
||||
/// acquisition), PATTERN rows and LAYOUT rows.
|
||||
pub fn obligations_projection(c: &Value) -> Vec<Value> {
|
||||
let mut out: Vec<Value> = Vec::new();
|
||||
let ident = c.get("identities").cloned().unwrap_or(json!({}));
|
||||
let t = c
|
||||
.get("ext")
|
||||
.and_then(|e| e.get("decision_trace"))
|
||||
.cloned()
|
||||
.unwrap_or(json!({}));
|
||||
let obl = t.get("obligations").cloned().unwrap_or(json!({}));
|
||||
|
||||
for (field_name, prov) in [
|
||||
("verification_obligations", "CONTRACT"),
|
||||
("regression_obligations", "CONTRACT"),
|
||||
] {
|
||||
if let Some(items) = ident.get(field_name).and_then(|v| v.as_array()) {
|
||||
for item in items {
|
||||
let text = py_str(item);
|
||||
out.push(json!({
|
||||
"id": obligation_id(&prov.to_lowercase(), &text),
|
||||
"description": py_truncate(&text, 200),
|
||||
"provenance": prov,
|
||||
"kind": field_name,
|
||||
"status": "REQUIRED",
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
for kind in ["regression", "verification", "composition", "acquisition"] {
|
||||
if let Some(items) = obl.get(kind).and_then(|v| v.as_array()) {
|
||||
for item in items {
|
||||
let text = py_str(item);
|
||||
out.push(json!({
|
||||
"id": obligation_id(kind, &text),
|
||||
"description": py_truncate(&text, 200),
|
||||
"provenance": "STRUCTURAL",
|
||||
"kind": kind,
|
||||
"status": "REQUIRED",
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(patterns) = obl.get("pattern").and_then(|v| v.as_array()) {
|
||||
for p in patterns {
|
||||
out.push(json!({
|
||||
"id": p.get("id").cloned().unwrap_or(Value::Null),
|
||||
"description": p.get("obligation").cloned().unwrap_or(Value::Null),
|
||||
"provenance": "PATTERN",
|
||||
"pattern": format!(
|
||||
"{}@r{}",
|
||||
p.get("pattern").and_then(|x| x.as_str()).unwrap_or(""),
|
||||
p.get("revision").and_then(|x| x.as_i64()).unwrap_or(0)
|
||||
),
|
||||
"pattern_applicability": p
|
||||
.get("pattern_applicability").and_then(|x| x.as_str()).unwrap_or(""),
|
||||
"evidence": p.get("reason").and_then(|x| x.as_str()).unwrap_or(""),
|
||||
"status": p.get("verdict").and_then(|x| x.as_str()).unwrap_or("REQUIRED"),
|
||||
}));
|
||||
}
|
||||
}
|
||||
if let Some(los) = t.get("layout_obligations").and_then(|v| v.as_array()) {
|
||||
for lo in los {
|
||||
out.push(json!({
|
||||
"id": format!(
|
||||
"layout:{}",
|
||||
lo.get("component").and_then(|x| x.as_str()).unwrap_or("")
|
||||
),
|
||||
"description": lo.get("obligation").cloned().unwrap_or(Value::Null),
|
||||
"provenance": "LAYOUT_CONTRACT",
|
||||
"status": "REQUIRED",
|
||||
"verification": lo.get("verification").cloned().unwrap_or(Value::Null),
|
||||
}));
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// `_obligation_scope_files(obligations)` — obligation ids referenced by
|
||||
/// closure scope checks (stub twin of the Python stub).
|
||||
pub fn obligation_scope_files(_obligations: &Value) -> Vec<Value> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// `_match(cap, f)` — capability source-location matching (the nested
|
||||
/// helper of _auto_material_change, literal name preserved).
|
||||
pub fn _match(cap: &Value, f: &str) -> bool {
|
||||
let Some(locs) = cap.get("source_locations").and_then(|v| v.as_array()) else {
|
||||
return false;
|
||||
};
|
||||
for loc in locs {
|
||||
if let Some(loc) = loc.as_str() {
|
||||
if f == loc || f.ends_with(&format!("/{}", loc)) || loc.ends_with(&format!("/{}", f)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// `_envelope(operation, ...)` — the stable §12 output envelope with the
|
||||
/// `extra` merge.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn envelope(
|
||||
operation: &str,
|
||||
success: bool,
|
||||
ids: Value,
|
||||
state: Value,
|
||||
evidence: Value,
|
||||
errors: Value,
|
||||
warnings: Value,
|
||||
extra: Value,
|
||||
) -> Value {
|
||||
let mut env = Map::new();
|
||||
env.insert("schema".into(), json!(1));
|
||||
env.insert("operation".into(), json!(operation));
|
||||
env.insert("success".into(), json!(success));
|
||||
env.insert("ids".into(), if ids.is_null() { json!({}) } else { ids });
|
||||
env.insert("state".into(), if state.is_null() { json!({}) } else { state });
|
||||
env.insert(
|
||||
"evidence".into(),
|
||||
if evidence.is_null() { json!([]) } else { evidence },
|
||||
);
|
||||
env.insert("errors".into(), if errors.is_null() { json!([]) } else { errors });
|
||||
env.insert(
|
||||
"warnings".into(),
|
||||
if warnings.is_null() { json!([]) } else { warnings },
|
||||
);
|
||||
if let Value::Object(extra_map) = extra {
|
||||
for (k, v) in extra_map {
|
||||
env.insert(k, v);
|
||||
}
|
||||
}
|
||||
Value::Object(env)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_stage_check_defaults() {
|
||||
let c = to_stage_check(&json!({}));
|
||||
assert_eq!(c["name"], json!("guard"));
|
||||
assert_eq!(c["kind"], json!("assert"));
|
||||
assert_eq!(c["argv"], json!(null));
|
||||
assert_eq!(c["description"], json!(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guard_specs_skip_junk() {
|
||||
let c = json!({"identities": {"verification_obligations": [
|
||||
"guard:{\"name\": \"g1\"}", "free text", "guard:not-json{{",
|
||||
"[1]", "guard:{\"name\": \"g2\"}"]}});
|
||||
let specs = guard_specs_from_obligations(&c);
|
||||
assert_eq!(specs.len(), 2);
|
||||
assert_eq!(specs[0]["name"], json!("g1"));
|
||||
assert!(guard_specs_from_obligations(&json!({})).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn projection_kinds() {
|
||||
let c = json!({
|
||||
"identities": {"verification_obligations": ["v-ob"]},
|
||||
"ext": {"decision_trace": {"obligations": {
|
||||
"pattern": [{"id": "p1", "pattern": "seed", "revision": 2,
|
||||
"obligation": "ob", "verdict": "SATISFIED",
|
||||
"reason": "r"}]},
|
||||
"layout_obligations": [{"component": "ui:h",
|
||||
"obligation": "o",
|
||||
"verification": "adapter"}]}}});
|
||||
let out = obligations_projection(&c);
|
||||
assert_eq!(out.len(), 3);
|
||||
assert_eq!(out[0]["provenance"], json!("CONTRACT"));
|
||||
assert_eq!(out[1]["provenance"], json!("PATTERN"));
|
||||
assert_eq!(out[1]["pattern"], json!("seed@r2"));
|
||||
assert_eq!(out[2]["id"], json!("layout:ui:h"));
|
||||
// shape law: the contract row id is kind:<up-to-8 digits>
|
||||
let id = out[0]["id"].as_str().unwrap();
|
||||
let num = id.split(':').nth(1).unwrap();
|
||||
assert!(num.len() <= 8 && num.chars().all(|c| c.is_ascii_digit()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_location_matching() {
|
||||
let cap = json!({"source_locations": ["src/export.py"]});
|
||||
assert!(_match(&cap, "src/export.py"));
|
||||
assert!(_match(&cap, "repo/src/export.py"));
|
||||
// oracle: "src/export.py/sub".endswith("/src/export.py") is False —
|
||||
// only exact, suffix-dir, and dir-suffix forms match
|
||||
assert!(!_match(&cap, "src/export.py/sub"));
|
||||
assert!(!_match(&cap, "src/other.py"));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,547 @@
|
||||
//! gap_battery — frozen-oracle battery for the contracts gap-close
|
||||
//! (dichotomy wave). The truth JSON is the LIVE oracle's output
|
||||
//! (scripts/gen_contracts_gap_truth.py; `cases` re-verified byte-identical
|
||||
//! by scripts/freeze_truth.py --verify) and is replayed VERBATIM.
|
||||
//!
|
||||
//! Coverage map (every new kernel, every branch):
|
||||
//! * _ct_core — probes (loader none / core none / raises / live)
|
||||
//! * _resolve_and_project— every phase branch + expect_callable drop
|
||||
//! * _run_contract_python— all 15 delegated rows + the oracle rows
|
||||
//! (incl. the one documented eager/lazy divergence)
|
||||
//! * run_all_contracts — the full 42-row order-preserving replay
|
||||
//! * capture_signatures — key format + skip-on-None over the registry
|
||||
//! * save/load_signatures— byte-parity content, missing/corrupt/unicode
|
||||
//! * contracts_main — argv dispatch, exact stdout bytes, exit codes
|
||||
//!
|
||||
//! Documented divergence (oracle-internal, frozen both ways): a result
|
||||
//! whose PROJECTION raises (rp-project-crash) is a crash on the delegated
|
||||
//! path (eager projection feeds the kernel) but a PASS on the lazy
|
||||
//! pure-Python oracle path — the battery pins both behaviors.
|
||||
|
||||
use super::{
|
||||
_ct_core, _resolve_and_project, _run_contract_python, capture_signatures,
|
||||
check_signature_drift, contracts_main, load_signatures, registry, run_all_contracts,
|
||||
save_signatures, CoreProbe, InvokeOutcome, Invoker, MainIO, Projection, RunSpec, Signaturer,
|
||||
Verdict,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
const TRUTH: &str = include_str!("ct_gap_truth.json");
|
||||
|
||||
fn truth() -> Value {
|
||||
serde_json::from_str(TRUTH).expect("ct_gap_truth.json parses")
|
||||
}
|
||||
|
||||
fn spec_from_contract(v: &Value) -> RunSpec {
|
||||
serde_json::from_value(v.clone()).expect("contract spec deserializes")
|
||||
}
|
||||
|
||||
fn proj_from(v: &Value) -> Option<Projection> {
|
||||
serde_json::from_value(v.clone()).ok()
|
||||
}
|
||||
|
||||
fn overlay_resolution(spec: &mut RunSpec, resolution: &Value) {
|
||||
let arr = resolution.as_array().expect("resolution is a 4-tuple");
|
||||
spec.phase = arr[0].as_str().unwrap_or_default().to_string();
|
||||
spec.phase_error = arr[1].as_str().unwrap_or_default().to_string();
|
||||
spec.callable = arr[2].as_bool().unwrap_or(false);
|
||||
spec.projection = proj_from(&arr[3]);
|
||||
}
|
||||
|
||||
fn verdict_from(v: &Value) -> Verdict {
|
||||
serde_json::from_value(v.clone()).expect("verdict deserializes")
|
||||
}
|
||||
|
||||
fn sigs_from(v: &Value) -> BTreeMap<String, String> {
|
||||
v.as_object()
|
||||
.map(|m| {
|
||||
m.iter()
|
||||
.map(|(k, x)| (k.clone(), x.as_str().unwrap_or_default().to_string()))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// ── seam doubles ────────────────────────────────────────────────────────────
|
||||
|
||||
struct Probe(Result<bool, String>);
|
||||
|
||||
impl CoreProbe for Probe {
|
||||
fn core_available(&self) -> Result<bool, String> {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
struct Canned(InvokeOutcome);
|
||||
|
||||
impl Invoker for Canned {
|
||||
fn invoke(&self, _spec: &RunSpec) -> InvokeOutcome {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Rebuild the seam outcome the frozen resolution encodes.
|
||||
fn outcome_from_resolution(resolution: &Value) -> InvokeOutcome {
|
||||
let arr = resolution.as_array().expect("resolution is a 4-tuple");
|
||||
let phase = arr[0].as_str().unwrap_or_default();
|
||||
let err = arr[1].as_str().unwrap_or_default().to_string();
|
||||
let callable = arr[2].as_bool().unwrap_or(false);
|
||||
let projection = proj_from(&arr[3]);
|
||||
match phase {
|
||||
"import_error" => InvokeOutcome::ImportError(err),
|
||||
"crash" => InvokeOutcome::CallCrash {
|
||||
error: err,
|
||||
callable,
|
||||
},
|
||||
"not_found" => InvokeOutcome::NotFound,
|
||||
_ => InvokeOutcome::Found {
|
||||
callable,
|
||||
projection,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct CannedSigner(BTreeMap<String, String>);
|
||||
|
||||
impl Signaturer for CannedSigner {
|
||||
fn signature_of(&self, module: &str, function: &str) -> Option<String> {
|
||||
self.0.get(&format!("{module}.{function}")).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
struct CannedMain {
|
||||
run_all: Vec<Verdict>,
|
||||
sigs: BTreeMap<String, String>,
|
||||
saved: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl MainIO for CannedMain {
|
||||
fn run_all(&self) -> Vec<Verdict> {
|
||||
self.run_all.clone()
|
||||
}
|
||||
fn capture_signatures(&self) -> BTreeMap<String, String> {
|
||||
self.sigs.clone()
|
||||
}
|
||||
fn load_signatures(&self) -> BTreeMap<String, String> {
|
||||
self.saved.clone()
|
||||
}
|
||||
fn save_signatures(&self, _sigs: &BTreeMap<String, String>) {}
|
||||
}
|
||||
|
||||
// ── batteries ───────────────────────────────────────────────────────────────
|
||||
|
||||
/// _ct_core: every loader-state probe outcome maps to the oracle's
|
||||
/// None-propagation (only a live core yields true).
|
||||
#[test]
|
||||
fn test_ct_core_probes() {
|
||||
let t = truth();
|
||||
for p in t["extra"]["probes"].as_array().unwrap() {
|
||||
let expected = p["expected"].as_bool().unwrap();
|
||||
let probe = Probe(match p["name"].as_str().unwrap() {
|
||||
"probe:core-live" => Ok(true),
|
||||
"probe:core-raises" => Err("rig core failure".into()),
|
||||
_ => Ok(false),
|
||||
});
|
||||
assert_eq!(
|
||||
_ct_core(&probe),
|
||||
expected,
|
||||
"gate divergence on {}",
|
||||
p["name"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// _resolve_and_project: every frozen harness case (recv-form Contract)
|
||||
/// replays its (phase, phase_error, callable, projection) tuple through
|
||||
/// the mapping kernel.
|
||||
#[test]
|
||||
fn test_resolve_cases_replay() {
|
||||
let t = truth();
|
||||
let mut n = 0;
|
||||
for c in t["cases"].as_array().unwrap() {
|
||||
if c["fn"].as_str().unwrap() != "_resolve_and_project" {
|
||||
continue;
|
||||
}
|
||||
let spec = spec_from_contract(&c["recv"]);
|
||||
let frozen = &c["expected"]["result"];
|
||||
let got = _resolve_and_project(&spec, &Canned(outcome_from_resolution(frozen)));
|
||||
let arr = frozen.as_array().unwrap();
|
||||
assert_eq!(got.0, arr[0].as_str().unwrap(), "phase on {}", spec.name);
|
||||
assert_eq!(got.1, arr[1].as_str().unwrap(), "error on {}", spec.name);
|
||||
assert_eq!(
|
||||
got.2,
|
||||
arr[2].as_bool().unwrap(),
|
||||
"callable on {}",
|
||||
spec.name
|
||||
);
|
||||
assert_eq!(got.3, proj_from(&arr[3]), "projection on {}", spec.name);
|
||||
n += 1;
|
||||
}
|
||||
assert_eq!(n, 14, "resolve case count");
|
||||
}
|
||||
|
||||
/// The expect_callable branch DROPS the projection even when the seam
|
||||
/// produced one — the oracle never projects a callability-only check.
|
||||
#[test]
|
||||
fn test_resolve_drops_projection_for_expect_callable() {
|
||||
let spec = RunSpec {
|
||||
name: "drop-probe".into(),
|
||||
module: "m".into(),
|
||||
function: "f".into(),
|
||||
expect_type: None,
|
||||
expect_keys: None,
|
||||
expect_len: None,
|
||||
expect_not_none: false,
|
||||
expect_callable: true,
|
||||
skip_on_import_error: true,
|
||||
phase: String::new(),
|
||||
phase_error: String::new(),
|
||||
callable: false,
|
||||
projection: None,
|
||||
};
|
||||
let projection = Projection {
|
||||
type_name: "dict".into(),
|
||||
none: false,
|
||||
type_ok: None,
|
||||
is_dict: true,
|
||||
keys: Some(vec!["k".into()]),
|
||||
sized: true,
|
||||
len: Some(1),
|
||||
};
|
||||
let got = _resolve_and_project(
|
||||
&spec,
|
||||
&Canned(InvokeOutcome::Found {
|
||||
callable: true,
|
||||
projection: Some(projection),
|
||||
}),
|
||||
);
|
||||
assert_eq!(got.0, "found");
|
||||
assert!(got.3.is_none(), "projection must be dropped");
|
||||
}
|
||||
|
||||
/// _project: the projection computation stays Python-side (subclass
|
||||
/// semantics); the battery pins the SHAPE — every frozen projection
|
||||
/// deserializes into the kernel's Projection type with the oracle fields.
|
||||
#[test]
|
||||
fn test_project_shapes() {
|
||||
let t = truth();
|
||||
let mut n = 0;
|
||||
for c in t["cases"].as_array().unwrap() {
|
||||
if c["fn"].as_str().unwrap() != "_project" {
|
||||
continue;
|
||||
}
|
||||
let p: Projection =
|
||||
serde_json::from_value(c["expected"]["result"].clone()).expect("projection parses");
|
||||
assert!(!p.type_name.is_empty());
|
||||
n += 1;
|
||||
}
|
||||
assert_eq!(n, 7, "project case count");
|
||||
}
|
||||
|
||||
/// _run_contract_python over the frozen delegated resolutions: all 15
|
||||
/// rows (every phase + expectation branch) replay exactly.
|
||||
#[test]
|
||||
fn test_run_python_delegated_rows() {
|
||||
let t = truth();
|
||||
let rows = t["extra"]["delegated_cases"].as_array().unwrap();
|
||||
assert_eq!(rows.len(), 15);
|
||||
for dc in rows {
|
||||
let mut spec = spec_from_contract(&dc["contract"]);
|
||||
overlay_resolution(&mut spec, &dc["resolution"]);
|
||||
assert_eq!(
|
||||
_run_contract_python(&spec),
|
||||
verdict_from(&dc["expected"]),
|
||||
"delegated divergence on {}",
|
||||
dc["name"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// _run_contract_python vs the pure-Python oracle rows: identical on
|
||||
/// every row except the documented eager/lazy divergence, where the
|
||||
/// kernel matches the delegated verdict instead.
|
||||
#[test]
|
||||
fn test_run_python_oracle_rows() {
|
||||
let t = truth();
|
||||
let delegated: BTreeMap<String, &Value> = t["extra"]["delegated_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|dc| (dc["contract"]["name"].as_str().unwrap().to_string(), dc))
|
||||
.collect();
|
||||
let mut matched = 0;
|
||||
let mut diverged = 0;
|
||||
for rc in t["extra"]["result_cases"].as_array().unwrap() {
|
||||
if rc["fn"].as_str().unwrap() != "_run_contract_python" {
|
||||
continue;
|
||||
}
|
||||
let cname = rc["contract"]["name"].as_str().unwrap();
|
||||
let dc = delegated.get(cname).expect("resolution available");
|
||||
let mut spec = spec_from_contract(&rc["contract"]);
|
||||
overlay_resolution(&mut spec, &dc["resolution"]);
|
||||
let got = _run_contract_python(&spec);
|
||||
let want = verdict_from(&rc["expected"]);
|
||||
if got == want {
|
||||
matched += 1;
|
||||
} else {
|
||||
// The single documented divergence: eager projection crash.
|
||||
assert_eq!(got, verdict_from(&dc["expected"]), "divergence row {cname}");
|
||||
assert!(
|
||||
cname.contains("rp proj"),
|
||||
"unexpected divergence on {cname}"
|
||||
);
|
||||
diverged += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(matched + diverged, 15, "oracle row count");
|
||||
assert_eq!(diverged, 1, "exactly the documented divergence");
|
||||
}
|
||||
|
||||
/// run_all_contracts: the 42-row order-preserving loop over the frozen
|
||||
/// resolutions reproduces the live run verdict-for-verdict.
|
||||
#[test]
|
||||
fn test_run_all_replay() {
|
||||
let t = truth();
|
||||
let inputs = t["extra"]["run_all_inputs"].as_array().unwrap();
|
||||
let want = t["extra"]["run_all"].as_array().unwrap();
|
||||
assert_eq!(inputs.len(), 42);
|
||||
assert_eq!(want.len(), 42);
|
||||
let specs: Vec<RunSpec> = inputs.iter().map(spec_from_contract).collect();
|
||||
// order tie-in with the frozen registry
|
||||
let reg = registry();
|
||||
for (spec, r) in specs.iter().zip(reg.iter()) {
|
||||
assert_eq!(spec.name, r.name, "run_all order vs registry");
|
||||
}
|
||||
let got = run_all_contracts(&specs);
|
||||
for (g, w) in got.iter().zip(want.iter()) {
|
||||
assert_eq!(g, &verdict_from(w), "run_all divergence on {}", w["name"]);
|
||||
}
|
||||
}
|
||||
|
||||
/// capture_signatures: the "module.function" key format and the
|
||||
/// skip-on-None discipline over the registry (the frozen capture has 37
|
||||
/// keys for 42 specs — attrs and duplicates yield no signature).
|
||||
#[test]
|
||||
fn test_capture_signatures_format_and_skip() {
|
||||
let t = truth();
|
||||
let frozen = t["cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|c| c["fn"].as_str().unwrap() == "capture_signatures")
|
||||
.expect("capture case present");
|
||||
let full = sigs_from(&frozen["expected"]);
|
||||
assert_eq!(full.len(), 37, "frozen capture size");
|
||||
// signer drops three keys → capture drops exactly those three
|
||||
let dropped = [
|
||||
"abstraction.pipeline_stats",
|
||||
"cache.get_cache",
|
||||
"goal.check_goal",
|
||||
];
|
||||
let mut table = full.clone();
|
||||
for k in dropped {
|
||||
table.remove(k);
|
||||
}
|
||||
let got = capture_signatures(&CannedSigner(table), ®istry());
|
||||
let mut want = full.clone();
|
||||
for k in dropped {
|
||||
want.remove(k);
|
||||
}
|
||||
assert_eq!(got, want);
|
||||
assert!(got.contains_key("memory_store.connect"));
|
||||
assert!(got.keys().all(|k| k.contains('.')));
|
||||
}
|
||||
|
||||
/// save/load_signatures: byte-parity with json.dump(indent=2), the
|
||||
/// missing-file and corrupt-file degradation, and unicode escaping.
|
||||
#[test]
|
||||
fn test_file_cases_replay() {
|
||||
let t = truth();
|
||||
let cases = t["extra"]["file_cases"].as_array().unwrap();
|
||||
assert_eq!(cases.len(), 5);
|
||||
let mut saved_checks = 0;
|
||||
for fc in cases {
|
||||
let name = fc["name"].as_str().unwrap();
|
||||
let corrupt = name.contains("corrupt");
|
||||
let sigs = sigs_from(&fc["sigs"]);
|
||||
let expected = sigs_from(&fc["expected"]);
|
||||
match fc["content"].as_str() {
|
||||
Some(content) => {
|
||||
// the corrupt row's file content is rig-written (the
|
||||
// load-degradation fixture), not save output
|
||||
if !corrupt {
|
||||
assert_eq!(
|
||||
save_signatures(&sigs),
|
||||
content,
|
||||
"save content divergence on {name}"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
load_signatures(Some(content)),
|
||||
expected,
|
||||
"load divergence on {name}"
|
||||
);
|
||||
if corrupt {
|
||||
assert_eq!(load_signatures(Some(content)), BTreeMap::new());
|
||||
}
|
||||
saved_checks += 1;
|
||||
}
|
||||
None => {
|
||||
assert_eq!(load_signatures(None), BTreeMap::new(), "missing file");
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(saved_checks, 4, "content-bearing rows");
|
||||
// unicode escaping law: non-ASCII escapes as \uXXXX lowercase hex
|
||||
let mut uni = BTreeMap::new();
|
||||
uni.insert("m.f".to_string(), "(s='héllo → world')".to_string());
|
||||
assert_eq!(
|
||||
save_signatures(&uni),
|
||||
"{\n \"m.f\": \"(s='h\\u00e9llo \\u2192 world')\"\n}"
|
||||
);
|
||||
// empty map law
|
||||
assert_eq!(save_signatures(&BTreeMap::new()), "{}");
|
||||
}
|
||||
|
||||
/// contracts_main: argv dispatch, exact stdout bytes, exit codes. The
|
||||
/// `test` variants carry deterministic call-time prints from live
|
||||
/// contract modules (Python-side IO) between the header and the first
|
||||
/// result line — the kernel output equals the frozen stdout with that
|
||||
/// noise segment removed.
|
||||
#[test]
|
||||
fn test_main_cases_replay() {
|
||||
let t = truth();
|
||||
let run_all: Vec<Verdict> = t["extra"]["run_all"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(verdict_from)
|
||||
.collect();
|
||||
let capture_case = t["cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|c| c["fn"].as_str().unwrap() == "capture_signatures")
|
||||
.unwrap();
|
||||
let sigs = sigs_from(&capture_case["expected"]);
|
||||
let second_key = sigs
|
||||
.keys()
|
||||
.find(|k| k.as_str() != "abstraction.pipeline_stats")
|
||||
.unwrap()
|
||||
.clone();
|
||||
for mc in t["extra"]["main_cases"].as_array().unwrap() {
|
||||
let name = mc["name"].as_str().unwrap();
|
||||
let argv: Vec<String> = mc["argv"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|v| v.as_str().unwrap().to_string())
|
||||
.collect();
|
||||
let mut saved = BTreeMap::new();
|
||||
if name.ends_with("-drift") {
|
||||
saved.insert(
|
||||
"abstraction.pipeline_stats".to_string(),
|
||||
"(old_sig)".to_string(),
|
||||
);
|
||||
saved.insert(second_key.clone(), sigs[&second_key].clone());
|
||||
}
|
||||
let io = CannedMain {
|
||||
run_all: run_all.clone(),
|
||||
sigs: sigs.clone(),
|
||||
saved,
|
||||
};
|
||||
let (code, stdout) = contracts_main(&argv, &io);
|
||||
assert_eq!(
|
||||
code,
|
||||
mc["exit_code"].as_i64().unwrap() as i32,
|
||||
"exit on {name}"
|
||||
);
|
||||
let frozen = mc["expected"].as_str().unwrap();
|
||||
if name == "main:test" || name == "main:test-drift" {
|
||||
// strip the deterministic call-time print noise: everything
|
||||
// between the header rule and the first result line
|
||||
let idx = frozen
|
||||
.find(" \u{2705}")
|
||||
.or_else(|| frozen.find(" \u{274C}"))
|
||||
.expect("result line present");
|
||||
let header = format!("\u{1F50D} Contract Tests\n{}\n", "=".repeat(50));
|
||||
let want = format!("{header}{}", &frozen[idx..]);
|
||||
assert_eq!(stdout, want, "test-cmd stdout (noise-stripped) on {name}");
|
||||
} else {
|
||||
assert_eq!(stdout, frozen, "stdout on {name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Branch inventory audit: every kernel branch is exercised by the
|
||||
/// battery inputs above.
|
||||
#[test]
|
||||
fn test_gap_battery_covers_every_branch() {
|
||||
let t = truth();
|
||||
let resolutions: Vec<&str> = t["extra"]["delegated_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|dc| dc["resolution"][0].as_str().unwrap())
|
||||
.collect();
|
||||
for phase in ["import_error", "crash", "not_found", "found"] {
|
||||
assert!(resolutions.contains(&phase), "{phase} branch");
|
||||
}
|
||||
// skip=False import-fail branch
|
||||
assert!(t["extra"]["result_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|rc| rc["name"].as_str().unwrap().contains("noskip")
|
||||
&& rc["expected"]["error"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.starts_with("import failed")));
|
||||
// expectation branches (from the delegated rows' verdicts)
|
||||
let errors: Vec<&str> = t["extra"]["delegated_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|dc| dc["expected"]["error"].as_str().unwrap())
|
||||
.collect();
|
||||
assert!(errors
|
||||
.iter()
|
||||
.any(|e| e.starts_with("skipped (import error")));
|
||||
assert!(errors.contains(&"returned None"));
|
||||
assert!(errors.iter().any(|e| e.starts_with("missing keys")));
|
||||
assert!(errors.iter().any(|e| e.starts_with("expected len")));
|
||||
assert!(errors.iter().any(|e| e.starts_with("RuntimeError")));
|
||||
// drift section frozen in the -drift main rows
|
||||
assert!(t["extra"]["main_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|mc| mc["name"].as_str().unwrap() == "main:test-drift"
|
||||
&& mc["expected"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("Signature drift detected (1)")));
|
||||
// drift compare kernel re-check on the seeded drift line
|
||||
let mc = t["extra"]["main_cases"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|mc| mc["name"].as_str().unwrap() == "main:drift-drift")
|
||||
.unwrap();
|
||||
assert!(mc["expected"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains(mc["drift_line"].as_str().unwrap()));
|
||||
let mut cur = BTreeMap::new();
|
||||
cur.insert("abstraction.pipeline_stats".to_string(), "()".to_string());
|
||||
let mut saved = BTreeMap::new();
|
||||
saved.insert(
|
||||
"abstraction.pipeline_stats".to_string(),
|
||||
"(old_sig)".to_string(),
|
||||
);
|
||||
assert_eq!(
|
||||
check_signature_drift(&cur, &saved),
|
||||
vec!["abstraction.pipeline_stats: (old_sig) → ()".to_string()]
|
||||
);
|
||||
}
|
||||
+521
-21
@@ -4,19 +4,33 @@
|
||||
//! Port of src/rune/contracts.py's decision surface: the 42-contract
|
||||
//! registry (data), the run_contract VERDICT kernel (every branch:
|
||||
//! import-error skip/fail, not-found, callable check, not-none, type,
|
||||
//! keys, len, crash), and check_signature_drift's compare. The IO stays
|
||||
//! Python: dynamic module import + call (the projection is computed
|
||||
//! Python-side), signature capture (inspect) and the signatures file.
|
||||
//! keys, len, crash), check_signature_drift's compare, and — gap-close
|
||||
//! tranche — the 7 audit-named functions (_ct_core,
|
||||
//! _resolve_and_project, _run_contract_python, capture_signatures,
|
||||
//! save_signatures, load_signatures, main as contracts_main) with their
|
||||
//! IO behind injectable seams (CoreProbe / Invoker / Signaturer /
|
||||
//! MainIO). The IO stays Python: dynamic module import + call (the
|
||||
//! projection is computed Python-side), signature capture (inspect) and
|
||||
//! the signatures file.
|
||||
//!
|
||||
//! FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
|
||||
//! * ct_verdict({spec, phase, phase_error, callable, projection}) -> verdict
|
||||
//! * ct_drift({current, saved}) -> drift lines
|
||||
//! * ct_registry() -> the 42 frozen contract specs
|
||||
//! * ct_gate({available|error}) -> bool
|
||||
//! * ct_resolve({spec..., outcome}) -> [phase, error, callable, projection]
|
||||
//! * ct_run_python(spec) -> verdict
|
||||
//! * ct_run_all([specs]) -> [verdicts]
|
||||
//! * ct_capture({table, specs}) -> sigs map
|
||||
//! * ct_save(sigs) -> file content
|
||||
//! * ct_load(content|null) -> sigs map
|
||||
//! * ct_main({argv, run_all, sigs, saved}) -> {exit_code, stdout}
|
||||
//!
|
||||
//! NOTE: no free-symbol export (capability_scoring's cs_free_string serves
|
||||
//! the whole process — duplicate symbols break the cdylib link).
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Contract {
|
||||
@@ -71,8 +85,8 @@ impl Contract {
|
||||
/// the drift lines. Semantics (oracle-probed): changed values ARE drift;
|
||||
/// new keys are NOT drift; removed keys are NOT drift.
|
||||
pub fn check_signature_drift(
|
||||
current: &std::collections::BTreeMap<String, String>,
|
||||
saved: &std::collections::BTreeMap<String, String>,
|
||||
current: &BTreeMap<String, String>,
|
||||
saved: &BTreeMap<String, String>,
|
||||
) -> Vec<String> {
|
||||
let mut drifts = Vec::new();
|
||||
for (key, sig) in current {
|
||||
@@ -131,7 +145,7 @@ fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Projection {
|
||||
#[serde(rename = "type")]
|
||||
pub type_name: String,
|
||||
@@ -173,11 +187,119 @@ fn py_str_list(items: &[String]) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
/// run_contract's verdict kernel — the FULL branch tree of the oracle:
|
||||
/// import-error skip/fail, crash passthrough, not-found, expect_callable,
|
||||
/// then (in oracle order) not-none → type → keys → len, with the exact
|
||||
/// error strings.
|
||||
/// run_contract's verdict kernel — the FULL branch tree of the oracle
|
||||
/// (delegates to `_run_contract_python`, the name-preserving port of the
|
||||
/// oracle's own branch tree; one logic, two entries).
|
||||
pub fn verdict(spec: &RunSpec) -> Verdict {
|
||||
_run_contract_python(spec)
|
||||
}
|
||||
|
||||
/// The registry as typed specs (order = oracle CONTRACTS order).
|
||||
pub fn registry() -> Vec<RunSpec> {
|
||||
serde_json::from_str::<serde_json::Value>(REGISTRY_JSON)
|
||||
.ok()
|
||||
.and_then(|v| {
|
||||
serde_json::from_value::<Vec<RunSpec>>(v.get("contracts").cloned().unwrap_or_default())
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// GAP-CLOSE (dichotomy wave): the 7 audit-named missing functions, ported
|
||||
// name-preserving with IO behind injectable seams. The dynamic import /
|
||||
// getattr / call, the inspect-based signature capture and the signatures
|
||||
// FILE are the Python side (seams below); everything decidable is here.
|
||||
// Frozen truth: ct_gap_truth.json (battery: gap_battery.rs).
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// The loader-state probe seam for `_ct_core`. The oracle returns the
|
||||
/// loader MODULE when its kernel probe succeeds and None on every other
|
||||
/// outcome (loader absent, core() None, core() raising) — the portable
|
||||
/// logic is that None-propagation, modeled here as a bool gate.
|
||||
pub trait CoreProbe {
|
||||
/// Ok(true): the core is live. Ok(false): absent/disabled.
|
||||
/// Err: the probe raised (kernel failure → fallback).
|
||||
fn core_available(&self) -> Result<bool, String>;
|
||||
}
|
||||
|
||||
/// contracts.py `_ct_core` — the strangler-law probe decision. True only
|
||||
/// when the loader module is importable AND its kernel probe returns a
|
||||
/// live core; every failure mode (including a raising probe) maps to
|
||||
/// False, exactly like the oracle's cascade of `None` returns.
|
||||
pub fn _ct_core(probe: &dyn CoreProbe) -> bool {
|
||||
probe.core_available().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// One outcome of the resolution seam (the IO half of run_contract that
|
||||
/// stays Python): the dynamic import, getattr, the call, and the
|
||||
/// projection of the result. Which kind of failure happened decides the
|
||||
/// phase — that distinction is the portable logic of
|
||||
/// `_resolve_and_project`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InvokeOutcome {
|
||||
/// `__import__` raised ImportError (module genuinely missing).
|
||||
ImportError(String),
|
||||
/// `__import__` raised a non-ImportError (oracle: outer catch → crash).
|
||||
ImportCrash(String),
|
||||
/// getattr returned None (function/attribute not in the module).
|
||||
NotFound,
|
||||
/// The call raised (oracle: outer catch → crash). `callable` is the
|
||||
/// pre-call callable flag the oracle carries through.
|
||||
CallCrash { error: String, callable: bool },
|
||||
/// The projection raised on a hostile result (oracle: crash).
|
||||
ProjectCrash { error: String, callable: bool },
|
||||
/// Import + getattr (+ call for non-expect_callable specs) succeeded.
|
||||
/// `projection` is None when the spec short-circuited (expect_callable)
|
||||
/// — the projection itself is Python-computed (subclass semantics).
|
||||
Found {
|
||||
callable: bool,
|
||||
projection: Option<Projection>,
|
||||
},
|
||||
}
|
||||
|
||||
/// The resolution seam: performs the Python-side IO for one contract.
|
||||
pub trait Invoker {
|
||||
fn invoke(&self, spec: &RunSpec) -> InvokeOutcome;
|
||||
}
|
||||
|
||||
/// contracts.py `_resolve_and_project` — the resolution half's decision
|
||||
/// tree: import-error vs import-crash vs not-found vs call/project crash
|
||||
/// vs found, with the oracle's exact (phase, phase_error, callable,
|
||||
/// projection|None) tuple shape. The expect_callable branch DROPS the
|
||||
/// projection (the oracle never projects when only callability is
|
||||
/// checked).
|
||||
pub fn _resolve_and_project(
|
||||
spec: &RunSpec,
|
||||
invoker: &dyn Invoker,
|
||||
) -> (String, String, bool, Option<Projection>) {
|
||||
match invoker.invoke(spec) {
|
||||
InvokeOutcome::ImportError(e) => ("import_error".into(), e, false, None),
|
||||
InvokeOutcome::ImportCrash(e) => ("crash".into(), e, false, None),
|
||||
InvokeOutcome::NotFound => ("not_found".into(), String::new(), false, None),
|
||||
InvokeOutcome::CallCrash { error, callable }
|
||||
| InvokeOutcome::ProjectCrash { error, callable } => {
|
||||
("crash".into(), error, callable, None)
|
||||
}
|
||||
InvokeOutcome::Found {
|
||||
callable,
|
||||
projection,
|
||||
} => {
|
||||
if spec.expect_callable {
|
||||
("found".into(), String::new(), callable, None)
|
||||
} else {
|
||||
("found".into(), String::new(), callable, projection)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// contracts.py `_run_contract_python` — the full oracle branch tree over
|
||||
/// a resolved spec: import-error skip/fail, crash passthrough, not-found,
|
||||
/// expect_callable, then (in oracle order) not-none → type → keys → len,
|
||||
/// with the exact error strings. `verdict` (the FFI kernel) delegates
|
||||
/// here — one tree, two name-preserving entries.
|
||||
pub fn _run_contract_python(spec: &RunSpec) -> Verdict {
|
||||
let base = Verdict {
|
||||
name: spec.name.clone(),
|
||||
passed: false,
|
||||
@@ -290,15 +412,174 @@ pub fn verdict(spec: &RunSpec) -> Verdict {
|
||||
}
|
||||
}
|
||||
|
||||
/// The registry as typed specs (order = oracle CONTRACTS order).
|
||||
pub fn registry() -> Vec<RunSpec> {
|
||||
serde_json::from_str::<serde_json::Value>(REGISTRY_JSON)
|
||||
.ok()
|
||||
.and_then(|v| {
|
||||
serde_json::from_value::<Vec<RunSpec>>(v.get("contracts").cloned().unwrap_or_default())
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
/// contracts.py `run_all_contracts` — the order-preserving loop over the
|
||||
/// registry (resolution is pre-computed per spec by the caller's seam).
|
||||
pub fn run_all_contracts(specs: &[RunSpec]) -> Vec<Verdict> {
|
||||
specs.iter().map(_run_contract_python).collect()
|
||||
}
|
||||
|
||||
/// The signature-capture seam: `inspect.signature` on a contracted
|
||||
/// function is Python-only IO. Exceptions and non-callables surface as
|
||||
/// None (the oracle's suppressed-exception skip).
|
||||
pub trait Signaturer {
|
||||
fn signature_of(&self, module: &str, function: &str) -> Option<String>;
|
||||
}
|
||||
|
||||
/// contracts.py `capture_signatures` — the loop over the contract
|
||||
/// registry with the oracle's "module.function" key format and the
|
||||
/// skip-on-None discipline (import failures and non-callables drop out).
|
||||
pub fn capture_signatures(signer: &dyn Signaturer, specs: &[RunSpec]) -> BTreeMap<String, String> {
|
||||
let mut sigs = BTreeMap::new();
|
||||
for spec in specs {
|
||||
if let Some(sig) = signer.signature_of(&spec.module, &spec.function) {
|
||||
sigs.insert(format!("{}.{}", spec.module, spec.function), sig);
|
||||
}
|
||||
}
|
||||
sigs
|
||||
}
|
||||
|
||||
/// Python `json.dumps` string escaping (ensure_ascii=True): quotes and
|
||||
/// backslashes; \n \t \r \b \f shorthands; every other codepoint outside
|
||||
/// 0x20..=0x7E as \uXXXX lowercase hex (surrogate pairs above BMP).
|
||||
fn py_json_escape(s: &str) -> String {
|
||||
let mut out = String::with_capacity(s.len() + 2);
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'"' => out.push_str("\\\""),
|
||||
'\\' => out.push_str("\\\\"),
|
||||
'\n' => out.push_str("\\n"),
|
||||
'\t' => out.push_str("\\t"),
|
||||
'\r' => out.push_str("\\r"),
|
||||
'\u{8}' => out.push_str("\\b"),
|
||||
'\u{c}' => out.push_str("\\f"),
|
||||
c if (c as u32) >= 0x20 && (c as u32) <= 0x7E => out.push(c),
|
||||
c => {
|
||||
let cp = c as u32;
|
||||
if cp <= 0xFFFF {
|
||||
out.push_str(&format!("\\u{:04x}", cp));
|
||||
} else {
|
||||
let v = cp - 0x1_0000;
|
||||
let hi = 0xD800 + (v >> 10);
|
||||
let lo = 0xDC00 + (v & 0x3FF);
|
||||
out.push_str(&format!("\\u{:04x}\\u{:04x}", hi, lo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// contracts.py `save_signatures` — the file CONTENT half (the makedirs +
|
||||
/// write stay at the seam). Byte-parity with `json.dump(sigs, f,
|
||||
/// indent=2)`: two-space indent, ": " separators, ensure_ascii escaping.
|
||||
/// Key order: the oracle preserves dict insertion order; this port emits
|
||||
/// sorted order (BTreeMap) — identical bytes for every sorted-inserted
|
||||
/// map, including all frozen rows.
|
||||
pub fn save_signatures(sigs: &BTreeMap<String, String>) -> String {
|
||||
if sigs.is_empty() {
|
||||
return "{}".to_string();
|
||||
}
|
||||
let body: Vec<String> = sigs
|
||||
.iter()
|
||||
.map(|(k, v)| format!(" \"{}\": \"{}\"", py_json_escape(k), py_json_escape(v)))
|
||||
.collect();
|
||||
format!("{{\n{}\n}}", body.join(",\n"))
|
||||
}
|
||||
|
||||
/// contracts.py `load_signatures` — the parse half: missing file (None),
|
||||
/// corrupt JSON, and non-string values all degrade to the empty map,
|
||||
/// exactly like the oracle's suppressed-exception `return {}`.
|
||||
pub fn load_signatures(content: Option<&str>) -> BTreeMap<String, String> {
|
||||
let Some(text) = content else {
|
||||
return BTreeMap::new();
|
||||
};
|
||||
serde_json::from_str::<BTreeMap<String, String>>(text).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// The argv/stdout/exit-code IO seam for `contracts_main`.
|
||||
pub trait MainIO {
|
||||
/// The full registry run (resolution seam applied per spec).
|
||||
fn run_all(&self) -> Vec<Verdict>;
|
||||
/// Live signature capture (Signaturer seam applied).
|
||||
fn capture_signatures(&self) -> BTreeMap<String, String>;
|
||||
/// The saved signatures file (load seam).
|
||||
fn load_signatures(&self) -> BTreeMap<String, String>;
|
||||
/// Persist captured signatures (save seam).
|
||||
fn save_signatures(&self, sigs: &BTreeMap<String, String>);
|
||||
}
|
||||
|
||||
/// contracts.py `main` — the CLI dispatch kernel: argv branch selection,
|
||||
/// the exact output bytes (emoji, = rules, count line, drift section),
|
||||
/// and the exit-code rules (usage/bogus/failures exit 1). Returns
|
||||
/// (exit_code, stdout) instead of writing/process-exiting — the IO the
|
||||
/// oracle does to sys.stdout/sys.exit stays at the seam.
|
||||
pub fn contracts_main(argv: &[String], io: &dyn MainIO) -> (i32, String) {
|
||||
let mut out = String::new();
|
||||
if argv.len() < 2 {
|
||||
out.push_str("Usage: contracts.py [test|signatures|drift]\n");
|
||||
return (1, out);
|
||||
}
|
||||
let cmd = argv[1].as_str();
|
||||
match cmd {
|
||||
"test" => {
|
||||
out.push_str("\u{1F50D} Contract Tests\n");
|
||||
out.push_str(&"=".repeat(50));
|
||||
out.push('\n');
|
||||
let results = io.run_all();
|
||||
let passed = results.iter().filter(|r| r.passed).count();
|
||||
let failed = results.len() - passed;
|
||||
for r in &results {
|
||||
if r.passed {
|
||||
out.push_str(&format!(" \u{2705} {}\n", r.name));
|
||||
} else {
|
||||
out.push_str(&format!(" \u{274C} {}: {}\n", r.name, r.error));
|
||||
}
|
||||
}
|
||||
out.push_str(&"=".repeat(50));
|
||||
out.push('\n');
|
||||
out.push_str(&format!("Results: {passed} passed, {failed} failed\n"));
|
||||
let current = io.capture_signatures();
|
||||
let saved = io.load_signatures();
|
||||
let drifts = check_signature_drift(¤t, &saved);
|
||||
if !drifts.is_empty() {
|
||||
out.push_str(&format!(
|
||||
"\n\u{26A0}\u{FE0F} Signature drift detected ({}):\n",
|
||||
drifts.len()
|
||||
));
|
||||
for d in &drifts {
|
||||
out.push_str(&format!(" {d}\n"));
|
||||
}
|
||||
}
|
||||
io.save_signatures(¤t);
|
||||
(i32::from(failed > 0), out)
|
||||
}
|
||||
"signatures" => {
|
||||
let sigs = io.capture_signatures();
|
||||
for (key, sig) in &sigs {
|
||||
out.push_str(&format!("{key}{sig}\n"));
|
||||
}
|
||||
io.save_signatures(&sigs);
|
||||
(0, out)
|
||||
}
|
||||
"drift" => {
|
||||
let current = io.capture_signatures();
|
||||
let saved = io.load_signatures();
|
||||
let drifts = check_signature_drift(¤t, &saved);
|
||||
if !drifts.is_empty() {
|
||||
out.push_str(&format!("Signature drift detected ({}):\n", drifts.len()));
|
||||
for d in &drifts {
|
||||
out.push_str(&format!(" {d}\n"));
|
||||
}
|
||||
} else {
|
||||
out.push_str("No signature drift detected.\n");
|
||||
}
|
||||
(0, out)
|
||||
}
|
||||
other => {
|
||||
out.push_str(&format!("Unknown command: {other}\n"));
|
||||
(1, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── FFI ─────────────────────────────────────────────────────────────────────
|
||||
@@ -338,7 +619,7 @@ pub extern "C" fn ct_verdict(arg: *const std::os::raw::c_char) -> *mut std::os::
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_drift(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let parse = |k: &str| -> Result<std::collections::BTreeMap<String, String>, String> {
|
||||
let parse = |k: &str| -> Result<BTreeMap<String, String>, String> {
|
||||
match a.get(k) {
|
||||
Some(serde_json::Value::Object(m)) => m
|
||||
.iter()
|
||||
@@ -351,7 +632,7 @@ pub extern "C" fn ct_drift(arg: *const std::os::raw::c_char) -> *mut std::os::ra
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
_ => Ok(std::collections::BTreeMap::new()),
|
||||
_ => Ok(BTreeMap::new()),
|
||||
}
|
||||
};
|
||||
let current = parse("current")?;
|
||||
@@ -367,6 +648,221 @@ pub extern "C" fn ct_registry() -> *mut std::os::raw::c_char {
|
||||
envelope(Ok(serde_json::json!(registry())))
|
||||
}
|
||||
|
||||
// ── FFI (gap-close kernels) ─────────────────────────────────────────────────
|
||||
|
||||
struct FfiProbe(Result<bool, String>);
|
||||
|
||||
impl CoreProbe for FfiProbe {
|
||||
fn core_available(&self) -> Result<bool, String> {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// ct_gate({"available": bool} | {"error": str}) -> bool — the _ct_core
|
||||
/// gate decision over a loader-state probe outcome.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_gate(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).map(|a| {
|
||||
let probe = if let Some(e) = a.get("error").and_then(|v| v.as_str()) {
|
||||
FfiProbe(Err(e.to_string()))
|
||||
} else {
|
||||
FfiProbe(Ok(a
|
||||
.get("available")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false)))
|
||||
};
|
||||
serde_json::json!(_ct_core(&probe))
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_resolve({spec..., "outcome": {kind, error?, callable?, projection?}})
|
||||
/// -> [phase, phase_error, callable, projection|null] — the
|
||||
/// _resolve_and_project mapping over one resolution-seam outcome.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_resolve(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let spec: RunSpec = serde_json::from_value(a.clone()).map_err(|e| e.to_string())?;
|
||||
let out = a.get("outcome").cloned().unwrap_or(serde_json::Value::Null);
|
||||
let kind = out.get("kind").and_then(|v| v.as_str()).unwrap_or("found");
|
||||
let err = |k: &str| {
|
||||
out.get(k)
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or_default()
|
||||
.to_string()
|
||||
};
|
||||
let callable = out
|
||||
.get("callable")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
let projection: Option<Projection> = out
|
||||
.get("projection")
|
||||
.cloned()
|
||||
.and_then(|p| serde_json::from_value(p).ok());
|
||||
let outcome = match kind {
|
||||
"import_error" => InvokeOutcome::ImportError(err("error")),
|
||||
"import_crash" => InvokeOutcome::ImportCrash(err("error")),
|
||||
"not_found" => InvokeOutcome::NotFound,
|
||||
"call_crash" => InvokeOutcome::CallCrash {
|
||||
error: err("error"),
|
||||
callable,
|
||||
},
|
||||
"project_crash" => InvokeOutcome::ProjectCrash {
|
||||
error: err("error"),
|
||||
callable,
|
||||
},
|
||||
_ => InvokeOutcome::Found {
|
||||
callable,
|
||||
projection,
|
||||
},
|
||||
};
|
||||
struct FfiInvoker(InvokeOutcome);
|
||||
impl Invoker for FfiInvoker {
|
||||
fn invoke(&self, _spec: &RunSpec) -> InvokeOutcome {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
let (phase, phase_error, callable, projection) =
|
||||
_resolve_and_project(&spec, &FfiInvoker(outcome));
|
||||
Ok(serde_json::json!([
|
||||
phase,
|
||||
phase_error,
|
||||
callable,
|
||||
projection,
|
||||
]))
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_run_python(spec) -> ContractResult fields — the
|
||||
/// `_run_contract_python` tree over a resolved spec.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_run_python(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let spec: RunSpec = serde_json::from_value(a).map_err(|e| e.to_string())?;
|
||||
serde_json::to_value(_run_contract_python(&spec)).map_err(|e| e.to_string())
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_run_all([specs]) -> [ContractResult fields] — the
|
||||
/// `run_all_contracts` order-preserving loop.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_run_all(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let specs: Vec<RunSpec> = serde_json::from_value(a).map_err(|e| e.to_string())?;
|
||||
serde_json::to_value(run_all_contracts(&specs)).map_err(|e| e.to_string())
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_capture({"table": {"module.function": sig}, "specs": [specs]}) ->
|
||||
/// the capture_signatures map (missing table key = None → skipped).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_capture(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let table: BTreeMap<String, String> = a
|
||||
.get("table")
|
||||
.and_then(|v| v.as_object())
|
||||
.map(|m| {
|
||||
m.iter()
|
||||
.map(|(k, v)| Ok((k.clone(), v.as_str().ok_or("non-string sig")?.to_string())))
|
||||
.collect::<Result<_, String>>()
|
||||
})
|
||||
.unwrap_or_else(|| Ok(BTreeMap::new()))?;
|
||||
let specs: Vec<RunSpec> = serde_json::from_value(
|
||||
a.get("specs")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!([])),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
struct FfiSigner(BTreeMap<String, String>);
|
||||
impl Signaturer for FfiSigner {
|
||||
fn signature_of(&self, module: &str, function: &str) -> Option<String> {
|
||||
self.0.get(&format!("{module}.{function}")).cloned()
|
||||
}
|
||||
}
|
||||
serde_json::to_value(capture_signatures(&FfiSigner(table), &specs))
|
||||
.map_err(|e| e.to_string())
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_save(sigs) -> the save_signatures file content (Python
|
||||
/// json.dump(indent=2) bytes).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_save(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let sigs: BTreeMap<String, String> =
|
||||
serde_json::from_value(a).map_err(|e| e.to_string())?;
|
||||
Ok(serde_json::json!(save_signatures(&sigs)))
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_load(content | null) -> the load_signatures map (missing/corrupt →
|
||||
/// {}).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_load(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let content = a.as_str().map(|s| s.to_string());
|
||||
serde_json::to_value(load_signatures(content.as_deref())).map_err(|e| e.to_string())
|
||||
}))
|
||||
}
|
||||
|
||||
/// ct_main({"argv": [...], "run_all": [verdicts], "sigs": {...},
|
||||
/// "saved": {...}}) -> {exit_code, stdout} — the contracts_main dispatch
|
||||
/// kernel over canned runner state.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ct_main(arg: *const std::os::raw::c_char) -> *mut std::os::raw::c_char {
|
||||
envelope(read_arg(arg).and_then(|a| {
|
||||
let argv: Vec<String> = serde_json::from_value(
|
||||
a.get("argv")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!([])),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let run_all: Vec<Verdict> = serde_json::from_value(
|
||||
a.get("run_all")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!([])),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let sigs: BTreeMap<String, String> = serde_json::from_value(
|
||||
a.get("sigs")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!({})),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let saved: BTreeMap<String, String> = serde_json::from_value(
|
||||
a.get("saved")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| serde_json::json!({})),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
struct FfiMain {
|
||||
run_all: Vec<Verdict>,
|
||||
sigs: BTreeMap<String, String>,
|
||||
saved: BTreeMap<String, String>,
|
||||
}
|
||||
impl MainIO for FfiMain {
|
||||
fn run_all(&self) -> Vec<Verdict> {
|
||||
self.run_all.clone()
|
||||
}
|
||||
fn capture_signatures(&self) -> BTreeMap<String, String> {
|
||||
self.sigs.clone()
|
||||
}
|
||||
fn load_signatures(&self) -> BTreeMap<String, String> {
|
||||
self.saved.clone()
|
||||
}
|
||||
fn save_signatures(&self, _sigs: &BTreeMap<String, String>) {}
|
||||
}
|
||||
let (code, stdout) = contracts_main(
|
||||
&argv,
|
||||
&FfiMain {
|
||||
run_all,
|
||||
sigs,
|
||||
saved,
|
||||
},
|
||||
);
|
||||
Ok(serde_json::json!({"exit_code": code, "stdout": stdout}))
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -423,3 +919,7 @@ mod tests {
|
||||
#[cfg(test)]
|
||||
#[path = "ct_battery.rs"]
|
||||
mod ct_battery;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "gap_battery.rs"]
|
||||
mod gap_battery;
|
||||
@@ -20,5 +20,5 @@ construction_pattern dichotomy gap-close: 6 audit-missing functions (_need_dict,
|
||||
|
||||
- builder:factory-gap-cp
|
||||
- builder:factory-gap-cp
|
||||
- feat 0fb08c63 — battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins
|
||||
- feat 1ad658cf — battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Close the PARTIAL gaps in src/rust/memory_selector against the src/rune/memory_selector.py oracle (dichotomy wave, issue #2479 tranche): the three audit-named functions (add_source registry kernel — position-preserving replace; _source_store persona-lane gate through mse_persona_wanted + merge through mse_store_project; _mse_core probe contract frozen under the RUNE_MSE_CORE=python pin), frozen-truth battery generated against the live oracle through the ms_freeze_seams rig (FTS-seeded hermetic store, byte-identical --verify), Rust battery + clippy -D warnings clean, live parity 536/536 (frozen FFI rows, fuzz registry ops, dual-mode facade), Python oracle tests green under both pins, Phase B language-advantage pass.
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T17:35:03Z", "contract": "BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms", "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_memory_selector_parity.py", "scripts/gen_memory_selector_truth.py", "scripts/ms_freeze_seams/sitecustomize.py", "src/rune/memory_selector.py", "src/rune/mse_loader.py", "src/rust/memory_selector/frozen_truth.json", "src/rust/memory_selector/src/branch_battery.rs", "src/rust/memory_selector/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-gap-ms
|
||||
- builder:factory-gap-ms
|
||||
- builder:factory-gap-ms
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Close the identity_anchors dichotomy-port PARTIAL gaps (#2479 wave): port the 8 audit-missing functions (show_anchors, show_rules, show_pronouns, _announcement_patterns, _pronoun_patterns, _hedge_patterns, _sycophancy_patterns, _cc_core) from the Python oracle src/rune/identity_anchors.py into the existing cognition_core Rust kernels (src/rust/cognition_core/src/broker.rs — extended, no new crate) name-preserving, logic 1:1: the behavior lattices are the core port surface (embedded JSON snapshots generated from the frozen truth, replay-verified); the show surface renders behind the data-injection seam (table as argument, Python data stays the runtime authority); _pattern_triples is the real 35-row authority; check_genuineness matches over the embedded performative lattice; _cc_core is the pin-decision mirror; identity_handle_hook carries the 'default' envelope. doc-envelope FFI cc_* family via cc_loader (freeing via cc_free_string, never re-exported) + facade delegation pinned by the existing RUNE_COGNITION_CORE gate. Freeze shared-harness truth (scripts/freeze_truth.py, RUNE_COGNITION_CORE=python pinned via the ia_freeze_seams rig, show_* stdout captured by the rig wrappers, no absolute paths in truth) embedded VERBATIM in the Rust battery; clippy --all-targets -D warnings 0; crate builds; live parity 100% on the new fns both pins; Python suite both pins green; Phase B language-advantage pass (OnceLock lattice caches, prefixed() combinator, fmt::Write renderers).
|
||||
|
||||
## 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-13T17:41:38Z", "contract": "BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia", "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"]}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-gap-ia
|
||||
- builder:factory-gap-ia
|
||||
- builder:factory-gap-ia
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
Close the PARTIAL gaps in src/rust/contracts against the src/rune/contracts.py oracle (dichotomy wave, issue #2479 tranche): name-preserving 1:1 port of the 7 unmatched functions (_ct_core, _resolve_and_project, _run_contract_python, capture_signatures, save_signatures, load_signatures, main), IO behind injectable seams, frozen-truth battery generated against the live Python oracle via the shared harness scripts/freeze_truth.py (RUNE core pinned to python, deep-copied inputs), existing tests green + clippy clean, live parity 100% on the new functions, Phase B language-advantage pass.
|
||||
|
||||
## What it connects to
|
||||
|
||||
(no affected surface recorded)
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T17:55:45Z", "contract": "BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct", "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/ct_rig.py", "scripts/ct_rig_badimport.py", "scripts/gen_contracts_gap_truth.py", "scripts/open_contract_contracts_gap.py", "src/rune/contracts_loader.py", "src/rust/contracts/src/ct_gap_truth.json", "src/rust/contracts/src/gap_battery.rs", "src/rust/contracts/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-gap-ct
|
||||
- builder:factory-gap-ct
|
||||
- builder:factory-gap-ct
|
||||
- closure-record
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T22:11:49Z-3df478-factory-gap-mconn
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
model_connect dichotomy gap-close (GO): name-preserving port of the 4 audit-missing functions (_ctx_budget, _now, _get_cloud_models, handle_hook) into src/go/model-connect as CtxBudget / Now / GetCloudModels / HandleHook, wall clock behind the injectable MCONN_CLOCK seam, hermetic HOME via scripts/mconn_freeze_seams, frozen-truth battery (truth.json, 40-case envelope) generated against the live Python oracle and verified byte-identical via freeze_truth.py, embedded VERBATIM in truth_test.go TestFrozenTruthReplay (3/3); CI replay binary 40/40; live parity sweep 44/44 (scripts/check_model_connect_parity.py), gofmt/vet/go build clean, Python oracle smoke green both pins. Oracle quirks preserved and frozen: string-blind JSONC // strip (URL corruption -> []), partial cloud list on mid-provider shape errors, insertion-order provider/model iteration, live model_registry constants (OUTPUT_RESERVE default 2048 / TOOL_RESULT_RESERVE 1024). Dichotomy audit 7/11 PARTIAL -> 11/11 FULL. Delivered on gitea/master: feat 1f2fe468.
|
||||
|
||||
## 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: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- parity 1f2fe468
|
||||
- parity 1f2fe468
|
||||
- parity 1f2fe468
|
||||
- parity 1f2fe468
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T22:30:08Z-fd6e49-factory-gap-wi
|
||||
|
||||
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
witness dichotomy gap-close (GO): name-preserving port of the 4 audit-missing functions (_now, log_entry, read_log, log_stats) into src/go/witness as now / logEntry / readLog / logStats with the injectable clock + log-path seams, plus parity-driven defect fixes to the old-era port: current 20-pattern correction table + family tables, kernel-parity extract_topic (ASCII \w runs, cap 5), detect_signals kernel order (error → correction → completion → drift → commitment → contradiction → preference → urgency → learning) with case-insensitive family matching, rune-safe [:200] error_text and context[-500:], extraction-ordered new_topics, num_ctx 30720 via the _ctx_budget seam, and json.dumps byte-parity log lines (separators, insertion order, ensure_ascii). Frozen-truth battery (truth.json, 58 cases incl. the capital-letter is_correction quirk, completion triple, half-even skip_rate 37.5→38%) generated against the live oracle and verified byte-identical via freeze_truth.py, embedded VERBATIM in truth_test.go TestFrozenTruthReplay + seam units (deque read semantics, malformed/blank lines, list-shaped signal_types, log-line bytes, rune truncation); live parity sweep 59/59 with byte-compared log files (scripts/check_witness_parity.py); gofmt/vet/go build clean; Python oracle battery green both pins (16 live + 9 under RUNE_COGNITION_CORE=python). Dichotomy audit 11/15 PARTIAL -> 15/15 FULL. Delivered on gitea/master: feat cc51b181.
|
||||
|
||||
## 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: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- parity cc51b181
|
||||
- parity cc51b181
|
||||
- parity cc51b181
|
||||
- parity cc51b181
|
||||
@@ -0,0 +1,24 @@
|
||||
# Contract BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp
|
||||
|
||||
**Phase:** verifying · **Mode:** n/a · **Depth:** n/a
|
||||
|
||||
## What was built
|
||||
|
||||
growth_pipeline FULL Rust port (salvage landing — cancelled-agent commits verified + pushed post-cancel; contract closed post-hoc per the scaffolding law)
|
||||
|
||||
## What it connects to
|
||||
|
||||
- `src/rune/growth_pipeline.py`
|
||||
- `src/rust/growth_pipeline/`
|
||||
|
||||
## How to update those connections
|
||||
|
||||
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
|
||||
- Evidence trail: 3 checkpoint(s) recorded on the contract entity.
|
||||
- Quality at close: not recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
- builder:factory-salvage-gp
|
||||
- builder:factory-salvage-gp
|
||||
- builder:factory-salvage-gp
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
},
|
||||
{
|
||||
"at": "2026-10-13T17:00:32Z",
|
||||
"evidence": "feat 0fb08c63 \u2014 battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins",
|
||||
"evidence": "feat 1ad658cf \u2014 battery 14/14, clippy 0, harness 18/18, live parity 192/192 both pins, pytest 30/30+20/20 both pins",
|
||||
"note": "",
|
||||
"phase": "verifying"
|
||||
},
|
||||
|
||||
+5925
File diff suppressed because it is too large.
Load diff
+5984
File diff suppressed because it is too large.
Load diff
+6000
File diff suppressed because it is too large.
Load diff
+5927
File diff suppressed because it is too large.
Load diff
+5881
File diff suppressed because it is too large.
Load diff
+5959
File diff suppressed because it is too large.
Load diff
+6118
File diff suppressed because it is too large.
Load diff
@@ -3917,3 +3917,44 @@
|
||||
{"builder": "factory-gap-ec", "detail": "BUILDER-2026-10-13T17:23:31Z-6d39fd-factory-gap-ec closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:24:49Z", "operation": "close"}
|
||||
{"builder": "factory-gap-cp", "detail": "BUILDER-2026-10-13T13:18:48Z-5b5364-factory-gap-cp \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:00:32Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-cp", "detail": "BUILDER-2026-10-13T13:18:48Z-5b5364-factory-gap-cp closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:00:50Z", "operation": "close"}
|
||||
{"builder": "factory-gap-ms", "detail": "need-2026-10-13T17:33:38Z-factory-gap-ms \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:33:39Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-ms", "detail": "BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:34:02Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ms", "detail": "BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:34:21Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ms", "detail": "BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:34:41Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ms", "detail": "BUILDER-2026-10-13T17:33:39Z-236e93-factory-gap-ms closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:35:03Z", "operation": "close"}
|
||||
{"builder": "factory-gap-ia", "detail": "need-2026-10-13T17:40:20Z-factory-gap-ia \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:40:21Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-ia", "detail": "BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:40:40Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ia", "detail": "BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:40:59Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ia", "detail": "BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:41:19Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ia", "detail": "BUILDER-2026-10-13T17:40:21Z-dca2b3-factory-gap-ia closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:41:38Z", "operation": "close"}
|
||||
{"builder": "factory-gap-ct", "detail": "need-2026-10-13T17:54:27Z-factory-gap-ct \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:54:28Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-ct", "detail": "BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:54:47Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ct", "detail": "BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:55:06Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ct", "detail": "BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:55:26Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ct", "detail": "BUILDER-2026-10-13T17:54:28Z-10bd7d-factory-gap-ct closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T17:55:45Z", "operation": "close"}
|
||||
{"builder": "factory-gap-ci", "detail": "need-2026-10-13T18:05:48Z-factory-gap-ci \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T18:05:50Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-ci", "detail": "BUILDER-2026-10-13T18:05:50Z-7c2bad-factory-gap-ci \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T18:06:21Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ci", "detail": "BUILDER-2026-10-13T18:05:50Z-7c2bad-factory-gap-ci \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T18:06:44Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ci", "detail": "BUILDER-2026-10-13T18:05:50Z-7c2bad-factory-gap-ci \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T18:07:03Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-ci", "detail": "BUILDER-2026-10-13T18:05:50Z-7c2bad-factory-gap-ci closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T18:07:23Z", "operation": "close"}
|
||||
{"builder": "factory-gap-mconn", "detail": "need-2026-10-13T22:11:47Z-factory-gap-mconn \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:11:49Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-mconn", "detail": "BUILDER-2026-10-13T22:11:49Z-3df478-factory-gap-mconn \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:12:12Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-mconn", "detail": "BUILDER-2026-10-13T22:11:49Z-3df478-factory-gap-mconn \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:12:36Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-mconn", "detail": "BUILDER-2026-10-13T22:11:49Z-3df478-factory-gap-mconn \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:13:01Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-mconn", "detail": "BUILDER-2026-10-13T22:11:49Z-3df478-factory-gap-mconn \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:13:24Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-wi", "detail": "need-2026-10-13T22:30:01Z-factory-gap-wi \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:30:08Z", "operation": "submit_need"}
|
||||
{"builder": "factory-gap-wi", "detail": "BUILDER-2026-10-13T22:30:08Z-fd6e49-factory-gap-wi \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:31:12Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-wi", "detail": "BUILDER-2026-10-13T22:30:08Z-fd6e49-factory-gap-wi \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:32:13Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-wi", "detail": "BUILDER-2026-10-13T22:30:08Z-fd6e49-factory-gap-wi \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:33:08Z", "operation": "transition"}
|
||||
{"builder": "factory-gap-wi", "detail": "BUILDER-2026-10-13T22:30:08Z-fd6e49-factory-gap-wi \u2192 closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T22:34:04Z", "operation": "transition"}
|
||||
{"builder": "factory-salvage-gp", "detail": "need-2026-10-13T23:41:27Z-factory-salvage-gp \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:41:31Z", "operation": "submit_need"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:41:48Z", "operation": "transition"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:42:04Z", "operation": "transition"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:42:19Z", "operation": "transition"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:42:38Z", "operation": "close"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:44:49Z", "operation": "close"}
|
||||
{"builder": "factory-salvage-gp", "detail": "BUILDER-2026-10-13T22:45:00Z-gpsalv-factory-salvage-gp closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:45:54Z", "operation": "close"}
|
||||
{"builder": "test-kernel-rebuild-trap", "detail": "need-2026-10-13T23:53:16Z-test-kernel-rebuild-trap \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:53:20Z", "operation": "submit_need"}
|
||||
{"builder": "test-kernel-rebuild-trap", "detail": "BUILDER-2099-01-01T00:00:00Z-kerneltrap-regression \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:53:37Z", "operation": "transition"}
|
||||
{"builder": "test-kernel-rebuild-trap", "detail": "BUILDER-2099-01-01T00:00:00Z-kerneltrap-regression \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:53:53Z", "operation": "transition"}
|
||||
{"builder": "test-kernel-rebuild-trap", "detail": "BUILDER-2099-01-01T00:00:00Z-kerneltrap-regression \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:54:10Z", "operation": "transition"}
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Regression test: the kernel-rebuild trap in close_contract.
|
||||
|
||||
record_observed_impact delegates to the Rust core when the structural_store
|
||||
cdylib is live — and the kernel rebuilds doc["entities"] with FRESH objects.
|
||||
close_contract previously captured the entity reference BEFORE that call and
|
||||
mutated the orphaned object: contract_quality vanished from the store and
|
||||
construction_interface.close() KeyError'd on re-read. Only fired with the
|
||||
.so built (fresh worktrees lack it — agents never saw it; the coordinator's
|
||||
checkout did)."""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rune.structural_store import new_doc, add_entity
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ci():
|
||||
from rune.construction_interface import ConstructionInterface
|
||||
import os
|
||||
os.environ.setdefault(
|
||||
"CS_RUST_LIB",
|
||||
"/mnt/workdrive/rune/src/rust/capability_scoring/target/release/libcapability_scoring.so",
|
||||
)
|
||||
return ConstructionInterface(builder="test-kernel-rebuild-trap")
|
||||
|
||||
|
||||
def test_close_contract_persists_quality_with_kernel_live(ci, tmp_path):
|
||||
"""With the Rust core live (kernel-rebuild path), close_contract's
|
||||
quality mutation must survive into the persisted doc."""
|
||||
import os
|
||||
if not Path(os.environ["CS_RUST_LIB"]).exists():
|
||||
pytest.skip("capability_scoring kernel not built")
|
||||
cid = "BUILDER-2099-01-01T00:00:00Z-kerneltrap-regression"
|
||||
ci.submit_need(
|
||||
"regression probe",
|
||||
contract_id=cid,
|
||||
affected_surface=["src/rust/growth_pipeline/"],
|
||||
)
|
||||
for phase in ("approved", "building", "verifying"):
|
||||
r = ci.transition(cid, phase)
|
||||
assert r.get("success"), f"transition to {phase} failed: {r}"
|
||||
doc = ci.scaffold.load()
|
||||
ci.scaffold.close_contract(
|
||||
doc, cid,
|
||||
observed_evidence=[{"type": "commit", "ref": "deadbeef"}],
|
||||
scope_files=["src/rust/growth_pipeline/"],
|
||||
)
|
||||
ci.scaffold.commit(doc, what="regression test close")
|
||||
doc2 = ci.scaffold.load()
|
||||
e = [x for x in doc2["entities"] if x["id"] == f"contract:{cid}"][0]
|
||||
assert "contract_quality" in e.get("ext", {}), (
|
||||
"kernel-rebuild trap: quality mutation lost after "
|
||||
"record_observed_impact rebuilt doc entities"
|
||||
)
|
||||
assert e["phase"] == "closed"
|
||||
# cleanup: remove the probe contract so the shared store stays clean
|
||||
doc3 = ci.scaffold.load()
|
||||
doc3["entities"] = [x for x in doc3["entities"] if x["id"] != f"contract:{cid}"]
|
||||
ci.scaffold.commit(doc3, what="regression test cleanup")
|
||||
seg = Path(f"store/scaffold/segments/entities/contract__BUILDER-2099-01-01T00__00__00Z-kerneltrap-regression.json")
|
||||
if seg.exists():
|
||||
seg.unlink()
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1,62 @@
|
||||
# model_connect dichotomy gap-close — verification summary
|
||||
|
||||
- **Module**: model_connect (GO port, src/go/model-connect)
|
||||
- **Worktree**: /mnt/workdrive/rune-wave-cl (gitea/master base 64cc5125)
|
||||
- **Parity SHA**: see SHAs below (feat commit; filled at push time)
|
||||
|
||||
## Coverage
|
||||
|
||||
Dichotomy audit: model_connect **7/11 PARTIAL → 11/11 FULL** (GO).
|
||||
Ported name-preserving: `CtxBudget` (_ctx_budget), `Now` (_now),
|
||||
`GetCloudModels` (_get_cloud_models), `HandleHook` (handle_hook).
|
||||
Oracle quirks preserved (all frozen on the oracle shape):
|
||||
- JSONC `//` strip is string-blind — a URL inside the config loses its
|
||||
closing quote and the parse fails → `[]` (frozen row `url_corruption`)
|
||||
- mid-provider shape error returns the PARTIAL accumulated list (the
|
||||
oracle's try/except wraps the whole loop; frozen row `broken_late` → `[a/m1]`)
|
||||
- provider/model iteration order is dict insertion order — Go parses with
|
||||
a json.Decoder token walk preserving key order
|
||||
- `null` models dict → `None.items()` raises → partial/empty return
|
||||
- `_ctx_budget` constants from the LIVE model_registry oracle:
|
||||
OUTPUT_RESERVE["default"]=2048, TOOL_RESULT_RESERVE=1024 (non-local only),
|
||||
num_ctx floor 1024, 0-window → 8192 (`or` floor)
|
||||
- `_now` behind the injectable clock seam (no-clock law); battery/parity
|
||||
pin it (MCONN_CLOCK / frozen_now), unpinned default reads wall clock
|
||||
|
||||
## Commands and exit codes
|
||||
|
||||
| Check | Command | Exit | Evidence |
|
||||
|---|---|---|---|
|
||||
| truth generation | `PYTHONPATH=scripts/mconn_freeze_seams:src python3 scripts/gen_model_connect_truth.py` | 0 | `mconn-truth-gen.log/.exit` — 40 cases, `_now` pinned row asserted |
|
||||
| frozen truth byte-identical | `PYTHONPATH=scripts/mconn_freeze_seams:src python3 scripts/freeze_truth.py --verify src/go/model-connect/truth.json --module rune.model_connect` | 0 | `mconn-freeze-verify.log/.exit` — OK: 40 cases byte-identical against live oracle |
|
||||
| gofmt / vet / build | `gofmt -l . && go vet ./... && go build ./...` (src/go/model-connect) | 0 | `mconn-gofmt.log` (empty), `mconn-govet.log`, `mconn-gobuild.log` + `.exit` |
|
||||
| Go battery | `go test -count=1 -v ./...` (src/go/model-connect) | 0 | `mconn-gotest.log/.exit` — 3/3 PASS (TestFrozenTruthReplay verbatim truth.json embed, TestStripJsoncPreservesOracleQuirks, TestGetCloudModelsPartialOnLateShapeError) |
|
||||
| CI replay binary | `./model-connect replay truth.json` | 0 | `mconn-replay.log/.exit` — 40/40 passed |
|
||||
| live parity | `python3 scripts/check_model_connect_parity.py` | 0 | `mconn-parity.log/.exit` — parity: 44/44 match |
|
||||
| Python smoke (live) | `python3 /tmp/mconn-smoke.py` | 0 | `mconn-pysmoke-live.log/.exit` — all 7 ported fns healthy |
|
||||
| Python smoke (python pin) | `RUNE_MODEL_CONNECT_CORE=python python3 /tmp/mconn-smoke.py` | 0 | `mconn-pysmoke-python.log/.exit` — healthy (module has no loader seam; pin vacuous, run per protocol) |
|
||||
| audit | `dichotomy_audit.py` row capture | 0 | `mconn-audit.log/.exit` — 11/11 matched, status FULL |
|
||||
|
||||
Note: model_connect has no dedicated pytest suite and no
|
||||
RUNE_MODEL_CONNECT_CORE loader (plain plugin module — verified by grep);
|
||||
"Python suite green in BOTH pins" is satisfied by the oracle smoke above
|
||||
plus the byte-identity gate, which replays the live oracle itself.
|
||||
|
||||
## Truth rig
|
||||
|
||||
- `scripts/mconn_freeze_seams/sitecustomize.py` — pin_home (hermetic HOME)
|
||||
+ binds `_get_cloud_models_seeded` / `_get_cloud_models_missing` seams
|
||||
onto the oracle module (fixture text rides in the truth rows; the Go
|
||||
battery rebuilds the same rig from the case args via t.TempDir).
|
||||
- Envelope: frozen_now `2026-10-14T08:00:00+00:00`, 40 cases:
|
||||
8 clean / 8 moe / 6 route / 7 ctx_budget / 1 now / 3 hook / 6 seeded
|
||||
cloud configs / 1 missing config.
|
||||
|
||||
## Files
|
||||
|
||||
- `src/go/model-connect/main.go` — 4 gap fns + envelope replay + stdin op
|
||||
dispatch for the parity sweep
|
||||
- `src/go/model-connect/truth_test.go` — battery (verbatim truth embed)
|
||||
- `src/go/model-connect/truth.json` — 40-case freeze_truth envelope
|
||||
- `scripts/gen_model_connect_truth.py`, `scripts/check_model_connect_parity.py`,
|
||||
`scripts/mconn_freeze_seams/sitecustomize.py`
|
||||
@@ -0,0 +1 @@
|
||||
exit:0
|
||||
@@ -0,0 +1 @@
|
||||
exit=0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,62 @@
|
||||
# witness GO gap-close — verification summary (#2479, factory-gap-wi)
|
||||
|
||||
Worktree rune-wave-cn. Oracle: src/rune/witness.py (446 lines, 15 audit fns,
|
||||
11/15 → **15/15 FULL (GO)**; programme headline 82→83 FULL after regen).
|
||||
|
||||
## What was ported (name-preserving)
|
||||
|
||||
- `_now` → `now()` with the injectable `clock` seam (Python isoformat shape:
|
||||
6-digit micros when nonzero, `+00:00` offset).
|
||||
- `log_entry` → `logEntry` — append-only JSONL with Python json.dumps
|
||||
byte-parity (", "/": " separators, ensure_ascii, insertion key order:
|
||||
timestamp, session_id, signals, reflection, signal_count).
|
||||
- `read_log` → `readLog` — deque semantics (limit counts LINES), blank +
|
||||
malformed lines skipped, [] on missing file.
|
||||
- `log_stats` → `logStats` — 3-key zero shape without skip_rate on missing
|
||||
file; skip_rate replicates Python f"{x:.0f}%" half-even rounding
|
||||
(37.5→"38%", 62.5→"62%"); signal_types iterates dict keys OR list
|
||||
elements (oracle parity incl. int-key coercion "1"/"2").
|
||||
|
||||
## Defect fixes found by parity (pre-existing divergences)
|
||||
|
||||
- Correction table was the RETIRED 11-pattern set → now the current 20
|
||||
oracle patterns; family tables likewise.
|
||||
- `is_correction` quirk preserved: patterns match AS-IS against lowercased
|
||||
text, so capital-letter patterns (r"\bI (said|meant|asked)\b", …) never
|
||||
fire — frozen, not fixed ("I meant the left column" → False).
|
||||
- `extract_topic` was Fields+TrimRight punctuation → kernel parity:
|
||||
contiguous ASCII \w runs of the lowercased text, rune-len > 3,
|
||||
stopwords, cap 5 ("café résumé matters" → ["matters"]).
|
||||
- `detect_signals`: kernel signal ORDER (error → correction → completion →
|
||||
drift → commitment → contradiction → preference → urgency → learning);
|
||||
case-INSENSITIVE family matching (kernel lowercases pattern and text —
|
||||
richer than public is_correction); rune-safe [:200] error_text (was
|
||||
byte-slicing); new_topics keep EXTRACTION order (was map-random).
|
||||
- `witness_reflect`: num_ctx via the oracle's _ctx_budget(LOCAL_MODEL) =
|
||||
30720 (was hardcoded 8192); rune-safe context[-500:]; prompt renders
|
||||
signals with Python separators.
|
||||
- Log path derives from RUNE_MEMORY_DIR/RUNE_HOME like memory_env (was
|
||||
absent — the log family didn't exist).
|
||||
|
||||
## Divergences documented (not bugs)
|
||||
|
||||
- extract_topic under the RUNE_COGNITION_CORE=python pin: the retired
|
||||
pure-Python oracle used Unicode \w; the Go port follows the kernel's
|
||||
ASCII runs (the frozen authority; the _py oracle raises RuntimeError
|
||||
by design when the kernel is off).
|
||||
- Public is_correction vs kernel correction tables: kernel matching is
|
||||
case-insensitive, the public fn is not (capital-I patterns never fire).
|
||||
Both behaviors frozen separately in truth.json.
|
||||
|
||||
## Gates (all evidence in verification/wi-*.log, exits in wi-*.exit)
|
||||
|
||||
| Gate | Result | Evidence |
|
||||
|---|---|---|
|
||||
| truth freeze gen ×2 | 58 cases byte-identical | wi-freeze-gen.{log,exit} |
|
||||
| freeze_truth --verify ×2 | OK 58 cases byte-identical vs live oracle | wi-freeze-verify{1,2}.log, wi-freeze-verify.exit |
|
||||
| Go battery (truth.json embedded verbatim + seams) | ok rune/witness | wi-gotest.{log,exit} |
|
||||
| Live parity (oracle vs Go binary, incl. byte-compared log files) | 59/59 match | wi-parity.{log,exit} |
|
||||
| gofmt / go vet / go build ./... | clean | wi-gofmt / wi-govet / wi-gobuild |
|
||||
| pytest LIVE (delegation + pinned-paths + cc_loader seam) | 16 passed | wi-pytest-live.{log,exit} |
|
||||
| pytest PINNED (RUNE_COGNITION_CORE=python: pinned-paths + seam) | 9 passed | wi-pytest-pinned.{log,exit} |
|
||||
| ruff (new scripts) | clean | wi-ruff.{log,exit} |
|
||||
Reference in new issue
Block a user