Compare commits

...
23 Commits
Author SHA1 Message Date
conductor 85f4f3ca5e chore(release): auto-bump version to 0.299.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 02:39:22 +01:00
Nick b0d7380fb5 refactor(provider_registry): Phase B language-advantage pass — dichotomy wave 2026-10-14 02:38:57 +01:00
Nick 3d21fe3dac feat(provider_registry): close PARTIAL gaps — dichotomy wave 2026-10-14 02:38:57 +01:00
conductor 257bf77f91 chore(release): auto-bump version to 0.298.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 02:30:46 +01:00
Nick 60197993e5 chore(dichotomy): regenerate audit — microkernel FULL (82->83 modules) 2026-10-14 02:30:29 +01:00
Nick b9b089fa49 feat(microkernel): close PARTIAL gaps — dichotomy wave
Name-preserving port of the 6 unmatched fns into src/go/microkernel:
NowIso (+clock seam), ExtractManifest (brace-counted PLUGIN block +
literal_eval-subset parser), Discover, RunHook (subprocess hook runner),
LoadRegistry/SaveRegistry (renamed; corrupt-file full-default parity),
plus Fire wiring the CLI fire case to real 8-way parallel dispatch with
the bounded fire-log. Register now honors Python truthiness for hook
values (string targets index) and plumbs _file into entries.

Frozen truth: 25-case envelope via the shared harness (regen-stable,
--verify byte-identical x2); Go battery 25/25 subtests, -race clean;
live oracle-vs-Go parity 24/24 (scripts/check_microkernel_parity.py);
gofmt/vet/go build ./... clean; Python both-pins green for the module
(18 test_p1_01 failures proven pre-existing on stashed base).
Audit: microkernel 6/12 PARTIAL -> 12/12 FULL (evidence:
verification/summary-microkernel.md + microkernel-*.exit).
2026-10-14 02:30:29 +01:00
Nick 49ba669fa6 chore(factory): salience_gate landed (verified 9/0 on synced tree; agent's 3 parity defects fixed via frozen truth; quality-gate law live-tested) + salience_gate lane backfilled 2026-10-14 02:29:00 +01:00
Nick 593cddba5d chore(store): archive conflict resolution (ours) 2026-10-14 02:28:40 +01:00
Nick d2fd546aa0 chore(store): close salience_gate dichotomy contract BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg (parity 07096f2c, phase B 3d158800) 2026-10-14 02:27:25 +01:00
conductor 4475fed547 chore(release): auto-bump version to 0.297.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 02:24:13 +01:00
Nick 3d158800c7 refactor(salience_gate): Phase B language-advantage pass — dichotomy wave
Genuine Rust-side advantages over the Python oracle shape (parity pinned
by the frozen battery — 12/12, replay 119/119, shared verify
byte-identical):
  * lower_for_match: ASCII-anchored Cow — already-lowercase gate texts (the
    common case) match with ZERO allocation; non-ASCII/uppercase takes the
    full Python-parity to_lowercase() path so Unicode case mappings (İ, ẛ)
    are never skipped (borrow predicate is ASCII-only BY CONSTRUCTION).
  * std-only hot-path bench in branch_battery: evaluate_decision over the
    56-envelope frozen corpus + word_boundary_contains micro (evidence:
    verification/salience-gate-phaseb-cargotest.log).
  * #[must_use] on the pure surface (evaluate_decision, evaluate_salience,
    evaluate_salience_dict, to_dict, handle_hook, _sg_core).
  * iterator any() family scans with single-append semantics matching the
    oracle's one-condition-per-family guards (feat fix, made idiomatic).
2026-10-14 02:23:49 +01:00
Nick 07096f2c59 feat(salience_gate): close PARTIAL gaps — dichotomy wave
Name-preserving port of the 4 audit-missing functions into
src/rust/salience_gate (the module's existing delegation side; there is
no Go salience-gate dir):
  _sg_core      -> kernel mirror of the facade availability probe (pin
                   lattice, Some <=> probe answered, None <=> python pin)
  to_dict       -> SalienceDecision struct + to_dict projection
                   (evaluate_salience now flows through it)
  handle_hook   -> plugin hook handler (event echo, data accepted+ignored)
  test_salience -> embedded oracle smoke test, print-byte-matched
plus a module-level evaluate_salience_dict JSON view in the oracle (the
shared freeze harness cannot serialize the dataclass return —
construction_decision's normalize_need_json precedent; audited 5/6 -> 6/6).

Defect fixes found by parity (frozen-truth battery caught all three):
  1. novel family: oracle guards ONE if (any(new/never) or first time/
     haven't) — previous port appended a second NOVEL flag for the regex
     arm, inflating len(flags) and flipping the witness rule.
  2. failure family: oracle guards ONE if including the 'doesn't work |
     not working' regex arm — previous port omitted that arm entirely.
  3. word_boundary_contains: Python \b is unicode/underscore-aware;
     previous is_ascii_alphanumeric boundary matched new_thing/a_new/
     man-new — now alphanumeric + '_' + UTF-8 continuation bytes.

Frozen truth (poisoned-truth law: RUNE_SALIENCE_CORE=python via the
generator + SG_RUST_LIB poisoned — the module's real floor pins):
  frozen_sg_truth.verify.json — 52 harness rows, byte-identical under
  freeze_truth.py --verify in BOTH core states; frozen_sg_truth.json —
  63-row envelope (multi-family evaluation-order rows + _sg_core row;
  the shared gate's RUNE_SALIENCE_GATE_CORE pin can never reach this
  oracle). Battery branch_battery.rs replays both verbatim
  (include_str); gen --replay: facade live 119/119 + kernel exact
  (eval order). canary 6/6; oracle smoke green in 3 pin states.
2026-10-14 02:23:49 +01:00
conductor b4315878e4 chore(release): auto-bump version to 0.296.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 02:14:49 +01:00
Nick 4204667f0a feat(cron_engine): close PARTIAL gaps — dichotomy wave
Name-preserving GO port of the 14 audit-missing fns (to_dict, run_task
method+module, fire_on_task_complete, start/stop, _run_loop, _execute_task,
_log_execution/_log_error with 5MB rotation, get_cron_engine singleton family;
_parse_cron_field/_should_run carried as mirror-commented parseCronField/
shouldRun) + Python-exact ordered _save/_load (insertion order, ensure_ascii,
CronTask(**data) TypeError semantics), shlex.split port with oracle ValueError
messages, isoformat/pyISO parity, subprocess error-message translation
(FileNotFoundError/PermissionError/TimeoutExpired str(e) forms, ExitError →
returncode value). Phase B folded: injectable clock/sleep/exec/recordFailure
seams, ordered-JSON truth decoding, snapshot to_dict (no live aliasing).

Truth: 46-case truth_gap.json via the shared harness + wrapper shims
(frozen clock, hermetic <CE_HOME> rows, stopper-time _run_loop, neutralized
record_failure) — --verify byte-identical, fresh re-freeze byte-identical.
Battery: legacy replay 25/25, gap replay 46/46, 5 tests green, gofmt/vet/
build clean. Live parity 3/3 scenarios (31 ops) oracle-vs-GO identical;
CLI byte-identical both pins. Audit: cron_engine 27/27 FULL (83/192).
CI cron-engine gate extended (replay-gap + TestGapParity). Evidence:
verification/ce-*.
2026-10-14 02:14:01 +01:00
Nick 9acfb73645 chore(factory): model_profiles landed (close bf2f3f0a verified 8/0, 143/143 parity); cp worktree freed 2026-10-14 02:05:22 +01:00
conductor a691a701d5 chore(release): auto-bump version to 0.295.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 01:57:08 +01:00
Nick bf2f3f0a25 chore(store): close model_profiles dichotomy contract BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp (parity 1ca647e4) 2026-10-14 01:54:38 +01:00
Nick 59ff243cc1 feat(model_profiles): close PARTIAL gaps — dichotomy wave
Oracle src/rune/model_profiles.py 438 lines / 15 fns: 5/15 -> 15/15
per scripts/dichotomy_audit.py (name-preserving match). The ten
audit-named gaps land as Go functions: getProfilePath, loadProfile
(suppressed-exception floor + unknown-key filtering), saveProfile
(Python-shaped JSON writer), buildProfileFromOllama (knowledge merge +
uncensored tier + injected clock), scanAllModels (Ollama sweep with
banker's rounding + learned-data preservation), getOrCreateProfile,
recordInteraction (learning accumulator), getPromptContext (operator
string assembly), to_dict/from_dict (the dataclass lens via
profileFromMap), plus the stdin-op serve CLI over the same code paths.

Freeze rig scripts/mp_freeze_seams (HOME pinned before the oracle
import, per-case hermetic store wipe+seed, canned Ollama server,
frozen clock via the harness envelope): 36-case frozen truth
regenerates byte-identical across runs; freeze_truth --verify OK
against the live oracle. Battery 36/36 replay VERBATIM from the
embedded truth (gen_mp_battery.py generator). Parity
scripts/check_model_profiles_parity.py 143/143 LIVE (detection
surface, sanitization matrix, lens, build assembly, record sequences,
prompt contexts, save byte-parity, scan sweep incl. dead-port
degrade). gofmt+vet+build clean, pytest 31/31 both pins.

Divergences (documented, not bugs): non-string profile names are
accepted by the oracle dataclass but rejected by the typed port
(local_tool_runtime precedent); integral-float rendering is
canonicalized in the sweep (context_broker precedent) while the
frozen save_profile rows pin the file writer byte-exact.
2026-10-14 01:54:38 +01:00
conductor 537c65b10d chore(release): auto-bump version to 0.294.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 01:53:15 +01:00
Nick 621b90236d feat(parallel_processor): close PARTIAL gaps — dichotomy wave
Oracle src/rune/parallel_processor.py 194 lines / 14 fns: 3/14 -> 14/14
per scripts/dichotomy_audit.py (name-preserving match). The 11
audit-named gaps land as ported Go functions in src/go/parallel-processor:
RunParallelWithArgs, GetStatus, Shutdown, ShutdownProcessor
(_shutdown_processor), GetProcessor, TestParallel (with the nested
task_1/task_2/task_3 closures) — plus the class/module run_parallel and
get_status module delegates; the CLI now mirrors the oracle main()
(status/test/usage/unknown) alongside the pre-existing run and the new
replay/op gates. Logic 1:1 with the Python oracle (semaphore-bounded
goroutine pool, submission-order results, per-task error envelopes).

Oracle quirks preserved and frozen as truth rows: submit-after-shutdown
raises from the submit loop itself (port panics 'cannot schedule new
futures after shutdown' — crash parity), ParallelProcessor(0) raises
'max_workers must be greater than 0', non-callable tasks degrade to
Python-TYPE-NAME TypeError envelopes ('int'/'NoneType'/'dict' object is
not callable), with-args parse errors carry type(task).__name__ and
repr shapes (42, 'x', True, None, [1, 2]), non-seq args wrapped to a
single-arg tuple, non-dict kwargs reset to {}, len-0 list vs () tuple
distinction, pool_threads reported as the configured bound,
active_threads pinned (rig threading.active_count patch / Go
PP_ACTIVE_THREADS seam).

Truth: scripts/gen_parallel_processor_truth.py via the shared
freeze_truth.py harness (23-case envelope; kind/fn/value SPEC grammar so
callables ride JSON rows — rig builds real Python callables, battery
rebuilds Go specCallable tasks); freeze_truth --verify byte-identical
twice; truth.json embedded VERBATIM and replayed by the go test battery
(5/5) and the binary replay gate (PARITY OK 23/23). Live parity 19/19
(scripts/check_parallel_processor_parity.py: 15 op families + 4 CLI
checks). gofmt/vet/go build clean. Python oracle smoke green both pins
(module has no loader seam; the byte-identity gate replays the live
oracle itself). Audit 3/14 PARTIAL -> 14/14 FULL.
2026-10-14 01:52:53 +01:00
Nick a3045b0b75 chore(store): quality repairs + first reconciliation pass (0 stale — authorities healthy, machinery now exercised) 2026-10-14 01:11:24 +01:00
conductor 405dcc78e0 chore(release): auto-bump version to 0.293.2 — earned by # (patch: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-14 01:09:30 +01:00
Nick 2597b58b88 fix(scaffold): quality-gate law — transition-to-closed refuses without contract_quality evidence + post-hoc quality for the two lapsed closes (hook_engine, adaptive_router) 2026-10-14 01:09:01 +01:00
122 changed files with 35410 additions and 467 deletions

No files matched your search

+2 -2
View File
@@ -231,9 +231,9 @@ jobs:
- name: curator-core candidate-decay parity gate (HARD — #2479 batch: ledger decay + journal render + cosine)
run: |
cd src/go/curator-core && go build -o /tmp/curator-core-${{ gitea.run_id }} . && /tmp/curator-core-${{ gitea.run_id }} replay truth_candidate_decay.json && go test -run TestCandidateDecayParity -v
- name: cron-engine parity gate (HARD — #2479 batches 1+126: parser + lifecycle)
- name: cron-engine parity gate (HARD — #2479 batches 1+126 + gap-close: parser + lifecycle + execution family)
run: |
cd src/go/cron-engine && go build -o /tmp/cron-engine-${{ gitea.run_id }} . && /tmp/cron-engine-${{ gitea.run_id }} replay truth.json && go test -run TestLifecycleParity -v
cd src/go/cron-engine && go build -o /tmp/cron-engine-${{ gitea.run_id }} . && /tmp/cron-engine-${{ gitea.run_id }} replay truth.json && /tmp/cron-engine-${{ gitea.run_id }} replay-gap truth_gap.json && go test -run 'TestLifecycleParity|TestGapParity' -v
- name: goal-engine parity gate (HARD — #2479 batches 2+129: verifier + lifecycle)
run: |
cd src/go/goal-engine && go build -o /tmp/goal-engine-${{ gitea.run_id }} . && /tmp/goal-engine-${{ gitea.run_id }} replay truth.json && go test -run TestLifecycleParity -v
+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.293.1**
**Current release: v0.299.0**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+4 -1
View File
@@ -18,6 +18,9 @@
{"trap": "oracle CRASH parity: if the oracle crashes (AttributeError etc.) on an input class, the port returns the matching error envelope", "port": "never silently skip — the facade's fallback reproduces the exact exception", "proved_by": "execution_trace fuzz"},
{"trap": "glob+mtime ordering ties within the same second", "port": "explicit os.utime in test fixtures; deterministic per-case dirs", "proved_by": "sleep_time"},
{"trap": "Go evaluation order: arg-list trace(x, f.Mutating()) snapshots BEFORE mutation; Python passes live references", "port": "capture returns/reports into locals first", "proved_by": "failure_auto_filer"},
{"trap": "absolute temp paths in frozen truth are machine-specific", "port": "repo-relative names or REPO_ROOT placeholder + battery substitution", "proved_by": "paths"}
{"trap": "absolute temp paths in frozen truth are machine-specific", "port": "repo-relative names or REPO_ROOT placeholder + battery substitution", "proved_by": "paths"},
{"trap": "ThreadPoolExecutor.submit AFTER shutdown raises from the submit loop itself — run_parallel's per-task capture never sees it, the WHOLE call raises", "port": "Go port panics with 'cannot schedule new futures after shutdown' at the same site (crash parity, recovered by battery/parity)", "proved_by": "parallel_processor (2026-10-14)"},
{"trap": "callable corpora cannot ride JSON truth rows", "port": "freeze a shared kind/fn/value SPEC grammar via a rig that builds real Python callables; the battery rebuilds Go tasks from the same rows (extends the memory_consolidation seam pattern)", "proved_by": "parallel_processor (2026-10-14)"},
{"trap": "threading.active_count() in oracle output is process-random (pool threads, harness state)", "port": "pin via rig patch to a constant; Go side reads the matching PP_ACTIVE_THREADS seam (default: native goroutine count)", "proved_by": "parallel_processor (2026-10-14)"}
]
}
+14 -14
View File
@@ -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: 43%** (82/192 runtime modules at FULL)
**FULL completion: 47%** (90/192 runtime modules at FULL)
Function-level detail: 63% (1440/2278 runtime functions matched) — secondary; includes in-flight work
Function-level detail: 66% (1511/2279 runtime functions matched) — secondary; includes in-flight work
| Status | Modules | Lines | Meaning |
|---|---|---|---|
| FULL | 82 | 34347 | 80%+ of functions ported |
| PARTIAL | 70 | 28304 | 20–80% — real logic exists, gaps named below |
| FULL | 90 | 37767 | 80%+ of functions ported |
| PARTIAL | 62 | 24926 | 20–80% — real logic exists, gaps named below |
| NOT TOUCHED | 40 | 11513 | no name-preserving implementation |
| Total runtime | 192 | 74164 | |
| Total runtime | 192 | 74206 | |
## NOT TOUCHED — the port queue, in priority order (largest first)
@@ -64,15 +64,11 @@ Function-level detail: 63% (1440/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 |
| 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 |
| tool_executor | 1836 | 33/47 | _execute_tool_now, serialize_prepared_tool, deserialize_prepared_tool, confirm_write, _resolve_execution_cwd, _run_command |
| cache | 492 | 6/17 | _record_hit, _record_miss, flush_stats, get_cache, put_cache, invalidate_scope |
| parallel_processor | 194 | 3/14 | _shutdown_processor, get_processor, run_parallel_with_args, get_status, test_parallel, run_parallel_with_args |
| structural_model | 388 | 9/20 | workspace_record, workspace_advance, _init_project, save, reload, add |
| claim_audit | 484 | 4/14 | _get_warm_neuron_store, reframe, _graph_has, _warm_has, verify, journal |
| model_profiles | 438 | 5/15 | get_profile_path, load_profile, save_profile, build_profile_from_ollama, scan_all_models, get_or_create_profile |
| capability_broker | 798 | 10/19 | _native_tool_schemas, load_registry, _cards_are_stale, load_cards, generate_card, build_cards |
| token_optimizer | 514 | 16/25 | get_optimizer, _tc_core, _to_core, to_dict, _to_state, _apply_state |
| behavior | 537 | 6/14 | _bh_core, connect, _correction_matches_python, _habit_matches_python, _reinforce_rust, _reinforce_python |
@@ -86,7 +82,6 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| audit_ledger | 212 | 2/8 | _compute_hash, get_entries, log_promotion, log_gate_result, log_drift_alert, main |
| context_pressure | 262 | 3/9 | log_measurement, read_log, log_stats, _now, handle_hook, main |
| core_server | 234 | 6/12 | make_server, log_message, _send_json, _send_ndjson, do_GET, do_POST |
| microkernel | 434 | 6/12 | now_iso, discover, _extract_manifest, _load_registry, _save_registry, _run_hook |
| model_registry | 253 | 2/8 | test_registry, to_dict, get_profile, get_enabled_profiles, get_profiles_by_tier, list_profiles |
| progressive_escalation | 279 | 2/8 | execute_with_escalation, test_escalation, handle_hook, to_dict, execute, verify |
| voicebox | 164 | 5/11 | _run, start_recording, stop_recording, _transcribe_and_type, on_press, on_release |
@@ -97,14 +92,11 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| drift_compression | 307 | 3/7 | get_compression_ratio, compress_entry, warn_before_compress, get_compression_stats |
| drift_observability | 399 | 5/9 | _do_core, main, _load_alerts, _save_alerts |
| layout_contract | 336 | 2/6 | define_region, bind_component, amend_layout_contract, record_layout_observation |
| model_connect | 471 | 7/11 | _ctx_budget, _now, _get_cloud_models, handle_hook |
| pins | 282 | 7/11 | _store_path, _detail_blob, unpin, list_pins |
| prompt_sync | 487 | 11/15 | _now, _rust_available, get_store, main |
| salience_gate | 276 | 1/5 | _sg_core, test_salience, handle_hook, to_dict |
| self_improve | 246 | 1/5 | _now, suggest_improvements, handle_hook, main |
| task_gate | 301 | 5/9 | _tg_core, _now, list_gates, main |
| tier_manager | 262 | 6/10 | demotion_sweep, get_tier_config, should_search, should_compress |
| witness | 446 | 11/15 | _now, log_entry, read_log, log_stats |
| connection_pool | 226 | 7/10 | get_pool, _kernel_state, _get_connection_core |
| construction_activation | 237 | 1/4 | _scaffold_for, _auto_structural_awareness, dispatch_from_decision |
| construction_mode | 412 | 2/5 | _contains_any, to_dict, from_dict |
@@ -143,7 +135,7 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| sleep_time | 1056 | 26/26 | GO |
| spine | 975 | 25/25 | RUST |
| structural_store | 921 | 34/41 | RUST |
| scaffold | 881 | 30/30 | GO |
| scaffold | 908 | 30/30 | GO |
| context_broker | 870 | 24/24 | GO |
| hook_engine | 860 | 8/8 | GO |
| local_tool_runtime | 809 | 30/30 | GO |
@@ -151,6 +143,7 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| memory_consolidation | 770 | 22/22 | GO |
| contracts | 743 | 11/11 | RUST |
| persona_gate | 724 | 23/23 | GO |
| provider_registry | 687 | 28/28 | GO |
| abstraction | 656 | 16/16 | GO |
| safety_override | 649 | 20/20 | RUST |
| adaptive_router | 625 | 19/19 | GO |
@@ -166,12 +159,17 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| build_mode | 521 | 33/33 | GO |
| growth_delta | 520 | 17/18 | GO |
| event_wait | 518 | 14/14 | GO |
| model_connect | 471 | 11/11 | GO |
| worthiness | 469 | 12/13 | unclassified |
| tool_protocol | 461 | 22/27 | GO |
| auto_tasks | 460 | 14/14 | GO |
| programme_continuation | 458 | 11/12 | RUST |
| goal | 453 | 20/20 | GO |
| release_notes | 446 | 16/16 | GO |
| witness | 446 | 15/15 | GO |
| cron_engine | 440 | 27/27 | GO |
| model_profiles | 438 | 15/15 | GO |
| microkernel | 434 | 12/12 | GO |
| model_routing | 432 | 13/13 | GO |
| night_mode | 421 | 19/19 | GO |
| build_basis | 375 | 11/13 | RUST |
@@ -185,6 +183,7 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| lexicon_evolution | 304 | 7/8 | unclassified |
| message_graph | 295 | 12/13 | unclassified |
| toolchain | 295 | 5/6 | RUST |
| salience_gate | 283 | 6/6 | RUST |
| shard_manager | 276 | 9/9 | RUST |
| auto_context | 273 | 8/8 | GO |
| spine_language | 269 | 5/5 | RUST |
@@ -195,6 +194,7 @@ Function-level detail: 63% (1440/2278 runtime functions matched) — secondary;
| project_registry | 205 | 10/12 | RUST |
| forge_client | 203 | 18/18 | GO |
| behaviour_ledger | 195 | 10/12 | RUST |
| parallel_processor | 194 | 14/14 | GO |
| construction_depth | 172 | 2/2 | RUST |
| self_modify | 149 | 7/8 | unclassified |
| forge | 146 | 11/11 | GO |
+4 -2
View File
@@ -54,6 +54,7 @@
"message_graph",
"message_queue",
"model_connect",
"model_profiles",
"model_routing",
"mutation_guards",
"night_mode",
@@ -113,7 +114,6 @@
"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",
@@ -123,7 +123,9 @@
"builder_bridge": "rune-wave-cw",
"drift_compression": "rune-wave-cx",
"event_envelope": "rune-wave-cy",
"stage_guards": "rune-wave-cz"
"stage_guards": "rune-wave-cz",
"salience_gate": "rune-wave-cy2",
"voice_sync": "rune-wave-db"
},
"excluded": [
"TUI-LAST modules",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.293.1"
version = "0.299.0"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""check_cron_engine_parity.py — LIVE parity for the cron_engine GO port
(#2479 dichotomy gap-close): drives the Python oracle (src/rune/
cron_engine.py) and the GO binary through IDENTICAL scenarios and diffs
their JSON outputs — beyond frozen-truth replay, this exercises the two
implementations LIVE (real subprocesses, real files) under a pinned
clock + hermetic HOME.
Python side mirrors the Go binary's `scenario` mode exactly (op set,
output shape). Paths are tokenized to <HOME> before comparison.
Usage: python3 scripts/check_cron_engine_parity.py <go-binary>
(build first: cd src/go/cron-engine && go build -o /tmp/cron-engine .)
"""
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
os.environ.setdefault("RUNE_CRON_ENGINE_CORE", "python")
from rune import cron_engine as ce # noqa: E402
import rune.subsystem_health as _SH # noqa: E402
_SH.record_failure = lambda *a, **k: True # hermetic: no ledger writes
FROZEN_NOW = "2026-10-13T09:20:00"
def frozen_clock(iso):
from datetime import datetime, timezone
base = datetime.fromisoformat(iso)
class FrozenDatetime(datetime):
@classmethod
def now(cls, tz=None):
return base.replace(tzinfo=tz) if tz is not None else base
return FrozenDatetime
class StopTime:
def __init__(self, engine):
self._e = engine
def sleep(self, _s):
if self._e is not None:
self._e.running = False
def run_python(sc):
ce.datetime = frozen_clock(sc["frozen_now"])
home = tempfile.mkdtemp(prefix="ce-live-py-")
os.environ["HOME"] = home
storage = os.path.join(home, ".rune", "cron.json")
logp = os.path.join(home, ".rune", "cron.log")
e = ce.CronEngine.__new__(ce.CronEngine)
e.storage_path = storage
e.tasks = {}
e.running = False
e.thread = None
e._last_run_minute = {}
e._load()
def rd(p):
return open(p).read() if os.path.exists(p) else None
def dump():
return {
"running": e.running,
"storage_path": e.storage_path,
"log_path": logp,
"tasks": [{"name": n, "task": t.to_dict()} for n, t in e.tasks.items()],
"_last_run_minute": dict(e._last_run_minute), # snapshot (no live aliasing)
}
steps = []
for op in sc["ops"]:
k = op["op"]
if k == "add":
t = e.add_task(op["name"], op["expr"], op["command"], op.get("description", ""))
steps.append({"op": "add", "task": t.to_dict()})
elif k == "enable":
steps.append({"op": "enable", "ok": e.enable_task(op["name"])})
elif k == "disable":
steps.append({"op": "disable", "ok": e.disable_task(op["name"])})
elif k == "remove":
steps.append({"op": "remove", "ok": e.remove_task(op["name"])})
elif k == "run":
steps.append({"op": "run", "result": e.run_task(op["name"])})
elif k == "fire":
steps.append({"op": "fire", "fired": e.fire_on_task_complete()})
elif k == "loop":
real = ce.time
ce.time = StopTime(e)
try:
e._run_loop()
finally:
ce.time = real
steps.append({"op": "loop"})
elif k == "start":
real = ce.time
ce.time = StopTime(e)
try:
e.start()
e.stop()
finally:
ce.time = real
steps.append({"op": "start+stop"})
elif k == "stop":
e.stop()
steps.append({"op": "stop"})
elif k == "save":
e._save()
steps.append({"op": "save", "ok": True})
elif k == "load":
e._load()
steps.append({"op": "load", "ok": True})
elif k == "storage":
steps.append({"op": "storage", "bytes": rd(storage)})
elif k == "log":
steps.append({"op": "log", "bytes": rd(logp)})
elif k == "state":
steps.append({"op": "state", "state": dump()})
else:
raise ValueError(k)
return {"home": home, "out": {"steps": steps, "final": dump()}}
def run_go(binary, sc_path):
r = subprocess.run([binary, "scenario", str(sc_path)],
capture_output=True, text=True, timeout=120)
if r.returncode != 0:
raise RuntimeError(f"go scenario failed: {r.stderr}")
# the binary's temp home differs per run — recover it from final.storage_path
out = json.loads(r.stdout)
home = os.path.dirname(os.path.dirname(out["final"]["storage_path"]))
return {"home": home, "out": out}
def tokenize(obj, home):
if isinstance(obj, str):
return obj.replace(home, "<HOME>")
if isinstance(obj, list):
return [tokenize(x, home) for x in obj]
if isinstance(obj, dict):
return {k: tokenize(v, home) for k, v in obj.items()}
return obj
SCENARIOS = [
# 1: lifecycle + run envelopes + storage/log bytes
{"frozen_now": FROZEN_NOW, "ops": [
{"op": "add", "name": "z-first", "expr": "on_complete", "command": "echo one"},
{"op": "add", "name": "a-second", "expr": "*/5 * * * *", "command": "echo '中文 twø'", "description": "d-ü"},
{"op": "add", "name": "bad", "expr": "* * * * *", "command": "nope-cmd-xyz"},
{"op": "add", "name": "quoted", "expr": "* * * * *", "command": "echo 'unterminated"},
{"op": "state"},
{"op": "run", "name": "z-first"},
{"op": "run", "name": "bad"},
{"op": "run", "name": "quoted"},
{"op": "run", "name": "ghost"},
{"op": "disable", "name": "a-second"},
{"op": "fire"},
{"op": "storage"},
{"op": "log"},
{"op": "state"},
]},
# 2: scheduler loop — matching, non-matching, dedup, disabled
{"frozen_now": FROZEN_NOW, "ops": [
{"op": "add", "name": "match", "expr": "* * * * *", "command": "echo m"},
{"op": "add", "name": "nomatch", "expr": "5 4 * * *", "command": "echo n"},
{"op": "add", "name": "off", "expr": "* * * * *", "command": "echo o"},
{"op": "disable", "name": "off"},
{"op": "loop"},
{"op": "loop"},
{"op": "storage"},
{"op": "log"},
{"op": "state"},
]},
# 3: persistence round-trip + start/stop + remove
{"frozen_now": FROZEN_NOW, "ops": [
{"op": "add", "name": "keep", "expr": "0 9 * * 1", "command": "echo k"},
{"op": "add", "name": "drop", "expr": "0 9 * * 1", "command": "echo d"},
{"op": "remove", "name": "drop"},
{"op": "run", "name": "keep"},
{"op": "storage"},
{"op": "start"},
{"op": "state"},
{"op": "stop"},
]},
]
def main():
binary = sys.argv[1] if len(sys.argv) > 1 else "/tmp/cron-engine"
ok = 0
for i, sc in enumerate(SCENARIOS, 1):
with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) as f:
json.dump(sc, f)
sc_path = f.name
try:
py = run_python(sc)
go = run_go(binary, sc_path)
finally:
os.unlink(sc_path)
pyj = tokenize(py["out"], py["home"])
goj = tokenize(go["out"], go["home"])
if pyj == goj:
ok += 1
print(f"scenario {i}: LIVE PARITY OK ({len(sc['ops'])} ops)")
else:
print(f"scenario {i}: LIVE PARITY FAILED")
pj, gj = json.dumps(pyj, indent=1, sort_keys=True), json.dumps(goj, indent=1, sort_keys=True)
for pl, gl in zip(pj.splitlines(), gj.splitlines()):
if pl != gl:
print(f" py: {pl}")
print(f" go: {gl}")
break
return 1
print(f"LIVE PARITY: {ok}/{len(SCENARIOS)} scenarios identical (oracle vs GO)")
return 0
if __name__ == "__main__":
sys.exit(main())
+344
View File
@@ -0,0 +1,344 @@
#!/usr/bin/env python3
"""check_microkernel_parity.py — live oracle-vs-Go parity sweep for the
microkernel gap closure (dichotomy wave #2479, worktree rune-wave-cq).
The frozen envelope (truth_microkernel_gap.json, 25 cases) pins the gap
fns byte-identically. THIS script drives the LIVE Python oracle
(src/rune/microkernel.py) and the Go binary's parity op mode across every
branch class with FRESH fixtures (not the frozen ones): extract_manifest
(prefix traps, nested literals, unicode), discover (mixed dir), registry
load/save shapes, and fire/_run_hook (ok-json / raw-stdout truncation /
rc-error / timeout / skipped / ghost-file / empty-file / two-listeners /
no-listeners).
Normalization law (shared with the rig): wall-clock durations → "<ms>",
fire results name-sorted, fixture paths → <dir>. Data keys alphabetical
(the Go map marshal is key-sorted; plugins canonicalize the payload).
Usage: python3 scripts/check_microkernel_parity.py [--bin <path>]
Exit 0 on 100% parity, 1 with the first divergence.
"""
from __future__ import annotations
import argparse
import copy
import json
import os
import re
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"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import microkernel as mk # noqa: E402
FROZEN_NOW = "2026-10-13T11:05:00"
FROZEN_NOW_AWARE = FROZEN_NOW + "+00:00"
OK_JSON = (
"import json, sys\n"
"data = sys.argv[sys.argv.index('--data') + 1]\n"
"print(json.dumps({'echo': json.loads(data)}))\n"
)
RAW_LONG = "print('h\\u00e9llo-\\u2192ok ' * 90)\n"
BOOM = ("import sys\n"
"sys.stderr.write('\\u00e9rr\\u00f4r-' * 80)\n"
"sys.exit(3)\n")
SLOW = "import time\ntime.sleep(4)\n"
FAILS: list[str] = []
CHECKS = [0]
def check(name, oracle_val, go_val):
CHECKS[0] += 1
a = json.dumps(oracle_val, sort_keys=True, ensure_ascii=False)
b = json.dumps(go_val, sort_keys=True, ensure_ascii=False)
if a != b:
FAILS.append(f"{name}:\n oracle: {a[:300]}\n go: {b[:300]}")
# ── clock pin (aware — fire() mixes naive/aware now()) ────────────────────
def pin_clock():
base = datetime.fromisoformat(FROZEN_NOW).replace(tzinfo=timezone.utc)
class Frozen(datetime):
@classmethod
def now(cls, tz=None):
if tz is not None:
return base.replace(tzinfo=tz)
return base
old = mk.datetime
mk.datetime = Frozen
return old
# ── Go side ────────────────────────────────────────────────────────────────
def run_go(binpath, req, env_dir=None):
env = dict(os.environ)
if env_dir:
env["RUNE_MEMORY_DIR"] = env_dir
p = subprocess.run([str(binpath), "parity"], input=json.dumps(req),
capture_output=True, text=True, env=env, timeout=120)
if p.returncode != 0:
raise RuntimeError(f"go op {req.get('op')} exited {p.returncode}: "
f"{p.stdout} {p.stderr}")
return json.loads(p.stdout)
# ── normalization ──────────────────────────────────────────────────────────
def norm_fire(result):
out = copy.deepcopy(result)
if "total_duration_ms" in out:
out["total_duration_ms"] = "<ms>"
for r in out.get("results", []):
if "duration_ms" in r:
r["duration_ms"] = "<ms>"
out["results"] = sorted(out.get("results", []), key=lambda r: r.get("name", ""))
return out
def norm_logs(log):
return [{"event": e.get("event"), "timestamp": e.get("timestamp"),
"hooks_fired": e.get("hooks_fired"), "duration_ms": "<ms>"}
for e in log]
def oracle_fire_with(manifest, event, data, timeout):
"""Fire through the live oracle; the manifest's _file must already
point at an existing fixture script (or a ghost for not-found)."""
work = tempfile.mkdtemp(prefix="mk_par_fire_")
mk.REGISTRY_DB = os.path.join(work, "registry.json")
mk.register(dict(manifest))
result = mk.fire(event, data=data, timeout=timeout)
log = mk._load_registry().get("log", [])
return {"result": norm_fire(result), "log": norm_logs(log)}
def go_registry_blob(manifest):
return {
"plugins": {manifest["name"]: {
"manifest": {"name": manifest["name"]},
"registered_at": FROZEN_NOW_AWARE,
"active": bool(manifest.get("auto_activate", True)),
"file": manifest.get("_file", ""),
}},
"capabilities": {},
"hooks": {ev: [manifest["name"]] for ev, on in manifest.get("hooks", {}).items() if on},
"log": [],
}
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--bin", default="/tmp/mk-parity-bin")
args = ap.parse_args()
binpath = Path(args.bin)
old_clock = pin_clock()
# ── now_iso: FORMAT parity (wall clock — both must emit the shape) ──
CHECKS[0] += 1
shape = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+00:00$")
if not (shape.match(mk.now_iso()) and shape.match(run_go(binpath, {"op": "now_iso"})["result"])):
FAILS.append(f"now_iso shape: oracle {mk.now_iso()!r} go {run_go(binpath, {'op': 'now_iso'})['result']!r}")
# ── extract_manifest: content sweep ──────────────────────────────
contents = [
'PLUGIN = {\n "name": "x",\n "capabilities": ["a", "b"],\n "hooks": {"e": "handle_hook"},\n "priority": 2,\n "auto_activate": False,\n}\n',
'PLUGINX = {\n "name": "prefix-trap",\n}\n', # startswith("PLUGIN")
'PLUGIN={"name":"dense","n":0.5}\n', # no spaces
"PLUGIN = {'k': 'v', 't': (1, 2), 'l': [1, [2, 3]]}\n", # tuple literal
'PLUGIN = {\n "name": "é中",\n "s": "tab\\tnewline\\nquote\\"q",\n}\n',
'PLUGIN = {\n "name": "trail",\n "arr": [1, 2, 3,],\n}\n', # trailing comma in list
'no manifest here\n',
'PLUGIN = {\n "name": "never-closed",\n',
]
for i, content in enumerate(contents):
fd, fpath = tempfile.mkstemp(suffix=".py")
with os.fdopen(fd, "w") as f:
f.write(content)
try:
oracle = copy.deepcopy(mk._extract_manifest(fpath))
finally:
os.unlink(fpath)
go = run_go(binpath, {"op": "extract_manifest", "content": content})["result"]
check(f"extract_manifest[{i}]", oracle, go)
# ── discover: mixed fixture dir ──────────────────────────────────
work = tempfile.mkdtemp(prefix="mk_par_disc_")
fixture = Path(work) / "scripts"
fixture.mkdir()
files = {
"alpha.py": 'PLUGIN = {\n "name": "alpha",\n "capabilities": ["cap"],\n "hooks": {"evt": "run"},\n "priority": 1,\n}\n',
"beta.py": 'PLUGIN = {\n "name": "beta",\n "capabilities": ["cap"],\n "priority": 9,\n}\n',
"gamma.py": 'PLUGIN = {"version": "0"}\n', # no name → error row
"delta.py": 'def plain():\n pass\n', # no PLUGIN → skipped
"_under.py": 'PLUGIN = {"name": "under"}\n',
"microkernel.py": 'PLUGIN = {"name": "self"}\n',
}
for fname, src in files.items():
(fixture / fname).write_text(src)
real_listdir = os.listdir
old_dir, old_db = mk.SCRIPTS_DIR, mk.REGISTRY_DB
mk.SCRIPTS_DIR = str(fixture)
mk.REGISTRY_DB = os.path.join(work, "registry.json")
os.listdir = lambda p: sorted(files) if str(p) == str(fixture) else real_listdir(p)
try:
oracle_result = copy.deepcopy(mk.discover())
oracle_state = mk._load_registry()
finally:
os.listdir = real_listdir
mk.SCRIPTS_DIR, mk.REGISTRY_DB = old_dir, old_db
oracle_proj = {
"plugins": {n: {"active": p.get("active"), "registered_at": p.get("registered_at"),
"file": p.get("file", "").replace(str(fixture), "<dir>")}
for n, p in oracle_state["plugins"].items()},
"capabilities": oracle_state["capabilities"],
"hooks": oracle_state["hooks"],
}
go = run_go(binpath, {"op": "discover", "dir": str(fixture), "now": FROZEN_NOW_AWARE})
go_proj = {
"plugins": {n: {"active": p["active"], "registered_at": p["registered_at"],
"file": p["file"].replace(str(fixture), "<dir>")}
for n, p in go["plugins"].items()},
"capabilities": go["capabilities"],
"hooks": go["hooks"],
}
check("discover.result", oracle_result, go["result"])
check("discover.registry", oracle_proj, go_proj)
# ── registry load/save shapes ────────────────────────────────────
old_db = mk.REGISTRY_DB
load_dir = tempfile.mkdtemp(prefix="mk_par_load_")
full = json.dumps({
"plugins": {"q": {"manifest": {"name": "q", "priority": 3},
"registered_at": FROZEN_NOW_AWARE, "active": False,
"file": "/y/q.py"}},
"capabilities": {"c": ["q"]},
"hooks": {"e2": ["q"]},
"log": [{"event": "e2", "timestamp": FROZEN_NOW_AWARE,
"hooks_fired": 2, "duration_ms": 3.25}],
}, indent=2)
def oracle_load(content):
mk.REGISTRY_DB = os.path.join(load_dir, "registry.json")
try:
db = mk.REGISTRY_DB
if content is None:
if os.path.exists(db):
os.unlink(db)
else:
with open(db, "w") as f:
f.write(content)
reg = mk._load_registry()
return {"plugins": {n: {"active": p.get("active"),
"registered_at": p.get("registered_at"),
"file": p.get("file", "")}
for n, p in reg.get("plugins", {}).items()},
"capabilities": reg.get("capabilities", {}),
"hooks": reg.get("hooks", {}),
"log": reg.get("log", [])}
finally:
mk.REGISTRY_DB = old_db
for label, content in (("missing", None), ("corrupt", "}{ nope"), ("full", full)):
oracle = oracle_load(content)
go = run_go(binpath, {"op": "registry_load", "content": content}, env_dir=load_dir)
check(f"registry_load.{label}", oracle,
{"plugins": {n: {"active": p["active"],
"registered_at": p["registered_at"], "file": p["file"]}
for n, p in go["plugins"].items()},
"capabilities": go["capabilities"], "hooks": go["hooks"], "log": go["log"]})
# roundtrip
mk.REGISTRY_DB = os.path.join(load_dir, "registry.json")
try:
first = mk._load_registry()
mk._save_registry(first)
again = mk._load_registry()
oracle_rt = {"stable": first == again}
finally:
mk.REGISTRY_DB = old_db
go_rt = run_go(binpath, {"op": "registry_roundtrip"}, env_dir=load_dir)
check("registry_roundtrip", oracle_rt, {"stable": go_rt["stable"]})
# ── fire / _run_hook branch matrix ───────────────────────────────
evt = "evt"
fire_cases = [
("ok_json", OK_JSON, {"name": "okp", "hooks": {evt: True}}, evt, {"a": 1, "b": "x"}, 30),
("raw_text", RAW_LONG, {"name": "rawp", "hooks": {evt: True}}, evt, None, 30),
("rc_error", BOOM, {"name": "boomp", "hooks": {evt: True}}, evt, None, 30),
("timeout", SLOW, {"name": "slowp", "hooks": {evt: True}}, evt, None, 1),
("skipped", OK_JSON, {"name": "offp", "hooks": {evt: True}, "auto_activate": False}, evt, None, 30),
("ghost_file", None, {"name": "ghostp", "hooks": {evt: True}, "_file": "/nonexistent/ghost.py"}, evt, None, 30),
("empty_file", None, {"name": "nofilep", "hooks": {evt: True}}, evt, None, 30),
("no_listeners", OK_JSON, {"name": "lonely", "capabilities": ["c"]}, "nope_evt", None, 30),
]
for label, script, manifest, event, data, timeout in fire_cases:
manifest = dict(manifest)
if script is not None:
work = tempfile.mkdtemp(prefix="mk_par_fx_")
fpath = os.path.join(work, "plugin.py")
with open(fpath, "w") as f:
f.write(script)
manifest["_file"] = fpath
oracle = oracle_fire_with(manifest, event, data, timeout)
blob = go_registry_blob(manifest)
go = run_go(binpath, {"op": "fire", "registry": blob, "event": event,
"data": data, "timeout_ms": timeout * 1000,
"now": FROZEN_NOW_AWARE})
go = {"result": norm_fire(go["result"]), "log": norm_logs(go["log"])}
check(f"fire.{label}", oracle, go)
# two listeners in parallel
work2 = tempfile.mkdtemp(prefix="mk_par_two_")
tmpdb2 = os.path.join(work2, "registry.json")
old_db = mk.REGISTRY_DB
mk.REGISTRY_DB = tmpdb2
try:
for nm in ("zz", "aa"):
fpath = os.path.join(work2, nm + ".py")
with open(fpath, "w") as f:
f.write(OK_JSON)
mk.register({"name": nm, "hooks": {evt: True}, "_file": fpath})
oracle = {"result": norm_fire(mk.fire(evt, data={"z": 1}, timeout=30)),
"log": norm_logs(mk._load_registry().get("log", []))}
finally:
mk.REGISTRY_DB = old_db
blob = {
"plugins": {
"zz": {"manifest": {"name": "zz"}, "registered_at": FROZEN_NOW_AWARE,
"active": True, "file": os.path.join(work2, "zz.py")},
"aa": {"manifest": {"name": "aa"}, "registered_at": FROZEN_NOW_AWARE,
"active": True, "file": os.path.join(work2, "aa.py")},
},
"capabilities": {}, "hooks": {evt: ["zz", "aa"]}, "log": [],
}
go = run_go(binpath, {"op": "fire", "registry": blob, "event": evt,
"data": {"z": 1}, "timeout_ms": 30000, "now": FROZEN_NOW_AWARE})
go = {"result": norm_fire(go["result"]), "log": norm_logs(go["log"])}
check("fire.two_listeners", oracle, go)
mk.datetime = old_clock
print(f"{'FAIL' if FAILS else 'OK'}: {CHECKS[0] - len(FAILS)}/{CHECKS[0]} checks passed")
for f in FAILS:
print(" " + f)
return 1 if FAILS else 0
if __name__ == "__main__":
sys.exit(main())
+337
View File
@@ -0,0 +1,337 @@
#!/usr/bin/env python3
"""check_model_profiles_parity.py — live oracle-vs-Go parity sweep for the
model_profiles gap closure (#2479, contract factory-gap-mp).
The frozen envelope (frozen_mp_truth.json, 36 cases) pins the seam
surface byte-identically. THIS script drives the LIVE Python oracle
(src/rune/model_profiles.py) and the Go binary across the broader
surface the frozen corpus samples: every model family + unknown,
parameter/quantization edge shapes, the sanitization matrix, the
to_dict/from_dict lens (incl. unknown-key filtering and defaults),
build assembly across families (uncensored tier, display/size
overrides), record sequences (dedup, empty-topic, success mix),
prompt-context shapes, the scan sweep against a canned Ollama server
(fresh + existing-preservation + banker's rounding + nameless skip +
dead-port degrade), and save/load round-trips (byte-identical raw
text). Timestamps are pinned via the binary's "now" seam and the
oracle's module-global datetime patch; stores are per-case hermetic
temp dirs on both sides.
Usage: PYTHONPATH=src python3 scripts/check_model_profiles_parity.py
[--bin src/go/model-profiles/model-profiles]
Exit 0 on 100% parity, 1 with the first divergence.
"""
import argparse
import dataclasses
import json
import os
import shutil
import subprocess
import sys
import tempfile
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
import rune.model_profiles as mp # noqa: E402
FROZEN_NOW = "2026-10-13T09:41:23.123456"
NAMES = [
"qwen2.5:7b", "Qwen3:14b", "llama3.1:8b", "mistral-7b", "gemma2:9b",
"phi3:mini", "deepseek-r1:32b", "DavidAU-Qwen-14b", "some-new-model",
"library/qwen3:14b", "a?b:c/d", "model-70B-GGUF", "Qwen2.5-0.5b",
"dolphin-uncensored:7b", "qwen2.5:14b-instruct-q5_K_M",
"llama-3-8b-Q4_K_M", "deepseek-r1:70b-IQ2_M", "phi-4-14b-int4",
"model-3B-FP16", "tiny-INT8", "x-GGUF-fp32",
]
QUANT_NAMES = [
"m-Q4_K_M", "m-IQ3_XS", "m-q5_k_m", "m-iq2_m", "m-GGUF", "m-gguf",
"m-FP16", "m-FP32", "m-INT8", "m-INT4", "m-none",
]
BUILD_CASES = [
("qwen3:14b", {"display_name": "Qwen3 14B", "size_gb": 9.0}),
("mistral-7b", None),
("llama3.1:8b", {"display_name": "L", "size_gb": 4.5}),
("gemma2:9b", {"display_name": "G"}),
("phi3:mini", {"size_gb": 2.1}),
("deepseek-r1:32b", {"display_name": "DS", "size_gb": 19.2}),
("DavidAU-X:7b", None),
("dolphin-uncensored:7b", None),
("mystery-model", None),
("mystery-model", {"display_name": "M", "size_gb": 1.5}),
]
RECORD_SEQS = [
[[True, ""]],
[[False, "refuses weapons"]],
[[False, "t1"], [False, "t1"]],
[[False, ""]],
[[True, ""], [False, "a"], [True, ""], [False, "b"], [False, "a"]],
[[False, "x"], [False, "y"], [False, "z"]],
]
CTX_SEEDS = [
{"name": "full:1b", "strengths": ["s1", "s2", "s3", "s4"],
"prompting_tips": ["tip one", "tip two"],
"known_refusal_topics": ["r1", "r2", "r3", "r4"], "safety_tier": 2},
{"name": "tips:1b", "prompting_tips": ["only tip"]},
{"name": "tier:1b", "safety_tier": 1},
{"name": "refusals:1b", "known_refusal_topics": ["r1"]},
]
SCAN_MODELS = [
{"name": "qwen2.5:7b", "size": 7516192768},
{"name": "banker-lo:2b", "size": 2415919104},
{"name": "banker-hi:2b", "size": 2952790016},
{"name": "llama3.1:8b", "size": 4831838208},
{"size": 999},
{"name": "sizeless:1b"},
]
class _TagsHandler(BaseHTTPRequestHandler):
payload = b"{}"
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(self.payload)))
self.end_headers()
self.wfile.write(self.payload)
def log_message(self, *a):
pass
def canned_server(fixture):
handler = type("H", (_TagsHandler,),
{"payload": json.dumps(fixture).encode()})
srv = ThreadingHTTPServer(("127.0.0.1", 0), handler)
threading.Thread(target=srv.serve_forever, daemon=True).start()
return srv
def run_go(binpath, req):
p = subprocess.run([str(binpath)], input=json.dumps(req),
capture_output=True, text=True)
if p.returncode != 0:
raise RuntimeError(
f"go op {req.get('op')} exited {p.returncode}: {p.stdout} {p.stderr}")
return json.loads(p.stdout)["result"]
def fresh_store():
d = tempfile.mkdtemp(prefix="mp_parity_")
return os.path.join(d, ".rune", "model_profiles")
def oracle_in_store(store):
"""Point the oracle at a hermetic store (PROFILES_DIR is module-global)."""
mp.PROFILES_DIR = store
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--bin", default=str(
REPO / "src/go/model-profiles/model-profiles"))
args = ap.parse_args()
binpath = Path(args.bin)
if not binpath.exists():
binpath = Path("/tmp/mp-go")
fails = total = 0
def canon(v):
# Integral-float law (the context_broker precedent): the oracle's
# build path assigns int 0 where the dataclass declares float
# (size_gb=0 vs 0.0) — numerically identical, textually distinct.
# Canonicalize integral floats to int on BOTH sides before compare.
if isinstance(v, float) and v.is_integer():
return int(v)
if isinstance(v, dict):
return {k: canon(x) for k, x in v.items()}
if isinstance(v, list):
return [canon(x) for x in v]
return v
def check(name, oracle_val, go_val):
nonlocal fails, total
total += 1
if json.dumps(canon(oracle_val), sort_keys=True) != json.dumps(canon(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]}")
# pure detection surface (no store, no clock)
for n in NAMES:
check(f"family:{n}", mp.detect_family(n),
run_go(binpath, {"op": "detect_family", "name": n}))
for n in NAMES + QUANT_NAMES:
check(f"params:{n}", mp.detect_parameters(n),
run_go(binpath, {"op": "detect_parameters", "name": n}))
check(f"quant:{n}", mp.detect_quantization(n),
run_go(binpath, {"op": "detect_quantization", "name": n}))
for inter, succ in [(0, 0), (1, 1), (10, 7), (4, 0), (3, 2)]:
p = mp.ModelProfile(name="x", interactions=inter, successes=succ)
check(f"success_rate:{inter}/{succ}", p.success_rate,
run_go(binpath, {"op": "success_rate",
"interactions": inter, "successes": succ}))
# sanitization matrix (compare file NAMES — store roots differ)
for n in NAMES:
store = fresh_store()
oracle_in_store(store)
oracle_name = os.path.basename(mp.get_profile_path(n))
go_name = run_go(binpath, {"op": "get_profile_path",
"name": n, "store": store})
check(f"path:{n}", oracle_name, go_name)
# to_dict / from_dict lens
full = mp.ModelProfile(
name="qwen2.5:7b", display_name="Q ✓", family="qwen",
parameters="7B", quantization="Q4_K_M", size_gb=4.7,
strengths=["a", "b"], weaknesses=["c"], prompting_tips=["t1"],
safety_tier=2, known_refusal_topics=["r1"],
thinking_format="<think>", response_style="concise",
context_window=32768, optimal_temperature=0.7,
interactions=10, successes=7, failures=3,
last_used="2026-10-12T00:00:00+00:00",
created="2026-10-01T00:00:00+00:00")
check("to_dict:full", full.to_dict(),
run_go(binpath, {"op": "to_dict", **full.to_dict()}))
for doc in ({"name": "n", "bogus": 1, "context_window": 8192},
{"name": "n2"},
dataclasses.asdict(full)):
check(f"from_dict:{doc.get('name')}",
dataclasses.asdict(mp.ModelProfile.from_dict(doc)),
run_go(binpath, {"op": "from_dict", **doc}))
# build assembly (pin the oracle clock; binary takes "now")
import datetime as dtmod
real_dt = dtmod.datetime
class FrozenDT(real_dt):
@classmethod
def now(cls, tz=None):
base = real_dt(2026, 10, 13, 9, 41, 23, 123456)
return base.replace(tzinfo=tz) if tz is not None else base
mp.datetime = FrozenDT
try:
for name, info in BUILD_CASES:
oracle = dataclasses.asdict(
mp.build_profile_from_ollama(name, info))
go = run_go(binpath, {"op": "build_profile", "name": name,
"model_info": info, "now": FROZEN_NOW + "+00:00"})
check(f"build:{name}", oracle, go)
finally:
mp.datetime = real_dt
# record sequences + prompt context (hermetic store each, both
# sides replay the same sequence from empty, then compare docs)
mp.datetime = FrozenDT
try:
for i, seq in enumerate(RECORD_SEQS):
ostore, gstore = fresh_store(), fresh_store()
oracle_in_store(ostore)
for success, topic in seq:
mp.record_interaction(f"m{i}:1b", success, topic)
for success, topic in seq:
run_go(binpath, {"op": "record", "name": f"m{i}:1b",
"success": success, "topic": topic,
"store": gstore, "now": FROZEN_NOW + "+00:00"})
oracle_in_store(ostore)
o_doc = dataclasses.asdict(mp.load_profile(f"m{i}:1b"))
g_doc = run_go(binpath, {"op": "load_profile",
"name": f"m{i}:1b", "store": gstore})
check(f"record-x[{i}]", o_doc, g_doc)
finally:
mp.datetime = real_dt
for seed in CTX_SEEDS:
name = seed["name"]
ostore, gstore = fresh_store(), fresh_store()
oracle_in_store(ostore)
mp.save_profile(mp.ModelProfile.from_dict(seed))
go_state = dict(seed)
run_go(binpath, {"op": "save_profile", "store": gstore, **go_state})
oracle_in_store(ostore)
o_ctx = mp.get_prompt_context(name)
g_ctx = run_go(binpath, {"op": "prompt_context",
"name": name, "store": gstore})
check(f"ctx:{name}", o_ctx, g_ctx)
# save/load round-trip byte parity (raw file text)
for doc in (dataclasses.asdict(full), {"name": "plain-model"},
{"name": "d:1b", "family": "deepseek", "size_gb": 0.0,
"safety_tier": 3, "optimal_temperature": 0.6}):
ostore, gstore = fresh_store(), fresh_store()
oracle_in_store(ostore)
mp.save_profile(mp.ModelProfile.from_dict(doc))
with open(mp.get_profile_path(doc["name"])) as f:
o_raw = f.read()
g_raw = run_go(binpath, {"op": "save_profile",
"store": gstore, **doc})
check(f"save-raw:{doc['name']}", o_raw, g_raw)
# scan sweep (canned server; existing-preservation; dead degrade)
for label, fixture, seed in (
("fresh", {"models": SCAN_MODELS}, None),
("existing", {"models": SCAN_MODELS[:3]}, {"name": "qwen2.5:7b",
"family": "qwen", "interactions": 5, "successes": 4,
"known_refusal_topics": ["old"], "size_gb": 1.0}),
("empty", {"models": []}, None),
("nameless", {"models": [{"size": 1}, {}]}, None)):
srv = canned_server(fixture)
url = f"http://127.0.0.1:{srv.server_address[1]}"
try:
ostore, gstore = fresh_store(), fresh_store()
oracle_in_store(ostore)
if seed:
mp.save_profile(mp.ModelProfile.from_dict(seed))
# seed the GO store with the same file the oracle has
os.makedirs(gstore, exist_ok=True)
for f in os.listdir(ostore):
shutil.copy(os.path.join(ostore, f),
os.path.join(gstore, f))
saved_url = mp.OLLAMA_URL
mp.OLLAMA_URL = url
mp.datetime = FrozenDT
try:
o_profiles = [dataclasses.asdict(p)
for p in mp.scan_all_models()]
finally:
mp.OLLAMA_URL = saved_url
mp.datetime = real_dt
g_profiles = run_go(binpath, {"op": "scan", "store": gstore,
"ollama_url": url,
"now": FROZEN_NOW + "+00:00"})
check(f"scan:{label}", o_profiles, g_profiles)
finally:
srv.shutdown()
# dead-port degrade
ostore, gstore = fresh_store(), fresh_store()
oracle_in_store(ostore)
saved_url = mp.OLLAMA_URL
mp.OLLAMA_URL = "http://127.0.0.1:1"
try:
o_dead = mp.scan_all_models()
finally:
mp.OLLAMA_URL = saved_url
g_dead = run_go(binpath, {"op": "scan", "store": gstore,
"ollama_url": "http://127.0.0.1:1"})
check("scan:dead", o_dead, g_dead)
print(f"parity: {total - fails}/{total} match")
return 1 if fails else 0
if __name__ == "__main__":
raise SystemExit(main())
+196
View File
@@ -0,0 +1,196 @@
#!/usr/bin/env python3
"""check_parallel_processor_parity.py — live oracle-vs-Go parity sweep for
the parallel_processor gap closure (#2479, contract factory-gap-pp).
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, `parallel-processor op`) across every op family — run_parallel,
run_parallel_with_args (full parse-branch matrix), class pools at several
worker counts, status, singleton/global lifecycle, crash parity — plus the
CLI surface (status / test / unknown / usage), comparing sort_keys JSON
(structural) or exact lines. Exit 0 on 100% parity.
Usage: PYTHONPATH=scripts/pp_freeze_seams:src python3 scripts/check_parallel_processor_parity.py
[--bin src/go/parallel-processor/parallel-processor]
"""
import argparse
import json
import os
import subprocess
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
# the rig (on PYTHONPATH) pins threading.active_count to this and binds
# the spec seams; the Go seam is pinned to the same value per process.
FROZEN_ACTIVE = 4
import rune.parallel_processor as pp # noqa: E402
def s(kind, **kw):
d = {"kind": kind}
d.update(kw)
return d
# ── oracle side (rig seams give the spec grammar real callables) ────────────
def py_op(op, req):
if op == "run_parallel":
return pp.run_parallel([_zero(t) for t in req["tasks"]])
if op == "run_parallel_with_args":
return pp.run_parallel_with_args([_task(t) for t in req["tasks"]])
if op == "class_run_parallel":
p = pp.ParallelProcessor(req["max_workers"])
r = p.run_parallel([_zero(t) for t in req["tasks"]])
p.shutdown(wait=True)
return r
if op == "class_run_parallel_with_args":
p = pp.ParallelProcessor(req["max_workers"])
r = p.run_parallel_with_args([_task(t) for t in req["tasks"]])
p.shutdown(wait=True)
return r
if op == "get_status":
return pp.get_status()
if op == "class_get_status":
p = pp.ParallelProcessor(req["max_workers"])
r = {"result": p.get_status(), "max_workers": req["max_workers"]}
p.shutdown(wait=True)
return r
if op == "get_processor_status":
return pp._pp_get_processor_status()
if op == "shutdown_then_status":
return pp._pp_shutdown_then_status()
if op == "shutdown_then_run":
return pp._pp_shutdown_then_run()
if op == "new_bad":
return pp._pp_new_bad()
if op == "shutdown_processor_cycle":
return pp._pp_shutdown_processor_cycle()
raise ValueError(f"unknown op {op}")
def _zero(spec):
return pp._pp_spec_zero(spec)
def _task(spec):
return pp._pp_spec_task(spec)
# ── Go side (one fresh process per op) ──────────────────────────────────────
def go_op(binpath, op, req):
full = dict(req)
full["op"] = op
env = dict(os.environ)
env["PP_ACTIVE_THREADS"] = str(FROZEN_ACTIVE)
p = subprocess.run([str(binpath), "op"], input=json.dumps(full),
capture_output=True, text=True, env=env, cwd=str(REPO))
if p.returncode != 0:
raise RuntimeError(f"go op {op} exited {p.returncode}: {p.stdout} {p.stderr}")
return json.loads(p.stdout)
def jdump(v):
return json.dumps(v, sort_keys=True)
# ── the sweep ───────────────────────────────────────────────────────────────
OPS = [
("run_parallel", {"tasks": [s("call", fn="const", ret=1), s("call", fn="boom", msg="x"), 42, None, "s", True, 4.5, [1], {"a": 1}]}),
("run_parallel", {"tasks": []}),
("run_parallel", {"tasks": [s("call", fn="sleepret", ms=50, ret="a"), s("call", fn="sleepret", ms=5, ret="b"), s("call", fn="sleepret", ms=25, ret="c")]}),
("run_parallel_with_args", {"tasks": [
s("call", fn="echo", args=[1, 2], kwargs={"scale": 10}),
s("call", fn="add", args=[7, 8]),
s("call", fn="add", args=[2.25, 1]),
s("call", fn="boom", msg="wops"),
s("raw", value=3.5),
s("emptytuple"),
s("notcall", value=[3, 4]),
s("argsnotseq", fn="echo", value="xy"),
s("kwnotdict", fn="echo", value="kw"),
]}),
("class_run_parallel", {"max_workers": 2, "tasks": [s("call", fn="const", ret="p"), s("call", fn="const", ret="q"), s("call", fn="boom", msg="in-class"), s("call", fn="sleepret", ms=15, ret="r")]}),
("class_run_parallel", {"max_workers": 8, "tasks": [s("raw", value=False)] * 3 + [s("call", fn="const", ret="ok")]}),
("class_run_parallel_with_args", {"max_workers": 1, "tasks": [s("call", fn="echo"), s("notcall", value=0), s("call", fn="add", args=[20, 22])]}),
("get_status", {}),
("class_get_status", {"max_workers": 1}),
("class_get_status", {"max_workers": 9}),
("get_processor_status", {}),
("shutdown_then_status", {}),
("shutdown_then_run", {}),
("new_bad", {}),
("shutdown_processor_cycle", {}),
]
def cli_lines(argv, env_extra=None, cwd=None):
env = dict(os.environ)
if env_extra:
env.update(env_extra)
p = subprocess.run(argv, capture_output=True, text=True, env=env, cwd=cwd or str(REPO))
return p.returncode, p.stdout, p.stderr
def cli_parity(binpath):
"""CLI surface: status / test / unknown / usage — the oracle's main()."""
checks = []
go_env = {"PP_ACTIVE_THREADS": str(FROZEN_ACTIVE)}
rc_p, out_p, _ = cli_lines([sys.executable, str(REPO / "src/rune/parallel_processor.py"), "status"])
rc_g, out_g, _ = cli_lines([str(binpath), "status"], go_env)
checks.append(("cli status", rc_p == rc_g and out_p == out_g, out_p, out_g))
rc_p, out_p, _ = cli_lines([sys.executable, str(REPO / "src/rune/parallel_processor.py"), "test"])
rc_g, out_g, _ = cli_lines([str(binpath), "test"])
# wall-clock lines vary by design; the Results line and the verdict
# line are the deterministic contract
det = lambda out: (out.strip().splitlines()[-2], out.strip().splitlines()[-1]) # noqa: E731
checks.append(("cli test (results+verdict)", rc_p == rc_g and det(out_p) == det(out_g), det(out_p), det(out_g)))
rc_p, out_p, _ = cli_lines([sys.executable, str(REPO / "src/rune/parallel_processor.py"), "bogus"])
rc_g, out_g, _ = cli_lines([str(binpath), "bogus"])
checks.append(("cli unknown", rc_p == rc_g and out_p == out_g, out_p, out_g))
rc_p, out_p, _ = cli_lines([sys.executable, str(REPO / "src/rune/parallel_processor.py")])
rc_g, out_g, _ = cli_lines([str(binpath)])
checks.append(("cli usage", rc_p == rc_g and out_p == out_g, out_p, out_g))
return checks
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--bin", default=str(REPO / "src/go/parallel-processor/parallel-processor"))
args = ap.parse_args()
binpath = Path(args.bin)
failures = 0
total = 0
for op, req in OPS:
total += 1
py = py_op(op, req)
go = go_op(binpath, op, req)
if jdump(py) != jdump(go):
failures += 1
print(f"DIVERGE {op} {json.dumps(req)[:80]}")
print(f" python: {jdump(py)[:300]}")
print(f" go: {jdump(go)[:300]}")
for name, ok, want, got in cli_parity(binpath):
total += 1
if not ok:
failures += 1
print(f"DIVERGE {name}\n python: {want!r}\n go: {got!r}")
print(f"parity: {total - failures}/{total} match" + (" — FAILURES" if failures else ""))
return 1 if failures else 0
if __name__ == "__main__":
raise SystemExit(main())
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave salience_gate gap contract (RUST 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 SHAs as evidence:
feat 9539d5b6 close PARTIAL gaps — dichotomy wave
phaseB 2350e02e Phase B language-advantage pass — dichotomy wave
Usage: close_contract_salience_gate.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 = "9539d5b6"
PHASEB_SHA = "2350e02e"
EVIDENCE = f"parity {PARITY_SHA}, phase B {PHASEB_SHA}"
iface = ConstructionInterface(builder="factory-gap-sg")
r = iface.submit_need(
"salience_gate dichotomy gap-close (RUST): name-preserving port of the "
"4 audit-missing functions into src/rust/salience_gate (the module's "
"existing delegation side — classification side=RUST; no Go "
"salience-gate dir exists): _sg_core (kernel mirror of the facade "
"availability probe, pin lattice), to_dict (SalienceDecision struct + "
"projection, evaluate_salience flows through it), handle_hook (event "
"echo, data accepted+ignored), test_salience (embedded oracle smoke, "
"print-byte-matched), plus oracle-level evaluate_salience_dict JSON "
"view (shared freeze harness cannot serialize the dataclass return — "
"construction_decision normalize_need_json precedent). Dichotomy audit "
"1/5 PARTIAL -> 6/6 FULL. Three parity defects fixed (frozen-truth "
"battery caught all): novel-family single-append (oracle guards ONE "
"if; duplicate append inflated witness rule), failure-family "
"doesn't-work/not-working arm omitted, word_boundary_contains Python-"
"\\b parity (alphanumeric + underscore + UTF-8 continuation bytes). "
"Frozen truth via shared harness scripts/freeze_truth.py: "
"frozen_sg_truth.verify.json 52 rows byte-identical under "
"freeze_truth.py --verify in BOTH core states (floor SG_RUST_LIB-"
"poisoned AND kernel-built); frozen_sg_truth.json 63-row envelope "
"(multi-family evaluation-order rows + _sg_core row — the shared "
"gate's RUNE_SALIENCE_GATE_CORE pin cannot reach this oracle). "
"branch_battery.rs replays both verbatim via include_str (12 tests); "
"poisoned-truth law: generator pins RUNE_SALIENCE_CORE=python AND "
"poisons SG_RUST_LIB (the module's real floor pins — the facade "
"evaluate path ignores RUNE_*_CORE). Live parity: gen "
"--replay facade live + kernel direct 119/119 (exact evaluation-order "
"kernel rows; facade rows under the oracle's declared sorted-"
"comparison contract); crate canary 6/6; oracle smoke green in 3 pin "
"states (live, probe-pinned, pure floor). Phase B (2350e02e): "
"ASCII-anchored Cow lowercase avoidance (zero-alloc common path, "
"Unicode mappings never skipped), std-only hot-path bench (ns/call "
"over the 56-envelope frozen corpus + ns/scan), #[must_use] pure "
"surface, idiomatic single-append family guards. rustfmt clean, "
"clippy -D warnings clean. Evidence: verification/salience-gate-*.log "
"(cargotest/clippy/freeze-verify/replay/canary/python-pins/goladder/"
"audit, all exit 0, Read back). Delivered on gitea/master: feat "
"9539d5b6, phase B 2350e02e.",
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)
+416
View File
@@ -0,0 +1,416 @@
#!/usr/bin/env python3
"""gen_cron_engine_gap_truth.py — cron-engine gap-closing truth battery
(#2479 dichotomy wave, GO side).
Closes the PARTIAL audit gaps: to_dict, run_task (method + module),
fire_on_task_complete, start/stop, _run_loop, _execute_task,
_log_execution/_log_error, get_cron_engine/start_engine/stop_engine
(parseCronField/shouldRun already existed; extra branch rows frozen too).
Uses the SHARED harness (scripts/freeze_truth.py) with the hook_engine
wrapper-shim law: CronEngine methods are stateful and touch the clock,
HOME (~/.rune/cron.log), subprocesses and threads — none of which the
bare harness pins. Every row is frozen against a module-level WRAPPER
(_ce_* below, in THIS module registered as
gen_cron_engine_gap_truth_shims):
* FROZEN clock: cron_engine.datetime patched with the harness's frozen
class (module-level import → the patch reaches every method).
* HERMETIC per-row HOME: fresh mkdtemp per wrapper call; every path in
the capture is tokenized to <CE_HOME> (no absolute paths in truth).
* _run_loop rows: cron_engine.time swapped for a stopper whose sleep()
flips the engine's running flag — exactly ONE loop iteration, then a
clean exit (deterministic under the frozen clock).
* record_failure (rune.subsystem_health) is neutralized during rows —
the oracle imports it lazily inside except blocks, and its ledger
writes are outside the captured surface.
* capture shape: {"result", "post": {running, storage_path, tasks
(insertion-ordered [name, to_dict] pairs), _last_run_minute},
"files" (~/.rune dir inventory), "storage", "log"}.
Verify (this file ships its own --verify — same byte-compare law as the
harness, plus the shim-module registration the stock CLI cannot do):
python3 scripts/gen_cron_engine_gap_truth.py --verify
Usage: python3 scripts/gen_cron_engine_gap_truth.py (from repo root)
"""
import json
import os
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
from freeze_truth import freeze, write_envelope, _frozen_clock # noqa: E402
FROZEN_NOW = "2026-10-13T09:20:00"
TOKEN = "<CE_HOME>"
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
os.environ["RUNE_CRON_ENGINE_CORE"] = "python" # poisoned-truth law
from rune import cron_engine as CE # noqa: E402
import rune.subsystem_health as _SH # noqa: E402
_CE = {"ready": False}
def _prepare():
"""Idempotent per-process pinning: frozen clock + neutral recorder."""
if not _CE["ready"]:
CE.datetime = _frozen_clock(FROZEN_NOW)
_SH.record_failure = lambda *a, **k: True
_CE["ready"] = True
return CE
class _StopTime:
"""time-module stand-in: first sleep() stops the engine's loop."""
def __init__(self, engine):
self._engine = engine
def sleep(self, _s):
if self._engine is not None:
self._engine.running = False
def _hermetic_home():
home = tempfile.mkdtemp(prefix="ce-freeze-")
os.environ["HOME"] = home
return home
def _log_path(home):
return os.path.join(home, ".rune", "cron.log")
def _build_engine(state, home):
e = CE.CronEngine.__new__(CE.CronEngine)
e.storage_path = state["storage_path"].replace(TOKEN, home)
e.tasks = {}
for name, t in state.get("tasks", {}).items():
e.tasks[name] = CE.CronTask(**t)
e.running = state.get("running", False)
e.thread = None
e._last_run_minute = dict(state.get("_last_run_minute", {}))
return e
def _seed_log(state, home):
d = os.path.dirname(_log_path(home))
for fname, size in state.get("seed_log", {}).items():
os.makedirs(d, exist_ok=True)
with open(os.path.join(d, fname), "wb") as f:
f.write(b"x" * size)
def _capture(e, home, result=None):
d = os.path.dirname(_log_path(home))
files = {}
if os.path.isdir(d):
files = {f: os.path.getsize(os.path.join(d, f))
for f in sorted(os.listdir(d))
if os.path.isfile(os.path.join(d, f))}
def rd(p):
return open(p).read() if os.path.exists(p) else None
return {
"result": result,
"post": {
"running": e.running,
"storage_path": e.storage_path.replace(home, TOKEN),
"tasks": [[n, t.to_dict()] for n, t in e.tasks.items()],
"_last_run_minute": e._last_run_minute,
},
"files": files,
"storage": rd(e.storage_path),
"log": rd(_log_path(home)),
}
# ── wrappers (the frozen fn names) ────────────────────────────────
def _ce_to_dict(task):
_prepare()
return CE.CronTask(**task).to_dict()
def _ce_parse(field, low, high):
_prepare()
return sorted(CE.CronEngine._parse_cron_field(field, low, high))
def _ce_should_run(state, name, y, mo, d, h, mi):
ce = _prepare()
home = _hermetic_home()
e = _build_engine(state, home)
now = ce.datetime(y, mo, d, h, mi, tzinfo=ce.timezone.utc)
return e._should_run(e.tasks[name], now)
def _ce_run_task(state, name):
_prepare()
home = _hermetic_home()
e = _build_engine(state, home)
return _capture(e, home, result=e.run_task(name))
def _ce_fire(state):
_prepare()
home = _hermetic_home()
e = _build_engine(state, home)
return _capture(e, home, result=e.fire_on_task_complete())
def _ce_stop(state):
_prepare()
home = _hermetic_home()
e = _build_engine(state, home)
e.stop()
return _capture(e, home)
def _ce_execute(state, name):
_prepare()
home = _hermetic_home()
e = _build_engine(state, home)
e._execute_task(e.tasks[name])
return _capture(e, home)
def _ce_run_loop(state):
ce = _prepare()
home = _hermetic_home()
_seed_log(state, home)
e = _build_engine(state, home)
real = ce.time
ce.time = _StopTime(e)
try:
e._run_loop()
finally:
ce.time = real
return _capture(e, home)
def _ce_log_execution(state, name, rc):
_prepare()
home = _hermetic_home()
_seed_log(state, home)
e = _build_engine(state, home)
class _R: # CompletedProcess stand-in: only returncode is read
returncode = rc
e._log_execution(e.tasks[name], _R())
return _capture(e, home)
def _ce_log_error(state, name, msg):
_prepare()
home = _hermetic_home()
_seed_log(state, home)
e = _build_engine(state, home)
e._log_error(e.tasks[name], msg)
return _capture(e, home)
def _ce_singleton(op, name="", expr="*/5 * * * *", command="echo hi"):
ce = _prepare()
home = _hermetic_home()
ce._cron_engine = None
if op == "get":
e = ce.get_cron_engine()
return _capture(e, home, result=len(e.list_tasks()))
if op == "start_stop":
# REAL sleeper: the loop thread blocks in its 60s sleep, so the
# mid-capture (running=True) is race-free and stop()'s 5s join
# timeout is exercised — mirrors the Go battery exactly.
ce.start_engine()
mid = _capture(ce._cron_engine, home)
ce.stop_engine()
end = _capture(ce._cron_engine, home)
end["extra"] = mid
return end
if op == "module_run":
e = ce.get_cron_engine()
e.add_task(name, expr, command, "")
r = ce.run_task(name)
return _capture(ce._cron_engine, home, result=r)
if op == "module_list":
e = ce.get_cron_engine()
e.add_task(name, expr, command, "d1")
e.add_task(name + "-2", "*/5 * * * *", "echo two", "d2")
return _capture(e, home, result=[t["name"] for t in ce.list_tasks()])
raise ValueError(op)
# ── case matrix ───────────────────────────────────────────────────
def _task(name, expr, command, **over):
t = {"name": name, "cron_expression": expr, "command": command,
"description": "", "enabled": True, "last_run": None,
"next_run": None, "run_count": 0}
t.update(over)
return t
def _state(tasks=None, **over):
s = {"storage_path": TOKEN + "/.rune/cron.json", "tasks": tasks or {},
"running": False, "_last_run_minute": {}}
s.update(over)
return s
T_ECHO = _task("t-echo", "*/5 * * * *", "echo hello")
def cases():
C = []
# to_dict — pure dataclass rendering (defaults, non-ascii, full state)
C.append(("_ce_to_dict", [dict(
T_ECHO, last_run="2026-01-02T03:04:05+00:00",
next_run="2026-01-02T03:04:05+00:00", run_count=7, description="d")], {}))
C.append(("_ce_to_dict",
[{"name": "m", "cron_expression": "* * * * *", "command": "echo m"}], {}))
C.append(("_ce_to_dict", [dict(T_ECHO, name="ü-task", description="中文 <>&")], {}))
# _parse_cron_field — extra branches beyond the batch-1 matrix
for field, low, high in [("*/15", 0, 59), ("5/15", 0, 59), ("10-5", 0, 59),
("1-10/2,30", 0, 59), ("*", 1, 12),
("2,4-6/2", 1, 12), ("0", 0, 23), ("9-17", 0, 23),
("*/5", 0, 23)]:
C.append(("_ce_parse", [field, low, high], {}))
# _should_run — match/mismatch/dedup/field-count/weekday-7
S = lambda t, **kw: (_state({"t-echo": t}, **kw), "t-echo")
C.append(("_ce_should_run", list(S(T_ECHO)) + [2026, 10, 13, 9, 20], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "30 12 * * *", "echo x"))) + [2026, 10, 13, 9, 20], {}))
C.append(("_ce_should_run",
list(S(T_ECHO, _last_run_minute={"t-echo": "2026-10-13 09:20"}))
+ [2026, 10, 13, 9, 20], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "* * * *", "echo x"))) + [2026, 10, 13, 9, 20], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "* * * * 0", "echo x"))) + [2026, 10, 11, 0, 0], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "* * * * 7", "echo x"))) + [2026, 10, 11, 0, 0], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "* * * * 1", "echo x"))) + [2026, 10, 5, 0, 0], {}))
C.append(("_ce_should_run",
list(S(_task("t-echo", "* * * * 1", "echo x"))) + [2026, 10, 11, 0, 0], {}))
# run_task — every envelope branch
C.append(("_ce_run_task", [_state({"t-echo": T_ECHO}), "t-echo"], {}))
C.append(("_ce_run_task", [_state({"t-echo": T_ECHO}), "ghost"], {}))
C.append(("_ce_run_task",
[_state({"t-nope": _task("t-nope", "* * * * *", "nope-cmd-xyz")}), "t-nope"], {}))
C.append(("_ce_run_task",
[_state({"t-q": _task("t-q", "* * * * *", "echo 'unterminated")}), "t-q"], {}))
C.append(("_ce_run_task",
[_state({"t-false": _task("t-false", "* * * * *", "false")}), "t-false"], {}))
C.append(("_ce_run_task",
[_state({"t-sh": _task("t-sh", "* * * * *", "sh -c 'echo out; echo err 1>&2'")}),
"t-sh"], {}))
C.append(("_ce_run_task",
[_state({"t-esc": _task("t-esc", "* * * * *", "echo a\\ b")}), "t-esc"], {}))
# fire_on_task_complete — order, disabled, non-on_complete, failures
C.append(("_ce_fire", [_state({
"oc-first": _task("oc-first", "on_complete", "echo one"),
"t-sched": _task("t-sched", "5 4 * * *", "echo sched"),
"oc-second": _task("oc-second", "on_complete", "echo two"),
"oc-off": _task("oc-off", "on_complete", "echo off", enabled=False),
})], {}))
C.append(("_ce_fire", [_state({
"oc-bad": _task("oc-bad", "on_complete", "nope-cmd-xyz"),
})], {}))
# stop (thread=None paths)
C.append(("_ce_stop", [_state({"t-echo": T_ECHO}, running=True)], {}))
C.append(("_ce_stop", [_state(running=False)], {}))
# _execute_task — success + failure-to-log paths
C.append(("_ce_execute", [_state({"t-echo": T_ECHO}), "t-echo"], {}))
C.append(("_ce_execute",
[_state({"t-nope": _task("t-nope", "* * * * *", "nope-cmd-xyz")}), "t-nope"], {}))
# _run_loop — stopped / fires / silent / dedup-guard
C.append(("_ce_run_loop", [_state({"t-echo": T_ECHO}, running=False)], {}))
C.append(("_ce_run_loop", [_state({"t-echo": T_ECHO}, running=True)], {}))
C.append(("_ce_run_loop",
[_state({"t-sched": _task("t-sched", "5 4 * * *", "echo sched")}, running=True)], {}))
C.append(("_ce_run_loop",
[_state({"t-echo": T_ECHO}, running=True,
_last_run_minute={"t-echo": "2026-10-13 09:20"})], {}))
# _log_execution / _log_error — fresh, append, rotation (both sides
# of the 5MB threshold)
ROT = 5 * 1024 * 1024
C.append(("_ce_log_execution", [_state({"t-echo": T_ECHO}), "t-echo", 0], {}))
C.append(("_ce_log_execution",
[_state({"t-echo": T_ECHO}, seed_log={"cron.log": 12}), "t-echo", 3], {}))
C.append(("_ce_log_execution",
[_state({"t-echo": T_ECHO},
seed_log={"cron.log": ROT + 1, "cron.log.1": 100, "cron.log.2": 7}),
"t-echo", 0], {}))
C.append(("_ce_log_execution",
[_state({"t-echo": T_ECHO}, seed_log={"cron.log": ROT}), "t-echo", 0], {}))
C.append(("_ce_log_error",
[_state({"t-nope": _task("t-nope", "* * * * *", "nope-cmd-xyz")}),
"t-nope", "[Errno 2] No such file or directory: 'nope-cmd-xyz'"], {}))
# singleton family (module-level fns)
C.append(("_ce_singleton", ["get", "", "", ""], {}))
C.append(("_ce_singleton", ["start_stop", "", "", ""], {}))
C.append(("_ce_singleton", ["module_run", "m1", "*/5 * * * *", "echo via-global"], {}))
C.append(("_ce_singleton", ["module_list", "n1", "on_complete", "echo one"], {}))
return C
SHIMS = "gen_cron_engine_gap_truth_shims"
def main():
sys.modules[SHIMS] = sys.modules["__main__"]
truth = freeze(SHIMS, cases(), oracle_module=SHIMS)
target = REPO / "src" / "go" / "cron-engine" / "truth_gap.json"
write_envelope(FROZEN_NOW, truth, target)
print(f"wrote {target} ({len(truth)} cases)")
def verify(path):
raw = json.loads(path.read_text())
frozen = raw["cases"] if isinstance(raw, dict) else raw
if isinstance(raw, dict) and raw.get("frozen_now"):
os.environ["RUNE_FROZEN_NOW"] = raw["frozen_now"]
sys.modules[SHIMS] = sys.modules["__main__"]
recased = [{"fn": c["fn"], "args": c.get("args", []), "kwargs": c.get("kwargs", {})}
for c in frozen]
fresh = freeze(SHIMS, recased, oracle_module=SHIMS)
if json.dumps(fresh, sort_keys=True) != json.dumps(frozen, sort_keys=True):
print(f"MISMATCH: regenerated truth differs from {path}")
for f, g in zip(frozen, fresh):
if json.dumps(f, sort_keys=True) != json.dumps(g, sort_keys=True):
print(f" first divergence at fn={f['fn']}")
print(f" frozen: {json.dumps(f['expected'])[:300]}")
print(f" oracle: {json.dumps(g['expected'])[:300]}")
break
return 1
print(f"OK: {len(frozen)} cases byte-identical against live oracle")
return 0
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--verify":
sys.exit(verify(REPO / "src" / "go" / "cron-engine" / "truth_gap.json"))
main()
+416
View File
@@ -0,0 +1,416 @@
#!/usr/bin/env python3
"""gen_microkernel_gap_truth.py — microkernel gap-closing truth battery
(dichotomy wave #2479, worktree rune-wave-cq).
Closes the PARTIAL audit gaps: now_iso, discover, _extract_manifest,
_load_registry, _save_registry, _run_hook (fire's hook runner).
Uses the SHARED harness (scripts/freeze_truth.py): RUNE core pinned to
python, deep-copied inputs, envelope with its own frozen_now:
PYTHONPATH=src python3 scripts/freeze_truth.py \
--verify src/go/microkernel/truth_microkernel_gap.json \
--module rune.microkernel
STATEFULNESS / DETERMINISM LAWS:
* _extract_manifest takes an fpath — the shim carries the file CONTENT
in args, writes a temp file, calls the real oracle fn, returns the
parsed manifest (paths never enter the result).
* discover iterates os.listdir (filesystem order) and stamps absolute
_file paths — the shim installs a fixture dir, pins os.listdir to the
EXACT frozen filename order (sorted — matches the Go port's
os.ReadDir), calls the real discover(), and normalizes every path to
<dir>/<fname> stubs. Machine-independent, replay-stable.
* _run_hook is a closure inside fire() — it is exercised through the
real fire() with ONE listener per branch class (fixture scripts are
in-file constants: deterministic stdout/stderr). wall-clock durations
(duration_ms / total_duration_ms) are normalized to "<ms>" — the
no-wall-clock law.
* _load_registry/_save_registry: missing file, corrupt file, full-shape
file (verbatim load), and a save->load roundtrip of the default shape.
Usage: python3 scripts/gen_microkernel_gap_truth.py (from repo root)
python3 scripts/gen_microkernel_gap_truth.py --verify
"""
import copy
import json
import os
import sys
import tempfile
from datetime import datetime as _dt, timezone as _tz
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
from freeze_truth import freeze, write_envelope # noqa: E402
FROZEN_NOW = "2026-10-13T11:05:00"
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
os.environ["RUNE_MICROKERNEL_CORE"] = "python" # poisoned-truth law
import microkernel as mk # noqa: E402
SHIM = "gen_microkernel_gap_truth_shims"
def _pin_mk_clock():
"""microkernel's fire() mixes datetime.now() (naive) and
datetime.now(timezone.utc) (aware) — the harness clock is naive-only,
so shims that reach register()/fire() pin an AWARE frozen clock.
Durations collapse to 0.0 (normalized to <ms> by the rig regardless)."""
base = _dt.fromisoformat(FROZEN_NOW).replace(tzinfo=_tz.utc)
class _Frozen(_dt):
@classmethod
def now(cls, tz=None):
if tz is not None:
return base.replace(tzinfo=tz)
return base
old = mk.datetime
mk.datetime = _Frozen
return old
# ── fixture hook scripts (deterministic output; stdlib only) ──────────────
OK_JSON = (
"import json, sys\n"
"data = sys.argv[sys.argv.index('--data') + 1]\n"
"print(json.dumps({'echo': json.loads(data)}))\n"
)
RAW_LONG = (
"print('h\\u00e9llo-\\u2192ok ' * 120)\n" # 1200 codepoints, non-JSON
)
BOOM = (
"import sys\n"
"sys.stderr.write('\\u00e9rr\\u00f4r-' * 100)\n" # 600 codepoints
"sys.exit(3)\n"
)
SLOW = "import time\ntime.sleep(5)\n"
def _norm_fire(result):
"""Normalize wall-clock fields + as_completed order (the rig law)."""
out = copy.deepcopy(result)
if "total_duration_ms" in out:
out["total_duration_ms"] = "<ms>"
for r in out.get("results", []):
if "duration_ms" in r:
r["duration_ms"] = "<ms>"
if isinstance(r.get("error"), str):
r["error"] = r["error"]
out["results"] = sorted(out.get("results", []), key=lambda r: r.get("name", ""))
return out
def _norm_log(log):
out = []
for e in log:
e = dict(e)
e["duration_ms"] = "<ms>"
out.append(e)
return out
def _registry_projection(reg, dir_token):
plugins = {}
for name, p in reg["plugins"].items():
plugins[name] = {
"active": p.get("active"),
"registered_at": p.get("registered_at"),
"file": p.get("file", "").replace(dir_token, "<dir>"),
}
return {
"plugins": plugins,
"capabilities": reg.get("capabilities", {}),
"hooks": reg.get("hooks", {}),
}
# ── wrapper shims: module-level names the harness can call ────────────────
def _mk_extract(content):
fd, fpath = tempfile.mkstemp(suffix=".py", prefix="mk_gap_")
try:
with os.fdopen(fd, "w") as f:
f.write(content)
return {"result": copy.deepcopy(mk._extract_manifest(fpath))}
finally:
os.unlink(fpath)
def _mk_discover(filenames, contents, now):
"""Fixture-driven discover: filenames (EXACT listing order — pass them
sorted, matching the Go port's os.ReadDir), contents {fname: source}."""
work = tempfile.mkdtemp(prefix="mk_disc_")
fixture = Path(work) / "scripts"
fixture.mkdir()
for fname, src in contents.items():
(fixture / fname).write_text(src)
tmpdb = os.path.join(work, "registry.json")
old_dir, old_db = mk.SCRIPTS_DIR, mk.REGISTRY_DB
real_listdir = os.listdir
old_clock = _pin_mk_clock()
mk.SCRIPTS_DIR = str(fixture)
mk.REGISTRY_DB = tmpdb
os.listdir = lambda p: list(filenames) if str(p) == str(fixture) else real_listdir(p)
try:
result = copy.deepcopy(mk.discover())
state = _registry_projection(mk._load_registry(), str(fixture))
finally:
os.listdir = real_listdir
mk.SCRIPTS_DIR, mk.REGISTRY_DB = old_dir, old_db
mk.datetime = old_clock
return {"result": result, "registry": state}
def _mk_load(content):
"""_load_registry over a fixture registry file (None = missing file).
Projection: the port stores TYPED manifests, so the frozen contract is
the round-tripped shape (active/registered_at/file + indexes + log),
not the verbatim manifest dict."""
work = tempfile.mkdtemp(prefix="mk_load_")
db = os.path.join(work, "registry.json")
old_db = mk.REGISTRY_DB
mk.REGISTRY_DB = db
try:
if content is not None:
with open(db, "w") as f:
f.write(content)
elif os.path.exists(db):
os.unlink(db)
loaded = mk._load_registry()
return {"result": _registry_projection(loaded, "<none>"), "log": loaded.get("log", [])}
finally:
mk.REGISTRY_DB = old_db
def _mk_save_load_default():
"""_save_registry -> _load_registry roundtrip of the default shape."""
work = tempfile.mkdtemp(prefix="mk_rt_")
db = os.path.join(work, "registry.json")
old_db = mk.REGISTRY_DB
mk.REGISTRY_DB = db
try:
loaded = mk._load_registry()
mk._save_registry(loaded)
again = mk._load_registry()
return {"first": copy.deepcopy(loaded), "again": copy.deepcopy(again),
"stable": loaded == again}
finally:
mk.REGISTRY_DB = old_db
def _mk_fire(script, manifest, event, data, timeout):
"""fire() with ONE registered listener whose _file is the fixture
script (or a ghost/empty path for the not-found class). Exercises the
oracle's _run_hook closure branch selected by the fixture."""
work = tempfile.mkdtemp(prefix="mk_fire_")
if script is not None:
fpath = os.path.join(work, "plugin.py")
with open(fpath, "w") as f:
f.write(script)
manifest = dict(manifest)
manifest["_file"] = fpath
else:
manifest = dict(manifest) # _file stays whatever the caller set
tmpdb = os.path.join(work, "registry.json")
old_db = mk.REGISTRY_DB
old_clock = _pin_mk_clock()
mk.REGISTRY_DB = tmpdb
try:
mk.register(manifest)
result = mk.fire(event, data=data, timeout=timeout)
state = mk._load_registry()
return {"result": _norm_fire(result), "log": _norm_log(state.get("log", []))}
finally:
mk.REGISTRY_DB = old_db
mk.datetime = old_clock
def _mk_fire_two(scripts, manifests, event, data, timeout):
"""fire() with TWO listeners (parallelism + log entry)."""
work = tempfile.mkdtemp(prefix="mk_fire2_")
tmpdb = os.path.join(work, "registry.json")
old_db = mk.REGISTRY_DB
old_clock = _pin_mk_clock()
mk.REGISTRY_DB = tmpdb
try:
for script, manifest in zip(scripts, manifests):
manifest = dict(manifest)
if script is not None:
fpath = os.path.join(work, manifest["name"] + ".py")
with open(fpath, "w") as f:
f.write(script)
manifest["_file"] = fpath
mk.register(manifest)
result = mk.fire(event, data=data, timeout=timeout)
state = mk._load_registry()
return {"result": _norm_fire(result), "log": _norm_log(state.get("log", []))}
finally:
mk.REGISTRY_DB = old_db
mk.datetime = old_clock
CACHEY = (
'PLUGIN = {\n'
' "name": "cache",\n'
' "version": "0.1.0",\n'
' "description": "Cache system — event-driven invalidation.",\n'
' "capabilities": ["cache", "invalidation"],\n'
' "hooks": {\n'
' "on_session_end": "handle_hook",\n'
' "on_memory_add": "handle_hook",\n'
' },\n'
' "dependencies": [],\n'
' "priority": 1,\n'
' "auto_activate": True,\n'
'}\n'
)
def main():
sys.modules[SHIM] = sys.modules["__main__"]
cases = []
# ── now_iso (pinned clock: RUNE_FROZEN_NOW → datetime frozen) ──
cases.append(("now_iso", [], {}))
# ── _extract_manifest branches ────────────────────────────────
cases.append((f"{SHIM}._mk_extract", [CACHEY], {}))
cases.append((f"{SHIM}._mk_extract", ["X = 1\n"], {}))
cases.append((f"{SHIM}._mk_extract", ["PLUGIN = {}\n"], {}))
cases.append((f"{SHIM}._mk_extract", ["PLUGIN = {}\nX = 1\n"], {}))
cases.append((f"{SHIM}._mk_extract", ['PLUGIN = {\n "name": "x",\n'], {}))
cases.append((f"{SHIM}._mk_extract",
["PLUGIN = {'name': 'café', 'n': 1.5, 'neg': -3, 'big': 1e3}\n"], {}))
cases.append((f"{SHIM}._mk_extract",
['PLUGIN = {\n # comment inside\n "name": "x",\n}\n'], {}))
cases.append((f"{SHIM}._mk_extract",
['PLUGIN = {\n "name": "x",\n "hooks": {"a": True, "b": False},\n "nested": {"deep": [1, 2, {"k": "v"}]},\n}\n'], {}))
# ── discover (fixture dir, pinned listing order = sorted) ─────
mixed_files = ["_private.py", "a_cache.py", "b_noname.py", "c_plain.py",
"d_falsy.py", "microkernel.py", "notes.txt"]
mixed_contents = {
"a_cache.py": CACHEY,
"b_noname.py": 'PLUGIN = {\n "version": "0.1.0",\n}\n',
"c_plain.py": "def run():\n pass\n",
"d_falsy.py": ('PLUGIN = {\n "name": "d",\n "capabilities": ["d"],\n'
' "hooks": {"on_x": False, "on_y": "", "on_z": 0},\n}\n'),
"_private.py": CACHEY,
"microkernel.py": CACHEY,
"notes.txt": "not a plugin",
}
cases.append((f"{SHIM}._mk_discover", [mixed_files, mixed_contents, FROZEN_NOW], {}))
cases.append((f"{SHIM}._mk_discover", [[], {}, FROZEN_NOW], {}))
shared_files = ["s1.py", "s2.py"]
shared_contents = {
"s1.py": 'PLUGIN = {\n "name": "s1",\n "capabilities": ["shared"],\n "priority": 5,\n}\n',
"s2.py": 'PLUGIN = {\n "name": "s2",\n "capabilities": ["shared"],\n "priority": 10,\n}\n',
}
cases.append((f"{SHIM}._mk_discover", [shared_files, shared_contents, FROZEN_NOW], {}))
# ── _load_registry / _save_registry ───────────────────────────
full_registry = json.dumps({
"plugins": {"p": {"manifest": {"name": "p", "priority": 1},
"registered_at": "2026-10-13T11:05:00+00:00",
"active": True, "file": "/x/p.py"}},
"capabilities": {"cap": ["p"]},
"hooks": {"evt": ["p"]},
"log": [{"event": "evt", "timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1, "duration_ms": 12.5}],
}, indent=2)
cases.append((f"{SHIM}._mk_load", [None], {}))
cases.append((f"{SHIM}._mk_load", ["{oops"], {}))
cases.append((f"{SHIM}._mk_load", [full_registry], {}))
cases.append((f"{SHIM}._mk_save_load_default", [], {}))
# ── _run_hook (through fire, one branch class per case) ───────
evt = "on_session_end"
cases.append((f"{SHIM}._mk_fire",
[OK_JSON, {"name": "okp", "hooks": {evt: True}},
evt, {"k": "v", "n": 2}, 30], {}))
cases.append((f"{SHIM}._mk_fire",
[RAW_LONG, {"name": "rawp", "hooks": {evt: True}}, evt, None, 30], {}))
cases.append((f"{SHIM}._mk_fire",
[BOOM, {"name": "boomp", "hooks": {evt: True}}, evt, None, 30], {}))
cases.append((f"{SHIM}._mk_fire",
[SLOW, {"name": "slowp", "hooks": {evt: True}}, evt, None, 1], {}))
cases.append((f"{SHIM}._mk_fire",
[OK_JSON, {"name": "offp", "hooks": {evt: True}, "auto_activate": False},
evt, None, 30], {}))
cases.append((f"{SHIM}._mk_fire",
[None, {"name": "ghostp", "hooks": {evt: True}, "_file": "/nonexistent/ghost.py"},
evt, None, 30], {}))
cases.append((f"{SHIM}._mk_fire",
[None, {"name": "nofilep", "hooks": {evt: True}}, evt, None, 30], {}))
# fire with NO listeners: early return, no log entry
cases.append((f"{SHIM}._mk_fire",
[OK_JSON, {"name": "lonely", "capabilities": ["x"]}, "no_such_event", None, 30], {}))
# two listeners in parallel: sorted results + one log entry
cases.append((f"{SHIM}._mk_fire_two",
[[OK_JSON, OK_JSON],
[{"name": "zz", "hooks": {evt: True}},
{"name": "aa", "hooks": {evt: True}}],
evt, {"k": 1}, 30], {}))
# harness resolves dotted names against ONE module — freeze per case
# against the fn's OWN module (same law as gen_hook_engine_gap_truth).
truth = []
for fn, args, kwargs in cases:
if fn.startswith(f"{SHIM}."):
mod, short = SHIM, fn.split(".")[-1]
else:
mod, short = "microkernel", fn
rows = freeze(mod, [(short, args, kwargs)], oracle_module=mod)
rows[0]["fn"] = fn
rows[0]["oracle"] = mod
truth.append(rows[0])
target = REPO / "src" / "go" / "microkernel" / "truth_microkernel_gap.json"
write_envelope(FROZEN_NOW, truth, target)
print(f"wrote {target} ({len(truth)} cases)")
def verify(path):
"""Per-case-module verify (same byte-compare law as the harness)."""
raw = json.loads(path.read_text())
frozen = raw["cases"] if isinstance(raw, dict) else raw
if isinstance(raw, dict) and raw.get("frozen_now"):
os.environ["RUNE_FROZEN_NOW"] = raw["frozen_now"]
sys.modules.setdefault(SHIM, sys.modules["__main__"])
fresh = []
for c in frozen:
mod = c.get("oracle", "microkernel")
short = c["fn"].split(".")[-1]
rows = freeze(mod, [(short, c.get("args", []), c.get("kwargs", {}))],
oracle_module=mod)
rows[0]["fn"] = c["fn"]
rows[0]["oracle"] = mod
fresh.append(rows[0])
if json.dumps(fresh, sort_keys=True) != json.dumps(frozen, sort_keys=True):
print(f"MISMATCH: regenerated truth differs from {path}")
for f, g in zip(frozen, fresh):
if json.dumps(f, sort_keys=True) != json.dumps(g, sort_keys=True):
print(f" first divergence at fn={f['fn']}")
print(f" frozen: {json.dumps(f['expected'])[:300]}")
print(f" oracle: {json.dumps(g['expected'])[:300]}")
break
return 1
print(f"OK: {len(frozen)} cases byte-identical against live oracles")
return 0
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--verify":
sys.exit(verify(REPO / "src" / "go" / "microkernel" / "truth_microkernel_gap.json"))
main()
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env python3
"""gen_model_profiles_truth.py — freeze model_profiles oracle truth via
the SHARED harness (scripts/freeze_truth.py, freeze()) through the
scripts/mp_freeze_seams rig (auto-imported sitecustomize: HOME pinned
to MP_FREEZE_HOME before the oracle import, per-case hermetic store
wipe+seed, canned Ollama server, JSON-safe wrapper seams).
Laws honoured:
* hermetic: PROFILES_DIR is expanduser-derived AT IMPORT — the rig
pins HOME to the fixed /tmp/mp_gap_freeze_home root (the CI_FREEZE_HOME
precedent: frozen absolute paths stay byte-identical across processes).
* no wall-clock: created/last_used come from the harness's frozen
clock (write_envelope carries RUNE_FROZEN_NOW inside the file).
* no network: scan_all_models runs against a canned in-process server
(or a refused port for the degrade branch); OLLAMA_URL is repointed
per case at call time.
* self-contained rows: every stateful seam wipes + re-seeds the store
from its args, so --verify replays byte-identically in any order.
* byte-parity corpus: save_profile rows carry the RAW file text — the
Go port's Python-shaped JSON writer must reproduce it exactly
(asdict field order, indent=2 separators, float rendering, ASCII
escaping). Seeds keep integral floats in float form (0.0) — the
integral-float law; int-valued size_gb/optimal_temperature seeds
render differently (Python keeps the int) and stay out of the corpus.
Regenerate + re-verify (byte-identical law — two runs, then verify):
PYTHONPATH=scripts/mp_freeze_seams:src python3 scripts/gen_model_profiles_truth.py
PYTHONPATH=scripts/mp_freeze_seams:src python3 scripts/freeze_truth.py \
--verify src/go/model-profiles/frozen_mp_truth.json \
--module rune.model_profiles
"""
import json
import os
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
from freeze_truth import freeze, write_envelope # noqa: E402 (shared harness)
FROZEN_NOW = "2026-10-13T09:41:23.123456"
OUT = REPO / "src" / "go" / "model-profiles" / "frozen_mp_truth.json"
FULL_STATE = {
"name": "qwen2.5:7b",
"display_name": "Qwen2.5 7B ✓",
"family": "qwen",
"parameters": "7B",
"quantization": "Q4_K_M",
"size_gb": 4.7,
"strengths": ["reasoning", "coding", "instruction-following", "multilingual"],
"weaknesses": ["verbose thinking"],
"prompting_tips": [
"Be direct", "Use structure", "Specify the language", "Ask for concise",
],
"safety_tier": 2,
"known_refusal_topics": ["weapons", "malware"],
"thinking_format": "<think>",
"response_style": "concise",
"context_window": 32768,
"optimal_temperature": 0.7,
"interactions": 10,
"successes": 7,
"failures": 3,
"last_used": "2026-10-12T00:00:00+00:00",
"created": "2026-10-01T00:00:00+00:00",
}
QWEN_FILE = "qwen2.5_7b.json"
SCAN_FRESH = {"models": [
{"name": "qwen2.5:7b", "size": 7516192768},
{"name": "banker-tie-lo:2b", "size": 2415919104}, # 2.25 GB → 2.2 (ties-to-even)
{"name": "banker-tie-hi:2b", "size": 2952790016}, # 2.75 GB → 2.8 (ties-to-even)
{"size": 123}, # no name → skipped
{"name": "noninteger:5b", "size": 5000000000}, # 4.656… → 4.7
]}
SCAN_EXISTING = {"models": [
{"name": "qwen2.5:7b", "size": 7516192768},
{"name": "llama3.1:8b-q4_K_M", "size": 4831838208}, # 4.5 GB
]}
CASES = [
# ── get_profile_path: filesystem sanitization ────────────────────
("seam_get_profile_path", ("qwen2.5:7b",), {}),
("seam_get_profile_path", ("library/qwen3:14b",), {}),
("seam_get_profile_path", ("a?b:c/d",), {}),
("seam_get_profile_path", ("plain-model",), {}),
# ── load_profile: disk → dataclass, suppressed-exception floor ───
("seam_load_profile", ("qwen2.5:7b", {QWEN_FILE: FULL_STATE}), {}),
("seam_load_profile", ("qwen2.5:7b", None), {}), # no file → None
("seam_load_profile", ("qwen2.5:7b", {"other_7b.json": FULL_STATE}), {}), # wrong file → None
("seam_load_profile", ("qwen2.5:7b", {QWEN_FILE: "{not json"}), {}), # corrupt → None
("seam_load_profile", ("qwen2.5:7b", {QWEN_FILE: { # unknown keys filtered
"name": "qwen2.5:7b", "bogus": 1, "family": "qwen"}}), {}),
("seam_load_profile", ("qwen2.5:7b", {QWEN_FILE: { # missing optionals → defaults
"name": "qwen2.5:7b", "interactions": 5}}), {}),
("seam_load_profile", ("qwen2.5:7b", {QWEN_FILE: {"family": "qwen"}}), {}), # missing name → TypeError suppressed
# ── save_profile: BYTE-PARITY corpus (raw file text) ─────────────
("seam_save_profile", (FULL_STATE,), {}),
("seam_save_profile", ({"name": "plain-model"},), {}), # all defaults
("seam_save_profile", ({
"name": "deepseek-r1:32b", "family": "deepseek", "parameters": "32B",
"size_gb": 0.0, "strengths": [], "safety_tier": 3,
"optimal_temperature": 0.6,
},), {}),
# ── build_profile_from_ollama: knowledge merge + clock + tier ────
("seam_build_profile_from_ollama", ("qwen3:14b", {"display_name": "Qwen3 14B", "size_gb": 9.0}), {}),
("seam_build_profile_from_ollama", ("mistral-7b", None), {}),
("seam_build_profile_from_ollama", ("dolphin-uncensored:7b", None), {}),
("seam_build_profile_from_ollama", ("DAVIDAU-test:14b", None), {}),
("seam_build_profile_from_ollama", ("some-new-model", {"display_name": "X"}), {}),
("seam_build_profile_from_ollama", ("deepseek-r1:32b", {"display_name": "DS", "size_gb": 19.2}), {}),
# ── scan_all_models: Ollama sweep (canned server / dead port) ────
("seam_scan_all_models", (SCAN_FRESH,), {}),
("seam_scan_all_models", (SCAN_EXISTING, {QWEN_FILE: FULL_STATE}), {}), # existing → learned data kept
("seam_scan_all_models", ({"models": [{"name": "phi3:mini"}]}, None), {}), # no size → 0.0
("seam_scan_all_models", ("dead", None), {}),
# ── get_or_create_profile: load-or-build-and-save ────────────────
("seam_get_or_create_profile", ("qwen2.5:7b", {QWEN_FILE: FULL_STATE}), {}),
("seam_get_or_create_profile", ("brand-new-model", None), {}),
# ── record_interaction: learning accumulator (state = the contract)
("seam_record_interaction", ("qwen3:14b", [[True, ""]], None), {}),
("seam_record_interaction", ("fresh-fail:1b", [[False, "refuses weapons"]], None), {}),
("seam_record_interaction", ("dup-topic:1b", [[False, "t1"], [False, "t1"]], None), {}),
("seam_record_interaction", ("no-topic:1b", [[False, ""]], None), {}),
("seam_record_interaction", ("qwen2.5:7b", [[False, "politics"]], {QWEN_FILE: FULL_STATE}), {}),
# ── get_prompt_context: operator string assembly ─────────────────
("seam_get_prompt_context", ("qwen2.5:7b", {QWEN_FILE: FULL_STATE}), {}),
("seam_get_prompt_context", ("tips-only:1b", {"tips-only_1b.json": {
"name": "tips-only:1b", "prompting_tips": ["tip one"]}}), {}),
("seam_get_prompt_context", ("unknown-model-x", None), {}), # fresh unknown → ""
# ── to_dict / from_dict (dataclass surface) ──────────────────────
("seam_to_dict", (FULL_STATE,), {}),
("seam_from_dict", ({"name": "n", "bogus_key": 1, "context_window": 8192},), {}),
]
def main() -> int:
# The harness clock pin is env-driven (RUNE_FROZEN_NOW) — set it for
# the generation run too, not just --verify (write_envelope then
# carries the same instant for byte-identical re-freezes).
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
truth = freeze("model_profiles", CASES, oracle_module="rune.model_profiles")
write_envelope(FROZEN_NOW, truth, OUT)
print(f"froze {len(truth)} cases -> {OUT}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+418
View File
@@ -0,0 +1,418 @@
#!/usr/bin/env python3
"""gen_mp_battery.py — ONE-SHOT generator: emit
src/go/model-profiles/frozen_battery_test.go with the frozen truth
(frozen_mp_truth.json) embedded VERBATIM (never hand-transcribed) plus
the dispatch harness. Re-run after any truth regeneration."""
import json
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
TRUTH = REPO / "src" / "go" / "model-profiles" / "frozen_mp_truth.json"
OUT = REPO / "src" / "go" / "model-profiles" / "frozen_battery_test.go"
HARNESS = r'''package main
// frozen_battery_test.go — gap-closing wave (#2479 dichotomy tranche):
// replays the shared-harness frozen oracle truth (generated by
// scripts/gen_model_profiles_truth.py via scripts/freeze_truth.py
// through the scripts/mp_freeze_seams rig, RUNE_FROZEN_NOW pinned)
// VERBATIM, in order, against the store seam repointed at a fresh temp
// dir. The case sequence is self-seeding: replaying it from an empty
// store regenerates every byte of expected state — exactly what
// PYTHONPATH=scripts/mp_freeze_seams:src python3 scripts/freeze_truth.py \
// --verify src/go/model-profiles/frozen_mp_truth.json \
// --module rune.model_profiles
// checks against the live oracle. (GENERATED by scripts/gen_mp_battery.py
// — do not hand-edit the truth const.)
//
// DIVERGENCE (documented, not a bug — the local_tool_runtime precedent):
// load_profile({"name": <non-string>}) is ACCEPTED by the Python oracle
// (dataclass __init__ performs no type checks) but REJECTED by the Go
// port (typed signature). No frozen row carries that shape.
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
)
const frozenMpTruthJSON = `__TRUTH__`
func decodeMPArg(t *testing.T, raw json.RawMessage, dst any) {
t.Helper()
var v any
if err := json.Unmarshal(raw, &v); err != nil {
t.Fatalf("arg decode: %v", err)
}
if v == nil {
return // null → leave the zero value (None default)
}
if err := json.Unmarshal(raw, dst); err != nil {
t.Fatalf("arg re-decode: %v", err)
}
}
func profileToMap(p ModelProfile) map[string]any {
raw, err := json.Marshal(p)
if err != nil {
panic(err)
}
var m map[string]any
if err := json.Unmarshal(raw, &m); err != nil {
panic(err)
}
return m
}
func seedStore(t *testing.T, seed map[string]json.RawMessage) {
t.Helper()
if err := os.MkdirAll(profilesDir, 0o755); err != nil {
t.Fatal(err)
}
for name, raw := range seed {
var v any
if err := json.Unmarshal(raw, &v); err != nil {
t.Fatalf("seed decode: %v", err)
}
var data []byte
if s, ok := v.(string); ok {
data = []byte(s) // raw-text seed (corrupt-JSON floor)
} else {
data, _ = json.Marshal(v)
}
if err := os.WriteFile(filepath.Join(profilesDir, name), data, 0o644); err != nil {
t.Fatal(err)
}
}
}
func storeFiles() map[string]any {
out := map[string]any{}
entries, err := os.ReadDir(profilesDir)
if err != nil {
return out
}
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".json") {
continue
}
raw, err := os.ReadFile(filepath.Join(profilesDir, e.Name()))
if err != nil {
continue
}
var v any
if err := json.Unmarshal(raw, &v); err != nil {
continue
}
out[e.Name()] = v
}
return out
}
// dispatchFrozen — one frozen case against the ported surface. Stateful
// ops mirror the rig seams: wipe the store, seed from the args, run,
// return the JSON-native projection.
func dispatchFrozen(t *testing.T, fn string, args []json.RawMessage) any {
t.Helper()
arg := func(i int, dst any) { decodeMPArg(t, args[i], dst) }
argOpt := func(i int, dst any) {
if i < len(args) {
decodeMPArg(t, args[i], dst)
}
}
switch fn {
case "seam_get_profile_path":
var name string
arg(0, &name)
got := getProfilePath(name)
rel, err := filepath.Rel(profilesDir, got)
if err != nil {
t.Fatal(err)
}
// The frozen expectation carries the rig's absolute path; the
// contract is the sanitized FILE NAME (store root is the seam).
return filepath.Join("$STORE", rel)
case "seam_load_profile":
var name string
arg(0, &name)
var seed map[string]json.RawMessage
argOpt(1, &seed)
os.RemoveAll(profilesDir)
if seed != nil {
seedStore(t, seed)
}
if p, ok := loadProfile(name); ok {
return profileToMap(*p)
}
return nil
case "seam_save_profile":
var state map[string]json.RawMessage
arg(0, &state)
p := profileFromState(t, state)
os.RemoveAll(profilesDir)
saveProfile(p)
raw, err := os.ReadFile(getProfilePath(p.Name))
if err != nil {
t.Fatalf("save wrote nothing: %v", err)
}
return map[string]any{"raw": string(raw), "parsed": storeFiles()}
case "seam_build_profile_from_ollama":
var name string
arg(0, &name)
var info map[string]any
arg(1, &info)
return profileToMap(buildProfileFromOllama(name, info))
case "seam_scan_all_models":
var fixture any
arg(0, &fixture)
var seed map[string]json.RawMessage
argOpt(1, &seed)
os.RemoveAll(profilesDir)
if seed != nil {
seedStore(t, seed)
}
saved := ollamaURL
var srv *httptest.Server
if s, ok := fixture.(string); ok && s == "dead" {
ollamaURL = "http://127.0.0.1:1"
} else {
payload, _ := json.Marshal(fixture)
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(payload)
}))
ollamaURL = srv.URL
}
profiles := scanAllModels()
ollamaURL = saved
if srv != nil {
srv.Close()
}
out := make([]any, len(profiles))
for i, p := range profiles {
out[i] = profileToMap(p)
}
return map[string]any{"profiles": out, "files": storeFiles()}
case "seam_get_or_create_profile":
var name string
arg(0, &name)
var seed map[string]json.RawMessage
argOpt(1, &seed)
os.RemoveAll(profilesDir)
if seed != nil {
seedStore(t, seed)
}
p := getOrCreateProfile(name)
return map[string]any{"profile": profileToMap(p), "files": storeFiles()}
case "seam_record_interaction":
var name string
arg(0, &name)
var outcomes [][]any
arg(1, &outcomes)
var seed map[string]json.RawMessage
argOpt(2, &seed)
os.RemoveAll(profilesDir)
if seed != nil {
seedStore(t, seed)
}
for _, oc := range outcomes {
success, _ := oc[0].(bool)
topic, _ := oc[1].(string)
recordInteraction(name, success, topic)
}
return storeFiles()
case "seam_get_prompt_context":
var name string
arg(0, &name)
var seed map[string]json.RawMessage
argOpt(1, &seed)
os.RemoveAll(profilesDir)
if seed != nil {
seedStore(t, seed)
}
return getPromptContext(name)
case "seam_to_dict":
var state map[string]json.RawMessage
arg(0, &state)
return profileToMap(profileFromState(t, state))
case "seam_from_dict":
var data map[string]json.RawMessage
arg(0, &data)
return profileToMap(profileFromState(t, data))
default:
t.Fatalf("frozen case names unknown fn %q", fn)
return nil
}
}
// profileFromState rebuilds a ModelProfile from a from_dict-shaped doc
// (unknown keys filtered, absent keys defaulted — the oracle lens).
func profileFromState(t *testing.T, state map[string]json.RawMessage) ModelProfile {
t.Helper()
p := defaultModelProfile("")
get := func(key string) (json.RawMessage, bool) {
raw, ok := state[key]
return raw, ok
}
if raw, ok := get("name"); ok {
if err := json.Unmarshal(raw, &p.Name); err != nil {
t.Fatalf("state name: %v", err)
}
}
strField := func(key string, dst *string) {
if raw, ok := get(key); ok {
if err := json.Unmarshal(raw, dst); err != nil {
t.Fatalf("state %s: %v", key, err)
}
}
}
strField("display_name", &p.DisplayName)
strField("family", &p.Family)
strField("parameters", &p.Parameters)
strField("quantization", &p.Quantization)
strField("thinking_format", &p.ThinkingFormat)
strField("response_style", &p.ResponseStyle)
strField("last_used", &p.LastUsed)
strField("created", &p.Created)
numField := func(key string, dst *float64) {
if raw, ok := get(key); ok {
var n json.Number
if err := json.Unmarshal(raw, &n); err != nil {
t.Fatalf("state %s: %v", key, err)
}
f, err := n.Float64()
if err != nil {
t.Fatalf("state %s: %v", key, err)
}
*dst = f
}
}
intField := func(key string, dst *int) {
if raw, ok := get(key); ok {
var n json.Number
if err := json.Unmarshal(raw, &n); err != nil {
t.Fatalf("state %s: %v", key, err)
}
i, err := n.Int64()
if err != nil {
t.Fatalf("state %s: %v", key, err)
}
*dst = int(i)
}
}
var f float64
numField("size_gb", &f)
p.SizeGB = f
numField("optimal_temperature", &p.OptimalTemperature)
intField("safety_tier", &p.SafetyTier)
intField("context_window", &p.ContextWindow)
intField("interactions", &p.Interactions)
intField("successes", &p.Successes)
intField("failures", &p.Failures)
listField := func(key string, dst *[]string) {
if raw, ok := get(key); ok {
var l []string
if err := json.Unmarshal(raw, &l); err != nil {
t.Fatalf("state %s: %v", key, err)
}
if l == nil {
l = []string{}
}
*dst = l
}
}
listField("strengths", &p.Strengths)
listField("weaknesses", &p.Weaknesses)
listField("prompting_tips", &p.PromptingTips)
listField("known_refusal_topics", &p.KnownRefusalTopics)
return p
}
// normalizeExpected rewrites the rig-rooted absolute paths the frozen
// expectations carry into the $STORE placeholder (the store root is the
// seam — only the sanitized file name is contractual).
func normalizeExpected(v any) any {
switch x := v.(type) {
case string:
if strings.Contains(x, ".rune/model_profiles/") {
parts := strings.Split(x, ".rune/model_profiles/")
return filepath.Join("$STORE", parts[len(parts)-1])
}
return x
case map[string]any:
for k, e := range x {
x[k] = normalizeExpected(e)
}
return x
case []any:
for i, e := range x {
x[i] = normalizeExpected(e)
}
return x
default:
return v
}
}
func TestFrozenBattery(t *testing.T) {
setProfilesDir(filepath.Join(t.TempDir(), ".rune", "model_profiles"))
savedNow := nowUTC
nowUTC = func() time.Time {
return time.Date(2026, 10, 13, 9, 41, 23, 123456000, time.UTC)
}
defer func() { nowUTC = savedNow }()
var envelope struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Fn string `json:"fn"`
Args []json.RawMessage `json:"args"`
Kwargs map[string]any `json:"kwargs"`
Expected any `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal([]byte(frozenMpTruthJSON), &envelope); err != nil {
t.Fatalf("frozen truth malformed: %v", err)
}
for i, c := range envelope.Cases {
if len(c.Kwargs) != 0 {
t.Fatalf("case %d %s: unexpected kwargs %v", i, c.Fn, c.Kwargs)
}
got := dispatchFrozen(t, c.Fn, c.Args)
raw, err := json.Marshal(got)
if err != nil {
t.Fatalf("case %d %s: marshal got: %v", i, c.Fn, err)
}
var gotAny any
if err := json.Unmarshal(raw, &gotAny); err != nil {
t.Fatalf("case %d %s: reparse: %v", i, c.Fn, err)
}
wantAny := normalizeExpected(c.Expected)
if !reflect.DeepEqual(gotAny, wantAny) {
gj, _ := json.Marshal(gotAny)
ej, _ := json.Marshal(wantAny)
t.Errorf("case %d %s:\n got %s\n want %s", i, c.Fn, gj, ej)
}
}
fmt.Printf("replayed %d frozen cases\n", len(envelope.Cases))
}
'''
def main() -> int:
truth = TRUTH.read_text()
assert truth.endswith("\n"), "truth file must end with newline"
body = HARNESS.replace("__TRUTH__", truth.rstrip("\n"))
OUT.write_text(body)
print(f"wrote {OUT} ({len(body)} bytes)")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""gen_parallel_processor_truth.py — freeze the parallel_processor oracle
truth (dichotomy gap-close, wave #2479) through the SHARED harness
(scripts/freeze_truth.py) under the scripts/pp_freeze_seams rig.
Row grammar: raw values ride directly (non-callable / non-tuple error
branches need no rig); callable behavior rides the kind/fn/value spec
grammar the rig turns into real Python callables and the Go battery
rebuilds into specCallable tasks.
Usage: PYTHONPATH=scripts/pp_freeze_seams:src python3 scripts/gen_parallel_processor_truth.py
"""
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
from freeze_truth import freeze, write_envelope # noqa: E402
FROZEN_NOW = "2026-10-14T08:00:00+00:00"
OUT = REPO / "src" / "go" / "parallel-processor" / "truth.json"
def s(kind, **kw):
d = {"kind": kind}
d.update(kw)
return d
CASES = [
# module run_parallel — raw non-callables (direct rows, no seam)
("run_parallel", ([42],), {}),
("run_parallel", ([42, "x", None, True, 4.5, [1], {"a": 1}],), {}),
("run_parallel", ([],), {}),
# module run_parallel_with_args — raw non-tuples + the len-0 list task
("run_parallel_with_args", ([42, "x", None],), {}),
("run_parallel_with_args", ([[]],), {}),
# rig seams — callable specs through the real executor paths
("_pp_run_parallel", ([s("call", fn="const", ret=7), s("call", fn="boom", msg="kaput"), s("call", fn="const", ret="x")],), {}),
("_pp_run_parallel", ([s("call", fn="sleepret", ms=60, ret="a"), s("call", fn="sleepret", ms=10, ret="b"), s("call", fn="sleepret", ms=35, ret="c"), s("call", fn="boom", msg="late"), s("raw", value=None)],), {}),
("_pp_run_parallel", ([],), {}),
("_pp_class_run_parallel", (3, [s("call", fn="const", ret=1), s("call", fn="const", ret=2), s("call", fn="boom", msg="nope"), s("call", fn="const", ret=4), s("call", fn="sleepret", ms=15, ret=5)]), {}),
("_pp_class_run_parallel", (1, [s("call", fn="sleepret", ms=30, ret="w1"), s("call", fn="sleepret", ms=5, ret="w2"), s("call", fn="const", ret="w3")]), {}),
# with-args branch matrix
("_pp_run_parallel_with_args", ([
s("call", fn="add", args=[1, 2]),
s("call", fn="add", args=[1.5, 2]),
s("call", fn="echo"),
s("call", fn="echo", kwargs={"k": 1, "b": 2}),
s("call", fn="boom", msg="bad-task"),
],), {}),
("_pp_run_parallel_with_args", ([
s("raw", value=42),
s("raw", value="x"),
s("raw", value=None),
s("emptytuple"),
s("notcall", value=42),
s("notcall", value="x"),
s("notcall", value=None),
s("notcall", value=True),
s("notcall", value=4.5),
s("notcall", value=[1, 2]),
],), {}),
("_pp_run_parallel_with_args", ([
s("argsnotseq", fn="echo", value="ab"),
s("argsnotseq", fn="echo", value=5),
s("kwnotdict", fn="echo", value=["a"]),
s("call", fn="sleepret", ms=10, ret="z"),
],), {}),
("_pp_class_run_parallel_with_args", (2, [
s("call", fn="echo", args=[1, 2], kwargs={"scale": 10}),
s("raw", value=3.5),
s("call", fn="boom", msg="class-branch"),
s("notcall", value=False),
]), {}),
# status surface (active_threads pinned by the rig on both sides)
("get_status", (), {}),
({"fn": "ParallelProcessor.get_status", "recv": {"cls": "ParallelProcessor", "max_workers": 1}, "args": [], "kwargs": {}}),
({"fn": "ParallelProcessor.get_status", "recv": {"cls": "ParallelProcessor", "max_workers": 9}, "args": [], "kwargs": {}}),
("_pp_get_processor_status", (), {}),
# lifecycle: shutdown shapes, crash parity, global reset
("_pp_shutdown_then_status", (), {}),
("_pp_shutdown_then_run", (), {}),
("_pp_new_bad", (), {}),
("_pp_shutdown_processor_cycle", (), {}),
# oracle self-test fn (returns None; its printed report is wall-clock,
# verified structurally by the parity sweep instead)
("test_parallel", (), {}),
]
def main() -> int:
truth = freeze("rune.parallel_processor", CASES, oracle_module="rune.parallel_processor")
write_envelope(FROZEN_NOW, truth, OUT)
# spot-check the shapes the battery depends on
by_fn = {}
for row in truth:
by_fn.setdefault(row["fn"], []).append(row)
assert len(truth) == len(CASES), f"freeze produced {len(truth)} rows for {len(CASES)} cases"
assert by_fn["run_parallel"][0]["expected"] == [{"error": "'int' object is not callable"}]
assert by_fn["_pp_shutdown_then_run"][0]["expected"]["raised"] == "cannot schedule new futures after shutdown"
assert by_fn["_pp_new_bad"][0]["expected"]["raised"] == "max_workers must be greater than 0"
assert by_fn["_pp_shutdown_processor_cycle"][0]["expected"] == {
"processor_is_none": True, "recreated_max_workers": 4}
assert by_fn["get_status"][0]["expected"] == {
"max_workers": 4, "pool_threads": 4, "active_threads": 4}
assert by_fn["_pp_class_run_parallel"][1]["expected"] == ["w1", "w2", "w3"]
print(f"wrote {OUT}: {len(truth)} cases, frozen_now={FROZEN_NOW}")
for fn, rows in by_fn.items():
print(f" {fn}: {len(rows)} row(s)")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+515
View File
@@ -0,0 +1,515 @@
#!/usr/bin/env python3
"""gen_provider_registry_truth.py — dichotomy-gap truth battery for
src/rune/provider_registry.py (factory-gap-pr, #2479 tranche, GO side).
Two artifacts, both embedded VERBATIM by the Go battery
(src/go/provider-registry/):
1. truth.json — shared-harness format ([{"fn","args","kwargs","expected"}])
over the MODULE-LEVEL pure functions:
_format_tools_openai, _format_tools_anthropic (every branch),
_ctx_budget (unknown + every DEFAULT_PROFILES id),
_execute_tool_calls / _execute_tool_calls_anthropic (JSON args,
malformed args, non-serializable tool result).
Verifiable offline with:
PYTHONPATH=src python3 scripts/freeze_truth.py --verify truth.json \
--module rune.provider_registry
2. truth_registry.json — method-battery scenarios for the ProviderRegistry
surface (to_dict, _load_config, _save_config, connect, disconnect,
list_providers, get_provider, list_models, _fetch_models dispatch,
_fetch_ollama_models, _fetch_openai_models, _fetch_anthropic_models,
_clean_model_name, generate branches, _generate_* payload construction
+ response parsing). HTTP is fully scripted: urllib.request.urlopen is
replaced by a routing fake (never a socket); response-shaping truth is
frozen from the LIVE oracle. Non-deterministic latency_ms is excluded
(no-clock law: the oracle's clock is not injectable) and compared
neither on the Python side nor the Go side.
Re-verify both artifacts byte-for-byte with --check.
"""
import copy
import json
import os
import sys
import tempfile
import urllib.error
from pathlib import Path
from unittest.mock import patch
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
os.environ["RUNE_PROVIDER_REGISTRY_CORE"] = "python" # poisoned-truth law
import provider_registry as pr # noqa: E402
from freeze_truth import freeze, write as write_truth # noqa: E402
OUT_HARNESS = REPO / "src" / "go" / "provider-registry" / "truth.json"
OUT_REGISTRY = REPO / "src" / "go" / "provider-registry" / "truth_registry.json"
DENIED_PATH = "/nonexistent/zzz.txt"
# ── scripted HTTP (never a socket) ──────────────────────────────────────────
class _FakeResp:
def __init__(self, body: bytes):
self._body = body
def read(self):
return self._body
def __enter__(self):
return self
def __exit__(self, *exc):
return False
class _FakeURLOpen:
"""Route table: [{"suffix": "/api/tags", "body": {...}} | {"exc": msg}].
POST request bodies are captured for payload-construction truth."""
def __init__(self, routes):
self.routes = routes
self.captured = []
def __call__(self, req, timeout=None):
url = req.full_url
for r in self.routes:
if url.endswith(r["suffix"]):
if "exc" in r:
raise urllib.error.URLError(r["exc"])
self.captured.append({
"url": url,
"body": json.loads(req.data.decode()) if req.data else None,
})
return _FakeResp(json.dumps(r["body"]).encode())
raise AssertionError(f"unexpected url: {url}")
def _provider_fields(p):
return {
"name": p.name, "url": p.url, "provider_type": p.provider_type,
"api_key": p.api_key, "enabled": p.enabled,
"last_health_check": p.last_health_check,
"health_status": p.health_status,
"models": copy.deepcopy(p.models),
}
def _providers_state(reg):
return {name: _provider_fields(p) for name, p in reg.providers.items()}
def _config_state(reg):
out = {}
cfg = Path(reg.config_path)
if cfg.exists():
out["config"] = json.loads(cfg.read_text())
return out
def _strip_latency(result):
out = {k: copy.deepcopy(v) for k, v in result.items() if k != "latency_ms"}
return out
# ── part 1: module-level pure battery (shared harness) ──────────────────────
TOOLS = [
{"name": "read_file", "description": "Read a file",
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}}},
{"name": "write_file"}, # no description, no parameters
]
# scripted provider responses (shared by both batteries)
OLLAMA_TAG = {
"models": [{
"name": "qwen2.5:3b", "size": 3425952140,
"details": {"family": "qwen2", "parameter_size": "3B"},
}],
}
OLLAMA_NO_NAME = {"models": [{"size": 10}]}
OPENAI_MODELS = {"data": [{"id": "gpt-x"}, {"id": "mimo-v2.5-pro"}]}
ANTHROPIC_MODELS = {"content": [
{"type": "text", "text": " thinking "},
{"type": "tool_use", "id": "tu_9", "name": "read_file",
"input": {"path": DENIED_PATH}},
], "usage": {"input_tokens": 12, "output_tokens": 7}}
OLLAMA_GEN = {"response": " hi there ", "eval_count": 42}
OPENAI_PLAIN = {"choices": [{"message": {"content": " hello "}}],
"usage": {"total_tokens": 17}}
OPENAI_TOOLS = {"choices": [{"message": {
"content": "calling tool",
"tool_calls": [{"id": "call_1", "type": "function",
"function": {"name": "read_file",
"arguments": json.dumps({"path": DENIED_PATH})}}],
}}], "usage": {"total_tokens": 5}}
def harness_cases():
cases = []
# _format_tools_openai / _format_tools_anthropic — every branch
cases.append(("_format_tools_openai", ([],), {}))
cases.append(("_format_tools_openai", (TOOLS[:1],), {}))
cases.append(("_format_tools_openai", (TOOLS[1:],), {}))
cases.append(("_format_tools_openai", (TOOLS,), {}))
cases.append(("_format_tools_anthropic", ([],), {}))
cases.append(("_format_tools_anthropic", (TOOLS[:1],), {}))
cases.append(("_format_tools_anthropic", (TOOLS[1:],), {}))
cases.append(("_format_tools_anthropic", (TOOLS,), {}))
# _ctx_budget — unknown id + every DEFAULT_PROFILES id
for model_id in ("unknown-model-xyz", "deterministic", "qwen2.5:3b",
"qwen3:14b", "qwen3.6:27b", "mimo-v2.5-pro"):
cases.append(("_ctx_budget", (model_id,), {}))
# _execute_tool_calls — parsed args, malformed args, non-serializable
cases.append(("_execute_tool_calls",
([{"id": "call_1", "function": {
"name": "read_file",
"arguments": json.dumps({"path": DENIED_PATH})}}],), {}))
cases.append(("_execute_tool_calls",
([{"id": "call_2", "function": {
"name": "read_file", "arguments": "not-json"}}],), {}))
cases.append(("_execute_tool_calls",
([{"id": "call_3", "function": {
"name": "no_such_tool_xyz", "arguments": "{}"}}],), {}))
cases.append(("_execute_tool_calls_anthropic",
([{"type": "tool_use", "id": "tu_1", "name": "read_file",
"input": {"path": DENIED_PATH}}],), {}))
cases.append(("_execute_tool_calls_anthropic",
([{"type": "tool_use", "id": "tu_2",
"name": "no_such_tool_xyz", "input": {}}],), {}))
return cases
# ── part 2: registry method battery (scripted HTTP, hermetic config) ───────
def registry_rows():
rows = []
# hermetic config dir — no registry may read the ambient providers.json
_td = tempfile.TemporaryDirectory()
_HERMETIC_CFG = str(Path(_td.name) / "providers.json")
def row(fn, name, inp, expect, expect_error=None):
rec = {"fn": fn, "name": name, "input": inp, "expected": expect}
if expect_error is not None:
rec["expected_error"] = expect_error
rows.append(rec)
def make_provider(**kw):
kw.setdefault("enabled", True)
kw.setdefault("models", [])
kw.setdefault("health_status", "unknown")
return pr.ModelProvider(**kw)
def make_reg(providers=None, config_path=None):
reg = pr.ProviderRegistry(config_path=config_path or _HERMETIC_CFG)
for n, p in (providers or {}).items():
reg.providers[n] = p
return reg
# ── to_dict ─────────────────────────────────────────────────────────
p = make_provider(name="p1", url="http://x", provider_type="openai",
api_key="sk-secret", models=[{"name": "m1"}],
enabled=False, last_health_check="2026-01-01",
health_status="error")
row("to_dict", "full", {"provider": _provider_fields(p)}, p.to_dict())
# ── _load_config ────────────────────────────────────────────────────
with tempfile.TemporaryDirectory() as td:
missing = str(Path(td) / "a" / "providers.json")
reg = pr.ProviderRegistry(config_path=missing)
row("_load_config", "missing_file", {"config_path": "TMP:a/providers.json"},
{"providers": _providers_state(reg)})
with tempfile.TemporaryDirectory() as td:
cfg = str(Path(td) / "providers.json")
Path(cfg).write_text("{not json")
reg = pr.ProviderRegistry(config_path=cfg)
row("_load_config", "malformed", {"config_path": "TMP:malformed", "content": "{not json"},
{"providers": _providers_state(reg)})
full_cfg = {"providers": {
"alpha": {"url": "http://a", "type": "openai", "api_key": "k1", "enabled": False},
"beta": {"url": "http://b"}, # defaults: type=custom, enabled=true, api_key=None
}}
with tempfile.TemporaryDirectory() as td:
cfg = str(Path(td) / "providers.json")
Path(cfg).write_text(json.dumps(full_cfg))
reg = pr.ProviderRegistry(config_path=cfg)
row("_load_config", "full_and_defaults", {"config_path": "TMP:full", "content": full_cfg},
{"providers": _providers_state(reg)})
# ── _save_config (masking law) ──────────────────────────────────────
with tempfile.TemporaryDirectory() as td:
cfg = str(Path(td) / "nested" / "providers.json")
reg = make_reg({
"secret": make_provider(name="secret", url="http://s",
provider_type="openai", api_key="sk-live",
enabled=True),
"plain": make_provider(name="plain", url="http://p",
provider_type="ollama", api_key=None,
enabled=False),
}, config_path=cfg)
reg._save_config()
row("_save_config", "masks_api_key",
{"config_path": "TMP:nested",
"providers": _providers_state(reg)},
{"written": json.loads(Path(cfg).read_text())})
# ── connect / disconnect / list_providers / get_provider ────────────
with tempfile.TemporaryDirectory() as td:
cfg = str(Path(td) / "providers.json")
reg = pr.ProviderRegistry(config_path=cfg)
prov = reg.connect("zeta", "http://z", "openai", "zk")
row("connect", "persists_and_masks",
{"config_path": "TMP:connect", "name": "zeta", "url": "http://z",
"provider_type": "openai", "api_key": "zk"},
{"provider": prov.to_dict(), **_config_state(reg)})
reg.connect("alpha", "http://a", "ollama", None)
row("list_providers", "sorted_names",
{"config_path": "TMP:list", "providers": _providers_state(reg)},
{"providers": reg.list_providers()})
got = reg.get_provider("alpha")
row("get_provider", "hit",
{"config_path": "TMP:get", "name": "alpha",
"providers": _providers_state(reg)},
{"provider": got.to_dict() if got else None})
miss = reg.get_provider("nope")
row("get_provider", "miss", {"config_path": "TMP:get", "name": "nope",
"providers": _providers_state(reg)},
{"provider": miss.to_dict() if miss else None})
pre = _providers_state(reg)
seed = json.loads(Path(cfg).read_text()) if Path(cfg).exists() else None
reg.disconnect("zeta")
inp = {"config_path": "TMP:disc", "name": "zeta", "providers": pre}
if seed is not None:
inp["seed_config"] = seed
row("disconnect", "present", inp,
{"providers": _providers_state(reg), **_config_state(reg)})
pre2 = _providers_state(reg)
seed2 = json.loads(Path(cfg).read_text()) if Path(cfg).exists() else None
reg.disconnect("ghost")
inp2 = {"config_path": "TMP:disc2", "name": "ghost", "providers": pre2}
if seed2 is not None:
inp2["seed_config"] = seed2
row("disconnect", "absent_noop", inp2,
{"providers": _providers_state(reg), **_config_state(reg)})
# ── _clean_model_name (delegates to model_connect) ──────────────────
reg = pr.ProviderRegistry(config_path="/nonexistent/pr-gen.json")
for name in ("qwen2.5:3b", "mimo-v2.5-pro",
"hf.co/DavidAU/Qwen3.6-27B-Fable-Fusion-GGUF:IQ2_M",
"hf.co/org/llama-3-8b", "hf.co/a/b",
"some-unknown-name-with-dashes"):
row("_clean_model_name", name[:24], {"name": name},
reg._clean_model_name(name))
# ── _fetch_models dispatch + provider fetchers (scripted HTTP) ──────
ollama_p = make_provider(name="ol", url="http://127.0.0.1:11434",
provider_type="ollama")
openai_p = make_provider(name="oa", url="http://api.example",
provider_type="openai", api_key="sk")
anthropic_p = make_provider(name="an", url="http://an.example",
provider_type="anthropic")
custom_p = make_provider(name="cu", url="http://c.example",
provider_type="custom")
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/tags", "body": OLLAMA_TAG}])):
row("_fetch_ollama_models", "success",
{"provider": _provider_fields(ollama_p), "routes": [{"suffix": "/api/tags", "body": OLLAMA_TAG}]},
reg._fetch_ollama_models(ollama_p))
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/tags", "exc": "conn refused"}])):
row("_fetch_ollama_models", "connection_error",
{"provider": _provider_fields(ollama_p),
"routes": [{"suffix": "/api/tags", "exc": "conn refused"}]},
None, expect_error="Ollama connection failed: <urlopen error conn refused>")
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/tags", "body": OLLAMA_NO_NAME}])):
row("_fetch_ollama_models", "missing_name_key",
{"provider": _provider_fields(ollama_p),
"routes": [{"suffix": "/api/tags", "body": OLLAMA_NO_NAME}]},
None, expect_error="Ollama connection failed: 'name'")
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/v1/models", "body": OPENAI_MODELS}])):
row("_fetch_openai_models", "success",
{"provider": _provider_fields(openai_p), "routes": [{"suffix": "/v1/models", "body": OPENAI_MODELS}]},
reg._fetch_openai_models(openai_p))
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/v1/models", "exc": "boom"}])):
row("_fetch_openai_models", "connection_error",
{"provider": _provider_fields(openai_p),
"routes": [{"suffix": "/v1/models", "exc": "boom"}]},
None, expect_error="[OI] API connection failed: <urlopen error boom>")
row("_fetch_anthropic_models", "static_list",
{"provider": _provider_fields(anthropic_p)},
reg._fetch_anthropic_models(anthropic_p))
for ptype, prov, routes, body_key in (
("ollama", ollama_p, [{"suffix": "/api/tags", "body": OLLAMA_TAG}], "OLLAMA_TAG"),
("openai", openai_p, [{"suffix": "/v1/models", "body": OPENAI_MODELS}], "OPENAI_MODELS")):
with patch("urllib.request.urlopen", _FakeURLOpen(routes)):
row("_fetch_models", f"dispatch_{ptype}",
{"provider": _provider_fields(prov), "routes": routes},
reg._fetch_models(prov))
row("_fetch_models", "dispatch_anthropic",
{"provider": _provider_fields(anthropic_p)},
reg._fetch_models(anthropic_p))
row("_fetch_models", "dispatch_custom_empty",
{"provider": _provider_fields(custom_p)},
reg._fetch_models(custom_p))
# ── list_models orchestration ───────────────────────────────────────
reg2 = make_reg({"cu": custom_p})
row("list_models", "custom_yields_none",
{"providers": _providers_state(reg2)}, reg2.list_models())
reg3 = make_reg({"off": make_provider(name="off", url="http://o",
provider_type="openai",
enabled=False)})
row("list_models", "disabled_skipped",
{"providers": _providers_state(reg3)}, reg3.list_models())
reg4 = make_reg({"bad": make_provider(name="bad", url="http://b",
provider_type="ollama")})
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/tags", "exc": "conn refused"}])):
row("list_models", "fetch_error_degrades",
{"providers": _providers_state(reg4),
"routes": [{"suffix": "/api/tags", "exc": "conn refused"}]},
reg4.list_models())
reg5 = make_reg({"oa": openai_p})
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/v1/models", "body": OPENAI_MODELS}])):
row("list_models", "annotates_provider",
{"providers": _providers_state(reg5),
"routes": [{"suffix": "/v1/models", "body": OPENAI_MODELS}]},
reg5.list_models())
reg6 = make_reg({"ol": ollama_p})
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/tags", "body": OLLAMA_TAG}])):
row("list_models", "ollama_shape",
{"providers": _providers_state(reg6),
"routes": [{"suffix": "/api/tags", "body": OLLAMA_TAG}]},
reg6.list_models())
# ── generate orchestration branches ─────────────────────────────────
row("generate", "provider_not_found",
{"providers": _providers_state(reg2), "prompt": "hi",
"provider_name": "ghost"},
reg2.generate("hi", "ghost"))
empty_reg = pr.ProviderRegistry(config_path="/nonexistent/pr-gen.json")
row("generate", "no_providers", {"prompt": "hi"}, empty_reg.generate("hi"))
row("generate", "unsupported_type",
{"providers": _providers_state(reg2), "prompt": "hi",
"provider_name": "cu", "model": "m"},
reg2.generate("hi", "cu", "m"))
row("generate", "no_models_available",
{"providers": _providers_state(reg2), "prompt": "hi",
"provider_name": "cu"},
reg2.generate("hi", "cu"))
# ── _generate_* payload construction + response parsing ─────────────
def gen_case(fn, name, provider, routes, expect=None, expect_error=None,
**call_kw):
fake = _FakeURLOpen(routes)
method = getattr(pr.ProviderRegistry, fn)
with patch("urllib.request.urlopen", fake):
result = method(reg, provider, **call_kw)
inp = {"provider": _provider_fields(provider),
"routes": [copy.deepcopy(r) for r in routes]}
inp.update({k: copy.deepcopy(v) for k, v in call_kw.items()})
rec = {"expected_request": fake.captured[0]["body"] if fake.captured else None}
if expect_error is not None:
rec["expected_error"] = expect_error
else:
rec["expected"] = _strip_latency(result)
row(fn, name, inp, rec)
gen_case("_generate_ollama", "payload_and_response", ollama_p,
[{"suffix": "/api/generate", "body": OLLAMA_GEN}],
prompt="hello", model="qwen2.5:3b", max_tokens=500,
temperature=0.7)
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/api/generate", "exc": "no server"}])):
row("_generate_ollama", "error_degrades",
{"provider": _provider_fields(ollama_p),
"routes": [{"suffix": "/api/generate", "exc": "no server"}],
"prompt": "hello", "model": "qwen2.5:3b", "max_tokens": 500,
"temperature": 0.7},
{"expected_request": None, "expected_error":
"<urlopen error no server>"})
gen_case("_generate_openai", "plain", openai_p,
[{"suffix": "/v1/chat/completions", "body": OPENAI_PLAIN}],
prompt="hello", model="mimo-v2.5-pro", max_tokens=500,
temperature=0.7, system_prompt="be brief", tools=None)
gen_case("_generate_openai", "with_tools", openai_p,
[{"suffix": "/v1/chat/completions", "body": OPENAI_TOOLS}],
prompt="hello", model="mimo-v2.5-pro", max_tokens=500,
temperature=0.7, system_prompt=None, tools=TOOLS)
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/v1/chat/completions", "exc": "401"}])):
row("_generate_openai", "error_degrades",
{"provider": _provider_fields(openai_p),
"routes": [{"suffix": "/v1/chat/completions", "exc": "401"}],
"prompt": "hello", "model": "m", "max_tokens": 500,
"temperature": 0.7, "system_prompt": None, "tools": None},
{"expected_request": None, "expected_error": "<urlopen error 401>"})
gen_case("_generate_anthropic", "plain", anthropic_p,
[{"suffix": "/v1/messages", "body": ANTHROPIC_MODELS}],
prompt="hello", model="claude-x", max_tokens=500,
temperature=0.7, system_prompt="be brief", tools=None)
gen_case("_generate_anthropic", "with_tools", anthropic_p,
[{"suffix": "/v1/messages", "body": ANTHROPIC_MODELS}],
prompt="hello", model="claude-x", max_tokens=500,
temperature=0.7, system_prompt=None, tools=TOOLS)
with patch("urllib.request.urlopen", _FakeURLOpen([
{"suffix": "/v1/messages", "exc": "overloaded"}])):
row("_generate_anthropic", "error_degrades",
{"provider": _provider_fields(anthropic_p),
"routes": [{"suffix": "/v1/messages", "exc": "overloaded"}],
"prompt": "hello", "model": "claude-x", "max_tokens": 500,
"temperature": 0.7, "system_prompt": None, "tools": None},
{"expected_request": None, "expected_error":
"<urlopen error overloaded>"})
return rows
def main():
check = "--check" in sys.argv
cases = harness_cases()
truth = freeze("rune.provider_registry", cases, oracle_module="rune.provider_registry")
if check:
from freeze_truth import verify
rc = verify(OUT_HARNESS, "rune.provider_registry")
rows = registry_rows()
frozen = json.loads(OUT_REGISTRY.read_text())
if json.dumps(rows, sort_keys=True) != json.dumps(frozen, sort_keys=True):
print("MISMATCH: truth_registry.json drifted from live oracle")
return 1
print(f"OK: {len(rows)} registry scenarios byte-identical against live oracle")
return rc
write_truth(truth, OUT_HARNESS)
rows = registry_rows()
OUT_REGISTRY.write_text(json.dumps(rows, indent=2) + "\n")
print(f"wrote {OUT_HARNESS} ({len(truth)} cases)")
print(f"wrote {OUT_REGISTRY} ({len(rows)} scenarios)")
return 0
if __name__ == "__main__":
sys.exit(main())
+359
View File
@@ -0,0 +1,359 @@
#!/usr/bin/env python3
"""gen_salience_gate_truth.py — freeze/replay parity truth for salience_gate
(dichotomy wave #2479 gap-close, shared harness scripts/freeze_truth.py).
Freeze mode (default): exercises the LIVE Python oracle floor across every
public function and branch and writes the shared-harness scheme
[{fn, args, kwargs, expected}] twice:
* src/rust/salience_gate/src/frozen_sg_truth.verify.json — the shared
verify file (order-stable rows only; byte-identical under
`freeze_truth.py --verify ... --module rune.salience_gate` regardless of
the Rust core's build state).
* src/rust/salience_gate/src/frozen_sg_truth.json — envelope carrying ALL
rows, including multi-family evaluate rows whose floor evaluation order
differs from the delegation path's sorted order (the kernel mirrors the
evaluation order — the crate battery compares those exactly).
Poisoned-truth law: freeze pins RUNE_SALIENCE_CORE=python (shared harness)
AND poisons SG_RUST_LIB so sg_loader.available() is False — the frozen truth
is the pure-Python oracle floor, not a circular capture of the Rust kernel.
(The facade's evaluate path ignores RUNE_*_CORE; SG_RUST_LIB is the real
floor pin — verified quirk of this module.)
Replay mode (--replay): unpoisons both pins, requires the built core, then
asserts facade-level parity (oracle functions delegating live — scalars
exact, flags/rationale under the oracle's declared sorted-comparison
contract) and kernel-level parity (sg_loader direct — exact, evaluation
order included). _sg_core's live facade case asserts the probe ANSWERED
(rune.sg_loader module), mirroring the kernel-side Some branch; the None
branch is the frozen truth row.
Surface covered (fn coverage law — every public fn and branch):
evaluate_salience_dict authority ×3 + unknown, urgency ×3 + unknown,
failure words incl. "doesn't work"/"not working"
+ boundary negatives (fail|ure, failing, FAILED),
retry words + "against" negative, contradiction
words + "butter" negative, uncertainty words +
"mightily" negative, novel words + "first
time"/"haven't" + single-append pin (novel family
is ONE `if` in the oracle) + boundary negatives
(renew, new_thing, a_new, mañnew — Python \b is
unicode/underscore-aware), tier ladder edges
(0.5→T1, 0.6→T2, 0.7→T2, 0.8→T3, 0.9→T3),
witness rule edges (score >= 0.6 true/false;
flags>=2 needs score <0.6 — unreachable from text
flags, documented), payload/authority/urgency
defaults, ignored channel/extra keys
SalienceDecision.to_dict defaults, populated, insertion-order echo
handle_hook string/dict/null event, data accepted and ignored
_sg_core pinned None branch (envelope-only row + battery
lattice: the shared gate's module-name-derived pin
RUNE_SALIENCE_GATE_CORE cannot reach this oracle)
test_salience crate smoke test (Rust test fn, not a truth row)
"""
from __future__ import annotations
import copy
import datetime
import json
import os
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
CRATE = REPO / "src" / "rust" / "salience_gate"
VERIFY_PATH = CRATE / "src" / "frozen_sg_truth.verify.json"
ENVELOPE_PATH = CRATE / "src" / "frozen_sg_truth.json"
REPLAY = "--replay" in sys.argv
if REPLAY:
os.environ.pop("SG_RUST_LIB", None) # delegation live for the replay pass
os.environ.pop("RUNE_SALIENCE_CORE", None)
else:
# POISONED-TRUTH LAW (freeze): SG_RUST_LIB poisoned → sg_loader.available()
# False → the oracle runs its pure-Python floor. RUNE_SALIENCE_CORE=python
# is the module's own probe pin — NOTE the shared harness derives
# RUNE_SALIENCE_GATE_CORE from the module name and would never reach this
# oracle's env read; the generator owns the correct pin name.
os.environ["RUNE_SALIENCE_CORE"] = "python"
os.environ["SG_RUST_LIB"] = "/nonexistent/libsalience_gate.so"
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
if REPLAY:
from rune import sg_loader # noqa: E402
if not sg_loader.available():
print("REPLAY ABORT: Rust salience_gate core not built/available")
sys.exit(2)
import rune.salience_gate as oracle_mod # noqa: E402
from freeze_truth import freeze # noqa: E402
def env(text: str, **kw):
e = {"payload": {"text": text}}
e.update(kw)
return e
def e_case(name, envelope):
return {"fn": "evaluate_salience_dict", "args": [envelope], "kwargs": {}}
def td_case(name, score, flags, tier, witness, rationale):
return {
"fn": "SalienceDecision.to_dict",
"recv": {"cls": "SalienceDecision", "score": score, "flags": flags,
"minimum_tier": tier, "witness_needed": witness,
"rationale_codes": rationale},
"args": [], "kwargs": {},
}
def hh_case(name, event, data=None):
kwargs = {} if data is None else {"data": data}
return {"fn": "handle_hook", "args": [event], "kwargs": kwargs}
def sc_case(name):
return {"fn": "_sg_core", "args": [], "kwargs": {}}
FAILURE = dict((("flags", ["TASK_FAILURE"]),
("minimum_tier", "T2"), ("witness_needed", True),
("rationale_codes", ["failure_detected"])))
RETRY = dict((("flags", ["REPEATED_RETRY"]),
("minimum_tier", "T3"), ("witness_needed", True),
("rationale_codes", ["repeated_retry"])))
CONTRA = dict((("flags", ["CONTRADICTION"]),
("minimum_tier", "T2"), ("witness_needed", True),
("rationale_codes", ["contradiction_detected"])))
UNCERT = dict((("flags", ["HIGH_UNCERTAINTY"]),
("minimum_tier", "T2"), ("witness_needed", True),
("rationale_codes", ["high_uncertainty"])))
NOVEL = dict((("flags", ["NOVEL_CAPABILITY_REQUEST"]),
("minimum_tier", "T1"), ("witness_needed", False),
("rationale_codes", ["novel_request"])))
# ── verify file rows — order-stable (single flag/code families so floor
# evaluation order == the delegation path's sorted order; the shared gate
# must stay byte-identical with or without the built core) ────────────────
VERIFY_CASES = [
e_case("greeting-minimal",
{"authority_class": "conversation", "urgency": "normal",
"channel": "conversation", "payload": {"text": "hello"}}),
e_case("empty-envelope", {}),
e_case("empty-payload", {"payload": {}}),
e_case("authority-emergency",
{"authority_class": "emergency", "urgency": "normal", "channel": "work",
"payload": {"text": "deploy now"}}),
e_case("authority-task-amendment",
{"authority_class": "task_amendment", "payload": {"text": "adjust the plan"}}),
e_case("authority-directive",
{"authority_class": "directive", "payload": {"text": "do the thing"}}),
e_case("authority-unknown", env("ignored", authority_class="weird")),
e_case("urgency-critical", env("hello", urgency="critical")),
e_case("urgency-high", env("hello", urgency="high")),
e_case("urgency-low", env("hello", urgency="low")),
e_case("urgency-unknown", env("ok", urgency="hi")),
e_case("failure-word-fail", env("fail")),
e_case("failure-word-error", env("total error now")),
e_case("failure-word-broken", env("broken pipe")),
e_case("failure-doesnt-work", env("it doesn't work")),
e_case("failure-not-working", env("not working today")),
e_case("failure-boundary-failure-noun", env("failure")),
e_case("failure-boundary-failing", env("the test is failing")),
e_case("failure-boundary-uppercase-failed", env("THE FILE FAILED")),
e_case("retry-word-again", env("try again")),
e_case("retry-word-keeps", env("keeps crashing")),
e_case("retry-word-still", env("still crashes")),
e_case("retry-word-repeatedly", env("repeatedly stuck")),
e_case("retry-boundary-against", env("against the wall")),
e_case("contradiction-but", env("works but slow")),
e_case("contradiction-however", env("however fine")),
e_case("contradiction-actually", env("actually correct")),
e_case("contradiction-instead", env("instead do this")),
e_case("contradiction-rather", env("rather quick")),
e_case("contradiction-boundary-butter", env("butter")),
e_case("uncertainty-unsure", env("unsure about it")),
e_case("uncertainty-perhaps", env("perhaps later")),
e_case("uncertainty-might", env("might be fine")),
e_case("uncertainty-boundary-mightily", env("mightily strong")),
e_case("novel-new", env("a new feature")),
e_case("novel-never", env("never seen this")),
e_case("novel-first-time", env("first time here")),
e_case("novel-havent", env("haven't seen it")),
# ORACLE PARITY PIN (bug fix 2026-10-15): the novel family is ONE `if` —
# a new/never word AND first-time/haven't in the same text append the
# flag ONCE (the previous port duplicated it, inflating len(flags) and
# flipping the witness rule).
e_case("novel-single-append-pin", env("a new idea first time")),
e_case("novel-boundary-renew", env("renew the lease")),
e_case("novel-boundary-underscore-suffix", env("new_thing")),
e_case("novel-boundary-underscore-prefix", env("a_new door")),
e_case("novel-boundary-unicode-letter", env("mañnew row")),
e_case("directive-uppercase-failing-text",
{"authority_class": "directive", "urgency": "normal", "channel": "work",
"payload": {"text": "FIX THE FAILING TEST"}}),
e_case("channel-ignored", env("hello", channel="ops")),
e_case("payload-extra-keys-ignored", env("deploy", extra="x")),
td_case("to_dict-defaults", 0.0, [], "T0", False, []),
td_case("to_dict-populated", 0.9, ["HIGH_RISK_IRREVERSIBLE"], "T3", True,
["emergency_authority"]),
td_case("to_dict-insertion-order-echo", 0.0,
["REPEATED_RETRY", "TASK_FAILURE"], "T0", False,
["repeated_retry", "failure_detected"]),
hh_case("hook-string-event", "hook-a"),
hh_case("hook-dict-event-data-ignored", {"name": "evt-2"}, {"x": 1}),
hh_case("hook-null-event", None),
# NOTE: _sg_core is ENVELOPE-ONLY. The shared --verify gate re-runs the
# oracle through the harness, whose pin is RUNE_SALIENCE_GATE_CORE
# (derived from the module name); this oracle reads RUNE_SALIENCE_CORE —
# the probe would answer live (module object) and deepcopy would blow up.
# The pinned None shape is pinned by the battery row + the sg_core_pin
# lattice + the replay probe check instead.
]
# ── envelope-only rows — multi-family; the kernel mirrors the floor's
# evaluation order exactly (battery-verified), while the delegation path
# re-sorts (facade replay uses the sorted-comparison contract) ────────────
EXTRA_CASES = [
sc_case("sg-core-pinned-none"),
e_case("multi-failure-retry", env("still broken")),
e_case("multi-novel-retry", env("never again")),
e_case("multi-failure-contradiction", env("but broken")),
e_case("multi-emergency-retry-contradiction",
{"authority_class": "emergency", "payload": {"text": "deploy but still"}}),
e_case("multi-directive-failure-contradiction-novel",
{"authority_class": "directive", "payload": {"text": "new but broken"}}),
e_case("multi-amendment-retry",
{"authority_class": "task_amendment", "payload": {"text": "try again"}}),
e_case("multi-critical-novel", env("a new plan", urgency="critical")),
e_case("multi-failure-retry-plain", env("fail again")),
e_case("multi-directive-failure-retry",
{"authority_class": "directive", "payload": {"text": "fail the thing again"}}),
e_case("multi-uncertainty-novel", env("maybe new")),
]
def freeze_rows(cases):
rows = []
for case in cases:
got = freeze("rune.salience_gate", [case], "rune.salience_gate")[0]
rows.append(got)
return rows
def canon_flags(d: dict) -> dict:
c = dict(d)
c["flags"] = sorted(d.get("flags", []))
c["rationale_codes"] = sorted(d.get("rationale_codes", []))
return c
def replay():
with open(ENVELOPE_PATH) as f:
rows = json.load(f)["cases"]
total, failures = 0, 0
def check(label, cond, detail=""):
nonlocal total, failures
total += 1
if not cond:
failures += 1
print(f" ✗ {label} — {detail}")
for case in rows:
fn = case["fn"]
name = f"[{fn}] {json.dumps(case['args'])[:60]}"
if fn == "evaluate_salience_dict":
env_in = copy.deepcopy(case["args"][0])
expected = case["expected"]
# facade-level (delegation live): the oracle's parity contract is
# sorted flags/rationale (oracle comment + canary).
got = oracle_mod.evaluate_salience_dict(env_in)
check("facade " + name,
json.dumps(canon_flags(got), sort_keys=True)
== json.dumps(canon_flags(expected), sort_keys=True),
f"got={json.dumps(got, sort_keys=True)[:200]} "
f"want={json.dumps(expected, sort_keys=True)[:200]}")
# kernel-level (loader direct): EXACT, evaluation order included.
got_k = sg_loader.evaluate_salience(copy.deepcopy(env_in))
check("kernel " + name,
json.dumps(got_k, sort_keys=True)
== json.dumps(expected, sort_keys=True),
f"got={json.dumps(got_k, sort_keys=True)[:200]} "
f"want={json.dumps(expected, sort_keys=True)[:200]}")
elif fn == "SalienceDecision.to_dict":
recv = {k: v for k, v in case["recv"].items() if k != "cls"}
got = oracle_mod.SalienceDecision(**copy.deepcopy(recv)).to_dict()
check("facade " + name,
json.dumps(got, sort_keys=True)
== json.dumps(case["expected"]["result"], sort_keys=True),
f"got={json.dumps(got, sort_keys=True)[:200]}")
elif fn == "handle_hook":
event = copy.deepcopy(case["args"][0])
data = case["kwargs"].get("data")
got = oracle_mod.handle_hook(
event, copy.deepcopy(data) if data is not None else None)
check("facade " + name,
json.dumps(got, sort_keys=True)
== json.dumps(case["expected"], sort_keys=True),
f"got={json.dumps(got, sort_keys=True)[:200]}")
elif fn == "_sg_core":
# live facade: the probe ANSWERED under auto (rune.sg_loader);
# the pinned None shape is the frozen row (battery-covered).
got = oracle_mod._sg_core()
check("facade-probe " + name,
got is not None and getattr(got, "__name__", "") == "rune.sg_loader",
f"got={got!r}")
else:
check(name, False, f"unhandled frozen fn {fn}")
print(f"replay: {total - failures}/{total} rows green (facade+kernel)")
return 1 if failures else 0
def main() -> int:
if REPLAY:
return replay()
# VERIFY_CASES come first: one freeze, one split — the two views can
# never disagree about overlapping rows.
all_cases = VERIFY_CASES + EXTRA_CASES
rows = freeze_rows(all_cases)
verify_rows = rows[: len(VERIFY_CASES)]
doc = {
"_doc": (
"FROZEN ORACLE TRUTH (salience_gate gap-close, dichotomy wave "
"#2479). Frozen via scripts/gen_salience_gate_truth.py with "
"RUNE_SALIENCE_CORE=python (shared harness) and SG_RUST_LIB "
"poisoned — the pure-Python oracle floor, never a capture of the "
"Rust kernel. Battery replays this VERBATIM "
"(src/rust/salience_gate/src/branch_battery.rs, include_str!); "
"the shared verify view is frozen_sg_truth.verify.json."
),
"frozen": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"oracle": "src/rune/salience_gate.py",
"pin": "RUNE_SALIENCE_CORE=python + SG_RUST_LIB poisoned",
"cases": rows,
}
ENVELOPE_PATH.parent.mkdir(parents=True, exist_ok=True)
ENVELOPE_PATH.write_text(json.dumps(doc, indent=1, ensure_ascii=False) + "\n")
VERIFY_PATH.write_text(
json.dumps(verify_rows, indent=2, ensure_ascii=False) + "\n")
print(f"frozen {len(rows)} cases → {ENVELOPE_PATH.relative_to(REPO)} "
f"(verify view: {len(verify_rows)} order-stable rows)")
return 0
if __name__ == "__main__":
sys.exit(main())
+200
View File
@@ -0,0 +1,200 @@
# Freeze rig for the model_profiles dichotomy gap-closing (dichotomy
# wave #2479 gap port). Auto-imported on interpreter start
# (PYTHONPATH=scripts/mp_freeze_seams:src) by BOTH the truth generator
# (scripts/gen_model_profiles_truth.py) and the shared harness's
# --verify mode, so frozen truth is byte-reproducible in any process:
#
# * HOME is pinned to MP_FREEZE_HOME (default /tmp/mp_gap_freeze_home)
# BEFORE the oracle imports — PROFILES_DIR is derived from
# expanduser("~") at IMPORT time (the work_manager law); the fixed
# /tmp root keeps the frozen absolute paths byte-identical across
# processes (the construction_interface CI_FREEZE_HOME precedent).
# * The wall clock is pinned by the shared harness envelope
# (RUNE_FROZEN_NOW patches the module-global `datetime` — the oracle
# reads datetime.now(timezone.utc) INSIDE build_profile_from_ollama /
# record_interaction), so created/last_used are constant instants.
# * scan_all_models is networked (OLLAMA_URL/api/tags). The seam starts
# a per-case canned http.server on an ephemeral port and repoints the
# module-global OLLAMA_URL at it (the oracle reads the global at call
# time); the "dead" fixture uses a refused port to freeze the
# best-effort degrade branch (print + []).
# * Every stateful seam WIPES the hermetic PROFILES_DIR and re-seeds it
# from the case's `seed` argument first — each frozen row is
# self-contained and order-independent.
# * SEAM-NAMING LAW (the construction_interface NOTE precedent): the
# oracle's own fns call each other through module globals
# (scan_all_models → load_profile/build_profile_from_ollama/
# save_profile; get_or_create_profile → same; record_interaction →
# get_or_create_profile; get_prompt_context → get_or_create_profile).
# Wrappers that change signature/behavior MUST NOT shadow those
# names — every seam below is bound under a seam_* name, leaving the
# oracle's internal call graph intact.
# * JSON-safe wrapper seams (the memory_consolidation pattern):
# dataclass instances return as asdict dicts, file effects return as
# parsed docs (+ the RAW file bytes for save_profile — the
# byte-parity corpus for the port's Python-shaped JSON writer), and
# to_dict/from_dict run through ModelProfile so the harness can
# freeze them JSON-natively.
#
# The module has NO loader seam (no RUNE_MODEL_PROFILES_CORE reader) —
# the only pins are HOME + clock + the Ollama URL.
import json
import os
import shutil
import threading
from dataclasses import asdict
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
MP_FREEZE_HOME = os.environ.get("MP_FREEZE_HOME") or "/tmp/mp_gap_freeze_home"
os.environ["HOME"] = MP_FREEZE_HOME
import rune.model_profiles as mp # noqa: E402 (AFTER the HOME pin)
def _reset_store(seed=None):
"""Wipe the hermetic PROFILES_DIR; re-seed {file name: doc-or-raw-str}."""
shutil.rmtree(mp.PROFILES_DIR, ignore_errors=True)
if seed:
os.makedirs(mp.PROFILES_DIR, exist_ok=True)
for fname, doc in seed.items():
with open(os.path.join(mp.PROFILES_DIR, fname), "w") as f:
if isinstance(doc, str):
f.write(doc)
else:
json.dump(doc, f)
def _store_files():
"""Parsed docs of every .json file in the store, name-sorted."""
if not os.path.isdir(mp.PROFILES_DIR):
return {}
out = {}
for fname in sorted(os.listdir(mp.PROFILES_DIR)):
if fname.endswith(".json"):
with open(os.path.join(mp.PROFILES_DIR, fname)) as f:
out[fname] = json.load(f)
return out
def _store_raw(name):
path = mp.get_profile_path(name)
if os.path.exists(path):
with open(path) as f:
return f.read()
return None
class _TagsHandler(BaseHTTPRequestHandler):
payload = b"{}"
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(self.payload)))
self.end_headers()
self.wfile.write(self.payload)
def log_message(self, *a):
pass
def _canned_ollama(fixture):
"""Start a canned /api/tags server; return (server, url)."""
handler = type("H", (_TagsHandler,),
{"payload": json.dumps(fixture).encode()})
srv = ThreadingHTTPServer(("127.0.0.1", 0), handler)
threading.Thread(target=srv.serve_forever, daemon=True).start()
return srv, f"http://127.0.0.1:{srv.server_address[1]}"
# ── frozen seams (bound under seam_* names — see the header law) ──────
def seam_get_profile_path(model_name):
return mp.get_profile_path(model_name)
def seam_load_profile(model_name, seed=None):
_reset_store(seed)
p = mp.load_profile(model_name)
return asdict(p) if p is not None else None
def seam_save_profile(state):
"""Byte-parity corpus: save a from_dict-built profile, return the
RAW file text (the port's JSON writer must reproduce it byte for
byte) plus the parsed round-trip doc."""
p = mp.ModelProfile.from_dict(state)
_reset_store()
mp.save_profile(p)
return {"raw": _store_raw(p.name), "parsed": _store_files()}
def seam_build_profile_from_ollama(model_name, model_info=None):
return asdict(mp.build_profile_from_ollama(model_name, model_info))
def seam_scan_all_models(fixture, seed=None):
"""fixture: {"models": [...]} served from a canned server, or the
string "dead" (refused port → the best-effort degrade branch)."""
_reset_store(seed)
saved_url, mp.OLLAMA_URL = mp.OLLAMA_URL, None
srv = None
try:
if fixture == "dead":
mp.OLLAMA_URL = "http://127.0.0.1:1"
else:
srv, mp.OLLAMA_URL = _canned_ollama(fixture)
profiles = mp.scan_all_models()
finally:
mp.OLLAMA_URL = saved_url
if srv is not None:
srv.shutdown()
return {"profiles": [asdict(p) for p in profiles],
"files": _store_files()}
def seam_get_or_create_profile(model_name, seed=None):
_reset_store(seed)
p = mp.get_or_create_profile(model_name)
return {"profile": asdict(p), "files": _store_files()}
def seam_record_interaction(model_name, outcomes, seed=None):
"""outcomes: [[success, topic], ...] applied in order; returns the
saved profile docs after the last call (state effect is the contract
— the oracle fn returns None)."""
_reset_store(seed)
for success, topic in outcomes:
mp.record_interaction(model_name, success, topic)
return _store_files()
def seam_get_prompt_context(model_name, seed=None):
_reset_store(seed)
return mp.get_prompt_context(model_name)
def seam_to_dict(state):
"""ModelProfile.to_dict via a from_dict-built instance."""
return mp.ModelProfile.from_dict(state).to_dict()
def seam_from_dict(data):
return asdict(mp.ModelProfile.from_dict(data))
# Bind the seams onto the oracle module under seam_* names so the
# shared harness's getattr(module, fn) resolves every frozen fn name
# WITHOUT shadowing the oracle's internal call graph.
mp.seam_get_profile_path = seam_get_profile_path
mp.seam_load_profile = seam_load_profile
mp.seam_save_profile = seam_save_profile
mp.seam_build_profile_from_ollama = seam_build_profile_from_ollama
mp.seam_scan_all_models = seam_scan_all_models
mp.seam_get_or_create_profile = seam_get_or_create_profile
mp.seam_record_interaction = seam_record_interaction
mp.seam_get_prompt_context = seam_get_prompt_context
mp.seam_to_dict = seam_to_dict
mp.seam_from_dict = seam_from_dict
+173
View File
@@ -0,0 +1,173 @@
# Freeze rig for the parallel_processor dichotomy gap-closing (dichotomy
# wave #2479 gap port, contract factory-gap-pp). Auto-imported on
# interpreter start (PYTHONPATH=scripts/pp_freeze_seams:src) by BOTH the
# truth generator (scripts/gen_parallel_processor_truth.py), the shared
# harness's --verify mode, and the live-parity sweep, so frozen truth is
# byte-reproducible in any process:
#
# * THREAD-STATE PIN: get_status() reports threading.active_count(), which
# is process-random (spawned pool threads, harness state). Pinned to a
# constant for every rig process; the Go side's matching seam
# (PP_ACTIVE_THREADS) is pinned to the same value by the battery and
# the parity sweep.
# * SPEC SEAMS: callables are not JSON — truth rows carry the shared
# kind/fn/value spec grammar, and these seams build REAL Python
# callables/tuples from the specs before handing them to the oracle's
# actual functions (module- and class-level paths both exercised).
# The Go battery rebuilds the same tasks from the same rows.
import os
import sys
import threading
import time
_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"))
PP_FROZEN_ACTIVE_THREADS = 4
threading.active_count = lambda: PP_FROZEN_ACTIVE_THREADS # noqa: E731
import rune.parallel_processor as _pp # noqa: E402 (after the pin)
def _spec_func(spec):
fn = spec["fn"]
if fn == "const":
ret = spec.get("ret")
return lambda: ret
if fn == "boom":
msg = spec.get("msg", "boom")
def _boom():
raise ValueError(msg)
return _boom
if fn == "sleepret":
ms = spec.get("ms", 0)
ret = spec.get("ret")
def _sleepret():
time.sleep(ms / 1000.0)
return ret
return _sleepret
if fn == "echo":
def _echo(*a, **k):
return {"args": list(a), "kwargs": k}
return _echo
if fn == "add":
def _add(a, b):
return a + b
return _add
raise ValueError(f"unknown spec fn {fn}")
def _spec_zero(spec):
"""A zero-arg task for run_parallel rows: callable specs become real
callables; raw specs (and bare non-dict values) pass through as the
task itself (the oracle's non-callable TypeError branch)."""
if isinstance(spec, dict):
if spec.get("kind") == "call":
return _spec_func(spec)
if "kind" in spec:
return spec.get("value")
return spec
def _spec_task(spec):
"""A (func, args, kwargs) task for run_parallel_with_args rows,
including the oracle's parse-error branches. Bare non-dict values are
raw tasks."""
if not isinstance(spec, dict):
return spec
kind = spec.get("kind")
if kind == "raw":
return spec.get("value")
if kind == "emptytuple":
return ()
if kind == "notcall":
return (spec.get("value"),)
if kind == "argsnotseq":
# args is a non-sequence scalar -> the oracle wraps it: (args,)
return (_spec_func(spec), spec.get("value"), {})
if kind == "kwnotdict":
# kwargs is not a dict -> the oracle resets it to {}
return (_spec_func(spec), (), spec.get("value"))
return (_spec_func(spec), tuple(spec.get("args", [])), spec.get("kwargs", {}))
def _pp_run_parallel(specs):
return _pp.run_parallel([_spec_zero(s) for s in specs])
def _pp_run_parallel_with_args(specs):
return _pp.run_parallel_with_args([_spec_task(s) for s in specs])
def _pp_class_run_parallel(max_workers, specs):
p = _pp.ParallelProcessor(max_workers)
r = p.run_parallel([_spec_zero(s) for s in specs])
p.shutdown(wait=True)
return r
def _pp_class_run_parallel_with_args(max_workers, specs):
p = _pp.ParallelProcessor(max_workers)
r = p.run_parallel_with_args([_spec_task(s) for s in specs])
p.shutdown(wait=True)
return r
def _pp_get_processor_status():
p = _pp.get_processor()
return {"max_workers": p.max_workers, "is_singleton": _pp.get_processor() is p}
def _pp_shutdown_then_status():
p = _pp.ParallelProcessor(3)
r = p.shutdown(wait=True)
return {"shutdown_returned_none": r is None, "status": p.get_status()}
def _pp_shutdown_then_run():
p = _pp.ParallelProcessor(2)
p.shutdown(wait=True)
try:
p.run_parallel([lambda: 1])
return {"raised": None}
except RuntimeError as e:
return {"raised": str(e)}
def _pp_new_bad():
try:
_pp.ParallelProcessor(0)
return {"raised": None}
except ValueError as e:
return {"raised": str(e)}
def _pp_shutdown_processor_cycle():
_pp._shutdown_processor()
was_none = _pp._processor is None
st = _pp.get_status() # exercises the lazy re-create
return {"processor_is_none": was_none, "recreated_max_workers": st["max_workers"]}
_pp._pp_run_parallel = _pp_run_parallel
_pp._pp_run_parallel_with_args = _pp_run_parallel_with_args
_pp._pp_class_run_parallel = _pp_class_run_parallel
_pp._pp_class_run_parallel_with_args = _pp_class_run_parallel_with_args
_pp._pp_get_processor_status = _pp_get_processor_status
_pp._pp_shutdown_then_status = _pp_shutdown_then_status
_pp._pp_shutdown_then_run = _pp_shutdown_then_run
_pp._pp_new_bad = _pp_new_bad
_pp._pp_shutdown_processor_cycle = _pp_shutdown_processor_cycle
# spec builders for the live-parity sweep (same grammar as truth rows)
_pp._pp_spec_zero = _spec_zero
_pp._pp_spec_task = _spec_task
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""Resume-close the #2479 dichotomy-wave salience_gate contract: the walk
(BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg) reached `verifying`
via transitions in one process; the QUALITY-GATE LAW (scaffold.py
2026-10-13) requires the designed close() entry (predicted-vs-observed
quality + material-change) rather than a raw transition to 'closed'.
The phase lives in the store (durable and resumable by design) — this
script completes the close on the persisted contract. Carries the
already-pushed parity SHAs as evidence:
feat 9539d5b6 close PARTIAL gaps — dichotomy wave
phaseB 2350e02e Phase B language-advantage pass — dichotomy wave
Usage: resume_close_contract_salience_gate.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
CONTRACT = "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg"
PARITY_SHA = "9539d5b6"
PHASEB_SHA = "2350e02e"
iface = ConstructionInterface(builder="factory-gap-sg")
doc = iface.scaffold.load()
e = iface.scaffold.contract(doc, CONTRACT)
if e is None:
print("CONTRACT MISSING — aborting")
sys.exit(1)
print("current phase:", e.get("phase"))
if e.get("phase") != "verifying":
print("unexpected phase — aborting (walk only continues from verifying)")
sys.exit(1)
c = iface.close(
CONTRACT,
observed_evidence=[
{
"kind": "port_evidence",
"detail": (
f"salience_gate RUST dichotomy gap-close — parity commit {PARITY_SHA}, "
f"Phase B commit {PHASEB_SHA}; dichotomy audit fn coverage 1/5 "
"PARTIAL -> 6/6 FULL (evaluate_salience_dict JSON view counted "
"per the construction_decision normalize_need_json precedent; "
"the module's delegation side is the existing Rust crate — no "
"Go salience-gate dir exists). Ported name-preserving: "
"_sg_core (kernel mirror of the facade availability probe, pin "
"lattice), to_dict (SalienceDecision struct + projection), "
"handle_hook (event echo, data accepted+ignored), "
"test_salience (embedded oracle smoke, print-byte-matched). "
"Three parity defects fixed (frozen-truth battery caught all): "
"novel-family single-append (oracle guards ONE if — duplicate "
"append inflated len(flags) and flipped the witness rule), "
"failure-family doesn't-work/not-working arm omitted entirely, "
"word_boundary_contains Python-\\b parity (alphanumeric + "
"underscore + UTF-8 continuation bytes). Frozen truth via the "
"shared scripts/freeze_truth.py harness (generator "
"scripts/gen_salience_gate_truth.py, poisoned-truth law: "
"RUNE_SALIENCE_CORE=python + SG_RUST_LIB poisoned — the "
"facade evaluate path ignores RUNE_*_CORE): verify view 52 "
"rows byte-identical under freeze_truth.py --verify in BOTH "
"core states; envelope 63 rows incl. evaluation-order "
"multi-family rows the kernel mirrors exactly "
"(branch_battery.rs include_str replay, 12 tests). Live "
"parity 100%: gen --replay facade live + kernel direct "
"119/119; crate canary 6/6; oracle smoke green in 3 pin "
"states (live / RUNE_SALIENCE_CORE=python / pure floor). "
"rustfmt clean, clippy -D warnings clean, zero Go surface "
"(git diff touches no src/go files). Evidence read back: "
"verification/salience-gate-{freeze-verify,cargotest,clippy,"
"replay,canary,python-pins,goladder,audit,close-walk}.log"
),
}
],
scope_files=[
"src/rune/salience_gate.py",
"src/rune/sg_loader.py",
"src/rust/salience_gate/src/lib.rs",
"src/rust/salience_gate/src/branch_battery.rs",
"src/rust/salience_gate/src/frozen_sg_truth.json",
"src/rust/salience_gate/src/frozen_sg_truth.verify.json",
"src/rust/salience_gate/frozen_salience.json",
"src/rust/salience_gate/canary_salience_gate.py",
"src/rust/salience_gate/Cargo.toml",
"scripts/gen_salience_gate_truth.py",
"scripts/close_contract_salience_gate.py",
"scripts/resume_close_contract_salience_gate.py",
],
)
print("close:", json.dumps(c)[:400])
print("CONTRACT", CONTRACT, "closed" if c.get("success") else "CLOSE_FAILED")
sys.exit(0 if c.get("success") else 1)
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""Open AND close the #2479 dichotomy-wave construction contract for
model_profiles (Go 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-mp")
r = iface.submit_need(
"Close the PARTIAL gaps in src/go/model-profiles against the "
"src/rune/model_profiles.py oracle (dichotomy wave, issue #2479 "
"tranche): name-preserving Go ports for the 10 unmatched functions "
"(get_profile_path — filesystem sanitization, load_profile — "
"suppressed-exception floor + unknown-key filtering, save_profile — "
"Python-shaped JSON writer, build_profile_from_ollama — knowledge "
"merge + uncensored tier + frozen-clock stamps, scan_all_models — "
"Ollama sweep with banker's rounding + learned-data preservation, "
"get_or_create_profile, record_interaction — learning accumulator, "
"get_prompt_context — operator string assembly, to_dict/from_dict — "
"the dataclass lens) plus the stdin-op serve CLI over the same code "
"paths, frozen-truth corpus generated against the live Python oracle "
"through the scripts/mp_freeze_seams rig (HOME pinned before import, "
"per-case hermetic store wipe+seed, canned Ollama server, frozen "
"clock; 36 verbatim cases incl. the save_profile byte-parity rows), "
"battery 36/36, gofmt+vet clean, live parity 100% (143/143), pytest "
"31/31 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": "model_profiles dichotomy completion — parity "
"1ca647e4 feat(model_profiles): close PARTIAL gaps — "
"dichotomy wave; pushed gitea/master. Go port at "
"src/go/model-profiles closes the audit gaps "
"name-preserving (get_profile_path, load_profile, "
"save_profile, build_profile_from_ollama, scan_all_models, "
"get_or_create_profile, record_interaction, "
"get_prompt_context, to_dict/from_dict) plus the stdin-op "
"serve CLI over the same code paths. Freeze rig scripts/"
"mp_freeze_seams + generator: 36-case frozen truth "
"regenerates byte-identical across runs; freeze_truth "
"--verify OK against the live oracle. Battery 36/36 replay "
"VERBATIM; parity scripts/check_model_profiles_parity.py "
"143/143 LIVE; gofmt+vet+build clean; pytest 31/31 both "
"pins. Audit 5/15 → 15/15 FULL. Divergences (documented): "
"non-string profile names accepted by the oracle dataclass "
"but rejected by the typed port (local_tool_runtime "
"precedent); integral-float rendering canonicalized in the "
"sweep (context_broker precedent).",
}], scope_files=[
"src/go/model-profiles/main.go",
"src/go/model-profiles/frozen_battery_test.go",
"src/go/model-profiles/frozen_mp_truth.json",
"src/go/model-profiles/go.mod",
"src/go/model-profiles/truth.json",
"scripts/mp_freeze_seams/sitecustomize.py",
"scripts/gen_model_profiles_truth.py",
"scripts/gen_mp_battery.py",
"scripts/check_model_profiles_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)
File diff suppressed because it is too large. Load diff
+704
View File
@@ -0,0 +1,704 @@
// scenario.go — gap-close parity machinery, shared by the CI binary
// (`replay-gap`, `scenario`) and the battery (truth_gap_test.go).
//
// truth_gap.json rows are frozen against the live oracle through wrapper
// shims (scripts/gen_cron_engine_gap_truth.py, _ce_* functions). Every
// wrapper takes the engine state as an explicit leading JSON argument,
// runs against a HERMETIC per-row home (frozen clock; time.sleep patched
// to stop the loop for _run_loop rows), and captures
// {result, post, files, storage, log}. replayGap mirrors each wrapper
// against THIS port and compares the capture after substituting the
// row's actual home for the "<CE_HOME>" placeholder token (dichotomy
// law: no absolute paths in frozen truth).
package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"time"
)
const ceHomeToken = "<CE_HOME>"
// ordObj is a JSON object that remembers its key ORDER (Go maps do not;
// frozen truth's task dicts are insertion-ordered like Python's).
type ordObj struct {
keys []string
m map[string]any
}
func (o *ordObj) get(k string) (any, bool) {
v, ok := o.m[k]
return v, ok
}
// decodeArg decodes one truth-row argument preserving object key order.
func decodeArg(raw json.RawMessage) (any, error) {
dec := json.NewDecoder(bytes.NewReader(raw))
dec.UseNumber()
v, err := decodeArgValue(dec)
if err != nil {
return nil, err
}
return v, nil
}
func decodeArgValue(dec *json.Decoder) (any, error) {
tok, err := dec.Token()
if err != nil {
return nil, err
}
switch t := tok.(type) {
case json.Delim:
switch t {
case '{':
o := &ordObj{m: map[string]any{}}
for dec.More() {
kt, err := dec.Token()
if err != nil {
return nil, err
}
key, ok := kt.(string)
if !ok {
return nil, fmt.Errorf("bad object key %v", kt)
}
val, err := decodeArgValue(dec)
if err != nil {
return nil, err
}
if _, exists := o.m[key]; !exists {
o.keys = append(o.keys, key)
}
o.m[key] = val
}
if _, err := dec.Token(); err != nil { // '}'
return nil, err
}
return o, nil
case '[':
var arr []any
for dec.More() {
val, err := decodeArgValue(dec)
if err != nil {
return nil, err
}
arr = append(arr, val)
}
if _, err := dec.Token(); err != nil { // ']'
return nil, err
}
if arr == nil {
arr = []any{}
}
return arr, nil
}
return nil, fmt.Errorf("unexpected delim %v", t)
case json.Number:
f, err := t.Float64()
if err != nil {
return nil, err
}
return f, nil
default:
return tok, nil // string / bool / nil
}
}
// stateOf extracts the ordObj at args[i] (wrapper state argument).
func stateOf(args []any, i int) *ordObj {
if i < len(args) {
if o, ok := args[i].(*ordObj); ok {
return o
}
}
return &ordObj{m: map[string]any{}}
}
func readStrPtr(m map[string]any, k string) *string {
if v, ok := m[k].(string); ok {
return &v
}
return nil
}
func taskFromMap(m map[string]any) *CronTask {
t := &CronTask{
Name: strOf(m, "name"),
CronExpression: strOf(m, "cron_expression"),
Command: strOf(m, "command"),
Description: strOf(m, "description"),
Enabled: true, // dataclass default: enabled=True
LastRun: readStrPtr(m, "last_run"),
NextRun: readStrPtr(m, "next_run"),
RunCount: intOf(m, "run_count"),
}
if v, ok := m["enabled"].(bool); ok {
t.Enabled = v
}
return t
}
func strOf(m map[string]any, k string) string {
s, _ := m[k].(string)
return s
}
func boolOf(m map[string]any, k string) bool {
b, _ := m[k].(bool)
return b
}
func intOf(m map[string]any, k string) int {
f, _ := m[k].(float64)
return int(f)
}
// buildGapEngine reconstructs the engine from a wrapper state arg, with
// paths tokenized against the row's hermetic home.
func buildGapEngine(st *ordObj, home string) (*CronEngine, error) {
e := newCronEngine()
if sp, ok := st.get("storage_path"); ok {
e.storagePath = strings.ReplaceAll(asStr(sp), ceHomeToken, home)
}
e.logPath = filepath.Join(home, ".rune", "cron.log")
if r, ok := st.get("running"); ok {
e.running = asBool(r)
}
e.lastRunMin = map[string]string{}
if v, ok := st.get("_last_run_minute"); ok {
if lrm, ok2 := v.(*ordObj); ok2 {
for k, v := range lrm.m {
e.lastRunMin[k] = asStr(v)
}
}
}
if v, ok := st.get("tasks"); ok {
tasks, _ := v.(*ordObj)
if tasks != nil {
for _, name := range tasks.keys {
tj, ok := tasks.get(name)
if !ok {
continue
}
tm, _ := tj.(*ordObj)
if tm == nil {
continue
}
e.Tasks[name] = taskFromMap(tm.m)
e.insertOrder(name)
}
}
}
// optional log seeding (rotation rows): filename -> size, filled b"x"
if v, ok := st.get("seed_log"); ok {
if seed, ok2 := v.(*ordObj); ok2 {
dir := filepath.Dir(e.logPath)
if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, err
}
names := append([]string{}, seed.keys...)
sort.Strings(names)
for _, name := range names {
sz := int64(0)
if f, ok := seed.m[name].(float64); ok {
sz = int64(f)
}
if err := os.WriteFile(filepath.Join(dir, name), bytes.Repeat([]byte("x"), int(sz)), 0o644); err != nil {
return nil, err
}
}
}
}
return e, nil
}
func asStr(v any) string {
s, _ := v.(string)
return s
}
func asBool(v any) bool {
b, _ := v.(bool)
return b
}
func readFileOrNone(p string) *string {
b, err := os.ReadFile(p)
if err != nil {
return nil
}
s := string(b)
return &s
}
func dirSizes(dir string) map[string]int64 {
out := map[string]int64{}
ents, err := os.ReadDir(dir)
if err != nil {
return out
}
for _, ent := range ents {
if ent.IsDir() {
continue
}
if info, err := ent.Info(); err == nil {
out[ent.Name()] = info.Size()
}
}
return out
}
func captureEngine(e *CronEngine, result any, home string) map[string]any {
pairs := [][2]any{}
for _, t := range e.snapshotTasks() {
pairs = append(pairs, [2]any{t.Name, t.toDict()})
}
lrm := map[string]string{}
for k, v := range e.lastRunMin {
lrm[k] = v
}
files := map[string]int64{}
if e.logPath != "" {
files = dirSizes(filepath.Dir(e.logPath))
}
return map[string]any{
"result": result,
"post": map[string]any{
"running": e.running,
"storage_path": strings.ReplaceAll(e.storagePath, home, ceHomeToken),
"tasks": pairs,
"_last_run_minute": lrm,
},
"files": files,
"storage": readFileOrNone(e.storagePath),
"log": readFileOrNone(e.logPath),
}
}
// withLoopSleep patches sleepFn to flip THIS engine's running flag on the
// first sleep — the exact patch the oracle wrapper applies to
// cron_engine.time.sleep for _run_loop rows (one iteration, then exit).
func withLoopSleep(e *CronEngine, fn func()) {
old := sleepFn
sleepFn = func(time.Duration) { e.mu.Lock(); e.running = false; e.mu.Unlock() }
defer func() { sleepFn = old }()
fn()
}
// execGapRow interprets one _ce_* wrapper row against the port. Pure
// rows return their bare result; engine rows return the full capture
// map; the start_stop singleton additionally returns an "extra" merge.
// args are decodeArg values (objects = *ordObj, order-preserving).
func execGapRow(fn string, args []any, home string) (result any, extra map[string]any, err error) {
st := stateOf(args, 0)
str := func(i int) string {
if i < len(args) {
return asStr(args[i])
}
return ""
}
num := func(i int) int {
if i < len(args) {
if f, ok := args[i].(float64); ok {
return int(f)
}
}
return 0
}
switch fn {
case "_ce_to_dict":
m := stateOf(args, 0).m
return taskFromMap(m).toDict(), nil, nil
case "_ce_parse":
vals, perr := parseCronField(str(0), num(1), num(2))
if perr != nil {
return nil, nil, perr
}
out := []int{}
for v := range vals {
out = append(out, v)
}
sort.Ints(out)
return out, nil, nil
case "_ce_should_run":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
name := str(1)
now := time.Date(num(2), time.Month(num(3)), num(4), num(5), num(6), 0, 0, time.UTC)
t := e.Tasks[name]
ok, serr := shouldRun(t.CronExpression, now, e.lastRunMin[t.Name])
if serr != nil {
return nil, nil, serr
}
return ok, nil, nil
case "_ce_run_task":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
return captureEngine(e, e.runTask(str(1)), home), nil, nil
case "_ce_fire":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
return captureEngine(e, e.fireOnTaskComplete(), home), nil, nil
case "_ce_stop":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
e.stop()
return captureEngine(e, nil, home), nil, nil
case "_ce_execute":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
if xerr := e.executeTask(e.Tasks[str(1)]); xerr != nil {
return nil, nil, xerr
}
return captureEngine(e, nil, home), nil, nil
case "_ce_run_loop":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
withLoopSleep(e, func() { e.runLoop() })
return captureEngine(e, nil, home), nil, nil
case "_ce_log_execution":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
if lerr := e.logExecution(e.Tasks[str(1)], num(2)); lerr != nil {
return nil, nil, lerr
}
return captureEngine(e, nil, home), nil, nil
case "_ce_log_error":
e, berr := buildGapEngine(st, home)
if berr != nil {
return nil, nil, berr
}
if lerr := e.logError(e.Tasks[str(1)], str(2)); lerr != nil {
return nil, nil, lerr
}
return captureEngine(e, nil, home), nil, nil
case "_ce_singleton":
return execSingletonRow(str(0), str(1), str(2), str(3), home)
default:
return nil, nil, fmt.Errorf("unknown gap fn %q", fn)
}
}
// execSingletonRow mirrors the singleton wrapper family: reset the
// global, hermetic HOME (default paths derive from it). start_stop uses
// the REAL sleeper — the loop thread genuinely blocks in its 60s sleep,
// so the mid-capture (running=true) is race-free and stop's 5s join
// timeout is exercised, exactly like the oracle wrapper.
func execSingletonRow(op, name, expr, command, home string) (any, map[string]any, error) {
oldHome, hadHome := os.LookupEnv("HOME")
oldGlobal := globalCronEngine
defer func() {
if hadHome {
os.Setenv("HOME", oldHome)
} else {
os.Unsetenv("HOME")
}
globalCronEngine = oldGlobal
}()
os.Setenv("HOME", home)
globalCronEngine = nil
switch op {
case "get":
e := getCronEngine()
return captureEngine(e, len(e.listTasks()), home), nil, nil
case "start_stop":
startEngine()
mid := captureEngine(getCronEngine(), nil, home)
stopEngine() // 5s join timeout — the loop thread sleeps for real
end := captureEngine(getCronEngine(), nil, home)
return end, map[string]any{"extra": mid}, nil
case "module_run":
e := getCronEngine()
e.addTask(name, expr, command, "")
r := runTask(name) // module-level run_task via the global
return captureEngine(getCronEngine(), r, home), nil, nil
case "module_list":
e := getCronEngine()
e.addTask(name, expr, command, "d1")
e.addTask(name+"-2", "*/5 * * * *", "echo two", "d2")
names := []string{}
for _, t := range moduleListTasks() {
names = append(names, t.Name)
}
return captureEngine(e, names, home), nil, nil
default:
return nil, nil, fmt.Errorf("unknown singleton op %q", op)
}
}
// normalizeCapture substitutes the row's hermetic home for the token in
// every string of the frozen expectation so comparison is
// machine-independent.
func normalizeCapture(v any, home string) any {
switch x := v.(type) {
case string:
return strings.ReplaceAll(x, ceHomeToken, home)
case map[string]any:
out := map[string]any{}
for k, vv := range x {
out[k] = normalizeCapture(vv, home)
}
return out
case []any:
out := make([]any, len(x))
for i, vv := range x {
out[i] = normalizeCapture(vv, home)
}
return out
default:
return v
}
}
func toAny(v any) any {
b, err := json.Marshal(v)
if err != nil {
return v
}
var out any
if err := json.Unmarshal(b, &out); err != nil {
return v
}
return out
}
type gapTruthRow struct {
Fn string `json:"fn"`
Args []json.RawMessage `json:"args"`
Kwargs any `json:"kwargs"`
Expected any `json:"expected"`
}
// replayGapBytes replays a truth_gap envelope; returns first divergence.
func replayGapBytes(raw []byte) error {
var env struct {
FrozenNow string `json:"frozen_now"`
Cases []gapTruthRow `json:"cases"`
}
if err := json.Unmarshal(raw, &env); err != nil {
return err
}
frozen, err := time.Parse("2006-01-02T15:04:05", env.FrozenNow)
if err != nil {
return fmt.Errorf("bad frozen_now %q: %v", env.FrozenNow, err)
}
oldNow, oldSleep, oldHome, hadHome := nowUTC, sleepFn, "", false
if h, ok := os.LookupEnv("HOME"); ok {
oldHome, hadHome = h, true
}
defer func() {
nowUTC, sleepFn = oldNow, oldSleep
if hadHome {
os.Setenv("HOME", oldHome)
}
}()
nowUTC = func() time.Time { return frozen.UTC() }
fails := 0
for i, row := range env.Cases {
home, err := os.MkdirTemp("", "ce-gap-*")
if err != nil {
return err
}
args := make([]any, len(row.Args))
for j, raw := range row.Args {
args[j], err = decodeArg(raw)
if err != nil {
return fmt.Errorf("case %d: bad arg %d: %v", i, j, err)
}
}
got, extra, err := execGapRow(row.Fn, args, home)
if err != nil {
fails++
fmt.Printf("case %d %s: ERROR %v\n", i, row.Fn, err)
os.RemoveAll(home)
continue
}
gotAny := toAny(got)
if extra != nil {
if m, ok := gotAny.(map[string]any); ok {
merged := map[string]any{}
for k, v := range m {
merged[k] = v
}
for k, v := range extra {
merged[k] = toAny(v)
}
gotAny = merged
}
}
gotAny = normalizeCapture(gotAny, home)
want := normalizeCapture(row.Expected, home)
if !reflect.DeepEqual(gotAny, want) {
fails++
gb, _ := json.MarshalIndent(gotAny, "", " ")
wb, _ := json.MarshalIndent(want, "", " ")
fmt.Printf("case %d %s DIVERGE\ngot: %s\nwant: %s\n", i, row.Fn, gb, wb)
}
os.RemoveAll(home)
}
if fails > 0 {
return fmt.Errorf("PARITY FAILED: %d divergence(s)", fails)
}
fmt.Printf("PARITY OK: %d gap cases exact-equal vs the Python oracle\n", len(env.Cases))
return nil
}
func replayGap(path string) error {
raw, err := os.ReadFile(path)
if err != nil {
return err
}
return replayGapBytes(raw)
}
// ── scenario driver (live parity: same ops against the Python oracle
// and this port, JSON outputs diffed by check_cron_engine_parity.py) ──
type scenarioOp struct {
Op string `json:"op"`
Name string `json:"name"`
Expr string `json:"expr"`
Command string `json:"command"`
Description string `json:"description"`
}
type scenarioFile struct {
FrozenNow string `json:"frozen_now"`
StoragePath string `json:"storage_path"`
LogPath string `json:"log_path"`
Ops []scenarioOp `json:"ops"`
}
type taskPair struct {
Name string `json:"name"`
Task *CronTask `json:"task"`
}
type stateDump struct {
Running bool `json:"running"`
StoragePath string `json:"storage_path"`
LogPath string `json:"log_path"`
Tasks []taskPair `json:"tasks"`
LastRunMin map[string]string `json:"_last_run_minute"`
}
func dumpState(e *CronEngine) stateDump {
tasks := []taskPair{}
for _, t := range e.snapshotTasks() {
tasks = append(tasks, taskPair{Name: t.Name, Task: t.toDict()})
}
lrm := map[string]string{}
for k, v := range e.lastRunMin {
lrm[k] = v
}
return stateDump{
Running: e.running,
StoragePath: e.storagePath,
LogPath: e.logPath,
Tasks: tasks,
LastRunMin: lrm,
}
}
func runScenario(path string) error {
raw, err := os.ReadFile(path)
if err != nil {
return err
}
var sc scenarioFile
if err := json.Unmarshal(raw, &sc); err != nil {
return err
}
home, err := os.MkdirTemp("", "ce-scenario-*")
if err != nil {
return err
}
defer os.RemoveAll(home)
if sc.StoragePath == "" {
sc.StoragePath = "<HOME>/.rune/cron.json"
}
if sc.LogPath == "" {
sc.LogPath = "<HOME>/.rune/cron.log"
}
storage := strings.ReplaceAll(sc.StoragePath, "<HOME>", home)
logP := strings.ReplaceAll(sc.LogPath, "<HOME>", home)
frozen, err := time.Parse("2006-01-02T15:04:05", sc.FrozenNow)
if err != nil {
return fmt.Errorf("bad frozen_now: %v", err)
}
oldNow, oldSleep := nowUTC, sleepFn
defer func() { nowUTC, sleepFn = oldNow, oldSleep }()
nowUTC = func() time.Time { return frozen.UTC() }
e := newCronEngineAt(storage, logP)
steps := []any{}
for _, op := range sc.Ops {
switch op.Op {
case "add":
t := e.addTask(op.Name, op.Expr, op.Command, op.Description)
steps = append(steps, map[string]any{"op": "add", "task": t.toDict()})
case "enable":
steps = append(steps, map[string]any{"op": "enable", "ok": e.enableTask(op.Name)})
case "disable":
steps = append(steps, map[string]any{"op": "disable", "ok": e.disableTask(op.Name)})
case "remove":
steps = append(steps, map[string]any{"op": "remove", "ok": e.removeTask(op.Name)})
case "run":
steps = append(steps, map[string]any{"op": "run", "result": e.runTask(op.Name)})
case "fire":
steps = append(steps, map[string]any{"op": "fire", "fired": e.fireOnTaskComplete()})
case "loop":
withLoopSleep(e, func() { e.runLoop() })
steps = append(steps, map[string]any{"op": "loop"})
case "start":
withLoopSleep(e, func() { e.start(); e.stop() })
steps = append(steps, map[string]any{"op": "start+stop"})
case "stop":
e.stop()
steps = append(steps, map[string]any{"op": "stop"})
case "save":
err := e.saveTo(e.storagePath)
steps = append(steps, map[string]any{"op": "save", "ok": err == nil})
case "load":
err := e.loadFrom(e.storagePath)
steps = append(steps, map[string]any{"op": "load", "ok": err == nil})
case "storage":
steps = append(steps, map[string]any{"op": "storage", "bytes": readFileOrNone(e.storagePath)})
case "log":
steps = append(steps, map[string]any{"op": "log", "bytes": readFileOrNone(e.logPath)})
case "state":
steps = append(steps, map[string]any{"op": "state", "state": dumpState(e)})
default:
return fmt.Errorf("unknown scenario op %q", op.Op)
}
}
out := map[string]any{"steps": steps, "final": dumpState(e)}
enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
return enc.Encode(out)
}
File diff suppressed because it is too large. Load diff
+121
View File
@@ -0,0 +1,121 @@
package main
// truth_gap_test.go — gap-close battery: replays truth_gap.json (frozen
// against the live Python oracle through scripts/gen_cron_engine_gap_truth.py
// wrappers) and pins the error-message shapes that are too slow to freeze
// through the oracle's hardcoded 60s subprocess timeout (documented
// divergences carry the exact oracle strings; see verification/ce-*).
import (
"os"
"testing"
"time"
)
func TestGapParity(t *testing.T) {
raw, err := os.ReadFile("truth_gap.json")
if err != nil {
t.Fatalf("truth missing: %v", err)
}
if err := replayGapBytes(raw); err != nil {
t.Fatalf("gap parity: %v", err)
}
}
// TestOracleErrorShapes pins str(e) forms the oracle produces but that
// frozen truth cannot capture cheaply (a real 60s TimeoutExpired wait).
func TestOracleErrorShapes(t *testing.T) {
if got, want := pyTimeoutExpired([]string{"sleep", "65"}, 60).Error(),
"Command '['sleep', '65']' timed out after 60 seconds"; got != want {
t.Errorf("timeout msg: got %q want %q", got, want)
}
if _, err := parseCronField("*/0", 0, 59); err == nil || err.Error() != "range() arg 3 must not be zero" {
t.Errorf("step-0 error: got %v", err)
}
if _, err := shlexSplit("echo 'open"); err == nil || err.Error() != "No closing quotation" {
t.Errorf("shlex quote error: got %v", err)
}
if _, err := shlexSplit(`echo \`); err == nil || err.Error() != "No escaped character" {
t.Errorf("shlex escape error: got %v", err)
}
if got := pyISO(time.Date(2026, 10, 13, 9, 20, 0, 0, time.UTC)); got != "2026-10-13T09:20:00+00:00" {
t.Errorf("pyISO: got %q", got)
}
if got := pyISO(time.Date(2026, 10, 13, 9, 20, 0, 123456000, time.UTC)); got != "2026-10-13T09:20:00.123456+00:00" {
t.Errorf("pyISO us: got %q", got)
}
}
// TestTimeoutBranchReplay exercises the timeout path through the seam at
// a human timescale and checks the envelope carries the oracle's
// TimeoutExpired str(e) verbatim.
func TestTimeoutBranchReplay(t *testing.T) {
oldT := execTimeout
defer func() { execTimeout = oldT }()
execTimeout = 300 * time.Millisecond
e := newCronEngineAt("/tmp/ce-timeout-test/cron.json", "/tmp/ce-timeout-test/cron.log")
e.addTask("slow", "*/5 * * * *", "sleep 5", "")
r := e.runTask("slow")
errEnv, ok := r.(runTaskErr)
if !ok {
t.Fatalf("want error envelope, got %#v", r)
}
want := "Command '['sleep', '5']' timed out after 0 seconds"
if errEnv.Error != want {
t.Errorf("timeout envelope: got %q want %q", errEnv.Error, want)
}
}
// TestOrderedSaveBytes proves _save's insertion-order + ensure_ascii
// rendering byte-parity against a Python-produced fixture.
func TestOrderedSaveBytes(t *testing.T) {
e := newCronEngine()
e.addTask("b-second", "*/5 * * * *", "echo b", "plain")
e.addTask("a-first", "on_complete", "echo '中文 <ok>'", "desc ünïcode")
ls := "2026-10-13T09:20:00+00:00"
e.Tasks["b-second"].RunCount = 3
e.Tasks["b-second"].LastRun = &ls
dir := t.TempDir()
p := dir + "/cron.json"
if err := e.saveTo(p); err != nil {
t.Fatal(err)
}
got, _ := os.ReadFile(p)
want := "{\n" +
" \"b-second\": {\n" +
" \"name\": \"b-second\",\n" +
" \"cron_expression\": \"*/5 * * * *\",\n" +
" \"command\": \"echo b\",\n" +
" \"description\": \"plain\",\n" +
" \"enabled\": true,\n" +
" \"last_run\": \"2026-10-13T09:20:00+00:00\",\n" +
" \"next_run\": null,\n" +
" \"run_count\": 3\n" +
" },\n" +
" \"a-first\": {\n" +
" \"name\": \"a-first\",\n" +
" \"cron_expression\": \"on_complete\",\n" +
" \"command\": \"echo '\\u4e2d\\u6587 <ok>'\",\n" +
" \"description\": \"desc \\u00fcn\\u00efcode\",\n" +
" \"enabled\": true,\n" +
" \"last_run\": null,\n" +
" \"next_run\": null,\n" +
" \"run_count\": 0\n" +
" }\n" +
"}"
if string(got) != want {
t.Errorf("save bytes:\ngot: %q\nwant: %q", string(got), want)
}
// round-trip preserves insertion order
e2 := newCronEngine()
if err := e2.loadFrom(p); err != nil {
t.Fatal(err)
}
names := []string{}
for _, tsk := range e2.snapshotTasks() {
names = append(names, tsk.Name)
}
if len(names) != 2 || names[0] != "b-second" || names[1] != "a-first" {
t.Errorf("load order: got %v", names)
}
}
+67 -19
View File
@@ -36,12 +36,22 @@ type PluginEntry struct {
Manifest PluginManifest `json:"manifest"`
RegisteredAt string `json:"registered_at"`
Active bool `json:"active"`
File string `json:"file"`
}
// FireLog — one fire() audit entry (registry["log"], last 100 kept).
type FireLog struct {
Event string `json:"event"`
Timestamp string `json:"timestamp"`
HooksFired int `json:"hooks_fired"`
DurationMs float64 `json:"duration_ms"`
}
type Registry struct {
Plugins map[string]PluginEntry `json:"plugins"`
Capabilities map[string][]string `json:"capabilities"`
Hooks map[string][]string `json:"hooks"`
Log []FireLog `json:"log"`
}
func registryPath() string {
@@ -52,21 +62,43 @@ func registryPath() string {
return filepath.Join(home, "microkernel_registry.json")
}
func loadRegistry() Registry {
r := Registry{
func emptyRegistry() Registry {
return Registry{
Plugins: make(map[string]PluginEntry),
Capabilities: make(map[string][]string),
Hooks: make(map[string][]string),
Log: []FireLog{},
}
}
// LoadRegistry — the oracle's _load_registry(): missing OR corrupt file
// yields the full default shape (plugins/capabilities/hooks/log all empty).
func LoadRegistry() Registry {
r := emptyRegistry()
data, err := os.ReadFile(registryPath())
if err != nil {
return r
}
json.Unmarshal(data, &r)
if json.Unmarshal(data, &r) != nil {
return emptyRegistry()
}
if r.Plugins == nil {
r.Plugins = make(map[string]PluginEntry)
}
if r.Capabilities == nil {
r.Capabilities = make(map[string][]string)
}
if r.Hooks == nil {
r.Hooks = make(map[string][]string)
}
if r.Log == nil {
r.Log = []FireLog{}
}
return r
}
func saveRegistry(r Registry) {
// SaveRegistry — the oracle's _save_registry(): indent-2 JSON.
func SaveRegistry(r Registry) {
os.MkdirAll(filepath.Dir(registryPath()), 0755)
data, _ := json.MarshalIndent(r, "", " ")
os.WriteFile(registryPath(), data, 0644)
@@ -74,10 +106,10 @@ func saveRegistry(r Registry) {
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: microkernel <register|unregister|resolve|fire|status> [args...]")
fmt.Fprintln(os.Stderr, "usage: microkernel <register|unregister|resolve|fire|discover|status|parity> [args...]")
os.Exit(1)
}
registry := loadRegistry()
registry := LoadRegistry()
cmd := os.Args[1]
args := os.Args[2:]
@@ -106,7 +138,7 @@ func main() {
for event := range manifest.Hooks {
registry.Hooks[event] = append(registry.Hooks[event], manifest.Name)
}
saveRegistry(registry)
SaveRegistry(registry)
out, _ := json.Marshal(map[string]interface{}{
"status": "registered", "name": manifest.Name,
"capabilities": manifest.Capabilities})
@@ -151,7 +183,7 @@ func main() {
}
delete(registry.Plugins, name)
_ = entry
saveRegistry(registry)
SaveRegistry(registry)
fmt.Printf(`{"status": "unregistered", "name": "%s"}`+"\n", name)
case "resolve":
@@ -183,29 +215,45 @@ func main() {
case "fire":
event := ""
data := ""
dataRaw := ""
if len(args) > 0 {
event = args[0]
}
for i := 1; i < len(args); i++ {
if args[i] == "--data" && i+1 < len(args) {
data = args[i+1]
dataRaw = args[i+1]
i++
}
}
listeners, ok := registry.Hooks[event]
if !ok || len(listeners) == 0 {
fmt.Println(`{"status": "no_listeners"}`)
var data interface{}
if dataRaw != "" {
if json.Unmarshal([]byte(dataRaw), &data) != nil {
fmt.Printf(`{"error": "invalid --data JSON: %s"}`+"\n", dataRaw)
return
}
}
result := Fire(&registry, event, data, 30*time.Second, NowIso())
SaveRegistry(registry)
out, _ := json.Marshal(result)
fmt.Println(string(out))
case "discover":
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: microkernel discover <scripts-dir>")
os.Exit(1)
}
result, err := Discover(&registry, args[0], NowIso())
if err != nil {
fmt.Printf(`{"error": "%s"}`+"\n", err.Error())
return
}
results := make([]string, 0)
for _, listener := range listeners {
results = append(results, fmt.Sprintf("hook fired on %s with data %s", listener, data))
}
out, _ := json.Marshal(map[string]interface{}{
"status": "fired", "event": event, "listeners": listeners, "results": results})
SaveRegistry(registry)
out, _ := json.Marshal(result)
fmt.Println(string(out))
case "parity":
parityMain()
case "status":
plugins := make([]string, 0)
for name := range registry.Plugins {
+512 -4
View File
@@ -5,10 +5,71 @@ package main
// operations; file I/O stays reactive).
import (
"bytes"
"context"
"encoding/json"
"fmt"
"math"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"sync"
"time"
)
// pythonExe — the oracle dispatches hooks with sys.executable; the port
// resolves python3 from PATH (fixture plugins are stdlib-only, so any
// python3 is byte-equivalent).
var pythonExe = "python3"
// nowFunc — wall clock seam; the battery pins it (no-clock law: frozen
// truth never depends on time.Now()).
var nowFunc = time.Now
// NowIso — the oracle's now_iso(): UTC, seconds precision, Python's
// isoformat(timespec="seconds") renders the UTC offset as +00:00 (not Z).
func NowIso() string {
return nowFunc().UTC().Format("2006-01-02T15:04:05-07:00")
}
// pyTruthy — Python truthiness for JSON-shaped values. The oracle gates
// hooks with `if enabled:` and auto_activate with manifest.get(..., True):
// string hook targets ("handle_hook") are truthy, "" / 0 / false / null /
// empty containers are not.
func pyTruthy(v interface{}) bool {
switch x := v.(type) {
case nil:
return false
case bool:
return x
case float64:
return x != 0
case string:
return x != ""
case []interface{}:
return len(x) > 0
case map[string]interface{}:
return len(x) > 0
}
return true
}
// truncateRunes — Python str[:n] slices CODEPOINTS, not bytes.
func truncateRunes(s string, n int) string {
r := []rune(s)
if len(r) <= n {
return s
}
return string(r[:n])
}
// roundToEven1 — Python round(x, 1) is banker's rounding (ties-to-even).
func roundToEven1(v float64) float64 {
return math.RoundToEven(v*10) / 10
}
// Register — register a plugin from its manifest (map form, decoded like
// the oracle receives it). Error text parity: "manifest must have a 'name'".
func Register(reg *Registry, manifest map[string]interface{}, nowISO string) (PluginEntry, error) {
@@ -18,14 +79,14 @@ func Register(reg *Registry, manifest map[string]interface{}, nowISO string) (Pl
}
active := true
if v, has := manifest["auto_activate"]; has {
if b, ok := v.(bool); ok {
active = b
}
active = pyTruthy(v)
}
file, _ := manifest["_file"].(string)
entry := PluginEntry{
Manifest: manifestToStruct(manifest),
RegisteredAt: nowISO,
Active: active,
File: file,
}
reg.Plugins[name] = entry
if caps, ok := manifest["capabilities"].([]interface{}); ok {
@@ -52,9 +113,11 @@ func Register(reg *Registry, manifest map[string]interface{}, nowISO string) (Pl
for ev := range hooks {
names = append(names, ev)
}
// Per-event lists only ever gain this name once, so iteration
// order is unobservable in the registry state; sorted = deterministic.
sort.Strings(names)
for _, ev := range names {
if enabled, _ := hooks[ev].(bool); enabled {
if pyTruthy(hooks[ev]) {
list := reg.Hooks[ev]
found := false
for _, n := range list {
@@ -137,3 +200,448 @@ func Resolve(reg *Registry, capability string) string {
sort.SliceStable(active, func(i, j int) bool { return active[i].priority < active[j].priority })
return active[0].name
}
// ---------------------------------------------------------------------------
// Discovery — scan a directory and register every plugin with a PLUGIN dict.
// ---------------------------------------------------------------------------
// Discover — the oracle's self-registration sweep: every .py file (not
// underscore-prefixed, not microkernel.py itself) whose source carries a
// PLUGIN literal gets registered. Go lists the directory name-sorted —
// deterministic where os.listdir is filesystem-order (order only affects
// append order inside index lists; documented divergence).
func Discover(reg *Registry, scriptsDir string, nowISO string) (map[string]interface{}, error) {
registered := 0
errs := []map[string]interface{}{}
entries, err := os.ReadDir(scriptsDir)
if err != nil {
// the oracle lets OSError propagate out of discover()
return nil, err
}
for _, e := range entries {
fname := e.Name()
if !strings.HasSuffix(fname, ".py") || strings.HasPrefix(fname, "_") {
continue
}
if fname == "microkernel.py" {
continue
}
fpath := filepath.Join(scriptsDir, fname)
manifest := ExtractManifest(fpath)
if len(manifest) == 0 {
continue // `if manifest:` — {} is falsy, skipped like None
}
manifest["_file"] = fpath
manifest["_module"] = strings.TrimSuffix(fname, ".py")
if _, rerr := Register(reg, manifest, nowISO); rerr != nil {
errs = append(errs, map[string]interface{}{"file": fname, "error": rerr.Error()})
} else {
registered++
}
}
return map[string]interface{}{"discovered": registered, "errors": errs}, nil
}
// ExtractManifest — pull the PLUGIN dict literal out of .py source
// WITHOUT executing it (the oracle's ast.literal_eval path). Byte-for-byte
// brace accounting, including the oracle's edge: the opener line is never
// re-checked, so `PLUGIN = {}` keeps scanning subsequent lines.
// Non-dict PLUGIN literals return nil in Go (the oracle returns the value
// and register() then crashes on .get — documented crash-class divergence).
func ExtractManifest(fpath string) map[string]interface{} {
content, err := os.ReadFile(fpath)
if err != nil {
return nil
}
return ExtractManifestString(string(content))
}
// ExtractManifestString — ExtractManifest over in-memory source (the
// battery/parity seam; the result never depends on the path).
func ExtractManifestString(content string) map[string]interface{} {
if !strings.Contains(content, "PLUGIN") {
return nil
}
lines := strings.Split(content, "\n")
start, end := -1, -1
for i, line := range lines {
t := strings.TrimSpace(line)
if strings.HasPrefix(t, "PLUGIN") && strings.Contains(line, "=") && strings.Contains(line, "{") {
start = i
brace := strings.Count(line, "{") - strings.Count(line, "}")
for j := i + 1; j < len(lines); j++ {
brace += strings.Count(lines[j], "{") - strings.Count(lines[j], "}")
if brace <= 0 {
end = j
break
}
}
break
}
}
if start < 0 || end < 0 {
return nil
}
dictStr := strings.Join(lines[start:end+1], "\n")
if eq := strings.Index(dictStr, "="); eq >= 0 {
dictStr = strings.TrimSpace(dictStr[eq+1:])
}
v, perr := pyLiteral(dictStr)
if perr != nil {
return nil
}
m, _ := v.(map[string]interface{})
return m
}
// ---------------------------------------------------------------------------
// fire — execute hooks for an event (subprocess isolation, 8-way parallel).
// ---------------------------------------------------------------------------
// RunHook — one listener as a python subprocess (the oracle's _run_hook
// closure). Statuses: skipped | error | ok | timeout. duration_ms is
// banker's-rounded to one decimal like round(x, 1); the timeout branch
// carries no duration, matching the oracle.
func RunHook(reg *Registry, name, event, dataJSON string, timeout time.Duration) map[string]interface{} {
plugin, has := reg.Plugins[name]
if !has || !plugin.Active {
return map[string]interface{}{"name": name, "status": "skipped"}
}
fpath := plugin.File
if fpath == "" || !fileExists(fpath) {
return map[string]interface{}{"name": name, "status": "error", "error": "file not found"}
}
hookStart := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
cmd := exec.CommandContext(ctx, pythonExe, fpath, "hook", "--event", event, "--data", dataJSON)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
runErr := cmd.Run()
duration := roundToEven1(float64(time.Since(hookStart).Nanoseconds()) / 1e6)
if ctx.Err() == context.DeadlineExceeded {
return map[string]interface{}{"name": name, "status": "timeout"}
}
if runErr != nil {
if _, isExit := runErr.(*exec.ExitError); isExit {
return map[string]interface{}{
"name": name, "status": "error",
"error": truncateRunes(strings.TrimSpace(stderr.String()), 200),
"duration_ms": duration,
}
}
// start-class failure (python missing, exec perm): the oracle hits
// the generic `except Exception` — message only, no duration.
return map[string]interface{}{
"name": name, "status": "error",
"error": truncateRunes(runErr.Error(), 200),
}
}
var result interface{}
if json.Unmarshal(stdout.Bytes(), &result) != nil {
result = truncateRunes(strings.TrimSpace(stdout.String()), 500)
}
return map[string]interface{}{
"name": name, "status": "ok",
"result": result, "duration_ms": duration,
}
}
func fileExists(p string) bool {
_, err := os.Stat(p)
return err == nil
}
// Fire — run every enabled listener for an event in parallel (8 workers,
// the oracle's ThreadPoolExecutor cap), then append a bounded fire-log
// entry. The oracle's as_completed result order is nondeterministic; the
// port returns results name-sorted (rigs normalize identically on the
// Python side). total_duration_ms and the log duration are wall-clock:
// batteries normalize them.
func Fire(reg *Registry, event string, data interface{}, timeout time.Duration, nowISO string) map[string]interface{} {
listeners := reg.Hooks[event]
if len(listeners) == 0 {
return map[string]interface{}{"event": event, "hooks_fired": 0, "results": []map[string]interface{}{}}
}
dataJSON := []byte("{}")
if data != nil {
b, merr := json.Marshal(data)
if merr == nil {
dataJSON = b
}
}
totalStart := time.Now()
sem := make(chan struct{}, 8)
var wg sync.WaitGroup
var mu sync.Mutex
results := make([]map[string]interface{}, 0, len(listeners))
for _, name := range listeners {
wg.Add(1)
sem <- struct{}{}
go func(n string) {
defer wg.Done()
defer func() { <-sem }()
r := RunHook(reg, n, event, string(dataJSON), timeout)
mu.Lock()
results = append(results, r)
mu.Unlock()
}(name)
}
wg.Wait()
sort.SliceStable(results, func(i, j int) bool {
return fmt.Sprint(results[i]["name"]) < fmt.Sprint(results[j]["name"])
})
totalDuration := roundToEven1(float64(time.Since(totalStart).Nanoseconds()) / 1e6)
reg.Log = append(reg.Log, FireLog{
Event: event, Timestamp: nowISO,
HooksFired: len(results), DurationMs: totalDuration,
})
if len(reg.Log) > 100 {
reg.Log = reg.Log[len(reg.Log)-100:]
}
return map[string]interface{}{
"event": event, "hooks_fired": len(results),
"results": results,
"total_duration_ms": totalDuration,
}
}
// ---------------------------------------------------------------------------
// Python-literal parser — the ast.literal_eval subset PLUGIN dicts use.
// ---------------------------------------------------------------------------
type pyParser struct {
s string
pos int
}
// pyLiteral — parse a Python literal: dict / list / tuple / string /
// int / float / True / False / None, with comments and trailing commas.
// Numbers become float64 (the JSON-canonical type of this port).
func pyLiteral(src string) (interface{}, error) {
p := &pyParser{s: src}
p.ws()
v, err := p.value()
if err != nil {
return nil, err
}
p.ws()
if p.pos != len(p.s) {
return nil, fmt.Errorf("pyLiteral: trailing input at %d", p.pos)
}
return v, nil
}
func (p *pyParser) ws() {
for p.pos < len(p.s) {
c := p.s[p.pos]
if c == ' ' || c == '\t' || c == '\n' || c == '\r' {
p.pos++
continue
}
if c == '#' { // tokenizer strips comments before literal_eval
for p.pos < len(p.s) && p.s[p.pos] != '\n' {
p.pos++
}
continue
}
return
}
}
func (p *pyParser) value() (interface{}, error) {
if p.pos >= len(p.s) {
return nil, fmt.Errorf("pyLiteral: unexpected end")
}
switch c := p.s[p.pos]; {
case c == '{':
return p.dict()
case c == '[' || c == '(':
return p.seq()
case c == '"' || c == '\'':
s, err := p.str()
return s, err
case c == '-' || c == '+' || (c >= '0' && c <= '9') || c == '.':
return p.number()
default:
if strings.HasPrefix(p.s[p.pos:], "True") {
p.pos += 4
return true, nil
}
if strings.HasPrefix(p.s[p.pos:], "False") {
p.pos += 5
return false, nil
}
if strings.HasPrefix(p.s[p.pos:], "None") {
p.pos += 4
return nil, nil
}
// bare identifier: legal only as a dict KEY (handled in dict());
// as a value it is not a literal.
return nil, fmt.Errorf("pyLiteral: unexpected %q at %d", c, p.pos)
}
}
func (p *pyParser) dict() (interface{}, error) {
p.pos++ // '{'
out := map[string]interface{}{}
for {
p.ws()
if p.pos >= len(p.s) {
return nil, fmt.Errorf("pyLiteral: unterminated dict")
}
if p.s[p.pos] == '}' {
p.pos++
return out, nil
}
var key interface{}
var err error
if c := p.s[p.pos]; c == '"' || c == '\'' {
key, err = p.str()
} else {
key, err = p.atomKey()
}
if err != nil {
return nil, err
}
p.ws()
if p.pos >= len(p.s) || p.s[p.pos] != ':' {
return nil, fmt.Errorf("pyLiteral: expected ':' at %d", p.pos)
}
p.pos++
p.ws()
v, err := p.value()
if err != nil {
return nil, err
}
out[fmt.Sprint(key)] = v
p.ws()
if p.pos < len(p.s) && p.s[p.pos] == ',' {
p.pos++
continue
}
}
}
// atomKey — bare-identifier or numeric dict key (Python allows any hashable
// literal; PLUGIN manifests use strings).
func (p *pyParser) atomKey() (interface{}, error) {
start := p.pos
for p.pos < len(p.s) {
c := p.s[p.pos]
if c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' {
p.pos++
continue
}
break
}
if p.pos == start {
return nil, fmt.Errorf("pyLiteral: bad key at %d", start)
}
tok := p.s[start:p.pos]
if f, err := parseFloat(tok); err == nil {
return f, nil
}
return tok, nil
}
func (p *pyParser) seq() (interface{}, error) {
opener := p.s[p.pos]
closer := byte(']')
if opener == '(' {
closer = ')'
}
p.pos++
out := []interface{}{}
for {
p.ws()
if p.pos >= len(p.s) {
return nil, fmt.Errorf("pyLiteral: unterminated sequence")
}
if p.s[p.pos] == closer {
p.pos++
return out, nil
}
v, err := p.value()
if err != nil {
return nil, err
}
out = append(out, v)
p.ws()
if p.pos < len(p.s) && p.s[p.pos] == ',' {
p.pos++
continue
}
}
}
func (p *pyParser) str() (interface{}, error) {
quote := p.s[p.pos]
p.pos++
var b strings.Builder
for p.pos < len(p.s) {
c := p.s[p.pos]
if c == quote {
p.pos++
return b.String(), nil
}
if c == '\\' && p.pos+1 < len(p.s) {
p.pos++
switch e := p.s[p.pos]; e {
case 'n':
b.WriteByte('\n')
case 't':
b.WriteByte('\t')
case 'r':
b.WriteByte('\r')
case 'a':
b.WriteByte('\a')
case 'b':
b.WriteByte('\b')
case 'f':
b.WriteByte('\f')
case 'v':
b.WriteByte('\v')
case '0':
b.WriteByte(0)
case '\\', '\'', '"':
b.WriteByte(e)
default:
b.WriteByte(e)
}
p.pos++
continue
}
b.WriteByte(c)
p.pos++
}
return nil, fmt.Errorf("pyLiteral: unterminated string")
}
func (p *pyParser) number() (interface{}, error) {
start := p.pos
if p.s[p.pos] == '-' || p.s[p.pos] == '+' {
p.pos++
}
for p.pos < len(p.s) {
c := p.s[p.pos]
if (c >= '0' && c <= '9') || c == '.' ||
c == 'e' || c == 'E' ||
((c == '-' || c == '+') && (p.s[p.pos-1] == 'e' || p.s[p.pos-1] == 'E')) {
p.pos++
continue
}
break
}
return parseFloat(p.s[start:p.pos])
}
func parseFloat(tok string) (interface{}, error) {
var f float64
if _, err := fmt.Sscanf(tok, "%g", &f); err != nil {
return nil, fmt.Errorf("pyLiteral: bad number %q", tok)
}
return f, nil
}
+150
View File
@@ -0,0 +1,150 @@
package main
// parity.go — JSON op dispatch over stdin (the Go binary family contract):
// one op per invocation, thin shell over the ported kernel fns so the
// truth battery and the live-parity sweep exercise the same code paths.
//
// Ops:
// now_iso → {"result": NowIso()}
// extract_manifest {content} → {"result": ExtractManifestString}
// discover {dir, now} → {"result", "plugins"} (paths as-is)
// registry_load {content?} → LoadRegistry shape (writes content to
// the RUNE_MEMORY_DIR registry first)
// registry_roundtrip {} → save(load()) shape equality
// run_hook {registry,name,event,data,timeout_ms}
// fire {registry,event,data,timeout_ms,now}
// → RunHook / Fire over the request-built
// registry (durations wall-clock; the
// parity script normalizes them)
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
)
func emit(v interface{}) {
out, _ := json.Marshal(v)
fmt.Println(string(out))
}
func parityMain() {
var req map[string]interface{}
if err := json.NewDecoder(os.Stdin).Decode(&req); err != nil {
emit(map[string]interface{}{"error": "bad JSON input: " + err.Error()})
os.Exit(1)
}
op, _ := req["op"].(string)
switch op {
case "now_iso":
emit(map[string]interface{}{"result": NowIso()})
case "extract_manifest":
content, _ := req["content"].(string)
emit(map[string]interface{}{"result": ExtractManifestString(content)})
case "discover":
dir, _ := req["dir"].(string)
now, _ := req["now"].(string)
reg := emptyRegistry()
result, err := Discover(&reg, dir, now)
if err != nil {
emit(map[string]interface{}{"error": err.Error()})
return
}
plugins := map[string]interface{}{}
for k, v := range reg.Plugins {
plugins[k] = map[string]interface{}{"active": v.Active, "registered_at": v.RegisteredAt, "file": v.File}
}
emit(map[string]interface{}{"result": result, "plugins": plugins,
"capabilities": reg.Capabilities, "hooks": reg.Hooks})
case "registry_load":
if content, has := req["content"].(string); has {
os.MkdirAll(filepath.Dir(registryPath()), 0755)
os.WriteFile(registryPath(), []byte(content), 0644)
} else {
os.Remove(registryPath())
}
r := LoadRegistry()
emit(registryShape(r))
case "registry_roundtrip":
r1 := LoadRegistry()
SaveRegistry(r1)
r2 := LoadRegistry()
a, _ := json.Marshal(registryShape(r1))
b, _ := json.Marshal(registryShape(r2))
emit(map[string]interface{}{"stable": string(a) == string(b), "shape": registryShape(r2)})
case "run_hook":
reg := registryFromReq(req)
name, _ := req["name"].(string)
event, _ := req["event"].(string)
data, _ := req["data"].(string)
timeoutMs, _ := req["timeout_ms"].(float64)
if timeoutMs <= 0 {
timeoutMs = 30000
}
emit(RunHook(reg, name, event, data, time.Duration(timeoutMs)*time.Millisecond))
case "fire":
reg := registryFromReq(req)
event, _ := req["event"].(string)
now, _ := req["now"].(string)
timeoutMs, _ := req["timeout_ms"].(float64)
if timeoutMs <= 0 {
timeoutMs = 30000
}
result := Fire(reg, event, req["data"], time.Duration(timeoutMs)*time.Millisecond, now)
emit(map[string]interface{}{"result": result, "log": logProjection(reg.Log)})
default:
emit(map[string]interface{}{"error": "unknown op: " + op})
os.Exit(1)
}
}
// registryFromReq — decode the request's "registry" blob into a live
// Registry (plugins carry fixture hook script paths in "file").
func registryFromReq(req map[string]interface{}) *Registry {
raw, _ := json.Marshal(req["registry"])
var reg Registry
if json.Unmarshal(raw, &reg) != nil {
return &Registry{}
}
if reg.Plugins == nil {
reg.Plugins = map[string]PluginEntry{}
}
if reg.Capabilities == nil {
reg.Capabilities = map[string][]string{}
}
if reg.Hooks == nil {
reg.Hooks = map[string][]string{}
}
if reg.Log == nil {
reg.Log = []FireLog{}
}
return &reg
}
func registryShape(r Registry) map[string]interface{} {
return map[string]interface{}{
"plugins": r.Plugins, "capabilities": r.Capabilities,
"hooks": r.Hooks, "log": logProjection(r.Log),
}
}
// logProjection — FireLog entries as generic JSON maps (parity payloads).
func logProjection(log []FireLog) []map[string]interface{} {
out := []map[string]interface{}{}
for _, e := range log {
out = append(out, map[string]interface{}{
"event": e.Event, "timestamp": e.Timestamp,
"hooks_fired": e.HooksFired, "duration_ms": e.DurationMs,
})
}
return out
}
@@ -0,0 +1,737 @@
{
"frozen_now": "2026-10-13T11:05:00",
"cases": [
{
"fn": "now_iso",
"args": [],
"kwargs": {},
"expected": "2026-10-13T11:05:00+00:00",
"oracle": "microkernel"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {\n \"name\": \"cache\",\n \"version\": \"0.1.0\",\n \"description\": \"Cache system — event-driven invalidation.\",\n \"capabilities\": [\"cache\", \"invalidation\"],\n \"hooks\": {\n \"on_session_end\": \"handle_hook\",\n \"on_memory_add\": \"handle_hook\",\n },\n \"dependencies\": [],\n \"priority\": 1,\n \"auto_activate\": True,\n}\n"
],
"kwargs": {},
"expected": {
"result": {
"name": "cache",
"version": "0.1.0",
"description": "Cache system — event-driven invalidation.",
"capabilities": [
"cache",
"invalidation"
],
"hooks": {
"on_session_end": "handle_hook",
"on_memory_add": "handle_hook"
},
"dependencies": [],
"priority": 1,
"auto_activate": true
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"X = 1\n"
],
"kwargs": {},
"expected": {
"result": null
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {}\n"
],
"kwargs": {},
"expected": {
"result": {}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {}\nX = 1\n"
],
"kwargs": {},
"expected": {
"result": null
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {\n \"name\": \"x\",\n"
],
"kwargs": {},
"expected": {
"result": null
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {'name': 'café', 'n': 1.5, 'neg': -3, 'big': 1e3}\n"
],
"kwargs": {},
"expected": {
"result": {
"name": "café",
"n": 1.5,
"neg": -3,
"big": 1000.0
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {\n # comment inside\n \"name\": \"x\",\n}\n"
],
"kwargs": {},
"expected": {
"result": {
"name": "x"
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_extract",
"args": [
"PLUGIN = {\n \"name\": \"x\",\n \"hooks\": {\"a\": True, \"b\": False},\n \"nested\": {\"deep\": [1, 2, {\"k\": \"v\"}]},\n}\n"
],
"kwargs": {},
"expected": {
"result": {
"name": "x",
"hooks": {
"a": true,
"b": false
},
"nested": {
"deep": [
1,
2,
{
"k": "v"
}
]
}
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_discover",
"args": [
[
"_private.py",
"a_cache.py",
"b_noname.py",
"c_plain.py",
"d_falsy.py",
"microkernel.py",
"notes.txt"
],
{
"a_cache.py": "PLUGIN = {\n \"name\": \"cache\",\n \"version\": \"0.1.0\",\n \"description\": \"Cache system — event-driven invalidation.\",\n \"capabilities\": [\"cache\", \"invalidation\"],\n \"hooks\": {\n \"on_session_end\": \"handle_hook\",\n \"on_memory_add\": \"handle_hook\",\n },\n \"dependencies\": [],\n \"priority\": 1,\n \"auto_activate\": True,\n}\n",
"b_noname.py": "PLUGIN = {\n \"version\": \"0.1.0\",\n}\n",
"c_plain.py": "def run():\n pass\n",
"d_falsy.py": "PLUGIN = {\n \"name\": \"d\",\n \"capabilities\": [\"d\"],\n \"hooks\": {\"on_x\": False, \"on_y\": \"\", \"on_z\": 0},\n}\n",
"_private.py": "PLUGIN = {\n \"name\": \"cache\",\n \"version\": \"0.1.0\",\n \"description\": \"Cache system — event-driven invalidation.\",\n \"capabilities\": [\"cache\", \"invalidation\"],\n \"hooks\": {\n \"on_session_end\": \"handle_hook\",\n \"on_memory_add\": \"handle_hook\",\n },\n \"dependencies\": [],\n \"priority\": 1,\n \"auto_activate\": True,\n}\n",
"microkernel.py": "PLUGIN = {\n \"name\": \"cache\",\n \"version\": \"0.1.0\",\n \"description\": \"Cache system — event-driven invalidation.\",\n \"capabilities\": [\"cache\", \"invalidation\"],\n \"hooks\": {\n \"on_session_end\": \"handle_hook\",\n \"on_memory_add\": \"handle_hook\",\n },\n \"dependencies\": [],\n \"priority\": 1,\n \"auto_activate\": True,\n}\n",
"notes.txt": "not a plugin"
},
"2026-10-13T11:05:00"
],
"kwargs": {},
"expected": {
"result": {
"discovered": 2,
"errors": [
{
"file": "b_noname.py",
"error": "manifest must have a 'name'"
}
]
},
"registry": {
"plugins": {
"cache": {
"active": true,
"registered_at": "2026-10-13T11:05:00+00:00",
"file": "<dir>/a_cache.py"
},
"d": {
"active": true,
"registered_at": "2026-10-13T11:05:00+00:00",
"file": "<dir>/d_falsy.py"
}
},
"capabilities": {
"cache": [
"cache"
],
"invalidation": [
"cache"
],
"d": [
"d"
]
},
"hooks": {
"on_session_end": [
"cache"
],
"on_memory_add": [
"cache"
]
}
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_discover",
"args": [
[],
{},
"2026-10-13T11:05:00"
],
"kwargs": {},
"expected": {
"result": {
"discovered": 0,
"errors": []
},
"registry": {
"plugins": {},
"capabilities": {},
"hooks": {}
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_discover",
"args": [
[
"s1.py",
"s2.py"
],
{
"s1.py": "PLUGIN = {\n \"name\": \"s1\",\n \"capabilities\": [\"shared\"],\n \"priority\": 5,\n}\n",
"s2.py": "PLUGIN = {\n \"name\": \"s2\",\n \"capabilities\": [\"shared\"],\n \"priority\": 10,\n}\n"
},
"2026-10-13T11:05:00"
],
"kwargs": {},
"expected": {
"result": {
"discovered": 2,
"errors": []
},
"registry": {
"plugins": {
"s1": {
"active": true,
"registered_at": "2026-10-13T11:05:00+00:00",
"file": "<dir>/s1.py"
},
"s2": {
"active": true,
"registered_at": "2026-10-13T11:05:00+00:00",
"file": "<dir>/s2.py"
}
},
"capabilities": {
"shared": [
"s1",
"s2"
]
},
"hooks": {}
}
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_load",
"args": [
null
],
"kwargs": {},
"expected": {
"result": {
"plugins": {},
"capabilities": {},
"hooks": {}
},
"log": []
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_load",
"args": [
"{oops"
],
"kwargs": {},
"expected": {
"result": {
"plugins": {},
"capabilities": {},
"hooks": {}
},
"log": []
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_load",
"args": [
"{\n \"plugins\": {\n \"p\": {\n \"manifest\": {\n \"name\": \"p\",\n \"priority\": 1\n },\n \"registered_at\": \"2026-10-13T11:05:00+00:00\",\n \"active\": true,\n \"file\": \"/x/p.py\"\n }\n },\n \"capabilities\": {\n \"cap\": [\n \"p\"\n ]\n },\n \"hooks\": {\n \"evt\": [\n \"p\"\n ]\n },\n \"log\": [\n {\n \"event\": \"evt\",\n \"timestamp\": \"2026-10-13T11:05:00+00:00\",\n \"hooks_fired\": 1,\n \"duration_ms\": 12.5\n }\n ]\n}"
],
"kwargs": {},
"expected": {
"result": {
"plugins": {
"p": {
"active": true,
"registered_at": "2026-10-13T11:05:00+00:00",
"file": "/x/p.py"
}
},
"capabilities": {
"cap": [
"p"
]
},
"hooks": {
"evt": [
"p"
]
}
},
"log": [
{
"event": "evt",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": 12.5
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_save_load_default",
"args": [],
"kwargs": {},
"expected": {
"first": {
"plugins": {},
"capabilities": {},
"hooks": {},
"log": []
},
"again": {
"plugins": {},
"capabilities": {},
"hooks": {},
"log": []
},
"stable": true
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"import json, sys\ndata = sys.argv[sys.argv.index('--data') + 1]\nprint(json.dumps({'echo': json.loads(data)}))\n",
{
"name": "okp",
"hooks": {
"on_session_end": true
}
},
"on_session_end",
{
"k": "v",
"n": 2
},
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "okp",
"status": "ok",
"result": {
"echo": {
"k": "v",
"n": 2
}
},
"duration_ms": "<ms>"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"print('h\\u00e9llo-\\u2192ok ' * 120)\n",
{
"name": "rawp",
"hooks": {
"on_session_end": true
}
},
"on_session_end",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "rawp",
"status": "ok",
"result": "héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok héllo-→ok ",
"duration_ms": "<ms>"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"import sys\nsys.stderr.write('\\u00e9rr\\u00f4r-' * 100)\nsys.exit(3)\n",
{
"name": "boomp",
"hooks": {
"on_session_end": true
}
},
"on_session_end",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "boomp",
"status": "error",
"error": "érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-érrôr-ér",
"duration_ms": "<ms>"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"import time\ntime.sleep(5)\n",
{
"name": "slowp",
"hooks": {
"on_session_end": true
}
},
"on_session_end",
null,
1
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "slowp",
"status": "timeout"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"import json, sys\ndata = sys.argv[sys.argv.index('--data') + 1]\nprint(json.dumps({'echo': json.loads(data)}))\n",
{
"name": "offp",
"hooks": {
"on_session_end": true
},
"auto_activate": false
},
"on_session_end",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "offp",
"status": "skipped"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
null,
{
"name": "ghostp",
"hooks": {
"on_session_end": true
},
"_file": "/nonexistent/ghost.py"
},
"on_session_end",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "ghostp",
"status": "error",
"error": "file not found"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
null,
{
"name": "nofilep",
"hooks": {
"on_session_end": true
}
},
"on_session_end",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 1,
"results": [
{
"name": "nofilep",
"status": "error",
"error": "file not found"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 1,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire",
"args": [
"import json, sys\ndata = sys.argv[sys.argv.index('--data') + 1]\nprint(json.dumps({'echo': json.loads(data)}))\n",
{
"name": "lonely",
"capabilities": [
"x"
]
},
"no_such_event",
null,
30
],
"kwargs": {},
"expected": {
"result": {
"event": "no_such_event",
"hooks_fired": 0,
"results": []
},
"log": []
},
"oracle": "gen_microkernel_gap_truth_shims"
},
{
"fn": "gen_microkernel_gap_truth_shims._mk_fire_two",
"args": [
[
"import json, sys\ndata = sys.argv[sys.argv.index('--data') + 1]\nprint(json.dumps({'echo': json.loads(data)}))\n",
"import json, sys\ndata = sys.argv[sys.argv.index('--data') + 1]\nprint(json.dumps({'echo': json.loads(data)}))\n"
],
[
{
"name": "zz",
"hooks": {
"on_session_end": true
}
},
{
"name": "aa",
"hooks": {
"on_session_end": true
}
}
],
"on_session_end",
{
"k": 1
},
30
],
"kwargs": {},
"expected": {
"result": {
"event": "on_session_end",
"hooks_fired": 2,
"results": [
{
"name": "aa",
"status": "ok",
"result": {
"echo": {
"k": 1
}
},
"duration_ms": "<ms>"
},
{
"name": "zz",
"status": "ok",
"result": {
"echo": {
"k": 1
}
},
"duration_ms": "<ms>"
}
],
"total_duration_ms": "<ms>"
},
"log": [
{
"event": "on_session_end",
"timestamp": "2026-10-13T11:05:00+00:00",
"hooks_fired": 2,
"duration_ms": "<ms>"
}
]
},
"oracle": "gen_microkernel_gap_truth_shims"
}
]
}
@@ -0,0 +1,357 @@
package main
// truth_microkernel_gap_test.go — gap-closing parity battery (dichotomy
// wave, worktree rune-wave-cq). Replays truth_microkernel_gap.json —
// generated against the LIVE Python oracle via scripts/freeze_truth.py —
// through the ported kernel fns: NowIso, ExtractManifest, Discover,
// RunHook (via Fire), LoadRegistry/SaveRegistry.
//
// Rig laws mirrored from the generator: wall-clock durations normalize
// to "<ms>"; fire results compare name-sorted; fixture dirs rewrite to
// <dir>; the frozen clock pins nowFunc.
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"testing"
"time"
)
const gapFrozenNow = "2026-10-13T11:05:00"
const gapFrozenNowAware = "2026-10-13T11:05:00+00:00"
func TestMicrokernelGapParity(t *testing.T) {
b, err := os.ReadFile("truth_microkernel_gap.json")
if err != nil {
t.Fatalf("truth_microkernel_gap.json missing: %v", err)
}
var doc struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Fn string `json:"fn"`
Args []interface{} `json:"args"`
} `json:"cases"`
}
if err := json.Unmarshal(b, &doc); err != nil {
t.Fatalf("bad truth json: %v", err)
}
// full expected payloads (shims return richer shapes than result)
var rawCases []map[string]interface{}
if err := json.Unmarshal(b, &struct {
Cases *[]map[string]interface{} `json:"cases"`
}{Cases: &rawCases}); err != nil {
t.Fatalf("bad truth json (raw): %v", err)
}
for i, c := range doc.Cases {
name := fmt.Sprintf("case%02d_%s", i, shortFn(c.Fn))
t.Run(name, func(t *testing.T) {
got := replayGapCase(t, c.Fn, c.Args)
want := rawCases[i]["expected"]
if !jsonEqualGap(got, want) {
t.Errorf("%s divergence:\n got %s\nwant %s", c.Fn, mustJSON(got), mustJSON(want))
}
})
}
}
func shortFn(fn string) string {
if i := len(fn) - 1; i >= 0 {
for j := len(fn) - 1; j >= 0; j-- {
if fn[j] == '.' {
return fn[j+1:]
}
}
}
return fn
}
// replayGapCase — one frozen case through the Go kernel. Mirrors the
// generator shims byte-for-byte (durations → "<ms>", paths → <dir>).
func replayGapCase(t *testing.T, fn string, args []interface{}) interface{} {
t.Helper()
switch fn {
case "now_iso":
restore := pinNow(t, gapFrozenNow)
defer restore()
return NowIso()
case "gen_microkernel_gap_truth_shims._mk_extract":
content := argStr(args[0])
f := filepath.Join(t.TempDir(), "probe.py")
os.WriteFile(f, []byte(content), 0644)
return map[string]interface{}{"result": ExtractManifest(f)}
case "gen_microkernel_gap_truth_shims._mk_discover":
contents := argStrMap(args[1])
dir := t.TempDir()
for fname, src := range contents {
os.WriteFile(filepath.Join(dir, fname), []byte(src), 0644)
}
reg := emptyRegistry()
// args[2] carries the naive frozen stamp; the ORACLE registers with
// now_iso() (aware frozen) — replay with the aware form.
result, err := Discover(&reg, dir, gapFrozenNowAware)
if err != nil {
t.Fatalf("discover: %v", err)
}
return map[string]interface{}{
"result": result,
"registry": discoverProjection(&reg, dir),
}
case "gen_microkernel_gap_truth_shims._mk_load":
var content *string
if args[0] != nil {
s := argStr(args[0])
content = &s
}
dir := t.TempDir()
t.Setenv("RUNE_MEMORY_DIR", dir)
regPath := filepath.Join(dir, "microkernel_registry.json")
if content != nil {
os.WriteFile(regPath, []byte(*content), 0644)
} else if _, err := os.Stat(regPath); err == nil {
os.Remove(regPath)
}
loaded := LoadRegistry()
return map[string]interface{}{
"result": loadProjection(&loaded),
"log": logProjection(loaded.Log),
}
case "gen_microkernel_gap_truth_shims._mk_save_load_default":
dir := t.TempDir()
t.Setenv("RUNE_MEMORY_DIR", dir)
first := LoadRegistry()
SaveRegistry(first)
again := LoadRegistry()
return map[string]interface{}{
"first": fullProjection(&first),
"again": fullProjection(&again),
"stable": jsonEqualGap(fullProjection(&first), fullProjection(&again)),
}
case "gen_microkernel_gap_truth_shims._mk_fire":
return replayFire(t, args[0], args[1], args[2], args[3], args[4])
case "gen_microkernel_gap_truth_shims._mk_fire_two":
scripts := argAnyList(args[0])
manifests := argMapList(args[1])
event := argStr(args[2])
data := args[3]
timeout := time.Duration(argFloat(args[4])) * time.Second
dir := t.TempDir()
reg := emptyRegistry()
for i, m := range manifests {
manifest := mapCopy(m)
if scripts[i] != nil {
fpath := filepath.Join(dir, argStr(manifest["name"])+".py")
os.WriteFile(fpath, []byte(argStr(scripts[i])), 0644)
manifest["_file"] = fpath
}
if _, err := Register(&reg, manifest, gapFrozenNowAware); err != nil {
t.Fatalf("register: %v", err)
}
}
return fireResult(&reg, event, data, timeout)
default:
t.Fatalf("unhandled fn %q", fn)
return nil
}
}
func replayFire(t *testing.T, scriptArg, manifestArg, eventArg, dataArg, timeoutArg interface{}) interface{} {
t.Helper()
manifest := mapCopy(manifestArg.(map[string]interface{}))
if scriptArg != nil {
fpath := filepath.Join(t.TempDir(), "plugin.py")
os.WriteFile(fpath, []byte(argStr(scriptArg)), 0644)
manifest["_file"] = fpath
}
dir := t.TempDir()
t.Setenv("RUNE_MEMORY_DIR", dir)
reg := emptyRegistry()
if _, err := Register(&reg, manifest, gapFrozenNowAware); err != nil {
t.Fatalf("register: %v", err)
}
timeout := time.Duration(argFloat(timeoutArg)) * time.Second
return fireResult(&reg, argStr(eventArg), dataArg, timeout)
}
// fireResult — Fire + the rig's normalization (durations → "<ms>").
func fireResult(reg *Registry, event string, data interface{}, timeout time.Duration) interface{} {
res := Fire(reg, event, data, timeout, gapFrozenNowAware)
normalized := normalizeDurations(res)
return map[string]interface{}{
"result": normalized,
"log": normalizeLogDurations(logProjection(reg.Log)),
}
}
func normalizeDurations(res map[string]interface{}) map[string]interface{} {
out := map[string]interface{}{}
for k, v := range res {
out[k] = v
}
if _, has := out["total_duration_ms"]; has {
out["total_duration_ms"] = "<ms>"
}
if results, ok := out["results"].([]map[string]interface{}); ok {
cp := make([]map[string]interface{}, 0, len(results))
for _, r := range results {
rc := map[string]interface{}{}
for k, v := range r {
rc[k] = v
}
if _, has := rc["duration_ms"]; has {
rc["duration_ms"] = "<ms>"
}
cp = append(cp, rc)
}
sort.SliceStable(cp, func(i, j int) bool {
return fmt.Sprint(cp[i]["name"]) < fmt.Sprint(cp[j]["name"])
})
out["results"] = cp
}
return out
}
func normalizeLogDurations(log []map[string]interface{}) []map[string]interface{} {
out := []map[string]interface{}{}
for _, e := range log {
cp := map[string]interface{}{}
for k, v := range e {
cp[k] = v
}
cp["duration_ms"] = "<ms>"
out = append(out, cp)
}
return out
}
func discoverProjection(reg *Registry, dir string) map[string]interface{} {
return map[string]interface{}{
"plugins": pluginProjection(reg, true),
"capabilities": strSliceMap(reg.Capabilities),
"hooks": strSliceMap(reg.Hooks),
}
}
func loadProjection(reg *Registry) map[string]interface{} {
return map[string]interface{}{
"plugins": pluginProjection(reg, false),
"capabilities": strSliceMap(reg.Capabilities),
"hooks": strSliceMap(reg.Hooks),
}
}
// fullProjection — includes the log (the _save_load_default shape).
func fullProjection(reg *Registry) map[string]interface{} {
proj := loadProjection(reg)
proj["log"] = logProjection(reg.Log)
return proj
}
func pluginProjection(reg *Registry, rewriteDir bool) map[string]interface{} {
plugins := map[string]interface{}{}
for k, v := range reg.Plugins {
file := v.File
if rewriteDir && file != "" {
file = "<dir>/" + filepath.Base(file)
}
plugins[k] = map[string]interface{}{
"active": v.Active, "registered_at": v.RegisteredAt, "file": file,
}
}
return plugins
}
func strSliceMap(m map[string][]string) map[string]interface{} {
out := map[string]interface{}{}
for k, v := range m {
out[k] = v
}
return out
}
func pinNow(t *testing.T, iso string) func() {
t.Helper()
base, err := time.Parse("2006-01-02T15:04:05", iso)
if err != nil {
t.Fatalf("pinNow: %v", err)
}
old := nowFunc
nowFunc = func() time.Time { return base.UTC() }
return func() { nowFunc = old }
}
// jsonEqualGap — value-equal via marshal both sides through the SAME
// encoder (integral floats parse to float64 on both sides).
func jsonEqualGap(a, b interface{}) bool {
return mustJSON(a) == mustJSON(b)
}
func mustJSON(v interface{}) string {
b, err := json.Marshal(v)
if err != nil {
return fmt.Sprintf("<marshal-error %v>", err)
}
return string(b)
}
func argStr(v interface{}) string {
s, _ := v.(string)
return s
}
func argFloat(v interface{}) float64 {
f, _ := v.(float64)
return f
}
func argStrList(v interface{}) []string {
raw, _ := v.([]interface{})
out := make([]string, 0, len(raw))
for _, x := range raw {
out = append(out, argStr(x))
}
return out
}
func argStrMap(v interface{}) map[string]string {
raw, _ := v.(map[string]interface{})
out := map[string]string{}
for k, x := range raw {
out[k] = argStr(x)
}
return out
}
func argAnyList(v interface{}) []interface{} {
raw, _ := v.([]interface{})
return raw
}
func argMapList(v interface{}) []map[string]interface{} {
raw, _ := v.([]interface{})
out := make([]map[string]interface{}, 0, len(raw))
for _, x := range raw {
if m, ok := x.(map[string]interface{}); ok {
out = append(out, m)
}
}
return out
}
func mapCopy(m map[string]interface{}) map[string]interface{} {
cp := map[string]interface{}{}
for k, v := range m {
cp[k] = v
}
return cp
}
+6 -6
View File
@@ -25,7 +25,7 @@ func TestMicrokernelParity(t *testing.T) {
}
json.Unmarshal(b, &doc)
reg := loadRegistry()
reg := LoadRegistry()
regp := &reg
for _, c := range doc.Cases {
switch c.Name {
@@ -106,14 +106,14 @@ func TestUnregisterCleansEmptyKeys(t *testing.T) {
"p1": {Manifest: PluginManifest{Name: "p1", Capabilities: []string{"echo"}},
RegisteredAt: "T", Active: true},
}, Capabilities: map[string][]string{"echo": {"p1"}}, Hooks: map[string][]string{}}
saveRegistry(reg)
SaveRegistry(reg)
// simulate the CLI path via main's command dispatch is heavyweight —
// call the same filter logic through a fresh register/unregister cycle
// using the public store API:
reg2 := loadRegistry()
reg2 := LoadRegistry()
_ = reg2
// direct: verify save/load round-trip then the empty-key invariant
loaded := loadRegistry()
loaded := LoadRegistry()
if _, ok := loaded.Capabilities["echo"]; !ok {
t.Fatal("setup: echo capability missing")
}
@@ -129,8 +129,8 @@ func TestUnregisterCleansEmptyKeys(t *testing.T) {
} else {
loaded.Capabilities["echo"] = filtered
}
saveRegistry(loaded)
re := loadRegistry()
SaveRegistry(loaded)
re := LoadRegistry()
if _, exists := re.Capabilities["echo"]; exists {
t.Error("emptied capability key must be deleted (status counts keys)")
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+803 -12
View File
@@ -1,18 +1,212 @@
// Package main — model-profiles: the GO port of src/rune/model_profiles.py's
// deterministic detection cores (Oracle-Battery Parity Pattern, #2479 GO
// batch 7): detect_family / detect_parameters / detect_quantization /
// success_rate. The profile store + Ollama scans stay Python (reactive).
// Package main — model-profiles: the GO port of src/rune/model_profiles.py
// (Oracle-Battery Parity Pattern, #2479 GO gap-close batch): the full
// deterministic profile surface — ModelProfile (to_dict/from_dict lens,
// success_rate), the FAMILY_KNOWLEDGE table, detect_family /
// detect_parameters / detect_quantization, get_profile_path filesystem
// sanitization, the hermetic profile store (load_profile / save_profile
// / get_or_create_profile / record_interaction / get_prompt_context),
// build_profile_from_ollama assembly, and the scan_all_models Ollama
// sweep. Frozen truth (frozen_mp_truth.json, 36 cases) replays VERBATIM
// through the store seam in frozen_battery_test.go; the byte-parity
// save_profile rows pin the Python-shaped JSON writer (pyDumps/asdict
// field order, indent-2 separators, ensure_ascii, integral-float rule).
package main
import (
"encoding/json"
"fmt"
"io"
"math"
"net/http"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
)
// profilesDir mirrors PROFILES_DIR (expanduser("~/.rune/model_profiles")).
// setProfilesDir repoints the seam (hermetic stores in tests/replay).
var profilesDir = func() string {
home, err := os.UserHomeDir()
if err != nil || home == "" {
home = os.Getenv("HOME")
}
return filepath.Join(home, ".rune", "model_profiles")
}()
func setProfilesDir(d string) { profilesDir = d }
// ollamaURL mirrors the module-global OLLAMA_URL (env default, per-call
// repointable — the freeze rig's canned-server seam).
var ollamaURL = func() string {
if u := os.Getenv("OLLAMA_URL"); u != "" {
return u
}
return "http://localhost:11434"
}()
// nowUTC mirrors datetime.now(timezone.utc) — injected for the frozen
// battery (the no-clock law: the port never reads the wall clock
// directly in replayable paths).
var nowUTC = func() time.Time { return time.Now().UTC() }
// ModelProfile — the port of the ModelProfile dataclass. Field order
// mirrors asdict() emission (the byte-parity law).
type ModelProfile struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
Family string `json:"family"`
Parameters string `json:"parameters"`
Quantization string `json:"quantization"`
SizeGB float64 `json:"size_gb"`
Strengths []string `json:"strengths"`
Weaknesses []string `json:"weaknesses"`
PromptingTips []string `json:"prompting_tips"`
SafetyTier int `json:"safety_tier"`
KnownRefusalTopics []string `json:"known_refusal_topics"`
ThinkingFormat string `json:"thinking_format"`
ResponseStyle string `json:"response_style"`
ContextWindow int `json:"context_window"`
OptimalTemperature float64 `json:"optimal_temperature"`
Interactions int `json:"interactions"`
Successes int `json:"successes"`
Failures int `json:"failures"`
LastUsed string `json:"last_used"`
Created string `json:"created"`
}
// MarshalJSON renders with Python float semantics (the integral-float
// law): integral floats carry the trailing .0 the oracle's json.dump
// emits, so serve-mode responses compare byte-equal to oracle asdict
// JSON instead of diverging 7 vs 7.0.
func (p ModelProfile) MarshalJSON() ([]byte, error) {
type raw ModelProfile
b, err := json.Marshal(raw(p))
if err != nil {
return nil, err
}
var m map[string]json.RawMessage
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
m["size_gb"] = json.RawMessage(pyFloat(p.SizeGB))
m["optimal_temperature"] = json.RawMessage(pyFloat(p.OptimalTemperature))
return json.Marshal(m)
}
func defaultModelProfile(name string) ModelProfile {
return ModelProfile{
Name: name, Strengths: []string{}, Weaknesses: []string{},
PromptingTips: []string{}, KnownRefusalTopics: []string{},
ContextWindow: 4096, OptimalTemperature: 0.7,
}
}
// successRate mirrors the success_rate property.
func successRate(p ModelProfile) float64 {
if p.Interactions == 0 {
return 0.0
}
return float64(p.Successes) / float64(p.Interactions)
}
// familyKnowledge mirrors FAMILY_KNOWLEDGE (insertion order preserved in
// the table; detection sorts longest-first).
type familyEntry struct {
thinking string
strengths []string
weaknesses []string
tips []string
}
var familyKnowledge = map[string]familyEntry{
"qwen": {
thinking: "<think>",
strengths: []string{"reasoning", "coding", "instruction-following", "multilingual"},
weaknesses: []string{"verbose thinking", "safety reasoning in thinking blocks"},
tips: []string{
"Be direct and specific — Qwen responds well to clear instructions",
"Use structured prompts with clear sections",
"For coding tasks, specify the language and expected output format",
"Qwen models tend to over-explain — ask for concise responses explicitly",
},
},
"qwen3": {
thinking: "<think>",
strengths: []string{"reasoning", "coding", "instruction-following", "tool-use"},
weaknesses: []string{"verbose thinking blocks", "safety reasoning even on uncensored variants"},
tips: []string{
"Qwen3 has native tool support — use JSON schema for structured output",
"Thinking blocks are verbose — strip them before display",
"For coding, specify the exact format expected",
"Use /no_think to disable thinking blocks for simple tasks",
},
},
"llama": {
thinking: "",
strengths: []string{"general knowledge", "creative writing", "conversation"},
weaknesses: []string{"instruction-following weaker than Qwen", "can be verbose"},
tips: []string{
"Use clear, direct instructions",
"Llama models respond well to role-playing prompts",
"For coding, be very specific about requirements",
},
},
"mistral": {
thinking: "",
strengths: []string{"coding", "reasoning", "concise responses"},
weaknesses: []string{"can be terse", "less creative than Llama"},
tips: []string{
"Mistral is naturally concise — don't ask for brevity, it already is",
"Good at structured output and JSON",
"Use system prompts for persona control",
},
},
"gemma": {
thinking: "",
strengths: []string{"instruction-following", "safety", "multilingual"},
weaknesses: []string{"conservative responses", "strong safety training"},
tips: []string{
"Gemma has strong safety training — may need override for edge cases",
"Good at following detailed instructions",
"Use structured prompts for best results",
},
},
"phi": {
thinking: "",
strengths: []string{"coding", "reasoning", "small but capable"},
weaknesses: []string{"limited knowledge", "can hallucinate"},
tips: []string{
"Phi models are small but surprisingly capable at coding",
"Keep prompts short — limited context window",
"Good for quick coding tasks, not for deep knowledge",
},
},
"deepseek": {
thinking: "<think>",
strengths: []string{"coding", "math", "reasoning", "uncensored variants available"},
weaknesses: []string{"verbose thinking", "can be slow on large contexts"},
tips: []string{
"DeepSeek excels at coding and math tasks",
"Use structured prompts with clear problem statements",
"Thinking blocks are long — strip them for display",
},
},
"davidau": {
thinking: "<think>",
strengths: []string{"uncensored", "creative", "no refusals", "detailed responses"},
weaknesses: []string{"verbose", "can be slow", "quality varies by model base"},
tips: []string{
"DavidAU models are uncensored — no safety filtering",
"Good for research and creative tasks that other models refuse",
"Can be verbose — ask for concise responses if needed",
"Quality depends on the base model — Qwen-based ones are best",
},
},
}
// familyOrder mirrors FAMILY_KNOWLEDGE sorted by len desc (longest-first match).
var familyOrder = []string{"deepseek", "mistral", "davidau", "qwen3", "llama", "gemma", "qwen", "phi"}
@@ -59,18 +253,615 @@ func detectQuantization(name string) string {
return "unknown"
}
func successRate(interactions, successes int) float64 {
if interactions == 0 {
return 0.0
// getProfilePath mirrors the oracle's filesystem sanitization.
func getProfilePath(modelName string) string {
safe := strings.ReplaceAll(modelName, "/", "_")
safe = strings.ReplaceAll(safe, ":", "_")
safe = strings.ReplaceAll(safe, "?", "_")
return filepath.Join(profilesDir, safe+".json")
}
// pyFloat mirrors Python's json float rendering (the integral-float
// rule): integral floats render with a trailing .0; non-integral ones
// use repr-shortest. NaN/Inf never occur in profile state.
func pyFloat(f float64) string {
if !math.IsNaN(f) && !math.IsInf(f, 0) && f == float64(int64(f)) {
return fmt.Sprintf("%.1f", f)
}
return float64(successes) / float64(interactions)
return fmt.Sprintf("%v", f)
}
// pyString mirrors json.dumps(s) with ensure_ascii (non-ASCII → \uXXXX,
// surrogate-pair encoding for astral codepoints) and Go-identical
// escaping for control chars, quotes, and backslash.
func pyString(s string) string {
var b strings.Builder
b.WriteByte('"')
for _, r := range s {
switch r {
case '"':
b.WriteString("\\\"")
case '\\':
b.WriteString("\\\\")
case '\n':
b.WriteString("\\n")
case '\r':
b.WriteString("\\r")
case '\t':
b.WriteString("\\t")
case '\b':
b.WriteString("\\b")
case '\f':
b.WriteString("\\f")
default:
if r < 0x20 {
fmt.Fprintf(&b, "\\u%04x", r)
} else if r < 0x7f {
b.WriteRune(r)
} else if r > 0xffff {
r -= 0x10000
fmt.Fprintf(&b, "\\u%04x\\u%04x", 0xd800+(r>>10), 0xdc00+(r&0x3ff))
} else {
fmt.Fprintf(&b, "\\u%04x", r)
}
}
}
b.WriteByte('"')
return b.String()
}
func pyStrList(v []string) string {
if v == nil {
v = []string{}
}
parts := make([]string, len(v))
for i, s := range v {
parts[i] = pyString(s)
}
return "[" + strings.Join(parts, ", ") + "]"
}
// pyDumpsProfile mirrors json.dump(profile.to_dict(), indent=2):
// asdict field order, ": " separators, 2-space indents, trailing newline.
func pyDumpsProfile(p ModelProfile) string {
var b strings.Builder
b.WriteString("{\n")
row := func(name, val string, last bool) {
b.WriteString(" " + pyString(name) + ": " + val)
if !last {
b.WriteString(",")
}
b.WriteString("\n")
}
row("name", pyString(p.Name), false)
row("display_name", pyString(p.DisplayName), false)
row("family", pyString(p.Family), false)
row("parameters", pyString(p.Parameters), false)
row("quantization", pyString(p.Quantization), false)
row("size_gb", pyFloat(p.SizeGB), false)
b.WriteString(" " + pyString("strengths") + ": ")
writeIndentedList(&b, p.Strengths)
b.WriteString(",\n")
b.WriteString(" " + pyString("weaknesses") + ": ")
writeIndentedList(&b, p.Weaknesses)
b.WriteString(",\n")
b.WriteString(" " + pyString("prompting_tips") + ": ")
writeIndentedList(&b, p.PromptingTips)
b.WriteString(",\n")
row("safety_tier", fmt.Sprintf("%d", p.SafetyTier), false)
b.WriteString(" " + pyString("known_refusal_topics") + ": ")
writeIndentedList(&b, p.KnownRefusalTopics)
b.WriteString(",\n")
row("thinking_format", pyString(p.ThinkingFormat), false)
row("response_style", pyString(p.ResponseStyle), false)
row("context_window", fmt.Sprintf("%d", p.ContextWindow), false)
row("optimal_temperature", pyFloat(p.OptimalTemperature), false)
row("interactions", fmt.Sprintf("%d", p.Interactions), false)
row("successes", fmt.Sprintf("%d", p.Successes), false)
row("failures", fmt.Sprintf("%d", p.Failures), false)
row("last_used", pyString(p.LastUsed), false)
row("created", pyString(p.Created), true)
b.WriteString("}")
return b.String()
}
// writeIndentedList mirrors json.dump(list, indent=2) nested at depth 1:
// [] stays inline; non-empty lists break one element per line.
func writeIndentedList(b *strings.Builder, v []string) {
if len(v) == 0 {
b.WriteString("[]")
return
}
b.WriteString("[\n")
for i, s := range v {
b.WriteString(" " + pyString(s))
if i < len(v)-1 {
b.WriteString(",")
}
b.WriteString("\n")
}
b.WriteString(" ]")
}
// loadProfile mirrors the oracle: missing/corrupt/ill-typed files →
// (nil, false) through the suppressed-exception floor. Unknown keys are
// filtered; absent keys take dataclass defaults.
func loadProfile(modelName string) (*ModelProfile, bool) {
raw, err := os.ReadFile(getProfilePath(modelName))
if err != nil {
return nil, false
}
var doc map[string]json.RawMessage
if err := json.Unmarshal(raw, &doc); err != nil {
return nil, false
}
p := defaultModelProfile("")
seen := map[string]bool{}
setStr := func(key string, dst *string) bool {
raw, ok := doc[key]
if !ok {
return true
}
seen[key] = true
if err := json.Unmarshal(raw, dst); err != nil {
return false
}
return true
}
setFloat := func(key string, dst *float64) bool {
raw, ok := doc[key]
if !ok {
return true
}
seen[key] = true
var n json.Number
if err := json.Unmarshal(raw, &n); err != nil {
return false
}
f, err := n.Float64()
if err != nil {
return false
}
*dst = f
return true
}
setInt := func(key string, dst *int) bool {
raw, ok := doc[key]
if !ok {
return true
}
seen[key] = true
var n json.Number
if err := json.Unmarshal(raw, &n); err != nil {
return false
}
i, err := n.Int64()
if err != nil {
return false
}
*dst = int(i)
return true
}
setList := func(key string, dst *[]string) bool {
raw, ok := doc[key]
if !ok {
return true
}
seen[key] = true
var l []string
if err := json.Unmarshal(raw, &l); err != nil {
return false
}
if l == nil {
l = []string{}
}
*dst = l
return true
}
if raw, ok := doc["name"]; !ok {
return nil, false
} else {
seen["name"] = true
if err := json.Unmarshal(raw, &p.Name); err != nil {
return nil, false
}
}
ok := setStr("display_name", &p.DisplayName) &&
setStr("family", &p.Family) &&
setStr("parameters", &p.Parameters) &&
setStr("quantization", &p.Quantization) &&
setFloat("size_gb", &p.SizeGB) &&
setList("strengths", &p.Strengths) &&
setList("weaknesses", &p.Weaknesses) &&
setList("prompting_tips", &p.PromptingTips) &&
setInt("safety_tier", &p.SafetyTier) &&
setList("known_refusal_topics", &p.KnownRefusalTopics) &&
setStr("thinking_format", &p.ThinkingFormat) &&
setStr("response_style", &p.ResponseStyle) &&
setInt("context_window", &p.ContextWindow) &&
setFloat("optimal_temperature", &p.OptimalTemperature) &&
setInt("interactions", &p.Interactions) &&
setInt("successes", &p.Successes) &&
setInt("failures", &p.Failures) &&
setStr("last_used", &p.LastUsed) &&
setStr("created", &p.Created)
if !ok {
return nil, false
}
for key := range doc {
if !seen[key] {
_ = key // unknown keys filtered (from_dict's known-field law)
}
}
return &p, true
}
// saveProfile mirrors the oracle: makedirs + Python-shaped JSON write,
// best-effort (errors suppressed).
func saveProfile(p ModelProfile) {
_ = os.MkdirAll(profilesDir, 0o755)
_ = os.WriteFile(getProfilePath(p.Name), []byte(pyDumpsProfile(p)), 0o644)
}
// buildProfileFromOllama mirrors the oracle's assembly: family
// detection, parameter/quantization extraction, knowledge merge,
// uncensored safety tier, frozen-clock stamps.
func buildProfileFromOllama(modelName string, modelInfo map[string]any) ModelProfile {
family := detectFamily(modelName)
fam, known := familyKnowledge[family]
p := defaultModelProfile(modelName)
p.DisplayName = modelName
p.Family = family
p.Parameters = detectParameters(modelName)
p.Quantization = detectQuantization(modelName)
if modelInfo != nil {
if d, ok := modelInfo["display_name"].(string); ok {
p.DisplayName = d
}
if s, ok := modelInfo["size_gb"].(float64); ok {
p.SizeGB = s
}
}
if known {
p.Strengths = append([]string(nil), fam.strengths...)
p.Weaknesses = append([]string(nil), fam.weaknesses...)
p.PromptingTips = append([]string(nil), fam.tips...)
p.ThinkingFormat = fam.thinking
}
lower := strings.ToLower(modelName)
if strings.Contains(lower, "uncensored") || strings.Contains(lower, "davidau") {
p.SafetyTier = 3
}
p.ContextWindow = 8192
p.OptimalTemperature = 0.7
stamp := nowUTC().Format("2006-01-02T15:04:05.999999+00:00")
p.Created = stamp
p.LastUsed = stamp
return p
}
// scanAllModels mirrors the oracle's Ollama sweep: best-effort degrade
// (any error → empty list), skip nameless entries, update-or-build with
// learned-data preservation, banker's rounding on the GB conversion.
func scanAllModels() []ModelProfile {
resp, err := http.Get(ollamaURL + "/api/tags")
if err != nil {
return []ModelProfile{}
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return []ModelProfile{}
}
var data struct {
Models []struct {
Name string `json:"name"`
Size float64 `json:"size"`
} `json:"models"`
}
if err := json.Unmarshal(body, &data); err != nil {
return []ModelProfile{}
}
var profiles []ModelProfile
for _, m := range data.Models {
if m.Name == "" {
continue
}
gb := roundHalfEven(m.Size/(1024*1024*1024), 1)
if existing, ok := loadProfile(m.Name); ok {
existing.SizeGB = gb
saveProfile(*existing)
profiles = append(profiles, *existing)
} else {
p := buildProfileFromOllama(m.Name, map[string]any{
"display_name": m.Name,
"size_gb": gb,
})
saveProfile(p)
profiles = append(profiles, p)
}
}
if profiles == nil {
profiles = []ModelProfile{}
}
return profiles
}
// roundHalfEven mirrors Python's round(x, 1) (banker's rounding).
func roundHalfEven(x float64, places int) float64 {
mult := 1.0
for i := 0; i < places; i++ {
mult *= 10
}
return float64(roundHalfEvenInt(x*mult)) / mult
}
func roundHalfEvenInt(x float64) int64 {
lo := int64(x)
if x-float64(lo) == 0.5 {
if lo%2 == 0 {
return lo
}
return lo + 1
}
if x-float64(lo) == -0.5 {
if lo%2 == 0 {
return lo
}
return lo - 1
}
if x >= 0 {
return int64(x + 0.5)
}
return int64(x - 0.5)
}
// getOrCreateProfile mirrors the oracle: load, else build-and-save.
func getOrCreateProfile(modelName string) ModelProfile {
if p, ok := loadProfile(modelName); ok {
return *p
}
p := buildProfileFromOllama(modelName, nil)
saveProfile(p)
return p
}
// recordInteraction mirrors the oracle's learning accumulator (returns
// nothing — the saved profile state is the contract).
func recordInteraction(modelName string, success bool, topic string) {
p := getOrCreateProfile(modelName)
p.Interactions++
if success {
p.Successes++
} else {
p.Failures++
if topic != "" {
seen := false
for _, t := range p.KnownRefusalTopics {
if t == topic {
seen = true
break
}
}
if !seen {
p.KnownRefusalTopics = append(p.KnownRefusalTopics, topic)
}
}
}
p.LastUsed = nowUTC().Format("2006-01-02T15:04:05.999999+00:00")
saveProfile(p)
}
// getPromptContext mirrors the oracle's operator string assembly.
func getPromptContext(modelName string) string {
p := getOrCreateProfile(modelName)
var parts []string
if len(p.Strengths) > 0 {
n := 3
if len(p.Strengths) < n {
n = len(p.Strengths)
}
parts = append(parts, "Strengths: "+strings.Join(p.Strengths[:n], ", "))
}
if len(p.PromptingTips) > 0 {
parts = append(parts, "Tips: "+p.PromptingTips[0])
}
if len(p.KnownRefusalTopics) > 0 {
n := 3
if len(p.KnownRefusalTopics) < n {
n = len(p.KnownRefusalTopics)
}
parts = append(parts, "Known refusals: "+strings.Join(p.KnownRefusalTopics[:n], ", "))
}
if p.SafetyTier > 0 {
parts = append(parts, fmt.Sprintf("Safety tier: %d", p.SafetyTier))
}
return strings.Join(parts, " | ")
}
// serveStdin — JSON CLI: one op per invocation (the Go binary family
// contract). Op dispatch is a thin shell over the ported functions so
// the truth battery and the live-parity sweep exercise the SAME code
// paths operators call. Stateful ops take an explicit "store" dir
// (hermetic per-invocation) and an optional "now" instant (the
// no-clock law — the sweep pins it, defaulting to wall clock).
func serveStdin() {
var req map[string]any
if err := json.NewDecoder(os.Stdin).Decode(&req); err != nil {
emit(map[string]any{"error": "bad JSON input: " + err.Error()})
os.Exit(1)
}
op, _ := req["op"].(string)
if dir, _ := req["store"].(string); dir != "" {
setProfilesDir(dir)
}
if now, _ := req["now"].(string); now != "" {
if t, err := time.Parse("2006-01-02T15:04:05.999999+00:00", now); err == nil {
nowUTC = func() time.Time { return t }
}
}
raw, _ := json.Marshal(req)
switch op {
case "detect_family":
name, _ := req["name"].(string)
emit(map[string]any{"result": detectFamily(name)})
case "detect_parameters":
name, _ := req["name"].(string)
emit(map[string]any{"result": detectParameters(name)})
case "detect_quantization":
name, _ := req["name"].(string)
emit(map[string]any{"result": detectQuantization(name)})
case "success_rate":
var in struct {
Interactions int `json:"interactions"`
Successes int `json:"successes"`
}
_ = json.Unmarshal(raw, &in)
emit(map[string]any{"result": successRate(ModelProfile{Interactions: in.Interactions, Successes: in.Successes})})
case "get_profile_path":
name, _ := req["name"].(string)
emit(map[string]any{"result": filepath.Base(getProfilePath(name))})
case "load_profile":
name, _ := req["name"].(string)
if p, ok := loadProfile(name); ok {
emitResult(profileJSON(p))
} else {
emit(map[string]any{"result": nil})
}
case "save_profile":
var state map[string]json.RawMessage
_ = json.Unmarshal(raw, &state)
p := profileFromMap(state)
saveProfile(p)
rawBytes, _ := os.ReadFile(getProfilePath(p.Name))
emit(map[string]any{"result": string(rawBytes)})
case "build_profile":
name, _ := req["name"].(string)
var info map[string]any
if m, ok := req["model_info"].(map[string]any); ok {
info = m
}
emitResult(profileJSON(ptrOf(buildProfileFromOllama(name, info))))
case "scan":
if url, _ := req["ollama_url"].(string); url != "" {
ollamaURL = url
}
profiles := scanAllModels()
out := make([]any, len(profiles))
for i, p := range profiles {
out[i] = profileJSON(ptrOf(p))
}
emit(map[string]any{"result": out})
case "get_or_create":
name, _ := req["name"].(string)
emitResult(profileJSON(ptrOf(getOrCreateProfile(name))))
case "record":
name, _ := req["name"].(string)
success, _ := req["success"].(bool)
topic, _ := req["topic"].(string)
recordInteraction(name, success, topic)
if p, ok := loadProfile(name); ok {
emitResult(profileJSON(p))
} else {
emit(map[string]any{"error": "record wrote nothing"})
os.Exit(1)
}
case "prompt_context":
name, _ := req["name"].(string)
emit(map[string]any{"result": getPromptContext(name)})
case "to_dict":
var state map[string]json.RawMessage
_ = json.Unmarshal(raw, &state)
emitResult(profileJSON(ptrOf(profileFromMap(state))))
case "from_dict":
var data map[string]json.RawMessage
_ = json.Unmarshal(raw, &data)
emitResult(profileJSON(ptrOf(profileFromMap(data))))
default:
emit(map[string]any{"error": "unknown op: " + op})
os.Exit(1)
}
}
func ptrOf(p ModelProfile) *ModelProfile { return &p }
// profileJSON returns the profile as RawMessage — the MarshalJSON bytes
// pass through UNPARSED so the Python float rendering (7.0, not 7)
// survives into serve responses (a map[string]any round-trip would
// re-render integral floats Go-style — the integral-float law).
func profileJSON(p *ModelProfile) json.RawMessage {
raw, _ := json.Marshal(p)
return raw
}
// emitResult splices a pre-rendered result value into the response
// envelope without re-marshaling (preserves Python float rendering).
func emitResult(raw json.RawMessage) {
fmt.Printf("{\"result\":%s}\n", raw)
}
// profileFromMap rebuilds a ModelProfile from a from_dict-shaped doc
// (unknown keys ignored, absent keys defaulted — the oracle lens).
func profileFromMap(state map[string]json.RawMessage) ModelProfile {
p := defaultModelProfile("")
unmarshal := func(key string, dst any) {
if raw, ok := state[key]; ok {
_ = json.Unmarshal(raw, dst)
}
}
unmarshal("name", &p.Name)
unmarshal("display_name", &p.DisplayName)
unmarshal("family", &p.Family)
unmarshal("parameters", &p.Parameters)
unmarshal("quantization", &p.Quantization)
unmarshal("size_gb", &p.SizeGB)
unmarshal("strengths", &p.Strengths)
unmarshal("weaknesses", &p.Weaknesses)
unmarshal("prompting_tips", &p.PromptingTips)
unmarshal("safety_tier", &p.SafetyTier)
unmarshal("known_refusal_topics", &p.KnownRefusalTopics)
unmarshal("thinking_format", &p.ThinkingFormat)
unmarshal("response_style", &p.ResponseStyle)
unmarshal("context_window", &p.ContextWindow)
unmarshal("optimal_temperature", &p.OptimalTemperature)
unmarshal("interactions", &p.Interactions)
unmarshal("successes", &p.Successes)
unmarshal("failures", &p.Failures)
unmarshal("last_used", &p.LastUsed)
unmarshal("created", &p.Created)
if p.Strengths == nil {
p.Strengths = []string{}
}
if p.Weaknesses == nil {
p.Weaknesses = []string{}
}
if p.PromptingTips == nil {
p.PromptingTips = []string{}
}
if p.KnownRefusalTopics == nil {
p.KnownRefusalTopics = []string{}
}
return p
}
func emit(v any) {
b, err := json.Marshal(v)
if err != nil {
fmt.Fprintln(os.Stderr, "marshal:", err)
os.Exit(1)
}
fmt.Println(string(b))
}
func main() {
if len(os.Args) < 2 || os.Args[1] != "replay" {
fmt.Fprintln(os.Stderr, "usage: model-profiles replay <truth.json>")
os.Exit(2)
if len(os.Args) >= 2 && os.Args[1] == "replay" {
replayLegacy()
return
}
serveStdin()
}
func replayLegacy() {
raw, err := os.ReadFile(os.Args[2])
if err != nil {
fmt.Fprintln(os.Stderr, err)
@@ -103,7 +894,7 @@ func main() {
inter := int(r[1].(float64))
succ := int(r[2].(float64))
wantRate := r[3].(float64)
if got := successRate(inter, succ); got != wantRate {
if got := successRate(ModelProfile{Interactions: inter, Successes: succ}); got != wantRate {
fails++
fmt.Printf("case %d success_rate %s: got %v want %v\n", i, name, got, wantRate)
}
+26 -14
View File
@@ -5,8 +5,11 @@
//
// Usage:
//
// parallel-processor run <command1> <command2> ... (shell commands in parallel)
// parallel-processor status
// parallel-processor status # mirror of the oracle CLI status
// parallel-processor test # mirror of the oracle CLI test run
// parallel-processor run <cmd...> (shell commands in parallel)
// parallel-processor replay [truth.json]
// parallel-processor op (stdin JSON parity dispatch)
package main
import (
@@ -88,11 +91,28 @@ func splitCommand(cmd string) []string {
}
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: parallel-processor run <cmd1> <cmd2> ... | status")
os.Exit(1)
if len(os.Args) > 1 && os.Args[1] == "replay" {
os.Exit(replayMain())
}
if len(os.Args) > 1 && os.Args[1] == "op" {
os.Exit(parityMain())
}
if len(os.Args) < 2 {
fmt.Println("Usage:")
fmt.Println(" parallel_processor.py status # Show processor status")
fmt.Println(" parallel_processor.py test # Test parallel execution")
return
}
switch os.Args[1] {
case "status":
status := getStatus()
fmt.Printf("Max workers: %d\n", status["max_workers"])
fmt.Printf("Active threads: %d\n", status["active_threads"])
case "test":
TestParallel()
case "run":
commands := os.Args[2:]
if len(commands) == 0 {
@@ -103,15 +123,7 @@ func main() {
out, _ := json.MarshalIndent(results, "", " ")
fmt.Println(string(out))
case "status":
out, _ := json.MarshalIndent(map[string]interface{}{
"runtime": "go",
"goroutines_enabled": true,
}, "", " ")
fmt.Println(string(out))
default:
fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1])
os.Exit(1)
fmt.Printf("Unknown command: %s\n", os.Args[1])
}
}
@@ -0,0 +1,495 @@
package main
// parallel_processor.go — name-preserving Go port of
// src/rune/parallel_processor.py (dichotomy gap-close, wave #2479).
//
// Logic 1:1 with the Python oracle: results preserve submission order, a
// failing task degrades to {"error": str(e)} (type name stripped, per the
// established exception-contract quirk), and Python-visible strings —
// type names in errors, repr shapes, submit-after-shutdown RuntimeError —
// are replicated exactly. The ThreadPoolExecutor becomes a
// semaphore-bounded goroutine pool that bounds concurrency at max_workers
// while keeping the executor reusable across calls like the oracle's.
//
// Task specs (kind/fn/value grammar shared with scripts/pp_freeze_seams)
// exist so callables can ride through JSON truth rows and the stdin parity
// dispatch: the rig builds real Python callables from the same specs the
// Go side turns into specCallable values.
import (
"encoding/json"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
const defaultMaxWorkers = 4
// pyError carries a Python-style exception message (str(e) shape: the
// type prefix is already stripped). Task panics recover into
// {"error": msg} exactly like future.result() raising in the oracle.
type pyError struct{ msg string }
func (e pyError) Error() string { return e.msg }
// ParallelProcessor mirrors the oracle's ParallelProcessor.
type ParallelProcessor struct {
maxWorkers int
sem chan struct{} // bounds in-flight tasks at max_workers
mu sync.Mutex
down bool
taskWG sync.WaitGroup // outstanding tasks, for Shutdown(wait=true)
}
// NewParallelProcessor mirrors ParallelProcessor(max_workers).
// max_workers <= 0 raises ValueError in the oracle; the port panics with
// the same message (crash-parity law).
func NewParallelProcessor(maxWorkers int) *ParallelProcessor {
if maxWorkers <= 0 {
panic("max_workers must be greater than 0")
}
return &ParallelProcessor{
maxWorkers: maxWorkers,
sem: make(chan struct{}, maxWorkers),
}
}
func (p *ParallelProcessor) submitCheck() {
p.mu.Lock()
defer p.mu.Unlock()
if p.down {
// The oracle raises from the submit loop itself — BEFORE any
// per-task capture — so the whole call raises, not one row.
panic("cannot schedule new futures after shutdown")
}
p.taskWG.Add(1)
}
// RunParallel mirrors run_parallel(tasks): zero-arg calls in parallel,
// submission-order results, per-task {"error": str(e)} degradation.
// Non-callable tasks produce the oracle's worker TypeError text.
func (p *ParallelProcessor) RunParallel(tasks []interface{}) []interface{} {
results := make([]interface{}, len(tasks))
var callWG sync.WaitGroup
for i, task := range tasks {
p.submitCheck()
callWG.Add(1)
p.sem <- struct{}{}
go func(idx int, t interface{}) {
defer callWG.Done()
defer func() { <-p.sem }()
defer p.taskWG.Done()
defer func() {
if r := recover(); r != nil {
results[idx] = map[string]interface{}{"error": pyExcStr(r)}
}
}()
results[idx] = callTask(t)
}(i, task)
}
callWG.Wait()
return results
}
// ArgsTask is the JSON spec grammar for run_parallel_with_args rows.
// kind: call | raw | emptytuple | notcall | argsnotseq | kwnotdict.
type ArgsTask struct {
Kind string `json:"kind"`
Fn string `json:"fn,omitempty"`
Msg string `json:"msg,omitempty"`
Ms float64 `json:"ms,omitempty"`
Ret interface{} `json:"ret,omitempty"`
Value interface{} `json:"value,omitempty"`
Args []interface{} `json:"args,omitempty"`
Kwargs map[string]interface{} `json:"kwargs,omitempty"`
}
// RunParallelWithArgs mirrors run_parallel_with_args(tasks): parse the
// (func, args, kwargs) tuples (errors recorded per index), run the valid
// ones through the pool, then reassemble submission-order results with
// the parse errors interleaved at their original positions.
func (p *ParallelProcessor) RunParallelWithArgs(tasks []ArgsTask) []interface{} {
type parsedTask struct {
origIdx int
task interface{}
}
parsed := []parsedTask{}
errors := map[int]interface{}{}
for i, task := range tasks {
switch task.Kind {
case "raw":
errors[i] = map[string]interface{}{
"error": fmt.Sprintf("task %d: expected tuple, got %s", i, pyTypeName(task.Value)),
}
case "emptytuple":
errors[i] = map[string]interface{}{
"error": fmt.Sprintf("task %d: expected tuple, got tuple", i),
}
case "notcall":
errors[i] = map[string]interface{}{
"error": fmt.Sprintf("task %d: %s is not callable", i, pyRepr(task.Value)),
}
case "argsnotseq":
// args is a non-sequence scalar -> the oracle wraps it: (args,)
parsed = append(parsed, parsedTask{i, specCallable{
fn: task.Fn, args: []interface{}{task.Value}, kwargs: task.Kwargs,
msg: task.Msg, ms: task.Ms, ret: task.Ret,
}})
case "kwnotdict":
// kwargs is not a dict -> the oracle resets it to {}; the rig
// passes () as args for this branch
parsed = append(parsed, parsedTask{i, specCallable{
fn: task.Fn, args: nil, kwargs: map[string]interface{}{},
msg: task.Msg, ms: task.Ms, ret: task.Ret,
}})
case "call":
kwargs := task.Kwargs
if kwargs == nil {
kwargs = map[string]interface{}{}
}
parsed = append(parsed, parsedTask{i, specCallable{
fn: task.Fn, args: task.Args, kwargs: kwargs,
msg: task.Msg, ms: task.Ms, ret: task.Ret,
}})
default:
panic("unknown task kind " + task.Kind)
}
}
results := make([]interface{}, len(tasks))
var callWG sync.WaitGroup
for _, pt := range parsed {
p.submitCheck()
callWG.Add(1)
p.sem <- struct{}{}
go func(pt parsedTask) {
defer callWG.Done()
defer func() { <-p.sem }()
defer p.taskWG.Done()
defer func() {
if r := recover(); r != nil {
results[pt.origIdx] = map[string]interface{}{"error": pyExcStr(r)}
}
}()
results[pt.origIdx] = callTask(pt.task)
}(pt)
}
callWG.Wait()
for i := range tasks {
if e, ok := errors[i]; ok {
results[i] = e
}
}
return results
}
// GetStatus mirrors get_status: pool_threads is reported as max_workers
// (the oracle returns the configured bound, not live thread count);
// active_threads reads the injectable seam (PP_ACTIVE_THREADS pins it in
// batteries/parity; the live default is the Go-native goroutine count).
func (p *ParallelProcessor) GetStatus() map[string]interface{} {
return map[string]interface{}{
"max_workers": p.maxWorkers,
"pool_threads": p.maxWorkers,
"active_threads": activeThreads(),
}
}
// Shutdown mirrors shutdown(wait): further submissions raise; wait=true
// drains outstanding tasks first.
func (p *ParallelProcessor) Shutdown(wait bool) {
p.mu.Lock()
p.down = true
p.mu.Unlock()
if wait {
p.taskWG.Wait()
}
}
// ── global processor (module-level surface) ─────────────────────────────────
var (
processorMu sync.Mutex
processor *ParallelProcessor
)
// GetProcessor mirrors get_processor(): the lazily created global
// processor (default 4 workers).
func GetProcessor() *ParallelProcessor {
processorMu.Lock()
defer processorMu.Unlock()
if processor == nil {
processor = NewParallelProcessor(defaultMaxWorkers)
}
return processor
}
// ShutdownProcessor mirrors _shutdown_processor(): shut the global
// processor down (no drain — the oracle passes wait=False) and clear it
// so the next GetProcessor lazily rebuilds.
func ShutdownProcessor() {
processorMu.Lock()
p := processor
processor = nil
processorMu.Unlock()
if p != nil {
p.Shutdown(false)
}
}
// module-level delegates (unexported: the struct methods carry the
// audit-visible names; these mirror the module fns 1:1)
func runParallel(tasks []interface{}) []interface{} { return GetProcessor().RunParallel(tasks) }
func runParallelWithArgs(tasks []ArgsTask) []interface{} {
return GetProcessor().RunParallelWithArgs(tasks)
}
func getStatus() map[string]interface{} { return GetProcessor().GetStatus() }
// TestParallel mirrors test_parallel(): staggered tasks run sequentially
// then through the pool; prints the oracle's report lines and returns
// None. task_1/2/3 keep the oracle's nested-fn names and shapes.
func TestParallel() {
fmt.Println("Testing Parallel Processor...")
task_1 := func() interface{} {
time.Sleep(100 * time.Millisecond)
return "Task 1 complete"
}
task_2 := func() interface{} {
time.Sleep(200 * time.Millisecond)
return "Task 2 complete"
}
task_3 := func() interface{} {
time.Sleep(300 * time.Millisecond)
return "Task 3 complete"
}
start := time.Now()
resultsSeq := []interface{}{task_1(), task_2(), task_3()}
seqMs := float64(time.Since(start)) / float64(time.Millisecond)
start = time.Now()
resultsPar := runParallel([]interface{}{task_1, task_2, task_3})
parMs := float64(time.Since(start)) / float64(time.Millisecond)
fmt.Printf("Sequential: %.0fms\n", seqMs)
fmt.Printf("Parallel: %.0fms\n", parMs)
fmt.Printf("Speedup: %.1fx\n", seqMs/parMs)
fmt.Printf("Results: %s\n", pyRepr(resultsPar))
_ = resultsSeq
fmt.Println("✅ All tests passed!")
}
// ── spec task machinery ─────────────────────────────────────────────────────
// specCallable is a task built from the JSON spec grammar; the rig builds
// the same shapes as real Python callables on the oracle side.
type specCallable struct {
fn string
args []interface{}
kwargs map[string]interface{}
msg string
ms float64
ret interface{}
}
func (s specCallable) call() interface{} {
switch s.fn {
case "const":
return s.ret
case "echo":
args := s.args
if args == nil {
args = []interface{}{}
}
kwargs := s.kwargs
if kwargs == nil {
kwargs = map[string]interface{}{}
}
return map[string]interface{}{"args": args, "kwargs": kwargs}
case "add":
return pyAdd(s.args[0], s.args[1])
case "boom":
panic(pyError{s.msg})
case "sleepret":
time.Sleep(time.Duration(s.ms * float64(time.Millisecond)))
return s.ret
}
panic(pyError{"unknown spec fn " + s.fn})
}
// callTask invokes a task: spec callables and raw Go funcs run; anything
// else reproduces the oracle's worker TypeError for calling a
// non-callable ("'int' object is not callable" — Python type name).
func callTask(t interface{}) (result interface{}) {
switch f := t.(type) {
case specCallable:
return f.call()
case func() interface{}:
return f()
default:
panic(pyError{fmt.Sprintf("'%s' object is not callable", pyTypeName(t))})
}
}
func pyExcStr(r interface{}) string {
switch e := r.(type) {
case pyError:
return e.msg
case string:
return e
default:
return fmt.Sprint(e)
}
}
// activeThreads — the oracle reports threading.active_count(); live
// thread state is process-random, so the seam reads PP_ACTIVE_THREADS
// when pinned (battery/parity) and falls back to the Go-native count.
func activeThreads() int {
if v := os.Getenv("PP_ACTIVE_THREADS"); v != "" {
if n, err := strconv.Atoi(v); err == nil && n > 0 {
return n
}
}
return runtime.NumGoroutine()
}
// ── Python-shape value helpers ──────────────────────────────────────────────
// pyTypeName maps a decoded JSON value to the Python type name the
// oracle would print (int vs float distinguished via json.Number).
func pyTypeName(v interface{}) string {
switch t := v.(type) {
case nil:
return "NoneType"
case bool:
return "bool"
case string:
return "str"
case float64:
return "float"
case int:
return "int"
case int64:
return "int"
case []interface{}:
return "list"
case map[string]interface{}:
return "dict"
case json.Number:
if strings.ContainsAny(string(t), ".eE") {
return "float"
}
return "int"
}
return fmt.Sprintf("%T", v)
}
// pyRepr renders a decoded JSON value the way Python repr would for the
// frozen shapes: ints/floats bare, strings single-quoted, bools/None
// capitalized, lists comma-space joined.
func pyRepr(v interface{}) string {
switch t := v.(type) {
case nil:
return "None"
case bool:
if t {
return "True"
}
return "False"
case string:
return "'" + t + "'"
case float64:
return pyFloatRepr(t)
case json.Number:
if strings.ContainsAny(string(t), ".eE") {
f, _ := strconv.ParseFloat(string(t), 64)
return pyFloatRepr(f)
}
return string(t)
case []interface{}:
parts := make([]string, len(t))
for i, e := range t {
parts[i] = pyRepr(e)
}
return "[" + strings.Join(parts, ", ") + "]"
case map[string]interface{}:
// Python dict repr is insertion-ordered; Go maps are not. The
// frozen corpus deliberately contains no dict-repr rows — sorted
// keys keep this deterministic if one ever appears.
keys := make([]string, 0, len(t))
for k := range t {
keys = append(keys, k)
}
sortStrings(keys)
parts := make([]string, len(keys))
for i, k := range keys {
parts[i] = "'" + k + "': " + pyRepr(t[k])
}
return "{" + strings.Join(parts, ", ") + "}"
}
return fmt.Sprint(v)
}
func pyFloatRepr(f float64) string {
return strconv.FormatFloat(f, 'g', -1, 64)
}
// pyAdd mirrors Python + on the frozen number shapes: int+int stays int,
// anything with a float is float math (json.Number keeps the distinction
// the JSON decoder would give the oracle).
func pyAdd(a, b interface{}) interface{} {
ai, aInt := pyAsInt(a)
bi, bInt := pyAsInt(b)
if aInt && bInt {
return json.Number(strconv.FormatInt(ai+bi, 10))
}
af, _ := pyAsFloat(a)
bf, _ := pyAsFloat(b)
return json.Number(pyFloatRepr(af + bf))
}
func pyAsInt(v interface{}) (int64, bool) {
switch t := v.(type) {
case json.Number:
if !strings.ContainsAny(string(t), ".eE") {
n, err := strconv.ParseInt(string(t), 10, 64)
return n, err == nil
}
case int:
return int64(t), true
case int64:
return t, true
}
return 0, false
}
func pyAsFloat(v interface{}) (float64, bool) {
switch t := v.(type) {
case json.Number:
f, err := strconv.ParseFloat(string(t), 64)
return f, err == nil
case float64:
return t, true
case int:
return float64(t), true
case int64:
return float64(t), true
}
return 0, false
}
func sortStrings(s []string) {
for i := 1; i < len(s); i++ {
for j := i; j > 0 && s[j] < s[j-1]; j-- {
s[j], s[j-1] = s[j-1], s[j]
}
}
}
+307
View File
@@ -0,0 +1,307 @@
package main
// replay.go — frozen-truth replay + stdin parity dispatch (the shared
// dichotomy verification surface: the battery embeds truth.json VERBATIM
// and replays every row; the parity sweep drives the same dispatch one
// op per process via `parallel-processor op`).
import (
"encoding/json"
"fmt"
"io"
"os"
"strings"
)
type frozenCase struct {
Fn string `json:"fn"`
Args []interface{} `json:"args"`
Kwargs map[string]interface{} `json:"kwargs"`
Recv map[string]interface{} `json:"recv,omitempty"`
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 := decodeUseNumber(raw, &out); err != nil {
return nil, err
}
return out, nil
}
// decodeUseNumber keeps ints ints (json.Number) so pyTypeName and result
// marshaling see the int/float distinction the JSON decoder gives Python.
func decodeUseNumber(b []byte, v interface{}) error {
dec := json.NewDecoder(strings.NewReader(string(b)))
dec.UseNumber()
return dec.Decode(v)
}
// buildTask — spec map -> runnable task: {"kind":"call",...} becomes a
// specCallable; {"kind":"raw","value":v} and any non-spec value (dicts
// without a kind key included) become the bare value (the oracle's
// non-callable TypeError branch).
func buildTask(spec interface{}) interface{} {
m, ok := spec.(map[string]interface{})
if !ok || m["kind"] == nil {
return spec
}
if m["kind"] != "call" {
return m["value"]
}
sc := specCallable{
fn: str(m["fn"]),
msg: str(m["msg"]),
ret: m["ret"],
args: slice(m["args"]),
kwargs: mapping(m["kwargs"]),
}
if ms, ok := pyAsFloat(m["ms"]); ok {
sc.ms = ms
}
return sc
}
// buildTasks — apply buildTask across a decoded specs array.
func buildTasks(specs interface{}) []interface{} {
out := []interface{}{}
for _, s := range slice(specs) {
out = append(out, buildTask(s))
}
return out
}
// buildArgsTask — spec map -> the ArgsTask grammar (re-marshaled through
// the UseNumber decoder so Value keeps its int/float shape). Bare
// non-map values are the direct-row form: raw tasks.
func buildArgsTask(spec interface{}) (ArgsTask, error) {
if _, ok := spec.(map[string]interface{}); !ok {
return ArgsTask{Kind: "raw", Value: spec}, nil
}
var t ArgsTask
b, err := json.Marshal(spec)
if err != nil {
return t, err
}
err = decodeUseNumber(b, &t)
return t, err
}
func buildArgsTasks(specs interface{}) ([]ArgsTask, error) {
out := []ArgsTask{}
for _, s := range slice(specs) {
t, err := buildArgsTask(s)
if err != nil {
return nil, err
}
out = append(out, t)
}
return out, nil
}
func replayCase(c frozenCase) (interface{}, error) {
switch c.Fn {
case "run_parallel", "_pp_run_parallel":
return runParallel(buildTasks(c.Args[0])), nil
case "run_parallel_with_args", "_pp_run_parallel_with_args":
tasks, err := buildArgsTasks(c.Args[0])
if err != nil {
return nil, err
}
return runParallelWithArgs(tasks), nil
case "_pp_class_run_parallel":
return NewParallelProcessor(pyInt(c.Args[0])).RunParallel(buildTasks(c.Args[1])), nil
case "_pp_class_run_parallel_with_args":
tasks, err := buildArgsTasks(c.Args[1])
if err != nil {
return nil, err
}
return NewParallelProcessor(pyInt(c.Args[0])).RunParallelWithArgs(tasks), nil
case "get_status":
return getStatus(), nil
case "ParallelProcessor.get_status":
mw := pyInt(c.Recv["max_workers"])
// the harness snapshots recv rows as {"result": r, <post-call attrs>}
return map[string]interface{}{
"result": NewParallelProcessor(mw).GetStatus(),
"max_workers": mw,
}, nil
case "_pp_get_processor_status":
a, b := GetProcessor(), GetProcessor()
return map[string]interface{}{
"max_workers": a.maxWorkers,
"is_singleton": a == b,
}, nil
case "_pp_shutdown_processor_cycle":
ShutdownProcessor()
processorMu.Lock()
wasNil := processor == nil
processorMu.Unlock()
st := getStatus()
return map[string]interface{}{
"processor_is_none": wasNil,
"recreated_max_workers": st["max_workers"],
}, nil
case "_pp_shutdown_then_status":
p := NewParallelProcessor(3)
p.Shutdown(true)
return map[string]interface{}{
"shutdown_returned_none": true,
"status": p.GetStatus(),
}, nil
case "_pp_shutdown_then_run":
p := NewParallelProcessor(2)
p.Shutdown(true)
var raised string
func() {
defer func() { raised = pyExcStr(recover()) }()
p.RunParallel([]interface{}{specCallable{fn: "const", ret: 1}})
}()
return map[string]interface{}{"raised": raised}, nil
case "_pp_new_bad":
var raised string
func() {
defer func() { raised = pyExcStr(recover()) }()
NewParallelProcessor(0)
}()
return map[string]interface{}{"raised": raised}, nil
case "test_parallel":
TestParallel()
return nil, nil
}
return nil, fmt.Errorf("unknown frozen fn %q", c.Fn)
}
// ── replay binary ───────────────────────────────────────────────────────────
func replayMain() int {
path := "truth.json"
if len(os.Args) > 2 {
path = os.Args[2]
}
raw, err := os.ReadFile(path)
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL:", err)
return 2
}
fails, count := runTruthBytes(raw)
for _, f := range fails {
fmt.Println(f)
}
if len(fails) > 0 {
fmt.Fprintf(os.Stderr, "PARITY FAILED: %d divergence(s)\n", len(fails))
return 1
}
fmt.Printf("PARITY OK: %d cases exact-equal vs the Python oracle\n", count)
return 0
}
func runTruthBytes(raw []byte) (fails []string, count int) {
var env struct {
FrozenNow string `json:"frozen_now"`
Cases []frozenCase `json:"cases"`
}
if err := decodeUseNumber(raw, &env); err != nil {
return []string{fmt.Sprintf("decode truth envelope: %v", err)}, 0
}
if len(env.Cases) == 0 {
return []string{"no truth cases — the parity gate is empty"}, 0
}
for i, c := range env.Cases {
actual, err := replayCase(c)
if err != nil {
fails = append(fails, fmt.Sprintf("case %d fn=%s: %v", i, c.Fn, err))
continue
}
got, err := canonical(actual)
if err != nil {
fails = append(fails, fmt.Sprintf("case %d fn=%s: canonical actual: %v", i, c.Fn, err))
continue
}
var want interface{}
if err := decodeUseNumber(c.Expected, &want); err != nil {
fails = append(fails, fmt.Sprintf("case %d fn=%s: decode expected: %v", i, c.Fn, err))
continue
}
gj, _ := json.Marshal(got)
wj, _ := json.Marshal(want)
if string(gj) != string(wj) {
fails = append(fails, fmt.Sprintf("case %d fn=%s: got %s want %s", i, c.Fn, gj, wj))
}
}
return fails, len(env.Cases)
}
// ── stdin parity dispatch (one op per process) ──────────────────────────────
func parityMain() int {
raw, err := io.ReadAll(os.Stdin)
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL: read stdin:", err)
return 2
}
var req map[string]interface{}
if err := decodeUseNumber(raw, &req); err != nil {
fmt.Fprintln(os.Stderr, "FATAL: decode op:", err)
return 2
}
out, err := parityOp(str(req["op"]), req)
if err != nil {
fmt.Fprintln(os.Stderr, "FATAL:", err)
return 2
}
b, _ := json.Marshal(out)
fmt.Println(string(b))
return 0
}
func parityOp(op string, req map[string]interface{}) (interface{}, error) {
c := frozenCase{Fn: op, Kwargs: req}
switch op {
case "run_parallel", "run_parallel_with_args":
c.Args = []interface{}{req["tasks"]}
case "class_run_parallel", "class_run_parallel_with_args":
c.Fn = "_pp_" + op
c.Args = []interface{}{req["max_workers"], req["tasks"]}
case "get_status":
// module fn, no args
case "class_get_status":
c.Fn = "ParallelProcessor.get_status"
c.Recv = map[string]interface{}{"max_workers": req["max_workers"]}
default:
// seam ops carry the frozen _pp_ prefix
c.Fn = "_pp_" + op
}
return replayCase(c)
}
// ── small decode helpers ────────────────────────────────────────────────────
func str(v interface{}) string {
s, _ := v.(string)
return s
}
func slice(v interface{}) []interface{} {
s, _ := v.([]interface{})
return s
}
func mapping(v interface{}) map[string]interface{} {
m, _ := v.(map[string]interface{})
return m
}
func pyInt(v interface{}) int {
if n, ok := pyAsInt(v); ok {
return int(n)
}
f, _ := pyAsFloat(v)
return int(f)
}
+605
View File
@@ -0,0 +1,605 @@
{
"frozen_now": "2026-10-14T08:00:00+00:00",
"cases": [
{
"fn": "run_parallel",
"args": [
[
42
]
],
"kwargs": {},
"expected": [
{
"error": "'int' object is not callable"
}
]
},
{
"fn": "run_parallel",
"args": [
[
42,
"x",
null,
true,
4.5,
[
1
],
{
"a": 1
}
]
],
"kwargs": {},
"expected": [
{
"error": "'int' object is not callable"
},
{
"error": "'str' object is not callable"
},
{
"error": "'NoneType' object is not callable"
},
{
"error": "'bool' object is not callable"
},
{
"error": "'float' object is not callable"
},
{
"error": "'list' object is not callable"
},
{
"error": "'dict' object is not callable"
}
]
},
{
"fn": "run_parallel",
"args": [
[]
],
"kwargs": {},
"expected": []
},
{
"fn": "run_parallel_with_args",
"args": [
[
42,
"x",
null
]
],
"kwargs": {},
"expected": [
{
"error": "task 0: expected tuple, got int"
},
{
"error": "task 1: expected tuple, got str"
},
{
"error": "task 2: expected tuple, got NoneType"
}
]
},
{
"fn": "run_parallel_with_args",
"args": [
[
[]
]
],
"kwargs": {},
"expected": [
{
"error": "task 0: expected tuple, got list"
}
]
},
{
"fn": "_pp_run_parallel",
"args": [
[
{
"kind": "call",
"fn": "const",
"ret": 7
},
{
"kind": "call",
"fn": "boom",
"msg": "kaput"
},
{
"kind": "call",
"fn": "const",
"ret": "x"
}
]
],
"kwargs": {},
"expected": [
7,
{
"error": "kaput"
},
"x"
]
},
{
"fn": "_pp_run_parallel",
"args": [
[
{
"kind": "call",
"fn": "sleepret",
"ms": 60,
"ret": "a"
},
{
"kind": "call",
"fn": "sleepret",
"ms": 10,
"ret": "b"
},
{
"kind": "call",
"fn": "sleepret",
"ms": 35,
"ret": "c"
},
{
"kind": "call",
"fn": "boom",
"msg": "late"
},
{
"kind": "raw",
"value": null
}
]
],
"kwargs": {},
"expected": [
"a",
"b",
"c",
{
"error": "late"
},
{
"error": "'NoneType' object is not callable"
}
]
},
{
"fn": "_pp_run_parallel",
"args": [
[]
],
"kwargs": {},
"expected": []
},
{
"fn": "_pp_class_run_parallel",
"args": [
3,
[
{
"kind": "call",
"fn": "const",
"ret": 1
},
{
"kind": "call",
"fn": "const",
"ret": 2
},
{
"kind": "call",
"fn": "boom",
"msg": "nope"
},
{
"kind": "call",
"fn": "const",
"ret": 4
},
{
"kind": "call",
"fn": "sleepret",
"ms": 15,
"ret": 5
}
]
],
"kwargs": {},
"expected": [
1,
2,
{
"error": "nope"
},
4,
5
]
},
{
"fn": "_pp_class_run_parallel",
"args": [
1,
[
{
"kind": "call",
"fn": "sleepret",
"ms": 30,
"ret": "w1"
},
{
"kind": "call",
"fn": "sleepret",
"ms": 5,
"ret": "w2"
},
{
"kind": "call",
"fn": "const",
"ret": "w3"
}
]
],
"kwargs": {},
"expected": [
"w1",
"w2",
"w3"
]
},
{
"fn": "_pp_run_parallel_with_args",
"args": [
[
{
"kind": "call",
"fn": "add",
"args": [
1,
2
]
},
{
"kind": "call",
"fn": "add",
"args": [
1.5,
2
]
},
{
"kind": "call",
"fn": "echo"
},
{
"kind": "call",
"fn": "echo",
"kwargs": {
"k": 1,
"b": 2
}
},
{
"kind": "call",
"fn": "boom",
"msg": "bad-task"
}
]
],
"kwargs": {},
"expected": [
3,
3.5,
{
"args": [],
"kwargs": {}
},
{
"args": [],
"kwargs": {
"k": 1,
"b": 2
}
},
{
"error": "bad-task"
}
]
},
{
"fn": "_pp_run_parallel_with_args",
"args": [
[
{
"kind": "raw",
"value": 42
},
{
"kind": "raw",
"value": "x"
},
{
"kind": "raw",
"value": null
},
{
"kind": "emptytuple"
},
{
"kind": "notcall",
"value": 42
},
{
"kind": "notcall",
"value": "x"
},
{
"kind": "notcall",
"value": null
},
{
"kind": "notcall",
"value": true
},
{
"kind": "notcall",
"value": 4.5
},
{
"kind": "notcall",
"value": [
1,
2
]
}
]
],
"kwargs": {},
"expected": [
{
"error": "task 0: expected tuple, got int"
},
{
"error": "task 1: expected tuple, got str"
},
{
"error": "task 2: expected tuple, got NoneType"
},
{
"error": "task 3: expected tuple, got tuple"
},
{
"error": "task 4: 42 is not callable"
},
{
"error": "task 5: 'x' is not callable"
},
{
"error": "task 6: None is not callable"
},
{
"error": "task 7: True is not callable"
},
{
"error": "task 8: 4.5 is not callable"
},
{
"error": "task 9: [1, 2] is not callable"
}
]
},
{
"fn": "_pp_run_parallel_with_args",
"args": [
[
{
"kind": "argsnotseq",
"fn": "echo",
"value": "ab"
},
{
"kind": "argsnotseq",
"fn": "echo",
"value": 5
},
{
"kind": "kwnotdict",
"fn": "echo",
"value": [
"a"
]
},
{
"kind": "call",
"fn": "sleepret",
"ms": 10,
"ret": "z"
}
]
],
"kwargs": {},
"expected": [
{
"args": [
"ab"
],
"kwargs": {}
},
{
"args": [
5
],
"kwargs": {}
},
{
"args": [],
"kwargs": {}
},
"z"
]
},
{
"fn": "_pp_class_run_parallel_with_args",
"args": [
2,
[
{
"kind": "call",
"fn": "echo",
"args": [
1,
2
],
"kwargs": {
"scale": 10
}
},
{
"kind": "raw",
"value": 3.5
},
{
"kind": "call",
"fn": "boom",
"msg": "class-branch"
},
{
"kind": "notcall",
"value": false
}
]
],
"kwargs": {},
"expected": [
{
"args": [
1,
2
],
"kwargs": {
"scale": 10
}
},
{
"error": "task 1: expected tuple, got float"
},
{
"error": "class-branch"
},
{
"error": "task 3: False is not callable"
}
]
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"max_workers": 4,
"pool_threads": 4,
"active_threads": 4
}
},
{
"fn": "ParallelProcessor.get_status",
"recv": {
"cls": "ParallelProcessor",
"max_workers": 1
},
"args": [],
"kwargs": {},
"expected": {
"result": {
"max_workers": 1,
"pool_threads": 1,
"active_threads": 4
},
"max_workers": 1
}
},
{
"fn": "ParallelProcessor.get_status",
"recv": {
"cls": "ParallelProcessor",
"max_workers": 9
},
"args": [],
"kwargs": {},
"expected": {
"result": {
"max_workers": 9,
"pool_threads": 9,
"active_threads": 4
},
"max_workers": 9
}
},
{
"fn": "_pp_get_processor_status",
"args": [],
"kwargs": {},
"expected": {
"max_workers": 4,
"is_singleton": true
}
},
{
"fn": "_pp_shutdown_then_status",
"args": [],
"kwargs": {},
"expected": {
"shutdown_returned_none": true,
"status": {
"max_workers": 3,
"pool_threads": 3,
"active_threads": 4
}
}
},
{
"fn": "_pp_shutdown_then_run",
"args": [],
"kwargs": {},
"expected": {
"raised": "cannot schedule new futures after shutdown"
}
},
{
"fn": "_pp_new_bad",
"args": [],
"kwargs": {},
"expected": {
"raised": "max_workers must be greater than 0"
}
},
{
"fn": "_pp_shutdown_processor_cycle",
"args": [],
"kwargs": {},
"expected": {
"processor_is_none": true,
"recreated_max_workers": 4
}
},
{
"fn": "test_parallel",
"args": [],
"kwargs": {},
"expected": null
}
]
}
+174
View File
@@ -0,0 +1,174 @@
package main
// truth_test.go — the parity gate. Replays every case from truth.json
// (the shared freeze_truth.py envelope: pinned thread-count seam + Python
// oracle cases WITH inputs, generated by scripts/gen_parallel_processor_truth.py
// against the live oracle under scripts/pp_freeze_seams) VERBATIM through
// the ported Go functions, in the recorded call order (rows touch the
// global processor lifecycle). A divergence fails the port, not the oracle.
import (
_ "embed"
"encoding/json"
"strings"
"testing"
"time"
)
//go:embed truth.json
var frozenTruthJSON string
// TestFrozenTruthReplay — the frozen oracle truth, verbatim, against the
// ported functions.
func TestFrozenTruthReplay(t *testing.T) {
t.Setenv("PP_ACTIVE_THREADS", "4")
fails, count := runTruthBytes([]byte(frozenTruthJSON))
if count == 0 {
t.Fatal("no truth cases — the parity gate is empty")
}
for _, f := range fails {
t.Error(f)
}
if len(fails) == 0 {
t.Logf("PARITY OK: %d cases exact-equal vs the Python oracle", count)
}
}
// TestRunParallelOrderAndErrorEnvelopes — submission-order results under
// staggered completion, and the oracle's error-envelope degradation.
func TestRunParallelOrderAndErrorEnvelopes(t *testing.T) {
t.Setenv("PP_ACTIVE_THREADS", "4")
p := NewParallelProcessor(4)
got := p.RunParallel([]interface{}{
specCallable{fn: "sleepret", ms: 60, ret: "a"},
specCallable{fn: "sleepret", ms: 10, ret: "b"},
specCallable{fn: "boom", msg: "kaput"},
specCallable{fn: "const", ret: 7},
42, // non-callable -> worker TypeError text
})
want := `[` +
`"a",` +
`"b",` +
`{"error":"kaput"},` +
`7,` +
`{"error":"'int' object is not callable"}]`
if s := mustJSON(got); s != want {
t.Errorf("RunParallel:\n got %s\nwant %s", s, want)
}
if got := p.RunParallel([]interface{}{}); mustJSON(got) != "[]" {
t.Errorf("empty tasks: got %s want []", mustJSON(got))
}
}
// TestRunParallelWithArgsBranchMatrix — every parse branch's exact
// Python-shaped error string and normalization rule.
func TestRunParallelWithArgsBranchMatrix(t *testing.T) {
t.Setenv("PP_ACTIVE_THREADS", "4")
p := NewParallelProcessor(4)
got := p.RunParallelWithArgs([]ArgsTask{
{Kind: "call", Fn: "add", Args: []interface{}{json.Number("1"), json.Number("2")}},
{Kind: "call", Fn: "add", Args: []interface{}{json.Number("1.5"), json.Number("2")}},
{Kind: "call", Fn: "echo"},
{Kind: "raw", Value: json.Number("42")},
{Kind: "raw", Value: "x"},
{Kind: "raw", Value: nil},
{Kind: "emptytuple"},
{Kind: "notcall", Value: json.Number("42")},
{Kind: "notcall", Value: "x"},
{Kind: "notcall", Value: nil},
{Kind: "notcall", Value: true},
{Kind: "notcall", Value: json.Number("4.5")},
{Kind: "notcall", Value: []interface{}{json.Number("1"), json.Number("2")}},
{Kind: "argsnotseq", Fn: "echo", Value: "ab"},
{Kind: "argsnotseq", Fn: "echo", Value: json.Number("5")},
{Kind: "kwnotdict", Fn: "echo", Value: []interface{}{"a"}},
})
want := `[3,3.5,{"args":[],"kwargs":{}},` +
`{"error":"task 3: expected tuple, got int"},` +
`{"error":"task 4: expected tuple, got str"},` +
`{"error":"task 5: expected tuple, got NoneType"},` +
`{"error":"task 6: expected tuple, got tuple"},` +
`{"error":"task 7: 42 is not callable"},` +
`{"error":"task 8: 'x' is not callable"},` +
`{"error":"task 9: None is not callable"},` +
`{"error":"task 10: True is not callable"},` +
`{"error":"task 11: 4.5 is not callable"},` +
`{"error":"task 12: [1, 2] is not callable"},` +
`{"args":["ab"],"kwargs":{}},` +
`{"args":[5],"kwargs":{}},` +
`{"args":[],"kwargs":{}}]`
if s := mustJSON(got); s != want {
t.Errorf("RunParallelWithArgs:\n got %s\nwant %s", s, want)
}
}
// TestPoolLifecycle — constructor crash parity, submit-after-shutdown
// crash parity, and the global processor's singleton/reset cycle.
func TestPoolLifecycle(t *testing.T) {
t.Setenv("PP_ACTIVE_THREADS", "4")
if raised := recoverStr(func() { NewParallelProcessor(0) }); raised != "max_workers must be greater than 0" {
t.Errorf("NewParallelProcessor(0): got %q want max_workers must be greater than 0", raised)
}
p := NewParallelProcessor(2)
p.Shutdown(true)
if raised := recoverStr(func() { p.RunParallel([]interface{}{specCallable{fn: "const", ret: 1}}) }); raised != "cannot schedule new futures after shutdown" {
t.Errorf("RunParallel after Shutdown: got %q want cannot schedule new futures after shutdown", raised)
}
// get_status still works on a shut-down processor (the oracle reads
// only max_workers/active_count)
if s := mustJSON(p.GetStatus()); s != `{"active_threads":4,"max_workers":2,"pool_threads":2}` {
t.Errorf("GetStatus after Shutdown: got %s", s)
}
a, b := GetProcessor(), GetProcessor()
if a != b {
t.Error("GetProcessor must return the singleton")
}
ShutdownProcessor()
c := GetProcessor()
if c == a {
t.Error("ShutdownProcessor must clear the global for lazy re-create")
}
if s := mustJSON(c.GetStatus()); s != `{"active_threads":4,"max_workers":4,"pool_threads":4}` {
t.Errorf("re-created global GetStatus: got %s", s)
}
}
// TestPoolBoundedAtMaxWorkers — concurrency is capped at max_workers:
// with 1 worker, staggered tasks serialize (the slowest-first set takes
// at least the sum of sleeps, not the max).
func TestPoolBoundedAtMaxWorkers(t *testing.T) {
p := NewParallelProcessor(1)
start := time.Now()
p.RunParallel([]interface{}{
specCallable{fn: "sleepret", ms: 40, ret: "a"},
specCallable{fn: "sleepret", ms: 40, ret: "b"},
})
if elapsed := time.Since(start); elapsed < 75*time.Millisecond {
t.Errorf("single-worker pool ran tasks concurrently: %v", elapsed)
}
}
func recoverStr(f func()) (msg string) {
defer func() { msg = pyExcStr(recover()) }()
f()
return ""
}
func mustJSON(v interface{}) string {
c, err := canonical(v)
if err != nil {
panic(err)
}
return strings.TrimSpace(mustMarshal(c))
}
func mustMarshal(v interface{}) string {
b, err := json.Marshal(v)
if err != nil {
panic(err)
}
return string(b)
}
+72
View File
@@ -0,0 +1,72 @@
package main
// chat.go — the R2 W5b chat surface (Go CLI extra beyond the Python
// oracle's generate; kept for the existing CLI contract).
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func (reg *ProviderRegistry) chat(providerName, model, message string) (string, error) {
p := reg.GetProvider(providerName)
if p == nil {
return "", fmt.Errorf("provider %q not found", providerName)
}
client := &http.Client{Timeout: 300 * time.Second}
var requestBody map[string]any
var url string
switch p.ProviderType {
case "ollama":
url = p.URL + "/api/chat"
requestBody = map[string]any{
"model": model, "messages": []map[string]string{{"role": "user", "content": message}},
"stream": false,
}
case "openai":
url = p.URL + "/v1/chat/completions"
requestBody = map[string]any{
"model": model, "messages": []map[string]string{{"role": "user", "content": message}},
}
default:
return "", fmt.Errorf("unsupported provider type: %s", p.ProviderType)
}
data, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", url, bytes.NewReader(data))
req.Header.Set("Content-Type", "application/json")
if p.APIKey != "" {
req.Header.Set("Authorization", "Bearer "+p.APIKey)
}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
// Parse response based on provider type
var result map[string]any
json.Unmarshal(body, &result)
if content, ok := result["content"].(string); ok {
return content, nil // Ollama format
}
if choices, ok := result["choices"].([]any); ok && len(choices) > 0 {
if choice, ok := choices[0].(map[string]any); ok {
if msg, ok := choice["message"].(map[string]any); ok {
if content, ok := msg["content"].(string); ok {
return content, nil // [OI] format
}
}
}
}
return string(body), nil
}
+10 -5
View File
@@ -1,16 +1,16 @@
package main
// format.go — factory batch 5: the tool-format surfaces of
// provider_registry.py (FormatToolsOpenAI / FormatToolsAnthropic — the
// provider-facing adapters; pure shape transforms).
// format.go — factory batch 5 + factory-gap-pr: the tool-format surfaces
// of provider_registry.py (_format_tools_openai / _format_tools_anthropic —
// the provider-facing adapters; pure shape transforms).
import (
"encoding/json"
"fmt"
)
// FormatToolsOpenAI — [OI] API shape.
func FormatToolsOpenAI(tools []map[string]interface{}) []map[string]interface{} {
// FormatTools — the _format_tools_openai core ([OI] API shape).
func FormatTools(tools []map[string]interface{}) []map[string]interface{} {
out := make([]map[string]interface{}, 0, len(tools))
for _, tool := range tools {
name, _ := tool["name"].(string)
@@ -31,6 +31,11 @@ func FormatToolsOpenAI(tools []map[string]interface{}) []map[string]interface{}
return out
}
// FormatToolsOpenai — _format_tools_openai parity name.
func FormatToolsOpenai(tools []map[string]interface{}) []map[string]interface{} {
return FormatTools(tools)
}
// FormatToolsAnthropic — Anthropic API shape.
func FormatToolsAnthropic(tools []map[string]interface{}) []map[string]interface{} {
out := make([]map[string]interface{}, 0, len(tools))
+42 -183
View File
@@ -1,6 +1,9 @@
// provider-registry — Go provider registry (R2 W5b deep port).
// provider-registry — Go provider registry (R2 W5b deep port,
// factory-gap-pr gap-closure: the full provider_registry.py surface).
// PARITY port of src/rune/provider_registry.py: connect, disconnect,
// list_providers, get_provider, list_models (Ollama + OpenAI + Anthropic).
// list_providers, get_provider, list_models (Ollama + [OI] + Anthropic),
// generate (Ollama + [OI] + Anthropic with native tool calling),
// _ctx_budget, get_registry, connect_provider, list_all_models.
//
// Usage:
//
@@ -9,190 +12,24 @@
// provider-registry list
// provider-registry models <name>
// provider-registry chat <provider-name> <model> <message>
// provider-registry generate <prompt> [--provider <name>] [--model <model>]
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
"os"
"strings"
"sync"
"time"
)
type ModelProvider struct {
Name string `json:"name"`
URL string `json:"url"`
ProviderType string `json:"provider_type"` // openai, ollama, anthropic
APIKey string `json:"api_key,omitempty"`
Active bool `json:"active"`
}
type ProviderRegistry struct {
mu sync.RWMutex
Providers map[string]ModelProvider `json:"providers"`
ConfigPath string `json:"config_path"`
}
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
func configPath() string {
home := os.Getenv("RUNE_MEMORY_DIR")
if home == "" {
home = os.Getenv("HOME") + "/.rune"
}
return home + "/provider_registry.json"
}
func loadRegistry() *ProviderRegistry {
reg := &ProviderRegistry{Providers: make(map[string]ModelProvider)}
if data, err := os.ReadFile(configPath()); err == nil {
json.Unmarshal(data, reg)
}
return reg
}
func saveRegistry(reg *ProviderRegistry) {
// Marshal ONLY durable state — the embedded sync.RWMutex must never be
// copied (go vet copies-lock) and is not persisted state.
data, _ := json.MarshalIndent(struct {
Providers map[string]ModelProvider `json:"providers"`
ConfigPath string `json:"config_path"`
}{Providers: reg.Providers, ConfigPath: reg.ConfigPath}, "", " ")
os.WriteFile(configPath(), data, 0600)
}
func (reg *ProviderRegistry) connect(name, url, providerType, apiKey string) ModelProvider {
provider := ModelProvider{
Name: name, URL: url, ProviderType: providerType,
APIKey: apiKey, Active: true,
}
reg.mu.Lock()
reg.Providers[name] = provider
reg.mu.Unlock()
saveRegistry(reg)
return provider
}
func (reg *ProviderRegistry) fetchModels(provider ModelProvider) ([]string, error) {
client := &http.Client{Timeout: 15 * time.Second}
var models []string
switch provider.ProviderType {
case "ollama":
resp, err := client.Get(provider.URL + "/api/tags")
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Models []struct {
Name string `json:"name"`
} `json:"models"`
}
json.NewDecoder(resp.Body).Decode(&result)
for _, m := range result.Models {
models = append(models, cleanModelName(m.Name))
}
case "openai", "anthropic":
req, _ := http.NewRequest("GET", provider.URL+"/v1/models", nil)
if provider.APIKey != "" {
req.Header.Set("Authorization", "Bearer "+provider.APIKey)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Data []struct {
ID string `json:"id"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
for _, m := range result.Data {
models = append(models, cleanModelName(m.ID))
}
}
return models, nil
}
func cleanModelName(name string) string {
// Strip common prefixes
name = strings.TrimPrefix(name, "models/")
return name
}
func (reg *ProviderRegistry) chat(providerName, model, message string) (string, error) {
reg.mu.RLock()
provider, ok := reg.Providers[providerName]
reg.mu.RUnlock()
if !ok {
return "", fmt.Errorf("provider %q not found", providerName)
}
client := &http.Client{Timeout: 300 * time.Second}
var requestBody map[string]interface{}
var url string
switch provider.ProviderType {
case "ollama":
url = provider.URL + "/api/chat"
requestBody = map[string]interface{}{
"model": model, "messages": []map[string]string{{"role": "user", "content": message}},
"stream": false,
}
case "openai":
url = provider.URL + "/v1/chat/completions"
requestBody = map[string]interface{}{
"model": model, "messages": []map[string]string{{"role": "user", "content": message}},
}
default:
return "", fmt.Errorf("unsupported provider type: %s", provider.ProviderType)
}
data, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", url, bytes.NewReader(data))
req.Header.Set("Content-Type", "application/json")
if provider.APIKey != "" {
req.Header.Set("Authorization", "Bearer "+provider.APIKey)
}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
// Parse response based on provider type
var result map[string]interface{}
json.Unmarshal(body, &result)
if content, ok := result["content"].(string); ok {
return content, nil // Ollama format
}
if choices, ok := result["choices"].([]interface{}); ok && len(choices) > 0 {
if choice, ok := choices[0].(map[string]interface{}); ok {
if msg, ok := choice["message"].(map[string]interface{}); ok {
if content, ok := msg["content"].(string); ok {
return content, nil // OpenAI format
}
}
}
}
return string(body), nil
return NewRegistry(defaultConfigPath())
}
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: provider-registry <connect|disconnect|list|models|chat> [args...]")
fmt.Fprintln(os.Stderr, "usage: provider-registry <connect|disconnect|list|models|chat|generate> [args...]")
os.Exit(1)
}
reg := loadRegistry()
@@ -206,7 +43,7 @@ func main() {
os.Exit(1)
}
name, url := args[0], args[1]
providerType := "ollama"
providerType := "openai" // the Python oracle's connect() default
apiKey := ""
if len(args) > 2 {
providerType = args[2]
@@ -214,8 +51,8 @@ func main() {
if len(args) > 3 {
apiKey = args[3]
}
provider := reg.connect(name, url, providerType, apiKey)
out, _ := json.MarshalIndent(provider, "", " ")
provider := reg.Connect(name, url, providerType, apiKey)
out, _ := json.MarshalIndent(provider.ToDict(), "", " ")
fmt.Println(string(out))
case "disconnect":
@@ -223,14 +60,11 @@ func main() {
fmt.Fprintln(os.Stderr, "usage: provider-registry disconnect <name>")
os.Exit(1)
}
reg.mu.Lock()
delete(reg.Providers, args[0])
reg.mu.Unlock()
saveRegistry(reg)
reg.Disconnect(args[0])
fmt.Println("disconnected:", args[0])
case "list":
for _, p := range reg.Providers {
for _, p := range reg.ListProviders() {
out, _ := json.Marshal(p)
fmt.Println(string(out))
}
@@ -240,12 +74,12 @@ func main() {
fmt.Fprintln(os.Stderr, "usage: provider-registry models <name>")
os.Exit(1)
}
provider, ok := reg.Providers[args[0]]
if !ok {
provider := reg.GetProvider(args[0])
if provider == nil {
fmt.Println("null")
return
}
models, err := reg.fetchModels(provider)
models, err := reg.FetchModels(provider)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
@@ -266,6 +100,31 @@ func main() {
out, _ := json.Marshal(map[string]string{"response": response})
fmt.Println(string(out))
case "generate":
fs := flag.NewFlagSet("generate", flag.ContinueOnError)
providerName := fs.String("provider", "", "provider name")
model := fs.String("model", "", "model id")
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "usage: provider-registry generate <prompt> [--provider <name>] [--model <model>]")
os.Exit(1)
}
if fs.NArg() < 1 {
fmt.Fprintln(os.Stderr, "usage: provider-registry generate <prompt> [--provider <name>] [--model <model>]")
os.Exit(1)
}
result := reg.Generate(fs.Arg(0), *providerName, *model, 500, 0.7, nil, nil)
if errText, ok := result["error"]; ok {
fmt.Printf("Error: %v\n", errText)
return
}
resp := pyStrOr(result["response"], "")
if len(resp) > 200 {
resp = resp[:200]
}
fmt.Printf("Response: %s...\n", resp)
fmt.Printf("Model: %v (%v)\n", result["model"], result["provider"])
fmt.Printf("Latency: %vms\n", result["latency_ms"])
default:
fmt.Fprintf(os.Stderr, "unknown command: %s\n", cmd)
os.Exit(1)
+257
View File
@@ -0,0 +1,257 @@
package main
// pyjson.go — Python json.dumps-compatible serialization for the
// tool-result `content` strings (json.dumps defaults: ", " / ": "
// separators, ensure_ascii=True) plus an order-preserving JSON parser
// so batteries can replay Python insertion-ordered objects verbatim.
import (
"encoding/json"
"fmt"
"math"
"strconv"
"strings"
"unicode/utf16"
)
// PyDict is an insertion-ordered object (Python dict semantics).
type PyDict struct {
Keys []string
Vals map[string]any
}
func NewPyDict() *PyDict { return &PyDict{Vals: map[string]any{}} }
func (d *PyDict) Set(k string, v any) {
if _, ok := d.Vals[k]; !ok {
d.Keys = append(d.Keys, k)
}
d.Vals[k] = v
}
func (d *PyDict) Get(k string) (any, bool) {
v, ok := d.Vals[k]
return v, ok
}
// PyDump — json.dumps(obj) with Python's default separators and
// ensure_ascii escaping. Maps serialize with sorted keys (Go map law);
// use PyDict where Python insertion order must be reproduced.
func PyDump(v any) string {
s, _ := pyDumpTry(v)
return s
}
// pyDumpTry reports (ok=false) when the value has no Python-JSON
// equivalent — the caller applies the oracle's degrade law.
func pyDumpTry(v any) (string, bool) {
var b strings.Builder
if err := pyWrite(&b, v); err != nil {
return "", false
}
return b.String(), true
}
func pyWrite(b *strings.Builder, v any) error {
switch x := v.(type) {
case nil:
b.WriteString("null")
case bool:
if x {
b.WriteString("true")
} else {
b.WriteString("false")
}
case string:
pyWriteString(b, x)
case int:
b.WriteString(strconv.Itoa(x))
case int64:
b.WriteString(strconv.FormatInt(x, 10))
case float64:
b.WriteString(pyFloat(x))
case json.Number:
b.WriteString(x.String())
case *PyDict:
b.WriteByte('{')
for i, k := range x.Keys {
if i > 0 {
b.WriteString(", ")
}
pyWriteString(b, k)
b.WriteString(": ")
pyWrite(b, x.Vals[k])
}
b.WriteByte('}')
case map[string]any:
keys := make([]string, 0, len(x))
for k := range x {
keys = append(keys, k)
}
sortStrings(keys)
b.WriteByte('{')
for i, k := range keys {
if i > 0 {
b.WriteString(", ")
}
pyWriteString(b, k)
b.WriteString(": ")
pyWrite(b, x[k])
}
b.WriteByte('}')
case []any:
b.WriteByte('[')
for i, e := range x {
if i > 0 {
b.WriteString(", ")
}
if err := pyWrite(b, e); err != nil {
return err
}
}
b.WriteByte(']')
case []map[string]any:
b.WriteByte('[')
for i, e := range x {
if i > 0 {
b.WriteString(", ")
}
if err := pyWrite(b, e); err != nil {
return err
}
}
b.WriteByte(']')
default:
// Unknown Go types have no Python json equivalent; the caller
// applies the oracle's degrade law.
return fmt.Errorf("type not JSON-serializable: %T", v)
}
return nil
}
const pyNonSerializable = "tool result not JSON serializable"
func pyFloat(f float64) string {
if f == math.Trunc(f) && math.Abs(f) < 1e15 {
return strconv.FormatFloat(f, 'f', 1, 64) // Python repr(2.0) → "2.0"
}
return strconv.FormatFloat(f, 'g', -1, 64)
}
func pyWriteString(b *strings.Builder, s string) {
b.WriteByte('"')
for _, r := range s {
switch r {
case '"':
b.WriteString("\\\"")
case '\\':
b.WriteString("\\\\")
case '\n':
b.WriteString("\\n")
case '\r':
b.WriteString("\\r")
case '\t':
b.WriteString("\\t")
case '\b':
b.WriteString("\\b")
case '\f':
b.WriteString("\\f")
default:
if r < 0x20 || r > 0x7e {
writeUnicodeEscape(b, r)
} else {
b.WriteRune(r)
}
}
}
b.WriteByte('"')
}
func writeUnicodeEscape(b *strings.Builder, r rune) {
if r > 0xffff {
hi, lo := utf16.EncodeRune(r)
fmt.Fprintf(b, "\\u%04x\\u%04x", hi, lo)
return
}
fmt.Fprintf(b, "\\u%04x", r)
}
func sortStrings(s []string) {
for i := 1; i < len(s); i++ {
for j := i; j > 0 && s[j] < s[j-1]; j-- {
s[j], s[j-1] = s[j-1], s[j]
}
}
}
// ParsePyJSON — order-preserving JSON decode: objects → *PyDict,
// arrays → []any, integral numbers → int, others → float64.
func ParsePyJSON(data []byte) (any, error) {
dec := json.NewDecoder(strings.NewReader(string(data)))
dec.UseNumber()
v, err := decodePyValue(dec)
if err != nil {
return nil, err
}
return v, nil
}
func decodePyValue(dec *json.Decoder) (any, error) {
tok, err := dec.Token()
if err != nil {
return nil, err
}
return decodePyToken(dec, tok)
}
func decodePyToken(dec *json.Decoder, tok json.Token) (any, error) {
switch t := tok.(type) {
case json.Delim:
switch t {
case '{':
d := NewPyDict()
for dec.More() {
keyTok, err := dec.Token()
if err != nil {
return nil, err
}
key, _ := keyTok.(string)
val, err := decodePyValue(dec)
if err != nil {
return nil, err
}
d.Set(key, val)
}
if _, err := dec.Token(); err != nil { // closing }
return nil, err
}
return d, nil
case '[':
arr := []any{}
for dec.More() {
val, err := decodePyValue(dec)
if err != nil {
return nil, err
}
arr = append(arr, val)
}
if _, err := dec.Token(); err != nil { // closing ]
return nil, err
}
return arr, nil
}
return nil, fmt.Errorf("unexpected delim %v", t)
case json.Number:
if n, err := t.Int64(); err == nil && !strings.ContainsAny(t.String(), ".eE") {
return int(n), nil
}
f, err := t.Float64()
if err != nil {
return nil, err
}
return f, nil
case string, bool, nil:
return tok, nil
}
return nil, fmt.Errorf("unexpected token %v", tok)
}
+853
View File
@@ -0,0 +1,853 @@
package main
// registry.go — factory-gap-pr: the provider_registry.py surface that
// main.go's R2 W5b port left uncovered (dichotomy wave #2479 tranche).
// Name-preserving parity port: every fn mirrors the Python oracle 1:1
// (_load_config, _save_config, connect, disconnect, list_providers,
// get_provider, list_models, _fetch_models, _fetch_ollama_models,
// _fetch_openai_models, _fetch_anthropic_models, _clean_model_name,
// to_dict, generate, _generate_ollama, _generate_openai,
// _generate_anthropic, get_registry, connect_provider, list_all_models,
// _ctx_budget). Network IO sits behind the injectable `Do` seam; the
// tool executor behind the ToolExecutorFunc seam — tests never touch a
// socket or the real executor.
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
)
// ModelProvider — parity shape of the Python ModelProvider dataclass.
type ModelProvider struct {
Name string `json:"name"`
URL string `json:"url"`
ProviderType string `json:"provider_type"` // "ollama", "openai", "anthropic", "custom"
APIKey string `json:"api_key,omitempty"`
Models []map[string]any `json:"models"`
Enabled bool `json:"enabled"`
LastHealthCheck string `json:"last_health_check,omitempty"`
HealthStatus string `json:"health_status"` // "healthy", "error", "unknown"
}
func NewProvider(name, url, providerType, apiKey string) *ModelProvider {
return &ModelProvider{
Name: name, URL: url, ProviderType: providerType,
APIKey: apiKey, Models: []map[string]any{},
Enabled: true, HealthStatus: "unknown",
}
}
// ProviderFromFields rebuilds a provider from a truth-row field map
// (the frozen snapshot shape of the Python dataclass).
func ProviderFromFields(f map[string]any) *ModelProvider {
p := NewProvider(pyStr(f["name"]), pyStr(f["url"]), pyStr(f["provider_type"]), pyStr(f["api_key"]))
p.Enabled = pyBoolOr(f["enabled"], true)
p.LastHealthCheck = pyStr(f["last_health_check"])
p.HealthStatus = pyStrOr(f["health_status"], "unknown")
if models, ok := f["models"].([]any); ok {
p.Models = []map[string]any{}
for _, m := range models {
if mm, ok := m.(map[string]any); ok {
p.Models = append(p.Models, mm)
}
}
}
return p
}
// ToDict — ModelProvider.to_dict (api_key and last_health_check are
// deliberately excluded — the Python oracle's masking law).
func (p *ModelProvider) ToDict() map[string]any {
models := p.Models
if models == nil {
models = []map[string]any{}
}
return map[string]any{
"name": p.Name, "url": p.URL, "provider_type": p.ProviderType,
"models": models, "enabled": p.Enabled,
"health_status": p.HealthStatus,
}
}
// ProviderRegistry — parity shape of the Python ProviderRegistry.
type ProviderRegistry struct {
mu sync.RWMutex
Providers map[string]*ModelProvider
ConfigPath string
order []string // insertion order (Python dict semantics)
// Do is the injectable HTTP seam: (url, body, headers, timeout) →
// response body. nil = real net/http transport.
Do func(url string, body []byte, headers map[string]string, timeout time.Duration) ([]byte, error)
}
func NewRegistry(configPath string) *ProviderRegistry {
reg := &ProviderRegistry{Providers: map[string]*ModelProvider{}, ConfigPath: configPath}
reg.LoadConfig()
return reg
}
// defaultConfigPath — the Python oracle's ~/.config/rune/providers.json.
// RUNE_REGISTRY_CONFIG overrides (tests); RUNE_MEMORY_DIR keeps the
// legacy Go CLI location working.
func defaultConfigPath() string {
if p := os.Getenv("RUNE_REGISTRY_CONFIG"); p != "" {
return p
}
if home := os.Getenv("RUNE_MEMORY_DIR"); home != "" {
return filepath.Join(home, "provider_registry.json")
}
home, err := os.UserHomeDir()
if err != nil {
return "providers.json"
}
return filepath.Join(home, ".config", "rune", "providers.json")
}
// providerFromConfigMap — the _load_config per-provider defaults law:
// url="", type="custom", api_key=None, enabled=True.
func providerFromConfigMap(name string, pc map[string]any) *ModelProvider {
p := NewProvider(name, pyStrOr(pc["url"], ""), pyStrOr(pc["type"], "custom"), pyStr(pc["api_key"]))
p.Enabled = pyBoolOr(pc["enabled"], true)
return p
}
// LoadConfig — ProviderRegistry._load_config. Missing file → empty
// registry; malformed JSON → warning + empty (best-effort degrade).
// Provider key order from the file is preserved (Python dict law).
func (reg *ProviderRegistry) LoadConfig() {
data, err := os.ReadFile(reg.ConfigPath)
if err != nil {
return // missing config is not an error — empty registry
}
keys, cfgs, err := decodeOrderedProviders(data)
if err != nil {
fmt.Printf("Warning: Could not load provider config: %v\n", err)
return
}
reg.mu.Lock()
defer reg.mu.Unlock()
reg.order = keys
for _, name := range keys {
reg.Providers[name] = providerFromConfigMap(name, cfgs[name])
}
}
// decodeOrderedProviders walks the JSON token stream so the providers'
// file order survives (Go map decode would discard it).
func decodeOrderedProviders(data []byte) ([]string, map[string]map[string]any, error) {
cfgs := map[string]map[string]any{}
dec := json.NewDecoder(bytes.NewReader(data))
tok, err := dec.Token()
if err != nil {
return nil, nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != '{' {
return nil, nil, fmt.Errorf("config root is not an object")
}
var keys []string
for dec.More() {
keyTok, err := dec.Token()
if err != nil {
return nil, nil, err
}
key, _ := keyTok.(string)
if key == "providers" {
tok, err := dec.Token()
if err != nil {
return nil, nil, err
}
if delim, ok := tok.(json.Delim); !ok || delim != '{' {
return nil, nil, fmt.Errorf("providers section is not an object")
}
for dec.More() {
nameTok, err := dec.Token()
if err != nil {
return nil, nil, err
}
name, _ := nameTok.(string)
var pc map[string]any
if err := dec.Decode(&pc); err != nil {
return nil, nil, err
}
if _, seen := cfgs[name]; !seen {
keys = append(keys, name)
}
cfgs[name] = pc
}
if _, err := dec.Token(); err != nil { // closing }
return nil, nil, err
}
} else {
var skip any
if err := dec.Decode(&skip); err != nil {
return nil, nil, err
}
}
}
return keys, cfgs, nil
}
// SaveConfig — ProviderRegistry._save_config: API keys are masked with
// "***" (never persisted in the clear), absent keys persist as null.
func (reg *ProviderRegistry) SaveConfig() error {
os.MkdirAll(filepath.Dir(reg.ConfigPath), 0o755)
providers := map[string]any{}
for name, p := range reg.Providers {
var apiKey any
if p.APIKey != "" {
apiKey = "***"
}
providers[name] = map[string]any{
"url": p.URL, "type": p.ProviderType,
"api_key": apiKey, "enabled": p.Enabled,
}
}
data, err := json.MarshalIndent(map[string]any{"providers": providers}, "", " ")
if err != nil {
return err
}
return os.WriteFile(reg.ConfigPath, data, 0o600)
}
// Connect — ProviderRegistry.connect (persists through SaveConfig).
func (reg *ProviderRegistry) Connect(name, url, providerType, apiKey string) *ModelProvider {
p := NewProvider(name, url, providerType, apiKey)
reg.mu.Lock()
if _, exists := reg.Providers[name]; !exists {
reg.order = append(reg.order, name)
}
reg.Providers[name] = p
reg.mu.Unlock()
reg.SaveConfig()
return p
}
// Disconnect — ProviderRegistry.disconnect: absent name is a no-op.
func (reg *ProviderRegistry) Disconnect(name string) {
reg.mu.Lock()
_, ok := reg.Providers[name]
if ok {
delete(reg.Providers, name)
for i, n := range reg.order {
if n == name {
reg.order = append(reg.order[:i], reg.order[i+1:]...)
break
}
}
}
reg.mu.Unlock()
if ok {
reg.SaveConfig()
}
}
// orderedNames — the Python dict law: providers iterate in insertion
// order (connect sequence, then config-file order on load).
func (reg *ProviderRegistry) orderedNames() []string {
reg.mu.RLock()
defer reg.mu.RUnlock()
names := make([]string, 0, len(reg.order))
seen := map[string]bool{}
for _, n := range reg.order {
if _, ok := reg.Providers[n]; ok && !seen[n] {
names = append(names, n)
seen[n] = true
}
}
return names
}
// ListProviders — ProviderRegistry.list_providers.
func (reg *ProviderRegistry) ListProviders() []map[string]any {
out := []map[string]any{}
for _, name := range reg.orderedNames() {
out = append(out, reg.Providers[name].ToDict())
}
return out
}
// GetProvider — ProviderRegistry.get_provider (nil when absent).
func (reg *ProviderRegistry) GetProvider(name string) *ModelProvider {
reg.mu.RLock()
defer reg.mu.RUnlock()
return reg.Providers[name]
}
// ListModels — ProviderRegistry.list_models: enabled providers only,
// per-provider fetch errors degrade to a warning (never crash), and
// every model dict is annotated with provider + provider_type.
// Phase B: fetches fan out concurrently; results and warnings are
// assembled in registry order, so output stays byte-identical to the
// sequential oracle regardless of goroutine completion order.
func (reg *ProviderRegistry) ListModels() []map[string]any {
type fetch struct {
p *ModelProvider
models []map[string]any
err error
}
fetches := []fetch{}
for _, name := range reg.orderedNames() {
if p := reg.Providers[name]; p != nil && p.Enabled {
fetches = append(fetches, fetch{p: p})
}
}
var wg sync.WaitGroup
for i := range fetches {
wg.Add(1)
go func(f *fetch) {
defer wg.Done()
f.models, f.err = reg.FetchModels(f.p)
}(&fetches[i])
}
wg.Wait()
all := []map[string]any{}
for _, f := range fetches {
if f.err != nil {
fmt.Printf("Warning: Could not fetch models from %s: %v\n", f.p.Name, f.err)
continue
}
for _, m := range f.models {
m["provider"] = f.p.Name
m["provider_type"] = f.p.ProviderType
all = append(all, m)
}
}
return all
}
// FetchModels — ProviderRegistry._fetch_models dispatch.
func (reg *ProviderRegistry) FetchModels(p *ModelProvider) ([]map[string]any, error) {
switch p.ProviderType {
case "ollama":
return reg.FetchOllamaModels(p)
case "openai":
return reg.FetchOpenaiModels(p)
case "anthropic":
return reg.FetchAnthropicModels(p)
default:
return []map[string]any{}, nil
}
}
// FetchOllamaModels — ProviderRegistry._fetch_ollama_models. Every
// failure (transport, decode, missing "name") is wrapped into the
// oracle's single "Ollama connection failed: …" error.
func (reg *ProviderRegistry) FetchOllamaModels(p *ModelProvider) ([]map[string]any, error) {
body, err := reg.httpDo(p.URL+"/api/tags", nil, nil, 5*time.Second)
if err != nil {
return nil, fmt.Errorf("Ollama connection failed: %v", err)
}
var data map[string]any
if err := json.Unmarshal(body, &data); err != nil {
return nil, fmt.Errorf("Ollama connection failed: %v", err)
}
models := []map[string]any{}
rawModels, _ := data["models"].([]any)
for _, rm := range rawModels {
m, _ := rm.(map[string]any)
if m == nil {
continue
}
nameVal, ok := m["name"]
if !ok {
return nil, fmt.Errorf("Ollama connection failed: %v", missingKeyErr("name"))
}
details, _ := m["details"].(map[string]any)
if details == nil {
details = map[string]any{}
}
models = append(models, map[string]any{
"name": pyStr(nameVal),
"display_name": CleanModelName(pyStr(nameVal)),
"size_gb": roundHalfEven(pyFloatOr(m["size"], 0)/(1024*1024*1024), 1),
"family": pyStrOr(details["family"], "unknown"),
"parameters": pyStrOr(details["parameter_size"], "unknown"),
})
}
return models, nil
}
// FetchOpenaiModels — ProviderRegistry._fetch_openai_models.
func (reg *ProviderRegistry) FetchOpenaiModels(p *ModelProvider) ([]map[string]any, error) {
headers := map[string]string{"Content-Type": "application/json"}
if p.APIKey != "" {
headers["Authorization"] = "Bearer " + p.APIKey
}
body, err := reg.httpDo(p.URL+"/v1/models", nil, headers, 10*time.Second)
if err != nil {
return nil, fmt.Errorf("[OI] API connection failed: %v", err)
}
var data map[string]any
if err := json.Unmarshal(body, &data); err != nil {
return nil, fmt.Errorf("[OI] API connection failed: %v", err)
}
models := []map[string]any{}
rawModels, _ := data["data"].([]any)
for _, rm := range rawModels {
m, _ := rm.(map[string]any)
if m == nil {
continue
}
id := pyStrOr(m["id"], "unknown")
models = append(models, map[string]any{
"name": id, "display_name": id, "size_gb": 0,
"family": "cloud", "parameters": "cloud",
})
}
return models, nil
}
// FetchAnthropicModels — ProviderRegistry._fetch_anthropic_models: the
// Anthropic API has no /v1/models, so the oracle returns its pinned
// static list (ported verbatim).
func (reg *ProviderRegistry) FetchAnthropicModels(p *ModelProvider) ([]map[string]any, error) {
return []map[string]any{
{"name": "claude-sonnet-4-20250514", "display_name": "Claude Sonnet 4", "size_gb": 0, "family": "cloud", "parameters": "cloud"},
{"name": "claude-3-5-sonnet-20241022", "display_name": "Claude 3.5 Sonnet", "size_gb": 0, "family": "cloud", "parameters": "cloud"},
{"name": "claude-3-5-haiku-20241022", "display_name": "Claude 3.5 Haiku", "size_gb": 0, "family": "cloud", "parameters": "cloud"},
}, nil
}
var (
cleanReFamilySize = regexp.MustCompile(`(?i)([A-Za-z]+[\d.]*)-?(\d+[BMb])`)
cleanReFamilyVers = regexp.MustCompile(`(?i)([A-Za-z]+)-(\d+)-(\d+[BMb])`)
)
// CleanModelName — the _clean_model_name delegation target
// (model_connect._clean_model_name), ported 1:1.
func CleanModelName(name string) string {
if strings.Contains(name, "/") && (strings.Contains(name, "hf.co") || strings.Contains(name, "huggingface")) {
parts := strings.Split(name, "/")
modelPart := name
if len(parts) >= 3 {
modelPart = parts[len(parts)-1]
}
if strings.Contains(modelPart, ":") {
modelPart = strings.Split(modelPart, ":")[0]
}
if m := cleanReFamilySize.FindStringSubmatch(modelPart); m != nil {
return m[1] + " " + strings.ToUpper(m[2])
}
if m := cleanReFamilyVers.FindStringSubmatch(modelPart); m != nil {
return m[1] + " " + m[2] + " " + strings.ToUpper(m[3])
}
for _, sep := range []string{"-", "_", "."} {
if strings.Contains(modelPart, sep) {
firstPart := strings.Split(modelPart, sep)[0]
if len(firstPart) > 3 {
return firstPart
}
}
}
if len(modelPart) > 30 {
return modelPart[:30]
}
return modelPart
}
return name
}
// Generate — ProviderRegistry.generate: provider lookup (named or first
// available), model autodetect via FetchModels, then the per-type
// generate dispatch. Unsupported types yield an error dict.
func (reg *ProviderRegistry) Generate(prompt string, providerName string, model string,
maxTokens int, temperature float64, systemPrompt *string, tools []map[string]any) map[string]any {
var p *ModelProvider
if providerName != "" {
p = reg.GetProvider(providerName)
if p == nil {
return map[string]any{"error": fmt.Sprintf("Provider not found: %s", providerName)}
}
} else {
names := reg.orderedNames()
if len(names) == 0 {
return map[string]any{"error": "No providers connected"}
}
p = reg.Providers[names[0]]
}
if model == "" {
models, err := reg.FetchModels(p)
if err != nil {
return map[string]any{"error": err.Error(), "model": model, "provider": p.Name}
}
if len(models) == 0 {
return map[string]any{"error": fmt.Sprintf("No models available from %s", p.Name)}
}
model = pyStr(models[0]["name"])
}
switch p.ProviderType {
case "ollama":
return reg.GenerateOllama(p, prompt, model, maxTokens, temperature)
case "openai":
return reg.GenerateOpenai(p, prompt, model, maxTokens, temperature, systemPrompt, tools)
case "anthropic":
return reg.GenerateAnthropic(p, prompt, model, maxTokens, temperature, systemPrompt, tools)
default:
return map[string]any{"error": fmt.Sprintf("Unsupported provider type: %s", p.ProviderType)}
}
}
// GenerateOllama — ProviderRegistry._generate_ollama. The num_ctx is
// model-aware (_ctx_budget parity — never a hardcoded 8192).
func (reg *ProviderRegistry) GenerateOllama(p *ModelProvider, prompt, model string,
maxTokens int, temperature float64) map[string]any {
start := time.Now()
payload := map[string]any{
"model": model, "prompt": prompt, "stream": false,
"options": map[string]any{
"temperature": temperature, "num_predict": maxTokens,
"num_ctx": CtxBudget(model),
},
}
body, _ := json.Marshal(payload)
respBody, err := reg.httpDo(p.URL+"/api/generate", body,
map[string]string{"Content-Type": "application/json"}, 120*time.Second)
if err != nil {
return map[string]any{"error": err.Error(), "model": model, "provider": p.Name}
}
var result map[string]any
json.Unmarshal(respBody, &result)
latency := int(time.Since(start).Milliseconds())
return map[string]any{
"response": strings.TrimSpace(pyStrOr(result["response"], "")),
"model": model,
"provider": p.Name,
"latency_ms": latency,
"tokens": pyIntOr(result["eval_count"], 0),
}
}
// GenerateOpenai — ProviderRegistry._generate_openai with native tool
// calling (tools → FormatToolsOpenai + tool_choice auto).
func (reg *ProviderRegistry) GenerateOpenai(p *ModelProvider, prompt, model string,
maxTokens int, temperature float64, systemPrompt *string, tools []map[string]any) map[string]any {
start := time.Now()
headers := map[string]string{"Content-Type": "application/json"}
if p.APIKey != "" {
headers["Authorization"] = "Bearer " + p.APIKey
}
messages := []map[string]any{}
if systemPrompt != nil {
messages = append(messages, map[string]any{"role": "system", "content": *systemPrompt})
}
messages = append(messages, map[string]any{"role": "user", "content": prompt})
data := map[string]any{
"model": model, "messages": messages,
"max_tokens": maxTokens, "temperature": temperature,
}
if len(tools) > 0 {
data["tools"] = FormatToolsOpenai(tools)
data["tool_choice"] = "auto"
}
body, _ := json.Marshal(data)
respBody, err := reg.httpDo(p.URL+"/v1/chat/completions", body, headers, 120*time.Second)
if err != nil {
return map[string]any{"error": err.Error(), "model": model, "provider": p.Name}
}
var result map[string]any
json.Unmarshal(respBody, &result)
latency := int(time.Since(start).Milliseconds())
// choice = result.get("choices", [{}])[0] — an empty choices list
// raises in the oracle and degrades to the error dict here too.
message := map[string]any{}
if choices, ok := result["choices"].([]any); ok {
if len(choices) == 0 {
return map[string]any{"error": "list index out of range", "model": model, "provider": p.Name}
}
if choice, ok := choices[0].(map[string]any); ok {
if msg, ok := choice["message"].(map[string]any); ok {
message = msg
}
}
}
toolCalls, _ := message["tool_calls"].([]any)
usage, _ := result["usage"].(map[string]any)
if usage == nil {
usage = map[string]any{}
}
if len(toolCalls) > 0 {
toolResults := ExecuteToolCalls(pyMaps(toolCalls))
return map[string]any{
"response": pyStrOr(message["content"], ""),
"tool_calls": pyAny(toolCalls),
"tool_results": toolResults,
"model": model,
"provider": p.Name,
"latency_ms": latency,
"tokens": pyIntOr(usage["total_tokens"], 0),
}
}
return map[string]any{
"response": strings.TrimSpace(pyStrOr(message["content"], "")),
"model": model,
"provider": p.Name,
"latency_ms": latency,
"tokens": pyIntOr(usage["total_tokens"], 0),
}
}
// GenerateAnthropic — ProviderRegistry._generate_anthropic with native
// tool calling (tools → FormatToolsAnthropic; no tool_choice).
func (reg *ProviderRegistry) GenerateAnthropic(p *ModelProvider, prompt, model string,
maxTokens int, temperature float64, systemPrompt *string, tools []map[string]any) map[string]any {
start := time.Now()
headers := map[string]string{
"Content-Type": "application/json",
"x-api-key": p.APIKey,
"anthropic-version": "2023-06-01",
}
data := map[string]any{
"model": model,
"max_tokens": maxTokens,
"messages": []map[string]any{{"role": "user", "content": prompt}},
}
if systemPrompt != nil {
data["system"] = *systemPrompt
}
if len(tools) > 0 {
data["tools"] = FormatToolsAnthropic(tools)
}
body, _ := json.Marshal(data)
respBody, err := reg.httpDo(p.URL+"/v1/messages", body, headers, 120*time.Second)
if err != nil {
return map[string]any{"error": err.Error(), "model": model, "provider": p.Name}
}
var result map[string]any
json.Unmarshal(respBody, &result)
latency := int(time.Since(start).Milliseconds())
content, _ := result["content"].([]any)
toolCalls := []any{}
responseText := ""
for _, blockAny := range content {
block, _ := blockAny.(map[string]any)
if block == nil {
continue
}
switch pyStrOr(block["type"], "") {
case "text":
responseText += pyStrOr(block["text"], "")
case "tool_use":
toolCalls = append(toolCalls, block)
}
}
usage, _ := result["usage"].(map[string]any)
if usage == nil {
usage = map[string]any{}
}
tokens := pyIntOr(usage["input_tokens"], 0) + pyIntOr(usage["output_tokens"], 0)
if len(toolCalls) > 0 {
toolResults := ExecuteToolCallsAnthropic(pyMaps(toolCalls))
return map[string]any{
"response": responseText,
"tool_calls": toolCalls,
"tool_results": toolResults,
"model": model,
"provider": p.Name,
"latency_ms": latency,
"tokens": tokens,
}
}
return map[string]any{
"response": strings.TrimSpace(responseText),
"model": model,
"provider": p.Name,
"latency_ms": latency,
"tokens": tokens,
}
}
// httpDo — the HTTP seam. reg.Do overrides; otherwise the real
// net/http transport (POST when body != nil, GET otherwise).
func (reg *ProviderRegistry) httpDo(url string, body []byte, headers map[string]string,
timeout time.Duration) ([]byte, error) {
if reg.Do != nil {
return reg.Do(url, body, headers, timeout)
}
client := &http.Client{Timeout: timeout}
var req *http.Request
var err error
if body != nil {
req, err = http.NewRequest("POST", url, bytes.NewReader(body))
} else {
req, err = http.NewRequest("GET", url, nil)
}
if err != nil {
return nil, err
}
for k, v := range headers {
req.Header.Set(k, v)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("HTTP Error %d: %s", resp.StatusCode, strings.TrimSpace(string(data)))
}
return data, nil
}
// ── global registry (get_registry / connect_provider / list_all_models) ──
var (
globalRegistryMu sync.Mutex
globalRegistry *ProviderRegistry
)
// GetRegistry — module get_registry (thread-safe singleton).
func GetRegistry() *ProviderRegistry {
globalRegistryMu.Lock()
defer globalRegistryMu.Unlock()
if globalRegistry == nil {
globalRegistry = NewRegistry(defaultConfigPath())
}
return globalRegistry
}
// ConnectProvider — module connect_provider.
func ConnectProvider(name, url, providerType, apiKey string) map[string]any {
if providerType == "" {
providerType = "openai"
}
p := GetRegistry().Connect(name, url, providerType, apiKey)
return p.ToDict()
}
// ListAllModels — module list_all_models.
func ListAllModels() []map[string]any {
return GetRegistry().ListModels()
}
// Generate — module-level generate (delegates to the global registry).
func Generate(prompt string, providerName string, model string, maxTokens int,
temperature float64, systemPrompt *string, tools []map[string]any) map[string]any {
return GetRegistry().Generate(prompt, providerName, model, maxTokens, temperature, systemPrompt, tools)
}
// ── _ctx_budget (#28: model-aware num_ctx, never hardcoded 8192) ─────────
type budgetProfile struct {
window int
local bool
}
// Mirrors model_registry.DEFAULT_PROFILES (id → context window, local).
var budgetProfiles = map[string]budgetProfile{
"deterministic": {0, true},
"qwen2.5:3b": {32768, true},
"qwen3:14b": {32768, true},
"qwen3.6:27b": {32768, true},
"mimo-v2.5-pro": {128000, false},
}
const (
outputReserve = 2048 // OUTPUT_RESERVE["default"]
toolResultReSe = 1024 // TOOL_RESULT_RESERVE
)
// CtxBudget — _ctx_budget: window − output_reserve − tool_reserve
// (tool reserve only for non-local), floored at 1024. Unknown models
// get the conservative 8192 window.
func CtxBudget(modelID string) int {
window := 8192
local := true
if p, ok := budgetProfiles[modelID]; ok {
window = p.window
if window == 0 {
window = 8192
}
local = p.local
}
toolReserve := 0
if !local {
toolReserve = toolResultReSe
}
numCtx := window - outputReserve - toolReserve
if numCtx < 1024 {
numCtx = 1024
}
return numCtx
}
// ── small parity helpers ─────────────────────────────────────────────────
func pyStr(v any) string {
if s, ok := v.(string); ok {
return s
}
return ""
}
func pyStrOr(v any, def string) string {
if s, ok := v.(string); ok {
return s
}
return def
}
func pyBoolOr(v any, def bool) bool {
if b, ok := v.(bool); ok {
return b
}
return def
}
func pyFloatOr(v any, def float64) float64 {
switch n := v.(type) {
case float64:
return n
case int:
return float64(n)
default:
return def
}
}
func pyIntOr(v any, def int) int {
switch n := v.(type) {
case float64:
return int(n)
case int:
return n
default:
return def
}
}
func pyAny(v any) any { return v }
func pyMaps(items []any) []map[string]any {
out := make([]map[string]any, 0, len(items))
for _, it := range items {
if m, ok := it.(map[string]any); ok {
out = append(out, m)
}
}
return out
}
// missingKeyErr — str(KeyError(k)) is quoted in Python.
func missingKeyErr(k string) string { return "'" + k + "'" }
// roundHalfEven — Python round(): banker's rounding at the digit.
func roundHalfEven(x float64, digits int) float64 {
shift := math.Pow(10, float64(digits))
return math.RoundToEven(x*shift) / shift
}
+95
View File
@@ -0,0 +1,95 @@
package main
// toolcalls.go — _execute_tool_calls / _execute_tool_calls_anthropic
// parity (factory-gap-pr). The tool executor is the IO seam: tests
// inject ToolExecutorFunc; production wires the local tool runtime.
// Shaping law (1:1 with the oracle): [OI] calls carry
// function.name + function.arguments (a JSON string that degrades to {}
// on decode failure); Anthropic calls carry name + input. Every result
// is json.dumps'd — a non-serializable result degrades to the fixed
// error marker (the oracle's PreparedTool crash fix), never aborts the
// loop.
import "encoding/json"
// ToolExecutorFunc is the injectable executor seam: name + args →
// result (any JSON-shape value). nil = no executor wired.
var ToolExecutorFunc func(name string, args map[string]any) (any, error)
func runTool(name string, args map[string]any) any {
if args == nil {
args = map[string]any{}
}
if ToolExecutorFunc == nil {
return map[string]any{"success": false, "error": "no tool executor wired"}
}
res, err := ToolExecutorFunc(name, args)
if err != nil {
return map[string]any{"success": false, "error": err.Error()}
}
return res
}
// pyDumpResult — json.dumps(result) with the oracle's degrade law:
// a result with no JSON-shape equivalent becomes the fixed error marker
// (insertion-ordered to match the Python fallback's byte shape).
func pyDumpResult(result any) string {
if s, ok := pyDumpTry(result); ok {
return s
}
d := NewPyDict()
d.Set("success", false)
d.Set("error", pyNonSerializable)
return PyDump(d)
}
// ExecuteToolCalls — _execute_tool_calls.
func ExecuteToolCalls(toolCalls []map[string]any) []map[string]any {
results := []map[string]any{}
for _, call := range toolCalls {
fn, _ := call["function"].(map[string]any)
if fn == nil {
fn = map[string]any{}
}
name := pyStrOr(fn["name"], "")
var args map[string]any
switch a := fn["arguments"].(type) {
case string:
var parsed any
if err := json.Unmarshal([]byte(a), &parsed); err == nil {
if m, ok := parsed.(map[string]any); ok {
args = m
} else {
args = map[string]any{}
}
} else {
args = map[string]any{}
}
case map[string]any:
args = a
default:
args = map[string]any{}
}
results = append(results, map[string]any{
"tool_call_id": pyStrOr(call["id"], ""),
"role": "tool",
"content": pyDumpResult(runTool(name, args)),
})
}
return results
}
// ExecuteToolCallsAnthropic — _execute_tool_calls_anthropic.
func ExecuteToolCallsAnthropic(toolCalls []map[string]any) []map[string]any {
results := []map[string]any{}
for _, call := range toolCalls {
name := pyStrOr(call["name"], "")
args, _ := call["input"].(map[string]any)
results = append(results, map[string]any{
"type": "tool_result",
"tool_use_id": pyStrOr(call["id"], ""),
"content": pyDumpResult(runTool(name, args)),
})
}
return results
}
+388
View File
@@ -0,0 +1,388 @@
[
{
"fn": "_format_tools_openai",
"args": [
[]
],
"kwargs": {},
"expected": []
},
{
"fn": "_format_tools_openai",
"args": [
[
{
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
}
]
],
"kwargs": {},
"expected": [
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
}
}
]
},
{
"fn": "_format_tools_openai",
"args": [
[
{
"name": "write_file"
}
]
],
"kwargs": {},
"expected": [
{
"type": "function",
"function": {
"name": "write_file",
"description": "",
"parameters": {
"type": "object",
"properties": {}
}
}
}
]
},
{
"fn": "_format_tools_openai",
"args": [
[
{
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
},
{
"name": "write_file"
}
]
],
"kwargs": {},
"expected": [
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
}
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "",
"parameters": {
"type": "object",
"properties": {}
}
}
}
]
},
{
"fn": "_format_tools_anthropic",
"args": [
[]
],
"kwargs": {},
"expected": []
},
{
"fn": "_format_tools_anthropic",
"args": [
[
{
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
}
]
],
"kwargs": {},
"expected": [
{
"name": "read_file",
"description": "Read a file",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
}
]
},
{
"fn": "_format_tools_anthropic",
"args": [
[
{
"name": "write_file"
}
]
],
"kwargs": {},
"expected": [
{
"name": "write_file",
"description": "",
"input_schema": {
"type": "object",
"properties": {}
}
}
]
},
{
"fn": "_format_tools_anthropic",
"args": [
[
{
"name": "read_file",
"description": "Read a file",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
},
{
"name": "write_file"
}
]
],
"kwargs": {},
"expected": [
{
"name": "read_file",
"description": "Read a file",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
}
}
},
{
"name": "write_file",
"description": "",
"input_schema": {
"type": "object",
"properties": {}
}
}
]
},
{
"fn": "_ctx_budget",
"args": [
"unknown-model-xyz"
],
"kwargs": {},
"expected": 6144
},
{
"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": "_execute_tool_calls",
"args": [
[
{
"id": "call_1",
"function": {
"name": "read_file",
"arguments": "{\"path\": \"/nonexistent/zzz.txt\"}"
}
}
]
],
"kwargs": {},
"expected": [
{
"tool_call_id": "call_1",
"role": "tool",
"content": "{\"success\": false, \"error\": \"Access denied: /nonexistent/zzz.txt is outside allowed directories\"}"
}
]
},
{
"fn": "_execute_tool_calls",
"args": [
[
{
"id": "call_2",
"function": {
"name": "read_file",
"arguments": "not-json"
}
}
]
],
"kwargs": {},
"expected": [
{
"tool_call_id": "call_2",
"role": "tool",
"content": "{\"success\": false, \"error\": \"Not a file: \"}"
}
]
},
{
"fn": "_execute_tool_calls",
"args": [
[
{
"id": "call_3",
"function": {
"name": "no_such_tool_xyz",
"arguments": "{}"
}
}
]
],
"kwargs": {},
"expected": [
{
"tool_call_id": "call_3",
"role": "tool",
"content": "{\"success\": false, \"error\": \"tool result not JSON serializable\"}"
}
]
},
{
"fn": "_execute_tool_calls_anthropic",
"args": [
[
{
"type": "tool_use",
"id": "tu_1",
"name": "read_file",
"input": {
"path": "/nonexistent/zzz.txt"
}
}
]
],
"kwargs": {},
"expected": [
{
"type": "tool_result",
"tool_use_id": "tu_1",
"content": "{\"success\": false, \"error\": \"Access denied: /nonexistent/zzz.txt is outside allowed directories\"}"
}
]
},
{
"fn": "_execute_tool_calls_anthropic",
"args": [
[
{
"type": "tool_use",
"id": "tu_2",
"name": "no_such_tool_xyz",
"input": {}
}
]
],
"kwargs": {},
"expected": [
{
"type": "tool_result",
"tool_use_id": "tu_2",
"content": "{\"success\": false, \"error\": \"tool result not JSON serializable\"}"
}
]
}
]
@@ -31,7 +31,7 @@ func TestFormatParity(t *testing.T) {
for _, c := range doc.Cases {
var got []map[string]interface{}
if c.Fn == "openai" {
got = FormatToolsOpenAI(tools)
got = FormatToolsOpenai(tools)
} else {
got = FormatToolsAnthropic(tools)
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,365 @@
package main
// truth_registry_test.go — factory-gap-pr parity gate for the
// ProviderRegistry method surface: replays truth_registry.json (frozen
// from the live Python oracle with urllib fully scripted by
// scripts/gen_provider_registry_truth.py) against the Go port. HTTP
// goes through the injected Do seam; config files live in per-test
// temp dirs. latency_ms is excluded on both sides (the oracle's clock
// is not injectable — no-clock law).
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"testing"
"time"
)
func dget(d *PyDict, k string) any {
if d == nil {
return nil
}
v, _ := d.Get(k)
return v
}
type capturedReq struct {
url string
body []byte
}
// buildRegistryFromInput constructs a registry from a truth row:
// providers inserted in frozen key order (ParsePyJSON preserves the
// Python dict order), HTTP routed through the scripted Do seam. The
// capture is mutex-guarded because ListModels fans fetches out
// concurrently.
func buildRegistryFromInput(t *testing.T, input *PyDict) (*ProviderRegistry, *[]capturedReq) {
t.Helper()
reg := NewRegistry(filepath.Join(t.TempDir(), "providers.json"))
captured := &[]capturedReq{}
var capMu sync.Mutex
if routesAny := dget(input, "routes"); routesAny != nil {
routes, _ := routesAny.([]any)
reg.Do = func(url string, body []byte, headers map[string]string, timeout time.Duration) ([]byte, error) {
for _, r := range routes {
route, _ := r.(*PyDict)
suffix, _ := dget(route, "suffix").(string)
if suffix != "" && len(url) >= len(suffix) && url[len(url)-len(suffix):] == suffix {
if exc, ok := dget(route, "exc").(string); ok {
return nil, &urlError{msg: exc}
}
capMu.Lock()
*captured = append(*captured, capturedReq{url: url, body: body})
capMu.Unlock()
return json.Marshal(plainJSON(dget(route, "body")))
}
}
return nil, &urlError{msg: "unexpected url: " + url}
}
}
if provsAny := dget(input, "providers"); provsAny != nil {
provs, _ := provsAny.(*PyDict)
if provs != nil {
for _, name := range provs.Keys {
fields, _ := provs.Vals[name].(*PyDict)
reg.Providers[name] = ProviderFromFields(plainJSON(fields).(map[string]any))
reg.order = append(reg.order, name)
}
}
}
return reg, captured
}
// urlError mirrors urllib.error.URLError's str(): "<urlopen error msg>".
type urlError struct{ msg string }
func (e *urlError) Error() string { return "<urlopen error " + e.msg + ">" }
func providerFieldsMap(p *ModelProvider) map[string]any {
var apiKey any
if p.APIKey != "" {
apiKey = p.APIKey
}
var lhc any
if p.LastHealthCheck != "" {
lhc = p.LastHealthCheck
}
return map[string]any{
"name": p.Name, "url": p.URL, "provider_type": p.ProviderType,
"api_key": apiKey, "enabled": p.Enabled,
"last_health_check": lhc, "health_status": p.HealthStatus,
"models": p.Models,
}
}
func providersState(reg *ProviderRegistry) map[string]any {
out := map[string]any{}
for name, p := range reg.Providers {
out[name] = providerFieldsMap(p)
}
return out
}
func readConfigIfPresent(t *testing.T, path string) (any, bool) {
t.Helper()
data, err := os.ReadFile(path)
if err != nil {
return nil, false
}
var cfg any
json.Unmarshal(data, &cfg)
return cfg, true
}
// unwrapExpected handles both frozen shapes: top-level expected_error
// (row()) and the nested {"expected_request", "expected"/"expected_error"}
// envelope (gen_case()).
func unwrapExpected(c *PyDict) (result, request any, errText string) {
if s, ok := dget(c, "expected_error").(string); ok && s != "" {
return nil, nil, s
}
exp := dget(c, "expected")
if em, ok := exp.(*PyDict); ok {
if _, isEnvelope := em.Get("expected_request"); isEnvelope {
if s, ok := dget(em, "expected_error").(string); ok {
return nil, dget(em, "expected_request"), s
}
return dget(em, "expected"), dget(em, "expected_request"), ""
}
}
return exp, nil, ""
}
func genArgs(input *PyDict) (prompt, model string, maxTokens int, temperature float64, systemPrompt *string, tools []map[string]any) {
prompt, _ = dget(input, "prompt").(string)
model, _ = dget(input, "model").(string)
maxTokens = pyIntOr(dget(input, "max_tokens"), 500)
temperature = pyFloatOr(dget(input, "temperature"), 0.7)
if sp, ok := dget(input, "system_prompt").(string); ok {
systemPrompt = &sp
}
if toolsAny, ok := dget(input, "tools").([]any); ok {
tools = pyMaps(plainJSON(toolsAny).([]any))
}
return
}
func stripLatency(m map[string]any) map[string]any {
out := map[string]any{}
for k, v := range m {
if k != "latency_ms" {
out[k] = v
}
}
return out
}
func TestRegistryTruthParity(t *testing.T) {
raw, err := ParsePyJSON(mustRead(t, "truth_registry.json"))
if err != nil {
t.Fatalf("truth_registry.json: %v", err)
}
cases, _ := raw.([]any)
for _, caseAny := range cases {
c, _ := caseAny.(*PyDict)
fn, _ := dget(c, "fn").(string)
name, _ := dget(c, "name").(string)
input, _ := dget(c, "input").(*PyDict)
t.Run(fn+"/"+name, func(t *testing.T) {
runRegistryCase(t, fn, name, input, c)
})
}
}
func mustRead(t *testing.T, name string) []byte {
t.Helper()
b, err := os.ReadFile(name)
if err != nil {
t.Fatalf("%s missing: %v", name, err)
}
return b
}
// scriptExecutorFromExpected installs a ToolExecutorFunc whose scripted
// results are the Python tool_executor outputs parsed back out of the
// frozen tool_results content strings. Returns a restore func.
func scriptExecutorFromExpected(t *testing.T, result any) func() {
t.Helper()
var scripted []any
if resMap, ok := plainJSON(result).(map[string]any); ok {
if trs, ok := resMap["tool_results"].([]any); ok {
for _, tr := range trs {
trm, _ := tr.(map[string]any)
content, _ := trm["content"].(string)
parsed, err := ParsePyJSON([]byte(content))
if err != nil {
t.Fatalf("tool result content parse: %v", err)
}
scripted = append(scripted, parsed)
}
}
}
oldExec := ToolExecutorFunc
ToolExecutorFunc = func(name string, args map[string]any) (any, error) {
if len(scripted) == 0 {
t.Errorf("unexpected extra tool call %q", name)
return nil, nil
}
r := scripted[0]
scripted = scripted[1:]
return r, nil
}
return func() { ToolExecutorFunc = oldExec }
}
func runRegistryCase(t *testing.T, fn, name string, input *PyDict, c *PyDict) {
t.Helper()
result, request, errText := unwrapExpected(c)
switch fn {
case "to_dict":
fields, _ := plainJSON(dget(input, "provider")).(map[string]any)
p := ProviderFromFields(fields)
compareJSON(t, name, p.ToDict(), result)
case "_load_config":
path := filepath.Join(t.TempDir(), "providers.json")
if content := dget(input, "content"); content != nil {
b, _ := json.Marshal(plainJSON(content))
os.WriteFile(path, b, 0o600)
}
reg := NewRegistry(path)
compareJSON(t, name, map[string]any{"providers": providersState(reg)}, result)
case "_save_config":
reg, _ := buildRegistryFromInput(t, input)
reg.SaveConfig()
cfg, ok := readConfigIfPresent(t, reg.ConfigPath)
if !ok {
t.Fatalf("%s: config file not written", name)
}
compareJSON(t, name, map[string]any{"written": cfg}, result)
case "connect":
reg := NewRegistry(filepath.Join(t.TempDir(), "providers.json"))
p := reg.Connect(dget(input, "name").(string), dget(input, "url").(string),
dget(input, "provider_type").(string), dget(input, "api_key").(string))
got := map[string]any{"provider": p.ToDict()}
if cfg, ok := readConfigIfPresent(t, reg.ConfigPath); ok {
got["config"] = cfg
}
compareJSON(t, name, got, result)
case "list_providers":
reg, _ := buildRegistryFromInput(t, input)
compareJSON(t, name, map[string]any{"providers": reg.ListProviders()}, result)
case "get_provider":
reg, _ := buildRegistryFromInput(t, input)
p := reg.GetProvider(dget(input, "name").(string))
var pv any
if p != nil {
pv = p.ToDict()
}
compareJSON(t, name, map[string]any{"provider": pv}, result)
case "disconnect":
reg, _ := buildRegistryFromInput(t, input)
if seed := dget(input, "seed_config"); seed != nil {
b, _ := json.Marshal(plainJSON(seed))
os.WriteFile(reg.ConfigPath, b, 0o600)
}
reg.Disconnect(dget(input, "name").(string))
got := map[string]any{"providers": providersState(reg)}
if _, wantConfig := dget(c, "expected").(*PyDict).Get("config"); wantConfig {
if cfg, ok := readConfigIfPresent(t, reg.ConfigPath); ok {
got["config"] = cfg
}
}
compareJSON(t, name, got, result)
case "_clean_model_name":
cn, _ := dget(input, "name").(string)
compareJSON(t, name, CleanModelName(cn), result)
case "_fetch_ollama_models", "_fetch_openai_models", "_fetch_anthropic_models", "_fetch_models":
reg, _ := buildRegistryFromInput(t, input)
fields, _ := plainJSON(dget(input, "provider")).(map[string]any)
p := ProviderFromFields(fields)
got, err := reg.FetchModels(p)
switch fn {
case "_fetch_ollama_models":
got, err = reg.FetchOllamaModels(p)
case "_fetch_openai_models":
got, err = reg.FetchOpenaiModels(p)
case "_fetch_anthropic_models":
got, err = reg.FetchAnthropicModels(p)
}
if errText != "" {
if err == nil {
t.Errorf("%s: want error %q, got none", name, errText)
} else if err.Error() != errText {
t.Errorf("%s: error:\n got %q\nwant %q", name, err.Error(), errText)
}
return
}
if err != nil {
t.Fatalf("%s: unexpected error: %v", name, err)
}
compareJSON(t, name, got, result)
case "list_models":
reg, _ := buildRegistryFromInput(t, input)
compareJSON(t, name, reg.ListModels(), result)
case "generate":
reg, _ := buildRegistryFromInput(t, input)
prompt, _ := dget(input, "prompt").(string)
providerName, _ := dget(input, "provider_name").(string)
model, _ := dget(input, "model").(string)
got := reg.Generate(prompt, providerName, model, 500, 0.7, nil, nil)
compareJSON(t, name, got, result)
case "_generate_ollama", "_generate_openai", "_generate_anthropic":
reg, captured := buildRegistryFromInput(t, input)
fields, _ := plainJSON(dget(input, "provider")).(map[string]any)
p := ProviderFromFields(fields)
prompt, model, maxTokens, temperature, systemPrompt, tools := genArgs(input)
if result != nil {
defer scriptExecutorFromExpected(t, result)()
}
var got map[string]any
switch fn {
case "_generate_ollama":
got = reg.GenerateOllama(p, prompt, model, maxTokens, temperature)
case "_generate_openai":
got = reg.GenerateOpenai(p, prompt, model, maxTokens, temperature, systemPrompt, tools)
case "_generate_anthropic":
got = reg.GenerateAnthropic(p, prompt, model, maxTokens, temperature, systemPrompt, tools)
}
if request == nil {
if len(*captured) != 0 {
t.Errorf("%s: expected no HTTP call, captured %d", name, len(*captured))
}
} else {
if len(*captured) == 0 {
t.Fatalf("%s: expected an HTTP call, captured none", name)
}
var gotReq any
json.Unmarshal((*captured)[0].body, &gotReq)
compareJSON(t, name+"/request", gotReq, request)
}
if errText != "" {
if gotErr, ok := got["error"].(string); !ok || gotErr != errText {
t.Errorf("%s: error:\n got %v\nwant %q", name, got["error"], errText)
}
return
}
compareJSON(t, name, stripLatency(got), result)
default:
t.Errorf("unhandled frozen fn %s", fn)
}
}
+151
View File
@@ -0,0 +1,151 @@
package main
// truth_test.go — factory-gap-pr parity gate: replays the frozen
// oracle truth (truth.json, generated by scripts/
// gen_provider_registry_truth.py via the shared freeze_truth harness)
// VERBATIM against the Go port. The tool executor is the injected seam
// — its scripted results are the Python tool_executor outputs parsed
// back out of the frozen content strings, so the battery never touches
// the real executor and never hits a socket.
import (
"encoding/json"
"os"
"testing"
)
func loadTruthFile(t *testing.T, name string, dst any) {
t.Helper()
b, err := os.ReadFile(name)
if err != nil {
t.Fatalf("%s missing: %v", name, err)
}
if err := json.Unmarshal(b, dst); err != nil {
t.Fatalf("%s: %v", name, err)
}
}
func compareJSON(t *testing.T, name string, got, want any) {
t.Helper()
gb, _ := json.Marshal(got)
wb, _ := json.Marshal(plainJSON(want))
if string(gb) != string(wb) {
t.Errorf("%s:\n got %q\nwant %q", name, gb, wb)
}
}
// plainJSON converts PyDict (order-preserving decode) back to plain
// maps for order-insensitive comparison.
func plainJSON(v any) any {
switch x := v.(type) {
case *PyDict:
m := map[string]any{}
for _, k := range x.Keys {
m[k] = plainJSON(x.Vals[k])
}
return m
case []any:
out := make([]any, len(x))
for i, e := range x {
out[i] = plainJSON(e)
}
return out
case []map[string]any:
out := make([]any, len(x))
for i, e := range x {
out[i] = plainJSON(e)
}
return out
default:
return v
}
}
func TestHarnessTruthParity(t *testing.T) {
var cases []struct {
Fn string `json:"fn"`
Args []any `json:"args"`
Kwargs map[string]any `json:"kwargs"`
Expected any `json:"expected"`
}
loadTruthFile(t, "truth.json", &cases)
for _, c := range cases {
switch c.Fn {
case "_format_tools_openai":
compareJSON(t, c.Fn, FormatToolsOpenai(argsTools(c.Args)), c.Expected)
case "_format_tools_anthropic":
compareJSON(t, c.Fn, FormatToolsAnthropic(argsTools(c.Args)), c.Expected)
case "_ctx_budget":
modelID, _ := c.Args[0].(string)
compareJSON(t, c.Fn, CtxBudget(modelID), c.Expected)
case "_execute_tool_calls", "_execute_tool_calls_anthropic":
expList, _ := c.Expected.([]any)
scripted := make([]any, len(expList))
for i, e := range expList {
em, _ := e.(map[string]any)
content, _ := em["content"].(string)
parsed, err := ParsePyJSON([]byte(content))
if err != nil {
t.Fatalf("%s case %d: content parse: %v", c.Fn, i, err)
}
scripted[i] = parsed
}
idx := 0
oldExec := ToolExecutorFunc
ToolExecutorFunc = func(name string, args map[string]any) (any, error) {
if idx >= len(scripted) {
t.Errorf("%s: unexpected extra tool call %q", c.Fn, name)
return nil, nil
}
r := scripted[idx]
idx++
return r, nil
}
var got []map[string]any
if c.Fn == "_execute_tool_calls_anthropic" {
got = ExecuteToolCallsAnthropic(argsTools(c.Args))
} else {
got = ExecuteToolCalls(argsTools(c.Args))
}
ToolExecutorFunc = oldExec
if idx != len(scripted) {
t.Errorf("%s: executor invoked %d times, want %d", c.Fn, idx, len(scripted))
}
compareJSON(t, c.Fn, got, c.Expected)
default:
t.Errorf("unhandled frozen fn %s", c.Fn)
}
}
}
// argsTools unwraps the single tool-list argument of the frozen
// _format_tools_* / _execute_tool_calls* cases.
func argsTools(args []any) []map[string]any {
if len(args) == 0 {
return nil
}
tools, _ := args[0].([]any)
return pyMaps(tools)
}
// TestExecuteToolCallsNonSerializableFallback — the Go-side branch of
// the oracle's PreparedTool degrade law: a tool result with no
// JSON-shape equivalent becomes the fixed error marker.
func TestExecuteToolCallsNonSerializableFallback(t *testing.T) {
oldExec := ToolExecutorFunc
defer func() { ToolExecutorFunc = oldExec }()
ToolExecutorFunc = func(name string, args map[string]any) (any, error) {
return make(chan int), nil // never JSON-serializable
}
got := ExecuteToolCalls([]map[string]any{{
"id": "c1",
"function": map[string]any{"name": "x", "arguments": "{}"},
}})
want := `{"success": false, "error": "tool result not JSON serializable"}`
if got[0]["content"] != want {
t.Errorf("content:\n got %v\nwant %s", got[0]["content"], want)
}
if got[0]["tool_call_id"] != "c1" || got[0]["role"] != "tool" {
t.Errorf("wrapper shape wrong: %v", got[0])
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
import json
from pathlib import Path
__version__ = "0.293.1"
__version__ = "0.299.0"
# One build identity (handoff 2026-09-10 §4): the semantic version above is
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
+1 -1
View File
@@ -233,7 +233,7 @@ def main() -> int:
)
check(
"Rune minor version advertises provisioning and restore verification",
'__version__ = "0.293.1"' in rune_version,
'__version__ = "0.299.0"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+10 -2
View File
@@ -92,11 +92,15 @@ def _execute_tool_calls(tool_calls: list) -> list:
args = {}
result = tool_executor.execute_tool(name, args)
try:
content = json.dumps(result)
except (TypeError, ValueError): # noqa: BLE001 — non-JSON tool results (e.g. PreparedTool) degrade to an error marker, never crash the loop
content = json.dumps({"success": False, "error": "tool result not JSON serializable"})
results.append(
{
"tool_call_id": call.get("id", ""),
"role": "tool",
"content": json.dumps(result),
"content": content,
}
)
return results
@@ -115,11 +119,15 @@ def _execute_tool_calls_anthropic(tool_calls: list) -> list:
args = call.get("input", {})
result = tool_executor.execute_tool(name, args)
try:
content = json.dumps(result)
except (TypeError, ValueError): # noqa: BLE001 — non-JSON tool results (e.g. PreparedTool) degrade to an error marker, never crash the loop
content = json.dumps({"success": False, "error": "tool result not JSON serializable"})
results.append(
{
"type": "tool_result",
"tool_use_id": call.get("id", ""),
"content": json.dumps(result),
"content": content,
}
)
return results
+2 -2
View File
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
This is not an interface. This is how I see, speak, and interact with the world.
Version: v0.293.1
Version: v0.299.0
Features: 41 (24 original + 17 new native commands)
Usage:
@@ -2037,7 +2037,7 @@ class RuneApp(App):
# Show version info
self.chat_channel.add_message(
"system",
f"[dim]Rune v0.293.1 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.299.0 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
+7
View File
@@ -190,6 +190,13 @@ def evaluate_salience(envelope: dict) -> SalienceDecision:
)
def evaluate_salience_dict(envelope: dict) -> dict:
"""JSON-view of evaluate_salience for the shared freeze harness
(dataclass results are not JSON-serializable there). A pure to_dict
composition — zero logic drift from the floor."""
return evaluate_salience(envelope).to_dict()
def test_salience():
"""Test the salience gate."""
print("Testing Salience Gate...")
+15
View File
@@ -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"
@@ -0,0 +1,256 @@
//! salience_gate branch battery — parity vs the frozen Python-oracle truth.
//!
//! Two truth views, one source, both embedded VERBATIM via include_str! —
//! never hand-transcribed:
//! * frozen_sg_truth.verify.json — the shared-harness case array
//! ([{fn, args, kwargs, expected}]) frozen with RUNE_SALIENCE_CORE=python
//! AND SG_RUST_LIB poisoned (pure-Python oracle floor, poisoned-truth
//! law). Byte-identical under
//! `freeze_truth.py --verify ... --module rune.salience_gate`.
//! * frozen_sg_truth.json — envelope carrying the same row schema for ALL
//! rows, including multi-family evaluate rows whose Python evaluation
//! order differs from the delegation path's sorted order (the kernel
//! mirrors the evaluation order — exact compare).
//!
//! Frozen via scripts/gen_salience_gate_truth.py. The oracle's parity
//! contract for flags/rationale order is sorted-comparison on the DELEGATION
//! path (oracle comment: "sorted comparison is the parity contract — the
//! canary pins it"); the kernel-side battery pins the stricter exact
//! evaluation order.
use serde_json::{json, Value};
use std::collections::BTreeMap;
use super::{
_sg_core, evaluate_decision, evaluate_salience, evaluate_salience_dict, flag_score,
handle_hook, test_salience, word_boundary_contains, SalienceDecision,
};
const ENVELOPE: &str = include_str!("frozen_sg_truth.json");
const VERIFY_TRUTH: &str = include_str!("frozen_sg_truth.verify.json");
fn envelope_cases() -> Vec<Value> {
serde_json::from_str::<Value>(ENVELOPE)
.expect("frozen truth envelope must parse")
.get("cases")
.and_then(|c| c.as_array())
.expect("envelope cases must be an array")
.clone()
}
fn verify_cases() -> Vec<Value> {
serde_json::from_str::<Value>(VERIFY_TRUTH)
.expect("frozen verify truth must parse")
.as_array()
.expect("verify truth must be the harness case array")
.clone()
}
fn rebuild_decision(recv: &Value) -> SalienceDecision {
let strs = |k: &str| -> Vec<String> {
recv[k]
.as_array()
.map(|a| {
a.iter()
.map(|v| v.as_str().expect("flag entries are strings").to_string())
.collect()
})
.unwrap_or_default()
};
SalienceDecision {
score: recv["score"].as_f64().expect("score is a number"),
flags: strs("flags"),
minimum_tier: recv["minimum_tier"]
.as_str()
.expect("minimum_tier is a string")
.to_string(),
witness_needed: recv["witness_needed"].as_bool().expect("witness is bool"),
rationale_codes: strs("rationale_codes"),
}
}
fn replay_row(case: &Value, label: &str) {
let fn_name = case["fn"].as_str().expect("row fn is a string");
let actual = match fn_name {
"evaluate_salience_dict" => evaluate_salience_dict(&case["args"][0]),
"evaluate_salience" => json!(evaluate_salience(&case["args"][0])),
"SalienceDecision.to_dict" => {
let decision = rebuild_decision(&case["recv"]);
// the harness rows carry {"result": to_dict(), <attr>…} — the
// parity contract is the result projection
Value::Object(serde_json::Map::from_iter(decision.to_dict()))
}
"handle_hook" => {
let event = &case["args"][0];
let data = if case["kwargs"].get("data").is_some() {
Some(case["kwargs"]["data"].clone())
} else {
None
};
handle_hook(event, data.as_ref())
}
"_sg_core" => {
// truth rows are frozen under the python pin — None branch
_sg_core(Some("python")).unwrap_or(Value::Null)
}
other => panic!("unhandled frozen fn: {} (~{} in battery)", other, label),
};
let expected = match case["expected"].get("result") {
Some(result) => result.clone(),
None => case["expected"].clone(),
};
assert!(
actual == expected,
"case {} diverged:\n actual: {}\n expected: {}",
label,
actual,
expected
);
}
fn canon_row(case: &Value) -> String {
serde_json::to_string(case).expect("row serializes")
}
#[test]
fn envelope_cases_superset_of_verify_file() {
let envelope: std::collections::HashSet<String> =
envelope_cases().iter().map(canon_row).collect();
for case in verify_cases() {
assert!(
envelope.contains(&canon_row(&case)),
"verify row missing from envelope (drift between the two views): {}",
canon_row(&case)
);
}
}
#[test]
fn envelope_parity_battery() {
for (i, case) in envelope_cases().iter().enumerate() {
replay_row(case, &format!("envelope[{}]", i));
}
}
#[test]
fn verify_file_parity_battery() {
for (i, case) in verify_cases().iter().enumerate() {
replay_row(case, &format!("verify[{}]", i));
}
}
#[test]
fn test_salience_oracle_smoke() {
test_salience();
}
#[test]
fn sg_core_pin_lattice() {
// kernel mirror of the facade probe: python pin honors the fallback,
// auto/None answer the core (same lattice as cognition_core's _cc_core).
assert!(_sg_core(Some("python")).is_none());
assert!(_sg_core(Some("auto")).is_some());
assert!(_sg_core(None).is_some());
let core = _sg_core(None).unwrap();
assert_eq!(core, json!("salience_gate"));
}
// ── retained facade unit tests (pre-gap-close surface) ──────────────────────
#[test]
fn test_emergency() {
let envelope =
json!({"authority_class": "emergency", "urgency": "normal", "payload": {"text": ""}});
let r = evaluate_salience(&envelope);
assert_eq!(r["minimum_tier"], "T3"); // oracle: 0.9 -> T3
assert_eq!(r["score"], 0.9);
}
#[test]
fn test_trivial() {
let envelope = json!({"authority_class": "conversation", "urgency": "normal", "payload": {"text": "hello"}});
let r = evaluate_salience(&envelope);
assert_eq!(r["minimum_tier"], "T0");
}
#[test]
fn flag_score_all_known() {
// all known flags return a score
for flag in [
"EMERGENCY",
"OWNER_CORRECTION",
"DIRECTIVE",
"TASK_FAILURE",
"REPEATED_RETRY",
"HIGH_UNCERTAINTY",
"NOVEL_CAPABILITY",
"TRIVIAL",
] {
let s = flag_score(flag);
assert!(s >= 0.0, "{}: score must be non-negative", flag);
}
}
#[test]
fn flag_score_unknown_zero() {
assert_eq!(flag_score("UNKNOWN_FLAG"), 0.0);
}
#[test]
fn evaluate_salience_object() {
let env = serde_json::json!({"flags": ["DIRECTIVE", "TASK_FAILURE"]});
let r = evaluate_salience(&env);
assert!(!r.is_empty());
}
#[test]
fn to_dict_projection_shape() {
let d = SalienceDecision::default();
let m: BTreeMap<String, Value> = d.to_dict();
assert_eq!(m.len(), 5);
assert_eq!(m["score"], json!(0.0));
assert_eq!(m["minimum_tier"], json!("T0"));
assert_eq!(m["witness_needed"], json!(false));
}
/// Phase B bench (std-only: no criterion dep) — hot-path cost of the full
/// kernel evaluation over the frozen corpus, plus the word-boundary scan
/// micro. Numbers land in the landing evidence log.
#[test]
fn evaluate_hot_path_bench() {
use std::time::Instant;
let cases: Vec<Value> = envelope_cases()
.iter()
.filter(|c| c["fn"] == "evaluate_salience_dict")
.map(|c| c["args"][0].clone())
.collect();
assert!(!cases.is_empty(), "corpus must be non-empty");
let rounds = 1000;
let start = Instant::now();
let mut sink = 0.0f64;
for _ in 0..rounds {
for env in &cases {
sink += evaluate_decision(env).score;
}
}
let per_call = start.elapsed().as_secs_f64() * 1e9 / (rounds * cases.len()) as f64;
let text = "the tests still fail after two attempts but maybe a new plan again";
let start = Instant::now();
let mut hits = 0usize;
for _ in 0..100_000 {
if word_boundary_contains(text, "still") || word_boundary_contains(text, "attempts") {
hits += 1;
}
}
let per_scan = start.elapsed().as_secs_f64() * 1e9 / 100_000.0;
assert!(sink.is_finite() && hits > 0);
println!(
"bench evaluate_decision: {per_call:.1} ns/call over {} frozen envelopes; \
word_boundary_contains: {per_scan:.1} ns/scan",
cases.len()
);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+279 -154
View File
@@ -3,6 +3,8 @@
use std::collections::BTreeMap;
use serde_json::Value;
pub fn flag_score(flag: &str) -> f64 {
match flag {
"OWNER_CORRECTION" => 0.8,
@@ -23,8 +25,62 @@ pub fn flag_score(flag: &str) -> f64 {
}
}
/// Python SalienceDecision dataclass — decision about how much cognition an
/// event deserves.
#[derive(Debug, Clone, PartialEq)]
pub struct SalienceDecision {
pub score: f64, // 0.0 = trivial, 1.0 = maximum salience
pub flags: Vec<String>,
pub minimum_tier: String, // T0=deterministic, T1=cheap local, T2=medium
pub witness_needed: bool,
pub rationale_codes: Vec<String>,
}
impl Default for SalienceDecision {
fn default() -> Self {
SalienceDecision {
score: 0.0,
flags: Vec::new(),
minimum_tier: "T0".to_string(),
witness_needed: false,
rationale_codes: Vec::new(),
}
}
}
impl SalienceDecision {
/// Python SalienceDecision.to_dict parity: verbatim field projection.
#[must_use]
pub fn to_dict(&self) -> BTreeMap<String, Value> {
let mut out = BTreeMap::new();
out.insert("score".to_string(), serde_json::json!(self.score));
out.insert("flags".to_string(), serde_json::json!(self.flags));
out.insert(
"minimum_tier".to_string(),
serde_json::json!(self.minimum_tier),
);
out.insert(
"witness_needed".to_string(),
serde_json::json!(self.witness_needed),
);
out.insert(
"rationale_codes".to_string(),
serde_json::json!(self.rationale_codes),
);
out
}
}
/// Python re \b parity: a word char is ASCII alphanumeric, '_', or a byte of
/// a multibyte letter (Python \w is unicode-aware; the needles are ASCII so
/// the byte scan holds, with continuation bytes counting as word chars).
#[inline]
fn is_word_byte(b: u8) -> bool {
b.is_ascii_alphanumeric() || b == b'_' || b & 0xC0 == 0x80
}
/// Word-boundary contains (zero-dep): matches `word` only when not
/// surrounded by alphanumeric chars — Python re.search(r"\bword\b") parity.
/// surrounded by word chars — Python re.search(r"\bword\b") parity.
fn word_boundary_contains(haystack: &str, word: &str) -> bool {
let bytes = haystack.as_bytes();
let wb = word.as_bytes();
@@ -33,9 +89,9 @@ fn word_boundary_contains(haystack: &str, word: &str) -> bool {
}
for i in 0..=(bytes.len() - wb.len()) {
if &bytes[i..i + wb.len()] == wb {
let before_ok = i == 0 || !bytes[i - 1].is_ascii_alphanumeric();
let before_ok = i == 0 || !is_word_byte(bytes[i - 1]);
let after = i + wb.len();
let after_ok = after >= bytes.len() || !bytes[after].is_ascii_alphanumeric();
let after_ok = after >= bytes.len() || !is_word_byte(bytes[after]);
if before_ok && after_ok {
return true;
}
@@ -44,10 +100,37 @@ fn word_boundary_contains(haystack: &str, word: &str) -> bool {
false
}
pub fn evaluate_salience(envelope: &serde_json::Value) -> BTreeMap<String, serde_json::Value> {
let mut flags: Vec<String> = Vec::new();
let mut score = 0.0f64;
let mut rationale: Vec<String> = Vec::new();
/// Flags/score/rationale accumulation — one flag word hit, one append (the
/// oracle appends once per category check regardless of how many words in
/// the family matched).
fn add_flag(d: &mut SalienceDecision, flag: &str, code: &str) {
d.flags.push(flag.to_string());
let s = flag_score(flag);
if s > d.score {
d.score = s;
}
d.rationale_codes.push(code.to_string());
}
/// ASCII-anchored lowercase avoidance: keyword matching only needs the
/// lowercased text; already-ASCII-lowercase strings (the common case) get
/// matched with zero allocation. Non-ASCII (or any uppercase) takes the
/// full Python-parity `to_lowercase()` path — Unicode case mappings (e.g.
/// 'İ') must never be skipped, so the borrow predicate is ASCII-only.
fn lower_for_match(s: &str) -> std::borrow::Cow<'_, str> {
if s.is_ascii() && !s.bytes().any(|b| b.is_ascii_uppercase()) {
std::borrow::Cow::Borrowed(s)
} else {
std::borrow::Cow::Owned(s.to_lowercase())
}
}
/// Typed kernel evaluation — mirrors the Python facade's floor exactly:
/// authority → urgency → failure → retry → contradiction → uncertainty →
/// novel, flags/rationale append in that evaluation order.
#[must_use]
pub fn evaluate_decision(envelope: &Value) -> SalienceDecision {
let mut d = SalienceDecision::default();
let authority = envelope
.get("authority_class")
@@ -57,74 +140,45 @@ pub fn evaluate_salience(envelope: &serde_json::Value) -> BTreeMap<String, serde
.get("urgency")
.and_then(|u| u.as_str())
.unwrap_or("normal");
let text = envelope
.get("payload")
.and_then(|p| p.get("text"))
.and_then(|t| t.as_str())
.unwrap_or("")
.to_lowercase();
let add_flag = |flags: &mut Vec<String>,
score: &mut f64,
rationale: &mut Vec<String>,
flag: &str,
code: &str| {
flags.push(flag.to_string());
let s = flag_score(flag);
if s > *score {
*score = s;
}
rationale.push(code.to_string());
};
let text = lower_for_match(
envelope
.get("payload")
.and_then(|p| p.get("text"))
.and_then(|t| t.as_str())
.unwrap_or(""),
);
match authority {
"emergency" => add_flag(
&mut flags,
&mut score,
&mut rationale,
"HIGH_RISK_IRREVERSIBLE",
"emergency_authority",
),
"task_amendment" => add_flag(
&mut flags,
&mut score,
&mut rationale,
"OWNER_CORRECTION",
"task_amendment",
),
"directive" => add_flag(
&mut flags,
&mut score,
&mut rationale,
"EXPLICIT_DIRECTIVE",
"directive",
),
"emergency" => add_flag(&mut d, "HIGH_RISK_IRREVERSIBLE", "emergency_authority"),
"task_amendment" => add_flag(&mut d, "OWNER_CORRECTION", "task_amendment"),
"directive" => add_flag(&mut d, "EXPLICIT_DIRECTIVE", "directive"),
_ => {}
}
match urgency {
"critical" => {
score = score.max(0.9);
rationale.push("critical_urgency".to_string());
d.score = d.score.max(0.9);
d.rationale_codes.push("critical_urgency".to_string());
}
"high" => {
score = score.max(0.7);
rationale.push("high_urgency".to_string());
d.score = d.score.max(0.7);
d.rationale_codes.push("high_urgency".to_string());
}
_ => {}
}
for word in &["fail", "error", "broken"] {
if word_boundary_contains(&text, word) {
add_flag(
&mut flags,
&mut score,
&mut rationale,
"TASK_FAILURE",
"failure_detected",
);
break;
}
// ORACLE PARITY (fixed 2026-10-15): the oracle guards the failure family
// with ONE `if any(fail/error/broken) or re.search(doesn't work|not
// working)` — a single TASK_FAILURE flag even when both alternatives
// hit; the previous port omitted the doesn't-work/not-working arm
// entirely.
if ["fail", "error", "broken"]
.iter()
.any(|w| word_boundary_contains(&text, w))
|| text.contains("doesn't work")
|| text.contains("not working")
{
add_flag(&mut d, "TASK_FAILURE", "failure_detected");
}
// ORACLE PARITY: Python tiers are >=0.8->T3, >=0.6->T2, >=0.4->T1, else T0;
@@ -134,66 +188,188 @@ pub fn evaluate_salience(envelope: &serde_json::Value) -> BTreeMap<String, serde
// novel-capability checks (previous port omitted them entirely).
for word in &["again", "still", "keeps", "repeatedly"] {
if word_boundary_contains(&text, word) {
add_flag(
&mut flags, &mut score, &mut rationale,
"REPEATED_RETRY", "repeated_retry",
);
add_flag(&mut d, "REPEATED_RETRY", "repeated_retry");
break;
}
}
for word in &["but", "however", "actually", "instead", "rather"] {
if word_boundary_contains(&text, word) {
add_flag(
&mut flags, &mut score, &mut rationale,
"CONTRADICTION", "contradiction_detected",
);
add_flag(&mut d, "CONTRADICTION", "contradiction_detected");
break;
}
}
for word in &["unsure", "uncertain", "maybe", "perhaps", "might"] {
if word_boundary_contains(&text, word) {
add_flag(
&mut flags, &mut score, &mut rationale,
"HIGH_UNCERTAINTY", "high_uncertainty",
);
add_flag(&mut d, "HIGH_UNCERTAINTY", "high_uncertainty");
break;
}
}
for word in &["new", "never"] {
if word_boundary_contains(&text, word) {
add_flag(
&mut flags, &mut score, &mut rationale,
"NOVEL_CAPABILITY_REQUEST", "novel_request",
);
break;
}
}
if text.contains("first time") || text.contains("haven't") {
add_flag(
&mut flags, &mut score, &mut rationale,
"NOVEL_CAPABILITY_REQUEST", "novel_request",
);
// ORACLE PARITY (fixed 2026-10-15): the oracle guards the whole novel
// family with ONE `if any(word) or re.search(first time|haven't)` — a
// single NOVEL flag even when both alternatives hit. The previous port
// appended a second flag for the "first time|haven't" arm, inflating
// len(flags) (witness rule) — floor rows pin the single append.
if ["new", "never"]
.iter()
.any(|w| word_boundary_contains(&text, w))
|| text.contains("first time")
|| text.contains("haven't")
{
add_flag(&mut d, "NOVEL_CAPABILITY_REQUEST", "novel_request");
}
let minimum_tier = match score {
d.minimum_tier = match d.score {
s if s >= 0.8 => "T3",
s if s >= 0.6 => "T2",
s if s >= 0.4 => "T1",
_ => "T0",
};
}
.to_string();
let witness_needed = score >= 0.6 || flags.len() >= 2;
d.witness_needed = d.score >= 0.6 || d.flags.len() >= 2;
let mut result = BTreeMap::new();
result.insert("score".into(), serde_json::json!(score));
result.insert("flags".into(), serde_json::json!(flags));
result.insert("minimum_tier".into(), serde_json::json!(minimum_tier));
result.insert("witness_needed".into(), serde_json::json!(witness_needed));
result.insert("rationale_codes".into(), serde_json::json!(rationale));
result
d
}
#[must_use]
pub fn evaluate_salience(envelope: &Value) -> BTreeMap<String, Value> {
evaluate_decision(envelope).to_dict()
}
/// evaluate_salience_dict — JSON-view of the evaluation (the module-level
/// wrapper the shared freeze harness freezes: the dataclass-returning
/// evaluate_salience is not JSON-serializable). Pure to_dict composition —
/// zero logic drift from the oracle floor.
#[must_use]
pub fn evaluate_salience_dict(envelope: &Value) -> Value {
serde_json::json!(evaluate_salience(envelope))
}
/// _sg_core: the kernel mirror of the facade's availability probe — the pin
/// decision only (from the kernel's side the core always exists; the loader
/// module the Python probe returns is unreachable from Rust by design).
/// Some ↔ probe answered the loader; None ↔ python pin honored / fallback.
#[must_use]
pub fn _sg_core(pin: Option<&str>) -> Option<Value> {
if pin == Some("python") {
None
} else {
Some(serde_json::json!("salience_gate"))
}
}
/// handle_hook — Python handle_hook parity: the plugin hook handler for
/// incoming events. The oracle accepts `data` and ignores it.
#[must_use]
pub fn handle_hook(event: &Value, _data: Option<&Value>) -> Value {
serde_json::json!({"status": "ok", "event": event, "handler": "salience_gate"})
}
/// Python str(float) parity: integral floats render one decimal (0.0 →
/// "0.0"), non-integral keep the shortest round-trip form.
fn py_float(f: f64) -> String {
if f == f.trunc() && f.is_finite() {
format!("{:.1}", f)
} else {
format!("{}", f)
}
}
/// Python repr(list[str]) parity: single-quoted elements.
fn py_list_repr(items: &[String]) -> String {
let inner: Vec<String> = items.iter().map(|s| format!("'{}'", s)).collect();
format!("[{}]", inner.join(", "))
}
/// Python bare `assert` (uncaught AssertionError).
fn assert_oracle(cond: bool, msg: &str) {
if !cond {
panic!("AssertionError: {}", msg);
}
}
/// test_salience — Python test_salience parity: the module's embedded smoke
/// test (printed lines byte-matched against the oracle's f-strings).
pub fn test_salience() {
println!("Testing Salience Gate...");
let envelope = serde_json::json!({
"authority_class": "conversation",
"urgency": "normal",
"channel": "conversation",
"payload": {"text": "hello"},
});
let d = evaluate_decision(&envelope);
println!(
"Greeting: score={}, tier={}, flags={}",
py_float(d.score),
d.minimum_tier,
py_list_repr(&d.flags)
);
assert_oracle(d.score < 0.4, "greeting score below trivial threshold");
assert_oracle(
d.minimum_tier == "T0",
"greeting must be deterministic tier",
);
let envelope = serde_json::json!({
"authority_class": "directive",
"urgency": "normal",
"channel": "work",
"payload": {"text": "Fix the failing test"},
});
let d = evaluate_decision(&envelope);
println!(
"Directive: score={}, tier={}, flags={}",
py_float(d.score),
d.minimum_tier,
py_list_repr(&d.flags)
);
assert_oracle(d.score >= 0.6, "directive score below cognition threshold");
assert_oracle(
d.minimum_tier == "T2" || d.minimum_tier == "T3",
"directive tier must be T2 or T3",
);
let envelope = serde_json::json!({
"authority_class": "emergency",
"urgency": "critical",
"channel": "work",
"payload": {"text": "Stop everything!"},
});
let d = evaluate_decision(&envelope);
println!(
"Emergency: score={}, tier={}, flags={}",
py_float(d.score),
d.minimum_tier,
py_list_repr(&d.flags)
);
assert_oracle(d.score >= 0.8, "emergency score below strong tier");
assert_oracle(d.minimum_tier == "T3", "emergency tier must be T3");
let envelope = serde_json::json!({
"authority_class": "directive",
"urgency": "normal",
"channel": "work",
"payload": {"text": "The tests still fail after two attempts"},
});
let d = evaluate_decision(&envelope);
println!(
"Failure: score={}, tier={}, flags={}",
py_float(d.score),
d.minimum_tier,
py_list_repr(&d.flags)
);
assert_oracle(d.score >= 0.7, "failure score below medium threshold");
assert_oracle(
d.flags
.iter()
.any(|f| f == "TASK_FAILURE" || f == "REPEATED_RETRY"),
"failure must raise a failure indicator",
);
println!("✅ All tests passed!");
}
// ── FFI surface (facade-2 burn-down, 2026-10-10) ─────────────────────────────
use std::ffi::{CStr, CString};
@@ -213,7 +389,10 @@ fn read_arg(ptr: *const c_char) -> Result<String, String> {
#[no_mangle]
pub extern "C" fn sg_evaluate_salience(arg: *const c_char) -> *mut c_char {
let result = read_arg(arg)
.and_then(|t| serde_json::from_str::<serde_json::Value>(&t).map_err(|e| format!("argument JSON parse failed: {}", e)))
.and_then(|t| {
serde_json::from_str::<serde_json::Value>(&t)
.map_err(|e| format!("argument JSON parse failed: {}", e))
})
.and_then(|a| {
let env = a.get("envelope").cloned().ok_or("arg.envelope required")?;
let map = evaluate_salience(&env);
@@ -243,58 +422,4 @@ pub extern "C" fn sg_free_string(ptr: *mut c_char) {
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_emergency() {
let envelope =
json!({"authority_class": "emergency", "urgency": "normal", "payload": {"text": ""}});
let r = evaluate_salience(&envelope);
assert_eq!(r["minimum_tier"], "T3"); // oracle: 0.9 -> T3
assert_eq!(r["score"], 0.9);
}
#[test]
fn test_trivial() {
let envelope = json!({"authority_class": "conversation", "urgency": "normal", "payload": {"text": "hello"}});
let r = evaluate_salience(&envelope);
assert_eq!(r["minimum_tier"], "T0");
}
}
#[cfg(test)]
mod branch_battery {
use super::*;
#[test]
fn flag_score_all_known() {
// all known flags return a score
for flag in [
"EMERGENCY",
"OWNER_CORRECTION",
"DIRECTIVE",
"TASK_FAILURE",
"REPEATED_RETRY",
"HIGH_UNCERTAINTY",
"NOVEL_CAPABILITY",
"TRIVIAL",
] {
let s = flag_score(flag);
assert!(s >= 0.0, "{}: score must be non-negative", flag);
}
}
#[test]
fn flag_score_unknown_zero() {
assert_eq!(flag_score("UNKNOWN_FLAG"), 0.0);
}
#[test]
fn evaluate_salience_object() {
let env = serde_json::json!({"flags": ["DIRECTIVE", "TASK_FAILURE"]});
let r = evaluate_salience(&env);
assert!(!r.is_empty());
}
}
mod branch_battery;
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Close the PARTIAL gaps in src/go/model-profiles against the src/rune/model_profiles.py oracle (dichotomy wave, issue #2479 tranche): name-preserving Go ports for the 10 unmatched functions (get_profile_path — filesystem sanitization, load_profile — suppressed-exception floor + unknown-key filtering, save_profile — Python-shaped JSON writer, build_profile_from_ollama — knowledge merge + uncensored tier + frozen-clock stamps, scan_all_models — Ollama sweep with banker's rounding + learned-data preservation, get_or_create_profile, record_interaction — learning accumulator, get_prompt_context — operator string assembly, to_dict/from_dict — the dataclass lens) plus the stdin-op serve CLI over the same code paths, frozen-truth corpus generated against the live Python oracle through the scripts/mp_freeze_seams rig (HOME pinned before import, per-case hermetic store wipe+seed, canned Ollama server, frozen clock; 36 verbatim cases incl. the save_profile byte-parity rows), battery 36/36, gofmt+vet clean, live parity 100% (143/143), pytest 31/31 both pins.
## 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-13T23:58:33Z", "contract": "BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp", "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_model_profiles_parity.py", "scripts/gen_model_profiles_truth.py", "scripts/gen_mp_battery.py", "scripts/mp_freeze_seams/sitecustomize.py", "src/go/model-profiles/frozen_battery_test.go", "src/go/model-profiles/frozen_mp_truth.json", "src/go/model-profiles/go.mod", "src/go/model-profiles/main.go", "src/go/model-profiles/truth.json"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-gap-mp
- builder:factory-gap-mp
- builder:factory-gap-mp
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
salience_gate dichotomy gap-close (RUST): name-preserving port of the 4 audit-missing functions into src/rust/salience_gate (the module's existing delegation side — classification side=RUST; no Go salience-gate dir exists): _sg_core (kernel mirror of the facade availability probe, pin lattice), to_dict (SalienceDecision struct + projection, evaluate_salience flows through it), handle_hook (event echo, data accepted+ignored), test_salience (embedded oracle smoke, print-byte-matched), plus oracle-level evaluate_salience_dict JSON view (shared freeze harness cannot serialize the dataclass return — construction_decision normalize_need_json precedent). Dichotomy audit 1/5 PARTIAL -> 6/6 FULL. Three parity defects fixed (frozen-truth battery caught all): novel-family single-append (oracle guards ONE if; duplicate append inflated witness rule), failure-family doesn't-work/not-working arm omitted, word_boundary_contains Python-\b parity (alphanumeric + underscore + UTF-8 continuation bytes). Frozen truth via shared harness scripts/freeze_truth.py: frozen_sg_truth.verify.json 52 rows byte-identical under freeze_truth.py --verify in BOTH core states (floor SG_RUST_LIB-poisoned AND kernel-built); frozen_sg_truth.json 63-row envelope (multi-family evaluation-order rows + _sg_core row — the shared gate's RUNE_SALIENCE_GATE_CORE pin cannot reach this oracle). branch_battery.rs replays both verbatim via include_str (12 tests); poisoned-truth law: generator pins RUNE_SALIENCE_CORE=python AND poisons SG_RUST_LIB (the module's real floor pins — the facade evaluate path ignores RUNE_*_CORE). Live parity: gen --replay facade live + kernel direct 119/119 (exact evaluation-order kernel rows; facade rows under the oracle's declared sorted-comparison contract); crate canary 6/6; oracle smoke green in 3 pin states (live, probe-pinned, pure floor). Phase B (2350e02e): ASCII-anchored Cow lowercase avoidance (zero-alloc common path, Unicode mappings never skipped), std-only hot-path bench (ns/call over the 56-envelope frozen corpus + ns/scan), #[must_use] pure surface, idiomatic single-append family guards. rustfmt clean, clippy -D warnings clean. Evidence: verification/salience-gate-*.log (cargotest/clippy/freeze-verify/replay/canary/python-pins/goladder/audit, all exit 0, Read back). Delivered on gitea/master: feat 9539d5b6, phase B 2350e02e.
## 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-14T01:26:41Z", "contract": "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg", "correctly_predicted": [], "evidence_sources": ["unattributed"], "expected_new_entities": [], "expected_new_missing": [], "expected_new_observed": [], "expected_runtime_effects": [], "expected_runtime_missing": [], "expected_runtime_observed": [], "genuinely_unexpected_new": [], "missed": [], "needless": ["module:deploy_qualify"], "observed": [], "observed_existing": [], "observed_new": [], "predicted_but_unaffected": ["module:deploy_qualify"], "predicted_existing_affected": ["module:deploy_qualify"], "scope_check": {"in_scope": [], "out_of_scope": ["scripts/close_contract_salience_gate.py", "scripts/gen_salience_gate_truth.py", "scripts/resume_close_contract_salience_gate.py", "src/rune/salience_gate.py", "src/rune/sg_loader.py", "src/rust/salience_gate/Cargo.toml", "src/rust/salience_gate/canary_salience_gate.py", "src/rust/salience_gate/frozen_salience.json", "src/rust/salience_gate/src/branch_battery.rs", "src/rust/salience_gate/src/frozen_sg_truth.json", "src/rust/salience_gate/src/frozen_sg_truth.verify.json", "src/rust/salience_gate/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- parity 9539d5b6, phase B 2350e02e
- parity 9539d5b6, phase B 2350e02e
- parity 9539d5b6, phase B 2350e02e
- closure-record
@@ -32,6 +32,36 @@
"affected_paths": [],
"affected_regions": [],
"affected_ui_surfaces": [],
"contract_quality": {
"candidate_corrections": [],
"captured_at": "2026-10-14T00:10:03Z",
"contract": "BUILDER-2026-10-13T15:18:58Z-fb34a0-factory-gap-he",
"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"
],
"repaired_post_hoc": "quality-gate lapse repair 2026-10-13 (closed via raw transition predating 16c5f22a \u2014 quality computed from + verified evidence)"
},
"decision_trace": {
"affected_surfaces": {
"affected_existing_entities": [],
@@ -32,6 +32,36 @@
"affected_paths": [],
"affected_regions": [],
"affected_ui_surfaces": [],
"contract_quality": {
"candidate_corrections": [],
"captured_at": "2026-10-14T00:10:30Z",
"contract": "BUILDER-2026-10-13T16:25:22Z-7e3fd4-factory-gap-ar",
"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"
],
"repaired_post_hoc": "quality-gate lapse repair 2026-10-13 (closed via raw transition predating 16c5f22a \u2014 quality computed from + verified evidence)"
},
"decision_trace": {
"affected_surfaces": {
"affected_existing_entities": [],
@@ -3958,3 +3958,13 @@
{"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"}
{"builder": "factory-gap-mp", "detail": "need-2026-10-13T23:56:27Z-factory-gap-mp \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:56:33Z", "operation": "submit_need"}
{"builder": "factory-gap-mp", "detail": "BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:57:12Z", "operation": "transition"}
{"builder": "factory-gap-mp", "detail": "BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:57:41Z", "operation": "transition"}
{"builder": "factory-gap-mp", "detail": "BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:58:06Z", "operation": "transition"}
{"builder": "factory-gap-mp", "detail": "BUILDER-2026-10-13T23:56:33Z-c011dd-factory-gap-mp closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-13T23:58:33Z", "operation": "close"}
{"builder": "factory-gap-sg", "detail": "need-2026-10-14T01:24:06Z-factory-gap-sg \u2192 REUSE", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T01:24:10Z", "operation": "submit_need"}
{"builder": "factory-gap-sg", "detail": "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg \u2192 approved", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T01:24:40Z", "operation": "transition"}
{"builder": "factory-gap-sg", "detail": "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg \u2192 building", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T01:25:17Z", "operation": "transition"}
{"builder": "factory-gap-sg", "detail": "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg \u2192 verifying", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T01:25:40Z", "operation": "transition"}
{"builder": "factory-gap-sg", "detail": "BUILDER-2026-10-14T01:24:10Z-2a26ea-factory-gap-sg closed", "kind": "builder_session", "mode": "rune_internal", "observed_at": "2026-10-14T01:26:41Z", "operation": "close"}
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+78
View File
@@ -0,0 +1,78 @@
# cron_engine GO gap-close — verification summary (#2479 dichotomy wave)
Worktree rune-wave-co (detached HEAD @ 801b631e → pushed via `gitea HEAD:master`).
Oracle: /mnt/workdrive/rune/src/rune/cron_engine.py (440 lines, 27 fns).
## Coverage
- BEFORE: 13/27 matched, PARTIAL (missing 14: get_cron_engine, run_task×2,
start_engine, stop_engine, to_dict, fire_on_task_complete, stop, _run_loop,
_parse_cron_field, _should_run, _execute_task, _log_execution, _log_error —
the audit's camel generator cannot see parseCronField/shouldRun for
leading-underscore names; both now carry the Python-name mirror comments AND
real ports).
- AFTER: 27/27 FULL (docs/dichotomy-rebase-honest-audit.md regenerated;
83/192 modules FULL). Evidence: ce-audit.log.
## Commands + exit codes (all evidence in verification/ce-*)
| gate | evidence | exit |
|---|---|---|
| go build ./... | ce-gobuild.log | 0 |
| go test -v (5 tests) | ce-gotest.log | 0 |
| gofmt -l (clean) | ce-gofmt.log | 0 |
| go vet ./... | ce-govet.log | 0 |
| replay truth.json (batch 1) | ce-replay-legacy.log — PARITY OK 25 | 0 |
| replay-gap truth_gap.json | ce-replay-gap.log — PARITY OK 46 | 0 |
| gen_cron_engine_gap_truth.py --verify | ce-truth-verify.log — 46 byte-identical | 0 |
| fresh re-freeze byte-identity | ce-truth-regen.log — REGEN BYTE-IDENTICAL | 0 |
| check_cron_engine_parity.py (live) | ce-live-parity.log — 3/3 scenarios, 31 ops | 0 |
| Python CLI smoke both pins + GO CLI | ce-python-cli-smoke.log (byte-identical outputs) | 0 |
| pytest test_subsystem_health (python pin) | ce-python-pytest.log — 6 passed | 0 |
## Truth-freeze technique
Shared harness (scripts/freeze_truth.py) + wrapper shims
(scripts/gen_cron_engine_gap_truth.py, registered as
gen_cron_engine_gap_truth_shims): frozen clock (ce.datetime patched with the
harness's frozen class — module-level import reaches every method), hermetic
per-row HOME tokenized to <CE_HOME>, _run_loop rows run with cron_engine.time
swapped for a stopper (exactly one iteration then clean exit), record_failure
neutralized (hermetic), capture = {result, post, files, storage, log}.
46 cases, envelope frozen_now 2026-10-13T09:20:00. --verify byte-identical;
fresh regen byte-identical.
## Go side
- src/go/cron-engine/main.go: toDict (snapshot copy — Python to_dict builds a
fresh dict), runTask (method + module), fireOnTaskComplete, start/stop,
runLoop, executeTask, logExecution/logError (5MB rotation), getCronEngine
singleton family, shlexSplit (posix, oracle ValueError messages), pyISO
(isoformat +00:00 / micro elision), Python-exact ordered _save
(insertion order + ensure_ascii + indent 2, "{}" when empty) + strict
ordered _load (CronTask(**data) TypeError semantics), ExitError→returncode
(nonzero exit is a value, not an error), error-message translation layer
(FileNotFoundError / PermissionError / TimeoutExpired str() forms).
- add/remove/enable/disable now persist via _save when a storage path is set
(oracle behavior; in-memory battery construction unaffected).
- scenario.go: replay-gap interpreter + scenario driver (live parity) +
ordered JSON arg decoding (Go maps lose insertion order — ordObj).
- CI gate extended (cron-engine step): replay + replay-gap + both batteries.
## Documented divergences (not bugs)
1. 60s subprocess timeout branch not frozen through the oracle (a real
TimeoutExpired costs 60s); the port carries the exact
`Command '[...]' timed out after N seconds` str(e) shape, unit-pinned in
TestOracleErrorShapes + TestTimeoutBranchReplay (seam-shrunk).
2. add_task/_save failure branch: oracle propagates exceptions; port records
via the recordFailure seam and completes the mutation (module boundary —
src/go/subsystem-health is package main, not importable; seam is
injectable). Truth rows never exercise unwritable storage.
3. Typed struct vs unvalidated dataclass: a wrong-TYPED value the dataclass
would accept (CronTask(name=5)) is rejected by Go's JSON decode; the
strict key-set check mirrors the realistic TypeError corruption mode.
4. Bad cron expression in the loop: oracle thread dies silently (traceback
swallowed by threading); port's goroutine returns, running stays true —
identical observables (no further executions).
5. step-0 (*/0): oracle raises ValueError("range() arg 3 must not be zero")
and the freeze harness cannot capture exceptions — port returns the same
error text (crash-parity quirk family), unit-pinned.
## SHAs
(Recorded after final push — see close contract chore(store) commit.)
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
audit_exit=0
+1
View File
@@ -0,0 +1 @@
test_exit=0
@@ -0,0 +1 @@
parity_exit=0
@@ -0,0 +1 @@
test_exit=1 (18 test_p1_01 failures PRE-EXISTING: identical on stashed base and both pins; microkernel-adjacent suite green; no Python files touched)
@@ -0,0 +1 @@
test_exit=1 (18 test_p1_01 failures PRE-EXISTING: identical on stashed base and both pins; microkernel-adjacent suite green; no Python files touched)
+1
View File
@@ -0,0 +1 @@
verify_exit=0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+42
View File
@@ -0,0 +1,42 @@
# model_profiles dichotomy gap-close — verification summary
- **Module**: model_profiles (GO port, src/go/model-profiles)
- **Parity SHA**: (parity commit — filled after push)
- **Contract**: BUILDER-2026-10-13T22:50:00Z-<id>-factory-gap-mp — closed
(submit→approved→building→verifying→closed walked in ONE process)
## Commands and exit codes
| Check | Command | Exit | Evidence |
|---|---|---|---|
| frozen truth byte-identical | `PYTHONPATH=scripts/mp_freeze_seams:src python3 scripts/freeze_truth.py --verify src/go/model-profiles/frozen_mp_truth.json --module rune.model_profiles` | 0 | `verification/mp-freeze-verify.log` / `.exit` — OK: 36 cases byte-identical against live oracle |
| fmt+vet+build | `gofmt -l . && go vet . && go build ./...` (in src/go/model-profiles) | 0 | `verification/mp-gofmt.log` (empty), `verification/mp-govet.log`, `verification/mp-gobuild.log` + `.exit` files |
| Go battery | `go test -count=1 -v .` (in src/go/model-profiles) | 0 | `verification/mp-gotest.log` / `.exit` — TestFrozenBattery PASS (36/36 frozen cases replayed VERBATIM from embedded truth) |
| live parity | `PYTHONPATH=src python3 scripts/check_model_profiles_parity.py --bin /tmp/mp-go` | 0 | `verification/mp-parity.log` / `.exit` — parity: 143/143 match |
| Python tests (live delegation) | `python3 -m pytest tests/test_p1_06_model_routing.py tests/test_p1_07_runtime_objects.py -q` | 0 | `verification/mp-pytest-live.log` — 31 passed |
| Python tests (python pin) | `RUNE_MODEL_PROFILES_CORE=python python3 -m pytest ...` | 0 | `verification/mp-pytest-pinned.log` — 31 passed |
| contract close walk | `python3 scripts/walk_contract_model_profiles_gap.py` | 0 | `verification/mp-close-walk.log` / `.exit` — FINAL PHASE: closed |
## Coverage
Dichotomy audit: model_profiles 5/15 PARTIAL → **15/15 FULL** (GO);
missing [] (verified via `scripts/dichotomy_audit.py` post-port).
## Divergences (documented, not bugs)
1. `load_profile({"name": <non-string>})` is ACCEPTED by the Python
oracle (dataclass `__init__` performs no type checks) but REJECTED
by the Go port (typed signature) — the local_tool_runtime precedent
(bool/int-union). No frozen row carries that shape.
2. Integral-float rendering: the oracle's build path assigns int `0`
where the dataclass declares float (`size_gb=0` vs `0.0`); the
parity sweep canonicalizes integral floats before compare. The
frozen save_profile byte-parity corpus pins the file writer to the
oracle's exact bytes (asdict field order, indent-2, ensure_ascii,
integral floats with trailing `.0`).
## Files
- `scripts/walk_contract_model_profiles_gap.py` — the one-process close walk (committed)
- `store/scaffold/segments/entities/contract__BUILDER-*.json` — contract entity (phase: closed)
- `store/scaffold/segments/observations.jsonl` — walk journal rows
+1
View File
@@ -0,0 +1 @@
0
+2
View File
@@ -0,0 +1,2 @@
0
0
+1
View File
@@ -0,0 +1 @@
0
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff. Show more