Compare commits

...
26 Commits
Author SHA1 Message Date
conductor bdd3edfc3c chore(release): auto-bump version to 0.267.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 18s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / gitea-offline (push) Successful in 16s
Auto-version and Release / release (push) Successful in 54s
CI Pipeline / type-check (push) Failing after 50s
CI Pipeline / lint (push) Failing after 1m21s
CI Pipeline / canary (push) Failing after 2m20s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 6m6s
Promotion record: (unknown)
2026-10-13 07:58:46 +01:00
Nick e1904eb1dc chore(store): register self_model dichotomy contract BUILDER-2026-10-13T00:23:43Z-53857a-factory-batch-i (verifying)
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 14s
CI Pipeline / go-surface (push) Failing after 17s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 54s
CI Pipeline / lint (push) Canceled after 45s
CI Pipeline / unit-tests (push) Canceled after 45s
CI Pipeline / canary (push) Canceled after 46s
CI Pipeline / type-check (push) Canceled after 36s
deploy / deploy (push) Canceled after 56s
2026-10-13 07:57:44 +01:00
Nick 99bde7ba2a refactor(self_model): Phase B language-advantage pass — dichotomy wave (ASCII byte fast-path token estimate) 2026-10-13 07:57:34 +01:00
Nick dac4889c0b feat(self_model): port to FULL Rust — dichotomy wave 2026-10-13 07:57:34 +01:00
Nick cf7a10f6d6 chore(store): dedupe concurrent batch-g contract state in scaffold (keep latest observed_at)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 22s
CI Pipeline / gitea-offline (push) Successful in 16s
Auto-version and Release / release (push) Successful in 49s
CI Pipeline / type-check (push) Failing after 54s
CI Pipeline / lint (push) Failing after 1m24s
CI Pipeline / canary (push) Failing after 2m22s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 2m26s
CI Pipeline / unit-tests (push) Canceled after 2m52s
2026-10-13 07:54:55 +01:00
Nick ec9ec2efb3 chore(factory): claims — failure_auto_filer verified (6 PASS, 37-row truth)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 47s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / lint (push) Canceled after 1m1s
CI Pipeline / unit-tests (push) Canceled after 1m1s
CI Pipeline / canary (push) Canceled after 1m1s
CI Pipeline / type-check (push) Canceled after 49s
deploy / deploy (push) Canceled after 1m11s
2026-10-13 07:53:53 +01:00
Nick 05fab134af refactor(build_mode): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 46s
CI Pipeline / type-check (push) Failing after 48s
CI Pipeline / lint (push) Failing after 1m15s
CI Pipeline / canary (push) Failing after 2m16s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 4m41s
CI Pipeline / unit-tests (push) Canceled after 4m41s
Three Go-side wins the Python oracle can't express, parity-pinned against
the frozen gap battery:
1. Data-driven start_* transition registry with init-time completeness
   enforcement (a new Phases entry without a transition fails at boot,
   not silently); StartPhase dispatch byte-identical to the wrappers.
2. Typed StateStore seam replacing the module-global BUILDS_DIR:
   MemStore (zero-IO truth replays) + FileStore whose Save is atomic
   (temp + rename — Python's open(...,"w") can tear the ledger).
3. ReplayPipeline — the frozen battery fans out across goroutines with
   input-order reassembly, race-clean under -race.
2026-10-13 07:49:11 +01:00
conductor bfd6c9d530 chore(release): auto-bump version to 0.266.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / gitea-offline (push) Successful in 16s
Auto-version and Release / release (push) Successful in 45s
CI Pipeline / type-check (push) Failing after 48s
CI Pipeline / lint (push) Failing after 1m14s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 2m26s
CI Pipeline / unit-tests (push) Canceled after 2m31s
Promotion record: (unknown)
2026-10-13 07:46:43 +01:00
Nick b973b96a1e feat(work_manager): close PARTIAL gaps — dichotomy wave
CI Pipeline / rust-surface (push) Failing after 20s
CI Pipeline / go-surface (push) Failing after 20s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 51s
CI Pipeline / unit-tests (push) Canceled after 45s
CI Pipeline / lint (push) Canceled after 46s
CI Pipeline / gitea-offline (push) Canceled after 19s
CI Pipeline / type-check (push) Canceled after 26s
CI Pipeline / canary (push) Canceled after 46s
deploy / deploy (push) Canceled after 56s
2026-10-13 07:45:50 +01:00
Nick b6978e9dfc chore(store): merge concurrent batch state (final round, batch-f)
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 20s
CI Pipeline / go-surface (push) Failing after 21s
Auto-version and Release / release (push) Successful in 41s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Failing after 50s
CI Pipeline / lint (push) Failing after 1m18s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 1m20s
CI Pipeline / unit-tests (push) Canceled after 1m20s
CI Pipeline / canary (push) Canceled after 1m26s
# Conflicts:
#	store/scaffold/current.json
2026-10-13 07:44:19 +01:00
Nick 530309cfdb chore(store): close inference_paths dichotomy contract BUILDER-2026-10-13T06:41:01Z-4e8a36-factory-batch-f (Go verdict, parity 251fa36d, phase B 8d77e6aa) 2026-10-13 07:43:23 +01:00
Nick f8cd9ed7d1 chore(factory): claims — memory_consolidation (23/23), local_tool_runtime (30/30) verified through ladder
CI Pipeline / best-practices (push) Successful in 12s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 21s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / gitea-offline (push) Successful in 16s
Auto-version and Release / release (push) Successful in 49s
CI Pipeline / type-check (push) Failing after 51s
CI Pipeline / lint (push) Failing after 1m20s
CI Pipeline / canary (push) Failing after 2m24s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 3m25s
CI Pipeline / unit-tests (push) Canceled after 3m26s
2026-10-13 07:40:59 +01:00
conductor 0ed3fa8108 chore(release): auto-bump version to 0.265.1 — earned by # (patch: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 44s
CI Pipeline / type-check (push) Failing after 47s
CI Pipeline / lint (push) Failing after 1m13s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 2m18s
CI Pipeline / unit-tests (push) Canceled after 2m20s
Promotion record: (unknown)
2026-10-13 07:38:32 +01:00
Nick 0e8cc14a09 chore(store): close failure_auto_filer dichotomy contract BUILDER-2026-10-13T06:30:42Z-b381e6-factory-gap-faf (feat 5cadd401, phase B 8aa48134)
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 22s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 51s
CI Pipeline / type-check (push) Canceled after 1m1s
CI Pipeline / lint (push) Canceled after 1m10s
CI Pipeline / unit-tests (push) Canceled after 1m10s
deploy / deploy (push) Canceled after 56s
CI Pipeline / canary (push) Canceled after 1m16s
2026-10-13 07:37:04 +01:00
Nick 89ec2943da fix(verify): truth-name pattern covers truth_*.json (sleep_time transcript shape); claims — sleep_time, drift_resume verified
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 31s
CI Pipeline / gitea-offline (push) Canceled after 17s
CI Pipeline / lint (push) Canceled after 37s
CI Pipeline / type-check (push) Canceled after 25s
CI Pipeline / unit-tests (push) Canceled after 37s
Auto-version and Release / release (push) Canceled after 45s
deploy / deploy (push) Canceled after 45s
2026-10-13 07:36:35 +01:00
conductor a3b0814196 chore(release): auto-bump version to 0.265.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / rust-surface (push) Failing after 15s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 41s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / lint (push) Canceled after 50s
CI Pipeline / unit-tests (push) Canceled after 50s
CI Pipeline / canary (push) Canceled after 51s
CI Pipeline / type-check (push) Canceled after 46s
Promotion record: (unknown)
2026-10-13 07:35:39 +01:00
Nick 5503267d6c chore(store): merge concurrent batch state (round 1 + batch-f)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 19s
CI Pipeline / go-surface (push) Failing after 20s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 26s
CI Pipeline / canary (push) Canceled after 41s
Auto-version and Release / release (push) Canceled after 45s
CI Pipeline / lint (push) Canceled after 46s
CI Pipeline / unit-tests (push) Canceled after 46s
deploy / deploy (push) Canceled after 26s
2026-10-13 07:34:54 +01:00
Nick c80245ff0d chore(store): close meaningful_events dichotomy contract BUILDER-2026-10-13T00:46:01Z-28644a-factory-batch-g (parity a0d0215e, phase B 672b7cd4)
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / gitea-offline (push) Successful in 20s
Auto-version and Release / release (push) Successful in 46s
CI Pipeline / type-check (push) Failing after 57s
CI Pipeline / lint (push) Failing after 1m15s
CI Pipeline / canary (push) Failing after 2m19s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 3m30s
deploy / deploy (push) Canceled after 3m35s
2026-10-13 07:31:22 +01:00
conductor 711547d788 chore(release): auto-bump version to 0.264.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
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
CI Pipeline / unit-tests (push) Canceled after 4s
CI Pipeline / go-surface (push) Canceled after 4s
CI Pipeline / canary (push) Canceled after 4s
CI Pipeline / rust-surface (push) Canceled after 5s
CI Pipeline / lint (push) Canceled after 5s
CI Pipeline / best-practices (push) Canceled after 5s
Auto-version and Release / release (push) Canceled after 15s
Promotion record: (unknown)
2026-10-13 07:31:10 +01:00
Nick 672b7cd483 refactor(meaningful_events): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 18s
CI Pipeline / go-surface (push) Failing after 22s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 52s
CI Pipeline / lint (push) Canceled after 51s
CI Pipeline / unit-tests (push) Canceled after 50s
CI Pipeline / canary (push) Canceled after 51s
deploy / deploy (push) Canceled after 55s
CI Pipeline / type-check (push) Canceled after 41s
Typed FireDecision lattice (Stopped | Absent | RateLimited | Fire)
matched EXHAUSTIVELY — the JSON envelope is built once at the edge and
fire_due filters on the enum directly instead of re-parsing decision
JSON per trigger (8 fewer serialize/parse round-trips per tick).
Battery 4/4 replays frozen truth verbatim; live parity 1296/1296;
pytest 20 passed both ways; clippy -D warnings clean.
2026-10-13 07:30:18 +01:00
Nick a0d0215ee0 feat(meaningful_events): port to FULL Rust — dichotomy wave
Language verdict: RUST per docs/language-dichotomy-ledger.md (Law 4 —
deterministic trigger evaluation; the wall CLOCK is host-side by nature
(now passed per op, never null across FFI)).

- me_should_fire/me_fire_due/me_mark_fired doc-envelope FFI (me_*
  symbols; free via capability_scoring cs_free_string — no free
  re-export); me_loader mirroring broker_loader.py.
- Facade delegation with RUNE_ME_CORE=python pin; kernel floor on any
  kernel error; INT now keeps the Python floor in mark_fired (the
  oracle stores the value as-is; the kernel wire is float).
- Python laws replicated exactly: decision ordering (unknown → stop →
  absent → rate → fires), state truthiness (0/''/null are absent),
  falsy last_fired → 0, STRICTLY-LESS rate gate (equal fires),
  Python int() truncation toward zero INSIDE the reason string,
  fire_due in table (insertion) order, mark_fired shallow-copy with
  unknown-trigger recording.
- 96-case frozen oracle truth (RUNE_ME_CORE=python pinned, deep-copied
  inputs, every trigger class × every branch, truncation + boundary +
  future-last cases) embedded in the crate and replayed VERBATIM by the
  branch battery; live parity 1296/1296 (96 frozen + 1200 fuzz, seed
  2479); pytest 56 passed (kernel auto) and 32 per pin BOTH ways;
  clippy -D warnings clean.
2026-10-13 07:30:18 +01:00
conductor ffa8608f95 chore(release): auto-bump version to 0.263.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
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
Auto-version and Release / release (push) Canceled after 6s
CI Pipeline / canary (push) Canceled after 5s
CI Pipeline / rust-surface (push) Canceled after 5s
CI Pipeline / best-practices (push) Canceled after 5s
CI Pipeline / unit-tests (push) Canceled after 5s
CI Pipeline / go-surface (push) Canceled after 5s
CI Pipeline / lint (push) Canceled after 5s
Promotion record: (unknown)
2026-10-13 07:30:06 +01:00
Nick 3ada312a35 chore(store): merge concurrent batch state (factory-gap-ltr/faf + batch-f inference_paths) 2026-10-13 07:27:33 +01:00
Nick 8d77e6aae3 refactor(inference_paths): Phase B language-advantage pass — dichotomy wave
The side-path record becomes a typed SidePathRecord struct (schema
documented in one place; JSON key order fixed by declaration instead of
map-alphabetical accident — mirrors the Python dict's insertion order);
the census kind vocabulary is a typed Kind string (APPROVAL/COMPACTION/
SIDE/EMBED/EXCLUDED) with an isExcluded lattice method replacing
bare-string comparisons; the report is a typed Report with a
struct-level Exclusion entry and the fold extracted as CensusReportOf
(the exported CensusReport() keeps the oracle's function name).
Battery green throughout: go test replays the 7 frozen-oracle cases
VERBATIM + replay CLI 7/7; gofmt clean, go vet clean; live facade
replay 7/7; test_inference_paths.py 6/6.
2026-10-13 07:21:25 +01:00
Nick 3612786d33 feat(build_mode): close PARTIAL gaps — dichotomy wave
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 41s
Auto-version and Release / release (push) Canceled after 47s
CI Pipeline / type-check (push) Canceled after 32s
deploy / deploy (push) Canceled after 47s
CI Pipeline / lint (push) Canceled after 46s
CI Pipeline / unit-tests (push) Canceled after 46s
Port the 12 audit-missing fns of src/rune/build_mode.py name-preserving
into the existing Go impl (contract BUILDER-2026-10-13T02:02:02Z-dad27f-
factory-gap-bm): _load_state/_save_state (ledger IO seam, buildsDir
injected), assess_complexity, and the full start_* phase-transition
family — the build-pipeline state machine frozen transition-by-transition
in declaration order via the SHARED freeze_truth harness (extended
backward-compatibly: dotted fn resolution + recv receiver rebuild for
class-based modules + the pinned clock its docstring promised, envelope
files carry frozen_now so --verify needs no env).

43 frozen cases byte-identical against the live oracle; _save_state byte
contract pinned by ledger_load_fixture.json (Python json.dump(asdict,
indent=2), phases in dict-insertion order via ledger first-occurrence);
_load_state error text pinned. Coverage 20/33 → 33/33 (audit-named).
2026-10-13 07:21:00 +01:00
Nick 251fa36df1 feat(inference_paths): port to Go — dichotomy wave
LEDGER VERDICT: GO (docs/language-dichotomy-ledger.md) — the journal
write is I/O-bound file IO (decision tree: I/O-bound → Go) and the
census is simple counting over a static table (Laws 3/7: simple
operations stay in the caller's language; FFI overhead would exceed
the compute benefit — the census_report fold is ~16 increments).

parity: every public function of inference_paths ported — the CENSUS
table (all 16 call sites, insertion order preserved, notes verbatim),
trace_side_path's record shape (schema_version 1, kind side_path,
module/function/model/task_id/duration_ms, at) with the no-clock law
(`at` is a kernel argument — the oracle renders it via
time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()); the freeze pins
time.gmtime), and census_report (total / by_kind fold / the EXCLUDED
list with documented reasons). Boundary law: the JOURNAL attempt
(rune.inference_trace import + record_trace + the journaled flag)
stays in the Python facade — the Go kernel owns the record shape and
the report. ORACLE DIVERGENCE NOTE (observable behavior pinned, not
fixed): the oracle's journal path is currently dead — InferenceTrace's
signature drifted (requires resolved_context_window/input_budget/
model_calls; the oracle passes prompt_tokens/output_tokens/cost), so
trace_side_path ALWAYS returns journaled=False via the except branch.
The frozen truth records that faithfully; the facade keeps its own
float duration_ms (Python renders 0.0 where Go marshals 0 — the
battery compares semantically). Journal attempts in the battery write
to throwaway temp dirs, never the real journal. gen_inference_paths_
truth.py freezes 7 cases (record defaults/full/zero/float/empty +
journal-failure branch + full census report); replay mode re-verifies
the live oracle 7/7. Go battery: go test replays truth.json VERBATIM +
the `inference-paths replay` CLI — 7/7; gofmt clean, go vet clean;
test_inference_paths.py 6/6 (no Python-side delegation pin — Go ports
are standalone per recall-uplift precedent).
2026-10-13 07:01:40 +01:00
52 changed files with 46123 additions and 55 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.262.0**
**Current release: v0.267.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.**
+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: 23%** (44/192 runtime modules at FULL)
**FULL completion: 26%** (50/192 runtime modules at FULL)
Function-level detail: 48% (1132/2373 runtime functions matched) — secondary; includes in-flight work
Function-level detail: 51% (1219/2375 runtime functions matched) — secondary; includes in-flight work
| Status | Modules | Lines | Meaning |
|---|---|---|---|
| FULL | 44 | 15039 | 80%+ of functions ported |
| PARTIAL | 101 | 46642 | 20–80% — real logic exists, gaps named below |
| NOT TOUCHED | 47 | 11546 | no name-preserving implementation |
| Total runtime | 192 | 73227 | |
| FULL | 50 | 18817 | 80%+ of functions ported |
| PARTIAL | 97 | 43133 | 20–80% — real logic exists, gaps named below |
| NOT TOUCHED | 45 | 11390 | no name-preserving implementation |
| Total runtime | 192 | 73340 | |
## NOT TOUCHED — the port queue, in priority order (largest first)
@@ -46,9 +46,7 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| tui_transport | 108 | 10 | TUI-LAST |
| canary_unbounded | 105 | 2 | TEST-INFRA |
| message_widgets | 104 | 6 | TUI-LAST |
| inference_paths | 95 | 2 | unclassified |
| canary_schema_migration | 86 | 1 | TEST-INFRA |
| meaningful_events | 61 | 3 | unclassified |
| memory_types | 54 | 2 | unclassified |
| growth_pipeline | 53 | 2 | unclassified |
| paths | 53 | 6 | unclassified |
@@ -72,24 +70,19 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| memory_store | 2333 | 30/78 | _ctx_budget, now_iso, ensure_memory_type_column, _embed, _temp_json, _entities_to_json |
| rune_operator | 2746 | 25/68 | _build_model_router, _sorted_tool_names, _filter_safety_noise, _wire_auto_filer, _reconcile_guarded, get_operator |
| context_broker | 870 | 6/28 | _py_default_estimator, _cc_core, _py_default_budget, _py_default_memory_budget, _py_memory_disabled_value, reset_discovered_windows |
| local_tool_runtime | 809 | 8/30 | _find_capability_executor, _extract_context_length, context_length, reset_context_length_cache, supports_tools, supports_thinking |
| construction_interface | 1193 | 6/27 | _to_stage_check, _guard_specs_from_obligations, t_layout, _obligations_projection, _obligation_scope_files, main |
| structural_store | 690 | 13/34 | _ss_core, _sorted, new_doc, _redact_secrets, save, canonical_digest |
| sleep_time | 984 | 8/26 | _ctx_budget, _ensure_dirs, db_connect, fetch_sessions, retain_to_store, reflect_local |
| provider_registry | 679 | 11/28 | _ctx_budget, _format_tools_openai, _execute_tool_calls, _execute_tool_calls_anthropic, get_registry, connect_provider |
| warm_router | 1518 | 19/36 | _ensure_use_history_table, record_outcome, record_neuron_fire, _py_base_level_from_uses, base_level_activation, _db |
| construction_decision | 985 | 4/20 | normalize_need, _sc_core, _py_language_placement, resolve_surface, ss_entity, implemented_contracts |
| memory_consolidation | 770 | 7/23 | _consolidation_now, _consolidation_memory_oracle, _consolidation_neuron_oracle, _load_knowledge, _save_knowledge, _load_lessons |
| work_manager | 594 | 9/25 | group_by_file, load_config, save_config, load_batches, save_batches, create_work |
| growth_delta | 449 | 5/20 | _ctx_budget, _store_db, _llm, _parse_json, _load_deltas, _save_deltas |
| provider_budget | 357 | 5/20 | get_tracker, track_usage, check_provider, get_best_provider, failover, get_status |
| safety_override | 574 | 7/22 | _keyword_stopwords, _cc_probe, cc_loader_pin, self_test, _py_matches, escalation_rate |
| spine | 975 | 20/35 | _py_sorted, _module_imports, _py_declared_surfaces, _py_project_meta_surfaces, _gather_meta_inputs, _rust_core |
| tool_executor | 1836 | 32/47 | _execute_tool_now, serialize_prepared_tool, deserialize_prepared_tool, confirm_write, _resolve_execution_cwd, _run_command |
| cron_engine | 440 | 13/27 | get_cron_engine, run_task, start_engine, stop_engine, to_dict, fire_on_task_complete |
| night_mode | 421 | 5/19 | _ctx_budget, get_night_mode, start_night_mode, stop_night_mode, get_status, get_report |
| build_mode | 521 | 20/33 | _load_state, _save_state, assess_complexity, start_research, start_feasible, start_consult |
| failure_auto_filer | 527 | 11/24 | _error_text, unconsumed, mark_consumed, unconsumed, mark_consumed, submit |
| 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 |
| elastic_cognition | 774 | 3/14 | _ctx_budget, _build_constitution, _get_constitution, _load_cloud_config, execute_at_tier, _execute_deterministic |
| identity_anchors | 542 | 5/16 | show_anchors, show_rules, show_pronouns, _announcement_patterns, _pronoun_patterns, _hedge_patterns |
@@ -168,6 +161,7 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| abstraction_ladder | 102 | 3/4 | _core |
| construction_depth | 172 | 2/3 | _core |
| drift_resume | 153 | 3/4 | _dr_core |
| meaningful_events | 102 | 3/4 | _kernel |
| pane_authority | 98 | 2/3 | _kernel |
| recall_router | 165 | 2/3 | handle_hook |
@@ -176,12 +170,17 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| Module | Lines | Fns | Side |
|---|---|---|---|
| curator | 1838 | 43/43 | GO |
| sleep_time | 1056 | 26/27 | GO |
| local_tool_runtime | 809 | 30/30 | GO |
| memory_consolidation | 770 | 23/23 | GO |
| persona_gate | 724 | 26/26 | GO |
| abstraction | 656 | 17/17 | GO |
| system_registry | 603 | 14/16 | RUST |
| construction_intent | 580 | 13/16 | RUST |
| capability_ledger | 571 | 18/19 | RUST |
| drift_ledger | 548 | 20/22 | RUST |
| failure_auto_filer | 527 | 24/24 | GO |
| build_mode | 521 | 32/33 | GO |
| event_wait | 518 | 14/14 | GO |
| worthiness | 469 | 12/14 | unclassified |
| tool_protocol | 461 | 22/27 | GO |
@@ -215,6 +214,7 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| skill_compiler | 115 | 4/5 | unclassified |
| failure_recovery | 108 | 1/1 | RUST |
| outcome_utility | 100 | 4/5 | unclassified |
| inference_paths | 95 | 2/2 | unclassified |
| programme_gates | 85 | 4/5 | RUST |
| impact_preview | 78 | 2/2 | RUST |
| provider_context | 48 | 1/1 | GO |
+7 -5
View File
@@ -13,14 +13,18 @@
"curator",
"drift-ledger",
"drift_ledger",
"drift_resume",
"event_wait",
"evidence_probe",
"execution_trace",
"failure_auto_filer",
"failure_recovery",
"forge",
"forge_client",
"goal",
"impact_preview",
"local_tool_runtime",
"memory_consolidation",
"message_graph",
"message_queue",
"model_routing",
@@ -38,6 +42,7 @@
"rune_spinner",
"self_modify",
"shard_manager",
"sleep_time",
"spine_language",
"state_checkpoint",
"system_registry",
@@ -48,7 +53,6 @@
"worthiness"
],
"in_flight": {
"drift_resume": "rune-wave-bb",
"inference_paths": "rune-wave-bb",
"skill_compiler": "rune-wave-bc",
"meaningful_events": "rune-wave-bc",
@@ -61,19 +65,17 @@
"evidence_capsule": "rune-wave-be",
"builder_bridge_cli": "rune-wave-be",
"context_broker": "rune-wave-bf",
"local_tool_runtime": "rune-wave-bg",
"structural_store": "rune-wave-bh",
"sleep_time": "rune-wave-bj",
"work_manager": "rune-wave-bk",
"growth_delta": "rune-wave-bl",
"provider_budget": "rune-wave-bm",
"safety_override": "rune-wave-bn",
"construction_decision": "rune-wave-bo",
"memory_consolidation": "rune-wave-bp",
"provider_registry": "rune-wave-bq",
"night_mode": "rune-wave-br",
"build_mode": "rune-wave-bs",
"failure_auto_filer": "rune-wave-bt"
"construction_interface": "rune-wave-bu",
"spine": "rune-wave-bv"
},
"excluded": [
"TUI-LAST modules",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.262.0"
version = "0.267.0"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Live parity: meaningful_events Rust kernel vs Python oracle (dichotomy
wave). Layers:
1. FROZEN — the 96 frozen-oracle cases replayed through the facade in
BOTH core modes (RUNE_ME_CORE=python floor vs auto kernel); exact
compare, inputs deep-copied.
2. FUZZ — 400 seeded random trigger/state/now triples (seed 2479)
driven through both modes; exact compare (should_fire, fire_due,
mark_fired round-trips).
"""
import copy
import json
import os
import random
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import meaningful_events as me # noqa: E402
from rune import me_loader # noqa: E402
if not me_loader.available():
print("FATAL: Rust meaningful_events core not built")
sys.exit(2)
TRUTH = json.loads(
(REPO / "src" / "rust" / "meaningful_events" / "frozen_truth.json")
.read_text())
fails = []
counts = {"frozen": 0, "fuzz": 0}
def fail(layer, name, detail):
fails.append((layer, name, detail))
print(f"FAIL[{layer}] {name}: {detail}")
def drive(mode, fn, *args):
os.environ["RUNE_ME_CORE"] = mode
try:
return fn(*copy.deepcopy(args))
finally:
os.environ["RUNE_ME_CORE"] = "auto"
def frozen():
for c in TRUTH["should_fire_cases"]:
counts["frozen"] += 1
args = (c["args"]["trigger"], c["args"]["state"], c["args"]["now"])
py = drive("python", me.should_fire, *args)
rs = drive("auto", me.should_fire, *args)
if py != rs or py != c["expect"]:
fail("frozen", f"should_fire/{c['name']}", f"{py!r} != {rs!r}")
for c in TRUTH["fire_due_cases"]:
counts["frozen"] += 1
args = (c["args"]["state"], c["args"]["now"])
py = drive("python", me.fire_due, *args)
rs = drive("auto", me.fire_due, *args)
if py != rs or py != c["expect"]:
fail("frozen", f"fire_due/{c['name']}", f"{py!r} != {rs!r}")
for c in TRUTH["mark_fired_cases"]:
counts["frozen"] += 1
args = (c["args"]["state"], c["args"]["trigger"], c["args"]["now"])
py = drive("python", me.mark_fired, *args)
rs = drive("auto", me.mark_fired, *args)
if py != rs or py != c["expect"]:
fail("frozen", f"mark_fired/{c['name']}", f"{py!r} != {rs!r}")
TRIGGER_NAMES = list(me.TRIGGERS) + ["mystery", ""]
COND_KEYS = sorted({t[0] for t in me.TRIGGERS.values()})
STOP_KEYS = sorted({t[2] for t in me.TRIGGERS.values()})
VALUES = [True, False, 0, 1, "", "yes", None, 0.5]
def rand_state(rng):
state = {}
for k in COND_KEYS + STOP_KEYS:
if rng.random() < 0.3:
state[k] = rng.choice(VALUES)
for name in list(me.TRIGGERS):
if rng.random() < 0.3:
state[f"last_fired_{name}"] = rng.choice(
[0, 0.0, rng.uniform(-500, 1500), 999.0])
return state
def fuzz():
rng = random.Random(2479)
for i in range(400):
trigger = rng.choice(TRIGGER_NAMES)
state = rand_state(rng)
now = round(rng.uniform(-100, 5000), 4)
py = drive("python", me.should_fire, trigger, state, now)
rs = drive("auto", me.should_fire, trigger, state, now)
counts["fuzz"] += 1
if py != rs:
fail("fuzz", f"fire-{i}",
f"{trigger!r}@{now}: {py!r} != {rs!r}")
continue
py = drive("python", me.fire_due, state, now)
rs = drive("auto", me.fire_due, state, now)
counts["fuzz"] += 1
if py != rs:
fail("fuzz", f"due-{i}", f"{py!r} != {rs!r}")
continue
mark_trigger = rng.choice(TRIGGER_NAMES)
py = drive("python", me.mark_fired, state, mark_trigger, now)
rs = drive("auto", me.mark_fired, state, mark_trigger, now)
counts["fuzz"] += 1
if py != rs:
fail("fuzz", f"mark-{i}", f"{py!r} != {rs!r}")
frozen()
fuzz()
total = counts["frozen"] + counts["fuzz"]
print(f"parity: {total - len(fails)}/{total} "
f"(frozen {counts['frozen']}, fuzz {counts['fuzz']})")
sys.exit(1 if fails else 0)
+2 -2
View File
@@ -47,7 +47,7 @@ elif [ "$LANG_" = "go" ]; then
fi
# Layer 3: truth file exists and is consumed
TRUTH=$(find . \( -name "frozen_*_truth.json" -o -name "frozen_truth.json" -o -name "truth.json" \) 2>/dev/null | head -1)
TRUTH=$(find . \( -name "frozen_*_truth.json" -o -name "frozen_truth.json" -o -name "truth.json" -o -name "truth_*.json" \) 2>/dev/null | head -1)
if [ -n "$TRUTH" ]; then
ROWS=$(python3 -c "import json; d=json.load(open('$TRUTH')); print(len(d) if isinstance(d,list) else sum(len(v) if isinstance(v,list) else 0 for v in d.values()))" 2>/dev/null)
check "PASS" "truth file: $TRUTH ($ROWS rows)"
@@ -118,7 +118,7 @@ else
fi
fi
# 7c: battery test references the truth FILE (not self-generated truth)
if grep -rqE 'include_str!.*truth|frozen_.*truth|truth\.json' "$CRATE_DIR" \
if grep -rqE 'include_str!.*truth|frozen_.*truth|truth[_./-]' "$CRATE_DIR" \
--include='*.rs' --include='*.go' 2>/dev/null; then
check "PASS" "7c battery reads frozen truth"
else
+161 -24
View File
@@ -17,6 +17,23 @@ Usage (as a library, from a generator script):
("other_fn", (deep_copied_obj,), {}),
], oracle_module="rune.module_name")
Class-based modules: a case may be a dict with a dotted fn name and a
"recv" receiver spec — the receiver is rebuilt from JSON via shape-matched
module dataclasses, called as an unbound method, and the expected carries
BOTH the result and the post-call receiver attributes:
cases = freeze("rune.build_mode", [
{"fn": "BuildManager.start_plan", "recv": {"cls": "BuildManager", "state": {...}},
"args": [], "kwargs": {}},
], oracle_module="rune.build_mode")
Pinned clock: the harness docstring always promised one — now it exists.
Set RUNE_FROZEN_NOW (ISO-8601) to patch the oracle module's module-global
`datetime` with a frozen clock for BOTH freeze and verify (timestamp-bearing
fns stay byte-identical across processes). Envelope files written via
write_envelope({"frozen_now", "cases"}) carry their own clock, so `--verify`
needs no env at all.
Usage (as a script, to re-verify a frozen file against the live oracle):
python3 scripts/freeze_truth.py --verify src/rust/<crate>/frozen_truth.json \
--module rune.<module>
@@ -29,10 +46,12 @@ from __future__ import annotations
import argparse
import copy
import dataclasses
import importlib
import json
import os
import sys
from datetime import datetime
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
@@ -44,42 +63,136 @@ def _pin_oracle_cores(module_name: str) -> None:
os.environ[f"RUNE_{stem.upper()}_CORE"] = "python"
def _frozen_clock(iso: str):
"""A datetime subclass pinned to `iso` (naive); .now(tz) honors tz."""
base = datetime.fromisoformat(iso)
class FrozenDatetime(datetime):
@classmethod
def now(cls, tz=None):
if tz is not None:
return base.replace(tzinfo=tz)
return base
return FrozenDatetime
def _pin_clock(mod) -> None:
"""Patch the oracle module's module-global `datetime` when RUNE_FROZEN_NOW
is set (modules that read a global datetime — e.g. build_mode._log_phase —
then produce identical timestamps in every process)."""
frozen_now = os.environ.get("RUNE_FROZEN_NOW", "")
if frozen_now and hasattr(mod, "datetime"):
mod.datetime = _frozen_clock(frozen_now)
def _resolve_fn(mod, fn_name: str):
"""Module-level name OR dotted path to a class method ("Cls.method")."""
obj = mod
for part in fn_name.split("."):
obj = getattr(obj, part)
return obj
def _shape_rebuild(mod, value):
"""Rebuild a JSON value into module types: a dict whose key set EXACTLY
matches a module-level dataclass's field names is reconstructed as that
dataclass (the convention that lets a frozen `state` dict become a live
BuildState again in a fresh process). Everything else deep-copies."""
if isinstance(value, dict):
for name in dir(mod):
obj = getattr(mod, name)
if isinstance(obj, type) and dataclasses.is_dataclass(obj):
field_names = {f.name for f in dataclasses.fields(obj)}
if field_names and field_names == set(value.keys()):
return obj(**{k: _shape_rebuild(mod, v) for k, v in value.items()})
return {k: _shape_rebuild(mod, v) for k, v in value.items()}
if isinstance(value, list):
return [_shape_rebuild(mod, v) for v in value]
return copy.deepcopy(value)
def _rebuild_receiver(mod, recv: dict):
"""recv = {"cls": "BuildManager", <attr>: <json value>, ...} → a live
instance built via __new__ (no __init__ — that would touch the real
filesystem) with the named attrs rebuilt through _shape_rebuild."""
cls = getattr(mod, recv["cls"])
inst = cls.__new__(cls)
for key, value in recv.items():
if key == "cls":
continue
setattr(inst, key, _shape_rebuild(mod, value))
return inst
def _out(value):
"""JSON-safe outward snapshot: dataclass instances → asdict."""
if dataclasses.is_dataclass(value) and not isinstance(value, type):
return dataclasses.asdict(value)
return copy.deepcopy(value)
def _snap(value):
"""Deep-snapshot a value into JSON-safe form (live-reference aliasing law)."""
return copy.deepcopy(value)
def _run_case(mod, entry) -> dict:
"""Execute one case (tuple or dict form) against the live module."""
recv = None
if isinstance(entry, dict):
fn_name = entry["fn"]
args = entry.get("args", [])
kwargs = entry.get("kwargs", {})
recv = entry.get("recv")
elif len(entry) == 3:
fn_name, args, kwargs = entry
elif len(entry) == 2:
fn_name, args = entry
kwargs = {}
else:
raise ValueError(f"bad case entry: {entry!r}")
fn = _resolve_fn(mod, fn_name)
a_snap = _snap(list(args))
k_snap = _snap(dict(kwargs))
if recv is None:
result = fn(*copy.deepcopy(a_snap), **copy.deepcopy(k_snap))
expected = _snap(result)
return {"fn": fn_name, "args": a_snap, "kwargs": k_snap, "expected": expected}
inst = _rebuild_receiver(mod, dict(recv))
result = fn(inst, *copy.deepcopy(a_snap), **copy.deepcopy(k_snap))
expected = {"result": _snap(result)}
for key in recv:
if key == "cls":
continue
try:
expected[key] = _out(getattr(inst, key))
except AttributeError:
pass # attr was never set — the case reconstructed a bare receiver
return {
"fn": fn_name, "recv": dict(recv),
"args": a_snap, "kwargs": k_snap, "expected": expected,
}
def freeze(module_name: str, cases, oracle_module: str | None = None) -> list[dict]:
"""Run each (fn_name, args, kwargs) against the live oracle; return truth.
"""Run each case against the live oracle; return truth.
Args and kwargs are deep-copied before EVERY call — the oracle may
mutate its inputs (live-reference aliasing trap). The recorded "args"
are the post-copy snapshots, so the battery replays byte-identical
inputs.
inputs. Case entries are (fn, args[, kwargs]) tuples or dicts with a
dotted "fn" and optional "recv" receiver spec (class-based modules).
"""
_pin_oracle_cores(oracle_module or module_name)
mod = importlib.import_module(oracle_module or module_name)
_pin_clock(mod)
truth = []
for entry in cases:
if len(entry) == 3:
fn_name, args, kwargs = entry
elif len(entry) == 2:
fn_name, args = entry
kwargs = {}
else:
raise ValueError(f"bad case entry: {entry!r}")
fn = getattr(mod, fn_name, None)
if fn is None:
raise AttributeError(f"{oracle_module or module_name}.{fn_name} missing — case list must name real functions")
a_snap = _snap(list(args))
k_snap = _snap(dict(kwargs))
result = fn(*copy.deepcopy(a_snap), **copy.deepcopy(k_snap))
truth.append({
"fn": fn_name,
"args": a_snap,
"kwargs": k_snap,
"expected": _snap(result),
})
truth.append(_run_case(mod, entry))
return truth
@@ -88,14 +201,38 @@ def write(truth: list[dict], path: Path) -> None:
path.write_text(json.dumps(truth, indent=2, ensure_ascii=False, sort_keys=False) + "\n")
def write_envelope(frozen_now: str, truth: list[dict], path: Path) -> None:
"""Self-contained envelope: the file carries its own pinned clock, so
`--verify` needs no RUNE_FROZEN_NOW env. List-format files (write)
stay legacy-valid."""
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(
{"frozen_now": frozen_now, "cases": truth},
indent=2, ensure_ascii=False, sort_keys=False) + "\n")
def verify(path: Path, oracle_module: str) -> int:
"""Re-freeze from the live oracle and byte-compare against the frozen file.
Catches self-consistent misreads: the battery and the generator can
agree while the oracle drifted. Returns 0 on byte-exact match.
agree while the oracle drifted. Returns 0 on byte-exact match. Accepts
a bare case list (legacy) or a {"frozen_now", "cases"} envelope (clock
pinned from the file itself).
"""
frozen = json.loads(path.read_text())
cases = [(c["fn"], c["args"], c["kwargs"]) for c in frozen]
raw = json.loads(path.read_text())
if isinstance(raw, dict):
if raw.get("frozen_now"):
os.environ["RUNE_FROZEN_NOW"] = raw["frozen_now"]
frozen = raw["cases"]
else:
frozen = raw
cases = []
for c in frozen:
if isinstance(c, dict):
cases.append({"fn": c["fn"], "args": c.get("args", []),
"kwargs": c.get("kwargs", {}), "recv": c.get("recv")})
else:
cases.append((c["fn"], c["args"], c["kwargs"]))
fresh = freeze(oracle_module, cases, oracle_module)
if json.dumps(fresh, sort_keys=True) != json.dumps(frozen, sort_keys=True):
print(f"MISMATCH: regenerated truth differs from {path}")
+245
View File
@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""gen_build_mode_gap_truth.py — build-mode gap-closing truth battery
(contract BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm).
Closes the PARTIAL audit gaps: _load_state, _save_state, assess_complexity
and the full start_* phase-transition family (start_research, start_feasible,
start_consult, start_consent, start_plan, start_build_phase, start_verify,
start_integrate, start_record) — the build-pipeline state machine, frozen
transition-by-transition in declaration order (phase names and ordering are
load-bearing for the pipeline).
Uses the SHARED harness (scripts/freeze_truth.py): dotted fn names + recv
receiver rebuild + RUNE_FROZEN_NOW pinned clock. The envelope carries its
own frozen_now, so `--verify` needs no env:
PYTHONPATH=src python3 scripts/freeze_truth.py \
--verify src/go/build-mode/truth_buildmode_gap.json \
--module rune.build_mode
NOTE: the oracle's _log_phase/_save_state write to BUILDS_DIR (module
global from expanduser). Run generator AND verify with a sandboxed HOME to
contain the incidental state files (truth never reads them back):
HOME=$(mktemp -d) PYTHONPATH=src python3 scripts/freeze_truth.py ...
_load_state/_save_state are IO seams: _save_state's byte contract is frozen
as ledger_load_fixture.json (exact bytes of json.dump(asdict(state),
indent=2)); the generator also proves the oracle roundtrip (write fixture →
_load_state → equal state). _load_state's FileNotFoundError path is pinned
by the Go test (error text "Build <id> not found").
Usage: python3 scripts/gen_build_mode_gap_truth.py (from repo root)
"""
import dataclasses
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 _frozen_clock, freeze, write_envelope # noqa: E402
from rune import build_mode as bm # noqa: E402
FROZEN_NOW = "2026-10-13T02:20:00"
STAMP = FROZEN_NOW + "+00:00"
BUILD_ID = "20261013-022000"
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW # pinned clock for the harness
os.environ["RUNE_BUILD_MODE_CORE"] = "python" # poisoned-truth law
bm.datetime = _frozen_clock(FROZEN_NOW) # pin the SEED walk too (recv states
# must not carry live-clock timestamps — the truth must be self-consistent)
# BYTE-PARITY LAW for the IO fixture: Go maps marshal dict keys SORTED, so
# every generator-supplied dict below uses sorted keys (Python insertion
# order == sorted order) — then SaveState can reproduce json.dump bytes
# exactly. The oracle-internal feasible payload (feasible, risk, details)
# is the one unavoidable exception — fixture therefore comes from the
# correction-cycle state (single-key payloads only); dict-heavy states are
# parity-checked at the parsed level (truth replay + roundtrip test).
def fresh_mgr() -> bm.BuildManager:
m = bm.BuildManager.__new__(bm.BuildManager)
m.state = bm.BuildState(
build_id=BUILD_ID, description="gap battery build", created_at=STAMP)
return m
def seed(mgr) -> dict:
return dataclasses.asdict(mgr.state)
def main():
cases = []
mgr = fresh_mgr()
def call(fn, *args, **kwargs):
"""Freeze one transition: recv = PRE-state, then apply to the live
walk manager (the harness re-runs it on a rebuilt receiver)."""
cases.append({
"fn": f"BuildManager.{fn.__name__}",
"recv": {"cls": "BuildManager", "state": seed(mgr)},
"args": list(args), "kwargs": kwargs,
})
fn(mgr, *args, **kwargs)
# ── assess_complexity ────────────────────────────────────────────
# bare receiver (the fn never touches state) + a seeded receiver.
cases.append({"fn": "BuildManager.assess_complexity",
"recv": {"cls": "BuildManager"}, "args": [], "kwargs": {}})
cases.append({"fn": "BuildManager.assess_complexity",
"recv": {"cls": "BuildManager", "state": seed(mgr)},
"args": [], "kwargs": {}})
# ── the canonical 11-phase happy path, IN DECLARATION ORDER ──────
call(bm.BuildManager.complete_assess,
bm.BuildManager.assess_complexity(mgr))
call(bm.BuildManager.start_research)
call(bm.BuildManager.complete_research,
{"findings": "gap battery pattern", "source": "oracle"})
call(bm.BuildManager.start_feasible)
call(bm.BuildManager.complete_feasible, True, "low",
{"loc_estimate": 120, "worktree_isolated": True})
call(bm.BuildManager.start_consult)
call(bm.BuildManager.complete_consult, ["gap-closing pattern"])
call(bm.BuildManager.start_consent)
call(bm.BuildManager.complete_consent, True)
call(bm.BuildManager.start_plan)
call(bm.BuildManager.complete_plan,
[{"batch": 1, "files": ["a.py"]}, {"batch": 2, "files": ["b.py"]}])
call(bm.BuildManager.start_build_phase)
call(bm.BuildManager.complete_build_phase,
[{"batch": 1, "ok": True}, {"batch": 2, "ok": True}])
call(bm.BuildManager.start_verify)
call(bm.BuildManager.complete_verify, True, [])
call(bm.BuildManager.start_integrate)
call(bm.BuildManager.complete_integrate, True, [])
call(bm.BuildManager.start_record)
call(bm.BuildManager.complete_record)
# ── _save_state branches ─────────────────────────────────────────
# state None → early return (no file, no dirs)
cases.append({"fn": "BuildManager._save_state",
"recv": {"cls": "BuildManager", "state": None},
"args": [], "kwargs": {}})
# state present → writes BUILDS_DIR/<id>/ledger.json (sandboxed HOME);
# result None + state unchanged.
call(bm.BuildManager._save_state)
# ── correction cycle (corrections increment; fixed False and True) ─
cMgr = fresh_mgr()
cMgr.state.corrections = 1
def ccall(fn, *args, **kwargs):
cases.append({
"fn": f"BuildManager.{fn.__name__}",
"recv": {"cls": "BuildManager", "state": seed(cMgr)},
"args": list(args), "kwargs": kwargs,
})
fn(cMgr, *args, **kwargs)
ccall(bm.BuildManager.start_correct)
ccall(bm.BuildManager.complete_correct, False)
ccall(bm.BuildManager.start_correct)
ccall(bm.BuildManager.complete_correct, True)
# ── verify/integrate FAILURE branches (failure lives in DETAILS —
# status stays "complete", the pinned oracle quirk) ─────────────
fMgr = fresh_mgr()
def fcall(fn, *args, **kwargs):
cases.append({
"fn": f"BuildManager.{fn.__name__}",
"recv": {"cls": "BuildManager", "state": seed(fMgr)},
"args": list(args), "kwargs": kwargs,
})
fn(fMgr, *args, **kwargs)
fcall(bm.BuildManager.complete_verify, False, ["test_x failed"])
fcall(bm.BuildManager.start_integrate)
fcall(bm.BuildManager.complete_integrate, False, ["scope breach"])
# ── feasibility details=None branch (default {}) ─────────────────
dMgr = fresh_mgr()
cases.append({
"fn": "BuildManager.complete_feasible",
"recv": {"cls": "BuildManager", "state": seed(dMgr)},
"args": [True, "low"], "kwargs": {},
})
# ── resume scan branches (get_resume_point / can_resume) ─────────
# state None → None/False; empty phases → None; in_progress → found;
# failed → found; all complete → None.
def scan_case(state_dict):
cases.append({"fn": "BuildManager.get_resume_point",
"recv": {"cls": "BuildManager", "state": state_dict},
"args": [], "kwargs": {}})
cases.append({"fn": "BuildManager.can_resume",
"recv": {"cls": "BuildManager", "state": state_dict},
"args": [], "kwargs": {}})
scan_case(None)
scan_case(seed(fresh_mgr()))
p = seed(fresh_mgr())
p["phases"]["plan"] = "in_progress"
scan_case(p)
f = seed(fresh_mgr())
f["phases"]["verify"] = "failed"
scan_case(f)
scan_case(seed(mgr)) # fully walked: every phase complete
# ── get_status branches ──────────────────────────────────────────
cases.append({"fn": "BuildManager.get_status",
"recv": {"cls": "BuildManager", "state": None},
"args": [], "kwargs": {}})
cases.append({"fn": "BuildManager.get_status",
"recv": {"cls": "BuildManager", "state": seed(mgr)},
"args": [], "kwargs": {}})
# ── _load_state IO roundtrip + byte fixture ──────────────────────
# The fixture is the CORRECTION-CYCLE state: every dict in it is
# single-key or sorted-key (see BYTE-PARITY LAW) — the one state whose
# json.dump bytes Go can reproduce exactly. The full-walk state (with
# the oracle-internal feasible payload) is roundtrip-proven at the
# parsed level instead.
full_state = dataclasses.asdict(mgr.state)
fixture_state = dataclasses.asdict(cMgr.state)
with tempfile.TemporaryDirectory() as tmp:
bm.BUILDS_DIR = tmp # oracle reads the module global at call time
build_dir = Path(tmp) / BUILD_ID
build_dir.mkdir(parents=True)
ledger_bytes = json.dumps(fixture_state, indent=2,
ensure_ascii=False).encode("utf-8")
(build_dir / "ledger.json").write_bytes(ledger_bytes)
full_bytes = json.dumps(full_state, indent=2,
ensure_ascii=False).encode("utf-8")
(build_dir.parent / "full-walk-build").mkdir()
(build_dir.parent / "full-walk-build" / "ledger.json").write_bytes(
full_bytes)
m2 = bm.BuildManager.__new__(bm.BuildManager)
loaded = bm.BuildManager._load_state(m2, BUILD_ID)
assert dataclasses.asdict(loaded) == fixture_state, "roundtrip broke"
full_id = "full-walk-build"
m3 = bm.BuildManager.__new__(bm.BuildManager)
loaded_full = bm.BuildManager._load_state(m3, full_id)
assert dataclasses.asdict(loaded_full) == full_state, "full broke"
# missing build → FileNotFoundError("Build <id> not found")
try:
bm.BuildManager._load_state(m2, "no-such-build")
raise SystemExit("_load_state missing-path did NOT raise")
except FileNotFoundError as e:
assert str(e) == f"Build no-such-build not found", str(e)
fixture = REPO / "src/go/build-mode" / "ledger_load_fixture.json"
fixture.write_bytes(ledger_bytes)
print(f"wrote {fixture} ({len(ledger_bytes)} bytes, oracle roundtrip proven)")
truth = freeze("rune.build_mode", cases, "rune.build_mode")
out = REPO / "src/go/build-mode" / "truth_buildmode_gap.json"
write_envelope(FROZEN_NOW, truth, out)
print(f"wrote {out} ({len(truth)} frozen cases)")
if __name__ == "__main__":
main()
+196
View File
@@ -0,0 +1,196 @@
#!/usr/bin/env python3
"""gen_inference_paths_truth.py — freeze/replay parity truth for
inference_paths (#145 census + trace wiring, dichotomy wave #2479).
Freeze mode (default): exercises EVERY public function of the LIVE Python
oracle (src/rune/inference_paths.py) across every branch and records
(kernel_input, expected_kernel_output) pairs into
src/go/inference-paths/truth.json (the GO port's battery replays this
VERBATIM).
Replay mode (--replay): re-runs the SAME scenarios against the live
Python oracle and asserts facade-level parity against the frozen file.
Kernel-level (Go) parity runs via `go test ./...` + the `replay` CLI in
src/go/inference-paths — the battery embeds the frozen file verbatim.
No-clock law: the wall clock is frozen by patching time.gmtime, so every
kernel payload carries its own `at` and replay is deterministic
regardless of run date.
Boundary law (ledger verdict: GO — the journal write is I/O-bound file
IO and the census is simple counting): the JOURNAL attempt
(rune.inference_trace import + record_trace + the journaled flag) and
the grep-verified census-completeness obligations stay in the Python
facade — the Go kernel owns the record shape (schema_version, kind,
module, function, model, task_id, duration_ms, at) and census_report.
Journal attempts in the battery write to throwaway temp dirs (never the
real journal); the failure branch passes a non-creatable dir so the
oracle's except path (journaled=False) is exercised deterministically.
Deep-copy law: every input is deep-copied before it reaches the oracle.
"""
import copy
import datetime
import json
import os
import sys
import tempfile
import time
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TRUTH_PATH = os.path.join(REPO, "src", "go", "inference-paths", "truth.json")
REPLAY = "--replay" in sys.argv
os.environ["RUNE_IT_CORE"] = "python" # poisoned-truth law: the journal
# path's own delegated serializer must not vary under the freeze
sys.path.insert(0, os.path.join(REPO, "src"))
sys.path.insert(0, os.path.join(REPO, "src", "rune"))
import inference_paths as oracle_mod # noqa: E402
FROZEN_AT = "2026-10-12T12:34:56Z"
FROZEN_STRUCT = time.strptime(FROZEN_AT, "%Y-%m-%dT%H:%M:%SZ")
# no-clock law: freeze the wall clock BEFORE any scenario runs
oracle_mod.time.gmtime = lambda secs=None: FROZEN_STRUCT
class Case:
def __init__(self, name, fn):
self.name = name
self.fn = fn
# ── trace_side_path ──────────────────────────────────────────────────────────
def _tsp_case(rec, name, trace_dir, **kwargs):
args = {"module": "", "function": "", "model": "", "task_id": "",
"duration_ms": 0.0}
args.update(kwargs)
args_c = copy.deepcopy(args)
got = oracle_mod.trace_side_path(trace_dir=trace_dir, **copy.deepcopy(args))
rec(name, {**args_c, "at": FROZEN_AT}, got,
{"record": {k: v for k, v in got.items() if k != "journaled"}})
def c_tsp_defaults(rec):
_tsp_case(rec, "tsp-defaults-side-path", tempfile.mkdtemp(prefix="ip_t_"),
module="goal", function="_goal")
def c_tsp_full(rec):
_tsp_case(rec, "tsp-full-fields", tempfile.mkdtemp(prefix="ip_t_"),
module="rune_operator", function="_runtime_for_model",
model="llama3", task_id="t1", duration_ms=12.5)
def c_tsp_zero_duration(rec):
_tsp_case(rec, "tsp-zero-duration", tempfile.mkdtemp(prefix="ip_t_"),
module="witness", function="_witness")
def c_tsp_float_precision(rec):
_tsp_case(rec, "tsp-float-precision", tempfile.mkdtemp(prefix="ip_t_"),
module="tiered_executor", function="_execute",
model="qwen2.5", task_id="task-99", duration_ms=123.456)
def c_tsp_journal_failure(rec):
# non-creatable dir → record_trace raises → journaled=False branch
_tsp_case(rec, "tsp-journal-failure-false",
"/nonexistent-ip-truth/nope", module="curator", function="_embed")
def c_tsp_empty_module(rec):
_tsp_case(rec, "tsp-empty-module-function", tempfile.mkdtemp(prefix="ip_t_"))
# ── census_report ────────────────────────────────────────────────────────────
def c_cr_full(rec):
got = oracle_mod.census_report()
rec("cr-full-counts-and-exclusions", {}, got, got)
# ── driver ───────────────────────────────────────────────────────────────────
TRACE = [c_tsp_defaults, c_tsp_full, c_tsp_zero_duration,
c_tsp_float_precision, c_tsp_journal_failure, c_tsp_empty_module]
REPORT = [c_cr_full]
GROUPS = [("trace_side_path", TRACE), ("census_report", REPORT)]
def canon(x) -> str:
return json.dumps(json.loads(json.dumps(x, default=str)), sort_keys=True)
def main():
frozen = None
if REPLAY:
with open(TRUTH_PATH) as f:
frozen = json.load(f)["cases"]
groups = {}
for group, cases in GROUPS:
recs = []
def rec(name, inp, oracle_ret, expected, _r=recs):
entry = {"name": name, "input": inp, "return": oracle_ret,
"expected": expected}
if REPLAY:
old = next(c for c in frozen[group] if c["name"] == name)
for key_ in ("input", "return", "expected"):
got, want = entry[key_], old[key_]
if canon(got) != canon(want):
print(f"FACADE DIVERGE [{group}] {name} {key_}")
print(" got: ",
json.dumps(got, sort_keys=True, default=str)[:600])
print(" want:",
json.dumps(want, sort_keys=True, default=str)[:600])
recs.append({"name": name, "diverged": key_})
return
_r.append(entry)
for c in cases:
c(rec)
groups[group] = recs
total = sum(len(v) for v in groups.values())
if REPLAY:
failures = sum(1 for v in groups.values()
for c in v if "diverged" in c)
print(f"replay: facade {total - failures}/{total} "
f"(kernel/Go parity: `go test ./...` + `replay` CLI, "
f"battery embeds truth.json verbatim)")
return 1 if failures else 0
doc = {
"frozen": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"oracle": "src/rune/inference_paths.py",
"pin": "time.gmtime frozen at " + FROZEN_AT +
" + RUNE_IT_CORE=python",
"note": "Frozen via scripts/gen_inference_paths_truth.py against "
"the live Python oracle. Ledger verdict: GO (the journal "
"write is I/O-bound file IO; the census is simple "
"counting). The journal attempt (rune.inference_trace + "
"the journaled flag) stays in the Python facade — the Go "
"kernel owns the record shape (schema_version, kind, "
"module, function, model, task_id, duration_ms, at; `at` "
"is a kernel argument — no-clock law) and census_report. "
"Battery embeds this VERBATIM; float durations compare "
"semantically (Python renders 0.0, Go marshals 0 — same "
"value).",
"cases": groups,
}
os.makedirs(os.path.dirname(TRUTH_PATH), exist_ok=True)
with open(TRUTH_PATH, "w") as f:
json.dump(doc, f, indent=1)
f.write("\n")
print(f"frozen {total} cases → {os.path.relpath(TRUTH_PATH, REPO)}")
return 0
if __name__ == "__main__":
sys.exit(main())
+133
View File
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
"""Freeze the meaningful_events oracle truth (dichotomy wave, #2479).
Generator law: RUNE_ME_CORE=python pinned, every input deep-copied,
every public function exercised across ALL branches:
* should_fire — unknown trigger; each of the 8 stop conditions; each
of the 8 absent conditions; rate limiting incl. Python int()
truncation (fractional remaining), future last_fired, last_fired 0;
falsy condition/stop values (0, "", None) vs truthy
* fire_due — table-order listing, subsets, none due, stop-blocked
* mark_fired — key set on copy (original untouched), unknown trigger
still records, explicit now
"""
import copy
import json
import os
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
os.environ["RUNE_ME_CORE"] = "python"
import meaningful_events as me # noqa: E402
cases_should_fire = []
cases_fire_due = []
cases_mark_fired = []
def case_fire(name, trigger, state, now):
trigger = copy.deepcopy(trigger)
state = copy.deepcopy(state)
now = copy.deepcopy(now)
cases_should_fire.append({
"name": name,
"args": {"trigger": trigger, "state": state, "now": now},
"expect": me.should_fire(copy.deepcopy(trigger),
copy.deepcopy(state),
copy.deepcopy(now)),
})
def case_due(name, state, now):
state = copy.deepcopy(state)
now = copy.deepcopy(now)
cases_fire_due.append({
"name": name,
"args": {"state": state, "now": now},
"expect": me.fire_due(copy.deepcopy(state), copy.deepcopy(now)),
})
def case_mark(name, state, trigger, now):
state = copy.deepcopy(state)
trigger = copy.deepcopy(trigger)
now = copy.deepcopy(now)
st = copy.deepcopy(state)
expect = me.mark_fired(st, copy.deepcopy(trigger), copy.deepcopy(now))
cases_mark_fired.append({
"name": name,
"args": {"state": state, "trigger": trigger, "now": now},
"expect": expect,
"input_unchanged": st == state,
})
# ── should_fire: every branch ───────────────────────────────────────────────
case_fire("unknown-trigger", "nope", {}, 1000.0)
for trig in me.TRIGGERS:
cond, limit, stop = me.TRIGGERS[trig]
case_fire(f"fires-{trig}", trig, {cond: True}, 1000.0)
case_fire(f"fires-with-old-last-{trig}", trig,
{cond: True, f"last_fired_{trig}": 0.0}, 1000.0)
case_fire(f"stop-met-{trig}", trig, {cond: True, stop: True}, 1000.0)
case_fire(f"stop-truthy-string-{trig}", trig, {cond: True, stop: "yes"}, 1000.0)
case_fire(f"stop-falsy-zero-not-met-{trig}", trig,
{cond: True, stop: 0}, 1000.0)
case_fire(f"condition-absent-{trig}", trig, {}, 1000.0)
case_fire(f"condition-falsy-empty-str-{trig}", trig, {cond: ""}, 1000.0)
case_fire(f"condition-falsy-null-{trig}", trig, {cond: None}, 1000.0)
case_fire(f"rate-limited-{trig}", trig,
{cond: True, f"last_fired_{trig}": 1000.0 - (limit - 100.0)}, 1000.0)
case_fire(f"rate-limited-exact-boundary-{trig}", trig,
{cond: True, f"last_fired_{trig}": 1000.0 - limit}, 1000.0)
case_fire("rate-truncation-fractional", "task_blockers",
{"task_blocked": True, "last_fired_task_blockers": 400.5}, 1000.0)
case_fire("rate-truncation-tiny-remaining", "owner_corrections",
{"correction_received": True, "last_fired_owner_corrections": 700.0001},
1000.0)
case_fire("future-last-rate-limited", "task_blockers",
{"task_blocked": True, "last_fired_task_blockers": 5000.0}, 1000.0)
case_fire("negative-now-last-fractional", "curiosity_candidates",
{"novel_material_present": True, "last_fired_curiosity_candidates": -100.25},
1000.0)
case_fire("float-now-and-last", "repeated_failure",
{"same_failure_3x": True, "last_fired_repeated_failure": 123.456},
789.012)
# ── fire_due: ordering + subsets ────────────────────────────────────────────
ALL_DUE = {cond: True for cond, _, _ in me.TRIGGERS.values()}
case_due("all-eight-due-table-order", ALL_DUE, 1000.0)
case_due("none-due", {}, 1000.0)
case_due("subset-due", {"task_blocked": True, "correction_received": 1}, 1000.0)
case_due("stop-blocks-some", {**ALL_DUE, "task_unblocked": True}, 1000.0)
case_due("rate-limits-block-some",
{cond: True for cond, _, _ in me.TRIGGERS.values()}
| {"last_fired_owner_corrections": 999.0}, 1000.0)
case_due("falsy-conditions-only",
{cond: 0 for cond, _, _ in me.TRIGGERS.values()}, 1000.0)
# ── mark_fired: copy semantics ──────────────────────────────────────────────
case_mark("mark-explicit-now", {"task_blocked": True}, "task_blockers", 1000.0)
case_mark("mark-unknown-trigger-still-records", {}, "mystery", 55.5)
case_mark("mark-overwrites-existing", {"last_fired_task_blockers": 1.0},
"task_blockers", 2000.0)
case_mark("mark-empty-state", {}, "owner_corrections", 0.25)
truth = {
"module": "meaningful_events",
"core_pin": "RUNE_ME_CORE=python",
"should_fire_cases": cases_should_fire,
"fire_due_cases": cases_fire_due,
"mark_fired_cases": cases_mark_fired,
}
out = REPO / "src" / "rust" / "meaningful_events" / "frozen_truth.json"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(truth, indent=1, sort_keys=True) + "\n",
encoding="utf-8")
n = len(cases_should_fire) + len(cases_fire_due) + len(cases_mark_fired)
print(f"frozen {n} cases -> {out}")
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""gen_self_model_truth.py — freeze the self_model parity oracle (dichotomy
wave #2479 tranche).
Generator law: RUNE_SMM_CORE=python pinned, inputs deep-copied, every
public function and branch exercised (estimate_tokens incl. unicode and
sub/over boundaries; compile_self_model incl. empty corpus, exact-fit
boundary, evidence overflow, key defaults, stable weight ties, zero and
negative budgets, small-weight ordering, default budget; why_question incl.
statement match, evidence match, case-insensitivity, empty topic, empty
model). Output: src/rust/self_model/frozen_sm_truth.json — replayed
VERBATIM by the crate's cfg(test) battery.
"""
import copy
import json
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT / "src" / "rune"))
os.environ["RUNE_SMM_CORE"] = "python"
import self_model as sm # noqa: E402
cases: list = []
def freeze(fn, args):
args = copy.deepcopy(args)
f = getattr(sm, fn)
expected = f(**copy.deepcopy(args))
cases.append({"fn": fn, "args": args, "expected": expected})
# --- estimate_tokens: every boundary ---
for text in [
"", # max(1, 0) -> 1
"ab", # 0 // 4 -> 1
"abcd", # exactly 1
"abcde", # 1
"a" * 8, # 2
"a" * 9, # 2
"a" * 12, # 3
"hello — em-dash unicode", # char count, not bytes
"line one\nline two\nline three",
]:
freeze("estimate_tokens", {"text": text})
# --- compile_self_model: every branch ---
freeze("compile_self_model", {"corpus": []}) # empty, default budget
freeze("compile_self_model", { # single fits
"corpus": [{"text": "I speak plainly and show my work.",
"source": "persona.md", "weight": 0.9}],
})
freeze("compile_self_model", { # exact-fill boundary + overflow
"corpus": [
{"text": "a" * 16, "source": "s1", "weight": 2.0}, # tok 4
{"text": "b" * 16, "source": "s2", "weight": 1.5}, # tok 4 -> used 8 == budget
{"text": "c", "source": "s3", "weight": 1.0}, # tok 1 -> evidence
],
"budget_tokens": 8,
})
freeze("compile_self_model", { # missing keys -> defaults
"corpus": [{"text": "no weight no source"}, {"source": "only-source"},
{"weight": 0.1}],
})
freeze("compile_self_model", { # stable ties keep order
"corpus": [
{"text": "first", "source": "a", "weight": 1.0},
{"text": "second", "source": "b", "weight": 1.0},
{"text": "third", "source": "c", "weight": 1.0},
],
"budget_tokens": 3,
})
freeze("compile_self_model", {"corpus": [{"text": "x" * 40, "source": "big",
"weight": 9.9}],
"budget_tokens": 0}) # zero budget -> all evidence
freeze("compile_self_model", {"corpus": [{"text": "x" * 40, "source": "big",
"weight": 9.9}],
"budget_tokens": -3}) # negative budget
freeze("compile_self_model", { # small weights order round
"corpus": [{"text": "quarter weight", "source": "q", "weight": 0.25},
{"text": "three-quarter weight", "source": "t", "weight": 0.75}],
"budget_tokens": 50,
})
freeze("compile_self_model", { # 219/220 boundary at default budget
"corpus": [
{"text": "w" * 700, "source": "big1", "weight": 3.0}, # tok 175
{"text": "y" * 176, "source": "big2", "weight": 2.0}, # tok 44 -> 219
{"text": "z" * 4, "source": "over", "weight": 1.0}, # tok 1 -> evidence
],
})
freeze("compile_self_model", { # first item alone exceeds budget
"corpus": [{"text": "v" * 100, "source": "huge", "weight": 5.0},
{"text": "tiny", "source": "t", "weight": 0.4}],
"budget_tokens": 10,
})
compiled = sm.compile_self_model(copy.deepcopy([
{"text": "I prefer evidence over vibes.", "source": "s1", "weight": 2.0},
{"text": "CONTRADICTIONS get surfaced loudly.", "source": "s2", "weight": 1.5},
{"text": "Growth is measured, not asserted.", "source": "s3", "weight": 1.0},
{"text": "quiet evidence overflow note", "source": "s4", "weight": 0.1},
]), budget_tokens=10)
# --- why_question: every branch ---
freeze("why_question", {"model": compiled, "topic": "evidence"}) # statements + evidence hits
freeze("why_question", {"model": compiled, "topic": "EVIDENCE"}) # case-insensitive both ways
freeze("why_question", {"model": compiled, "topic": "growth"}) # single statement hit
freeze("why_question", {"model": compiled, "topic": "absent-topic"}) # no hits
freeze("why_question", {"model": compiled, "topic": ""}) # empty topic matches all
freeze("why_question", {"model": {}, "topic": "anything"}) # empty model
freeze("why_question", { # bare evidence-only model
"model": {"evidence_ref": [{"text": "overflowed raw note",
"source": "raw"}]},
"topic": "raw",
})
doc = {"module": "self_model", "core_env": "RUNE_SMM_CORE=python",
"cases": cases}
out = ROOT / "src" / "rust" / "self_model" / "frozen_sm_truth.json"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(doc, indent=1) + "\n")
print(f"frozen {len(cases)} cases -> {out}")
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
"""gen_work_manager_truth.py — freeze work_manager oracle truth via the
SHARED harness (scripts/freeze_truth.py, freeze()).
Laws honoured:
* poisoned-truth: freeze() pins RUNE_WORK_MANAGER_CORE=python.
* hermetic: the oracle derives WORK_DIR/BATCH_FILE/CONFIG_FILE/META_FILE
from expanduser("~") AT IMPORT — so HOME is repointed at a fresh temp
dir BEFORE the oracle import. Never touches the real ~/.rune/work.
* self-seeding: the case SEQUENCE is replayed in order from an EMPTY
home (that is exactly what `freeze_truth.py --verify` does), so every
expected value is reproducible from nothing.
* JSON-native: every arg and every expected value round-trips JSON
(harness law). Cases whose oracle return carries dataclass instances
(load_config/load_meta/update_meta_from_batches/get_next_batch/
non-empty group_by_file / audit_to_work_items / create_batches with
items) or wall-clock timestamps (create_batches/create_work `created`,
complete_batch `completed`) are exercised through their JSON-native
integration surface instead (get_status / get_meta_status /
auto_fill_from_audit summaries) and by the Go seam unit tests + live
parity sweep (timestamp-normalized).
Re-verify (fresh EMPTY home — the sequence self-seeds):
HOME=$(mktemp -d) PYTHONPATH=src python3 scripts/freeze_truth.py \
--verify src/go/work-manager/frozen_wm_truth.json \
--module rune.work_manager
"""
import json
import os
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "scripts"))
sys.path.insert(0, str(REPO / "src"))
os.environ["HOME"] = tempfile.mkdtemp(prefix="wm_truth_home_")
from freeze_truth import freeze, write # noqa: E402 (shared harness)
import rune.work_manager as wm # noqa: E402 (import AFTER the HOME pin)
OUT = REPO / "src" / "go" / "work-manager" / "frozen_wm_truth.json"
# ── audit fixtures ────────────────────────────────────────────────────────
# AUDIT_MIXED hits: auto-fix detection (R001/R013), rule grouping,
# rule=""→severity fallback, 4-files-in-one-group → file-split branch,
# second group (insertion order), missing finding keys (defaults).
AUDIT_MIXED = {
"groups": [
{"findings": [
{"message": "bare except", "file": "a.py", "line": 10,
"rule": "R001", "severity": "high"},
{"message": "retry wrap", "file": "a.py", "line": 22,
"rule": "R013", "severity": "medium"},
{"message": "m1", "file": "b.py", "line": 5,
"rule": "R100", "severity": "low"},
{"message": "m2", "file": "c.py", "line": 7,
"rule": "R100", "severity": "low"},
{"message": "m3", "file": "d.py", "line": 9,
"rule": "R100", "severity": "low"},
{"message": "m4", "file": "e.py", "line": 11,
"rule": "R100", "severity": "low"},
{"message": "fallback severity", "file": "f.py", "line": 3,
"rule": "", "severity": "high"},
]},
{"findings": [
{"message": "second group", "file": "g.py", "line": 1,
"rule": "R200", "severity": "medium"},
{"message": "defaults only"},
]},
],
}
# AUDIT_BIG hits: >MAX_BATCH_SIZE chunk split (15+3), cloud routing
# (>LOCAL_THRESHOLD under auto). Single file → the ≤MAX_FILES_PER_BATCH
# branch keeps files a 1-element list (Python builds it via list(set(..)),
# whose order is hash-randomised for >1 element — avoided in frozen truth).
AUDIT_BIG = {
"groups": [
{"findings": [
{"message": f"m{i}", "file": "big.py", "line": i,
"rule": "R300", "severity": "low"}
for i in range(18)
]},
],
}
cases = []
# ── A. fresh state ────────────────────────────────────────────────────────
cases.append(("get_status", (), {})) # zeros + default routing
cases.append(("load_batches", (), {})) # missing file → []
cases.append(("load_meta", (), {})) # missing file → None
cases.append(("save_batches", ([],), {})) # creates dir + writes []
cases.append(("load_batches", (), {})) # file-exists branch
cases.append(("group_by_file", ([],), {})) # empty group
cases.append(("create_batches", ([], "nothing"), {}))
cases.append(("create_work", ([], "empty task"), {})) # shell: load_config+save
cases.append(("audit_to_work_items", ({"groups": []},), {}))
cases.append(("audit_to_work_items", ({"groups": [{"findings": []}]},), {}))
cases.append(("auto_fill_from_audit", ({"groups": []},), {}))
# ── B. the integration case: audit → items → batches → routing ────────────
cases.append(("auto_fill_from_audit", (AUDIT_MIXED, "audit sweep"), {}))
cases.append(("get_status", (), {}))
cases.append(("complete_batch", ("B1", "auto-fixed all"), {}))
cases.append(("get_status", (), {}))
cases.append(("complete_batch", ("NOPE", "x"), {})) # unknown id → no-op
cases.append(("fail_batch", ("B2", "verify red"), {}))
cases.append(("get_status", (), {}))
cases.append(("get_meta_status", (), {})) # meta absent → create, partial
for bid in ("B3", "B4", "B5", "B6", "B7", "B8"):
cases.append(("complete_batch", (bid, "ok"), {}))
cases.append(("get_meta_status", (), {})) # all complete branch
cases.append(("get_status", (), {}))
cases.append(("clear_work", (), {}))
cases.append(("get_status", (), {})) # reload after clear
cases.append(("get_meta_status", (), {})) # meta exists; empty batches
cases.append(("save_config", ({"model_routing": "cloud"},), {})) # non-dataclass → suppressed
# ── C. chunk-split + cloud routing ────────────────────────────────────────
cases.append(("auto_fill_from_audit", (AUDIT_BIG, "big sweep"), {}))
cases.append(("get_status", (), {}))
cases.append(("get_meta_status", (), {})) # stale status, 0/18
truth = freeze("rune.work_manager", cases, oracle_module="rune.work_manager")
write(truth, OUT)
print(f"frozen {len(truth)} cases -> {OUT}")
print("work dir:", os.environ["HOME"])
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
"""Union-merge a conflicted store/scaffold/current.json during rebase.
Both sides append entities/observations/relationships to the shared
scaffold doc; the rebase conflict is two writers appending. Union by
exact-content identity: base side first (the rebased HEAD, i.e. what
other agents pushed), then the incoming commit's new items.
Rebase index stages: `git show :2:<path>` = ours = rebased HEAD,
`git show :3:<path>` = theirs = the incoming commit. Usage:
git show :2:store/scaffold/current.json > /tmp/base.json
git show :3:store/scaffold/current.json > /tmp/inc.json
python3 scripts/merge_scaffold_conflict.py /tmp/base.json /tmp/inc.json \
> store/scaffold/current.json
"""
import json
import sys
base = json.load(open(sys.argv[1]))
incoming = json.load(open(sys.argv[2]))
merged = dict(base)
for key in ("entities", "observations", "relationships"):
seen = set()
out = []
for side in (base, incoming):
for item in side.get(key, []):
ident = json.dumps(item, sort_keys=True)
if ident in seen:
continue
seen.add(ident)
out.append(item)
merged[key] = out
merged["generated_at"] = max(base.get("generated_at", ""), incoming.get("generated_at", ""))
print(json.dumps(merged, indent=2, ensure_ascii=False))
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Open + walk the #2479 dichotomy-wave construction contract for
self_model to verifying. Full lifecycle in ONE process."""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from rune.construction_interface import ConstructionInterface
iface = ConstructionInterface(builder="factory-batch-i")
r = iface.submit_need(
"Complete the self_model dichotomy port to FULL Rust (#2479 "
"tranche): the bounded persistent self-model kernel — "
"estimate_tokens / compile_self_model (greedy weight-fill with "
"stable tie ordering and evidence overflow) / why_question — as "
"doc-envelope FFI (smm_* symbols, free via capability_scoring "
"cs_free_string — no free re-export); smm_loader mirroring "
"broker_loader.py; facade keeps the Python floor, RUNE_SMM_CORE="
"python pin; frozen-oracle battery (every branch: empty corpus, "
"exact-fit boundary, evidence overflow, key defaults, stable "
"weight ties, zero budget, why-match across statements+evidence); "
"live parity 100% (frozen + fuzz seeds); Phase B language-advantage "
"pass (ASCII byte fast-path token estimate).",
origin="builder",
)
print("submit_need:", json.dumps(r)[:300])
if not r.get("success"):
print("NEED FAILED — aborting"); sys.exit(1)
cid = r["ids"]["contract_id"]
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:150])
if not t.get("success"):
sys.exit(1)
print("CONTRACT", cid, "verifying")
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Open + walk the gap-closing construction contract for work_manager to
verifying. Full lifecycle open in ONE process (builder=factory-gap-wm)."""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from rune.construction_interface import ConstructionInterface
iface = ConstructionInterface(builder="factory-gap-wm")
r = iface.submit_need(
"Close the work_manager dichotomy-port PARTIAL gaps (#2479 tranche, "
"GO verdict): port the 13 missing functions (group_by_file, "
"load_config, save_config, load_batches, save_batches, create_work, "
"clear_work, audit_to_work_items, auto_fill_from_audit, load_meta, "
"save_meta, update_meta_from_batches + full get_status/get_meta_"
"status and TaskMeta with progress/eta) from the Python oracle "
"src/rune/work_manager.py into src/go/work-manager name-preserving, "
"logic 1:1, file IO behind injectable seams (module-level path "
"constants mirrored as seam vars). Freeze shared-harness truth "
"(freeze_truth.py, RUNE_WORK_MANAGER_CORE=python pinned, HOME-pinned "
"temp work dir, self-seeding deterministic case sequence) embedded "
"VERBATIM in the Go battery; all existing tests green; gofmt + vet "
"clean; live parity 100% on the new fns (oracle subprocess, "
"timestamp-normalized); Phase B language-advantage pass.",
origin="builder",
)
print("submit_need:", json.dumps(r)[:300])
if not r.get("success"):
print("NEED FAILED — aborting"); sys.exit(1)
cid = r["ids"]["contract_id"]
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:150])
if not t.get("success"):
sys.exit(1)
print("CONTRACT", cid, "verifying")
+5
View File
@@ -223,7 +223,12 @@ func StartBuildID(nowUTC string) string {
// ResumePoint — reversed declaration-order scan: the first phase whose
// status is in_progress or failed; "" when all complete (Python None).
// Nil state → "" (the Python's `if not self.state: return None` guard,
// pinned by truth_buildmode_gap.json).
func ResumePoint(state *BuildState) string {
if state == nil {
return ""
}
for i := len(Phases) - 1; i >= 0; i-- {
status, has := state.Phases[Phases[i]]
if !has {
+185
View File
@@ -0,0 +1,185 @@
package main
// build_mode_gap.go — gap-closing batch: the PARTIAL audit's missing fns of
// src/rune/build_mode.py (contract BUILDER-2026-10-13T02:02:02Z-dad27f-
// factory-gap-bm). _load_state/_save_state (the ledger IO seam, buildsDir
// INJECTED — the Python reads a module global), assess_complexity, and the
// full start_* phase-transition family. Phase names and ordering are
// load-bearing for the pipeline: every transition here is frozen
// transition-by-transition in declaration order in
// truth_buildmode_gap.json (live oracle, clock pinned via the shared
// freeze_truth harness).
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
)
// LoadState — _load_state: read BUILDS_DIR/<build_id>/ledger.json into a
// BuildState. Missing file → the Python FileNotFoundError text.
func LoadState(buildsDir, buildID string) (*BuildState, error) {
ledgerPath := filepath.Join(buildsDir, buildID, "ledger.json")
if _, err := os.Stat(ledgerPath); err != nil {
return nil, fmt.Errorf("Build %s not found", buildID)
}
data, err := os.ReadFile(ledgerPath)
if err != nil {
return nil, err
}
var state BuildState
if err := json.Unmarshal(data, &state); err != nil {
return nil, err
}
return &state, nil
}
// SaveState — _save_state: write the state as asdict-shape JSON (indent 2,
// no HTML escaping, no trailing newline — Python json.dump byte contract,
// pinned by ledger_load_fixture.json). Nil state → no-op (the Python's
// `if not self.state: return`).
//
// BYTE PARITY TRAP: Python dict preserves INSERTION order and json.dump
// emits it; Go maps marshal sorted. The live manager creates the phases
// keys via _log_phase, so the ledger's first-occurrence order IS the dict
// order — the phases object is spliced in that order (keys missing from
// the ledger fall back to pipeline declaration order). The nil sentinel
// replaces exactly the one top-level "phases" key.
func SaveState(state *BuildState, buildsDir string) error {
if state == nil {
return nil
}
buildDir := filepath.Join(buildsDir, state.BuildID)
if err := os.MkdirAll(buildDir, 0o755); err != nil {
return err
}
data, err := stateJSON(state)
if err != nil {
return err
}
return os.WriteFile(filepath.Join(buildDir, "ledger.json"), data, 0o644)
}
// stateJSON — the Python json.dump byte contract (indent 2, no HTML
// escaping, no trailing newline, phases in dict-insertion order).
func stateJSON(state *BuildState) ([]byte, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
saved := state.Phases
state.Phases = nil
err := enc.Encode(state)
state.Phases = saved
if err != nil {
return nil, err
}
out := bytes.Replace(buf.Bytes(), []byte(`"phases": null`),
orderedPhasesJSON(state), 1)
return bytes.TrimRight(out, "\n"), nil
}
// orderedPhasesJSON — the phases object in Python-dict insertion order
// (ledger first-occurrence, then declaration order, then sorted rest).
func orderedPhasesJSON(state *BuildState) []byte {
order := make([]string, 0, len(state.Phases))
seen := make(map[string]bool, len(state.Phases))
for _, e := range state.Ledger {
if _, has := state.Phases[e.Phase]; has && !seen[e.Phase] {
seen[e.Phase] = true
order = append(order, e.Phase)
}
}
for _, p := range Phases {
if _, has := state.Phases[p]; has && !seen[p] {
seen[p] = true
order = append(order, p)
}
}
rest := make([]string, 0)
for p := range state.Phases {
if !seen[p] {
rest = append(rest, p)
}
}
sort.Strings(rest)
order = append(order, rest...)
var b bytes.Buffer
// Python json.dump(indent=2) nests the phases entries one level deeper
// (4-space entries, 2-space closing brace).
b.WriteString(`"phases": {`)
for i, p := range order {
if i > 0 {
b.WriteByte(',')
}
b.WriteString("\n ")
k, _ := json.Marshal(p)
v, _ := json.Marshal(state.Phases[p])
b.Write(k)
b.WriteString(": ")
b.Write(v)
}
if len(order) > 0 {
b.WriteString("\n ")
}
b.WriteString("}")
return b.Bytes()
}
// AssessComplexity — assess_complexity: the placeholder report, verbatim.
func AssessComplexity() map[string]interface{} {
return map[string]interface{}{
"complexity": "complex", // simple/medium/complex
"estimated_steps": 10,
"requires_build_mode": true,
}
}
// StartResearch — start_research.
func StartResearch(state *BuildState, nowISO string) {
LogPhase(state, "research", StatusInProgress, nil, nil, nowISO)
}
// StartFeasible — start_feasible.
func StartFeasible(state *BuildState, nowISO string) {
LogPhase(state, "feasible", StatusInProgress, nil, nil, nowISO)
}
// StartConsult — start_consult.
func StartConsult(state *BuildState, nowISO string) {
LogPhase(state, "consult", StatusInProgress, nil, nil, nowISO)
}
// StartConsent — start_consent.
func StartConsent(state *BuildState, nowISO string) {
LogPhase(state, "consent", StatusInProgress, nil, nil, nowISO)
}
// StartPlan — start_plan.
func StartPlan(state *BuildState, nowISO string) {
LogPhase(state, "plan", StatusInProgress, nil, nil, nowISO)
}
// StartBuildPhase — start_build_phase.
func StartBuildPhase(state *BuildState, nowISO string) {
LogPhase(state, "build", StatusInProgress, nil, nil, nowISO)
}
// StartVerify — start_verify.
func StartVerify(state *BuildState, nowISO string) {
LogPhase(state, "verify", StatusInProgress, nil, nil, nowISO)
}
// StartIntegrate — start_integrate.
func StartIntegrate(state *BuildState, nowISO string) {
LogPhase(state, "integrate", StatusInProgress, nil, nil, nowISO)
}
// StartRecord — start_record.
func StartRecord(state *BuildState, nowISO string) {
LogPhase(state, "record", StatusInProgress, nil, nil, nowISO)
}
@@ -0,0 +1,55 @@
{
"build_id": "20261013-022000",
"description": "gap battery build",
"created_at": "2026-10-13T02:20:00+00:00",
"worktree_path": null,
"current_phase": "assess",
"phases": {
"correct": "complete"
},
"ledger": [
{
"phase": "correct",
"status": "in_progress",
"timestamp": "2026-10-13T02:20:00+00:00",
"details": {},
"errors": []
},
{
"phase": "correct",
"status": "complete",
"timestamp": "2026-10-13T02:20:00+00:00",
"details": {
"fixed": false
},
"errors": []
},
{
"phase": "correct",
"status": "in_progress",
"timestamp": "2026-10-13T02:20:00+00:00",
"details": {},
"errors": []
},
{
"phase": "correct",
"status": "complete",
"timestamp": "2026-10-13T02:20:00+00:00",
"details": {
"fixed": true
},
"errors": []
}
],
"batches": [],
"corrections": 3,
"max_corrections": 3,
"current_build_phase": "foundation",
"trajectory": [],
"failure_patterns": [],
"complexity_score": 0,
"estimated_steps": 0,
"actual_steps": 0,
"files_changed": [],
"contracts": []
}
+242
View File
@@ -0,0 +1,242 @@
package main
// Phase B language-advantage pass — dichotomy wave (contract
// BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm). Three Go-side wins
// the Python oracle can't express:
//
// 1. A data-driven phase-transition registry with COMPILE-TIME-style
// completeness enforcement: Python's eleven start_* methods are
// hand-wired; Go turns the dispatch into data and panics at init if a
// Phases entry ever lacks a starter (a new pipeline phase without a
// transition is a boot-time failure, not a silent no-op).
// 2. A typed StateStore seam: the Python reads/writes a module-global
// BUILDS_DIR; Go binds load/save behind an interface with an
// in-memory store (zero-IO tests, truth replays) and a file store
// whose Save is ATOMIC (temp file + rename — a torn ledger.json is
// impossible mid-write, which Python's plain open(...,"w") cannot
// guarantee).
// 3. ReplayPipeline — the frozen case battery fans out across
// goroutines (per-case isolated receivers) and reassembles in input
// order, parity-verified under -race.
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"testing"
)
// ── 1. the transition registry ──────────────────────────────────────────
// startRegistry — phase name → its start_* transition (data, not a
// hand-maintained if/else chain).
var startRegistry = map[string]func(*BuildState, string){
"research": StartResearch,
"feasible": StartFeasible,
"consult": StartConsult,
"consent": StartConsent,
"plan": StartPlan,
"build": StartBuildPhase,
"verify": StartVerify,
"correct": StartCorrect,
"integrate": StartIntegrate,
"record": StartRecord,
// "assess" starts via start_build (BuildState construction + worktree),
// not a bare starter — its absence here is INTENTIONAL, see init.
}
// StartPhase — registry dispatch for the start_* family. Byte-identical
// to the direct wrappers (pinned by TestPhaseRegistryMatchesWrappers).
func StartPhase(state *BuildState, phase, nowISO string) error {
start, has := startRegistry[phase]
if !has {
return fmt.Errorf("no start transition for phase %q", phase)
}
start(state, nowISO)
return nil
}
// init — completeness enforcement: every pipeline phase must either have a
// registry starter or be the assess/build-bootstrap special case. Adding a
// phase to Phases without a transition now fails at boot.
func init() {
for _, p := range Phases {
if _, has := startRegistry[p]; !has && p != "assess" {
panic(fmt.Sprintf("build_mode: phase %q has no start transition", p))
}
}
}
// ── 2. the StateStore seam ──────────────────────────────────────────────
// StateStore — the ledger IO seam (Python: module-global BUILDS_DIR +
// open(...,"w")). Implementations: MemStore (tests, truth replays) and
// FileStore (atomic writes).
type StateStore interface {
Load(buildID string) (*BuildState, error)
Save(state *BuildState) error
}
// Compile-time assertions: both stores satisfy the seam (catches signature
// drift at build time, not test time).
var (
_ StateStore = (*MemStore)(nil)
_ StateStore = (*FileStore)(nil)
)
// MemStore — concurrency-safe in-memory ledger store.
type MemStore struct {
mu sync.RWMutex
builds map[string]*BuildState
missing string // load-error text for unknown ids (parity with FileStore)
}
// NewMemStore — empty store.
func NewMemStore() *MemStore {
return &MemStore{builds: map[string]*BuildState{}, missing: "no builds"}
}
// Put — seed a state (test/fixture helper).
func (m *MemStore) Put(state *BuildState) {
m.mu.Lock()
defer m.mu.Unlock()
cp := *state
m.builds[state.BuildID] = &cp
}
// Load — deep-enough copy semantics: the map entry is shared but the
// returned pointer is the caller's to mutate (single-manager convention).
func (m *MemStore) Load(buildID string) (*BuildState, error) {
m.mu.RLock()
defer m.mu.RUnlock()
s, has := m.builds[buildID]
if !has {
return nil, fmt.Errorf("Build %s not found", buildID)
}
cp := *s
return &cp, nil
}
// Save — upsert.
func (m *MemStore) Save(state *BuildState) error {
if state == nil {
return nil
}
m.mu.Lock()
defer m.mu.Unlock()
cp := *state
m.builds[state.BuildID] = &cp
return nil
}
// FileStore — the buildsDir-backed store. Save is ATOMIC: the state is
// written to a temp file in the same directory and renamed over
// ledger.json, so a reader never observes a torn ledger (Python's
// open(ledger_path, "w") truncates in place — a crash mid-write loses the
// ledger; Go's rename is atomic on POSIX).
type FileStore struct {
BuildsDir string
}
// NewFileStore — store rooted at buildsDir.
func NewFileStore(buildsDir string) *FileStore {
return &FileStore{BuildsDir: buildsDir}
}
// Load — LoadState against the store's buildsDir.
func (f *FileStore) Load(buildID string) (*BuildState, error) {
return LoadState(f.BuildsDir, buildID)
}
// Save — SaveState bytes, atomically (temp + rename, same directory so
// the rename never crosses a filesystem).
func (f *FileStore) Save(state *BuildState) error {
if state == nil {
return nil
}
buildDir := filepath.Join(f.BuildsDir, state.BuildID)
if err := os.MkdirAll(buildDir, 0o755); err != nil {
return err
}
data, err := stateJSON(state)
if err != nil {
return err
}
tmp, err := os.CreateTemp(buildDir, ".ledger-*")
if err != nil {
return err
}
tmpName := tmp.Name()
defer os.Remove(tmpName) // no-op after a successful rename
if _, err := tmp.Write(data); err != nil {
tmp.Close()
return err
}
if err := tmp.Close(); err != nil {
return err
}
return os.Rename(tmpName, filepath.Join(buildDir, "ledger.json"))
}
// ── 3. ReplayPipeline — fan-out truth replay ────────────────────────────
// GapCase — one frozen truth case (the shape of
// truth_buildmode_gap.json's cases, decoded).
type GapCase struct {
Fn string `json:"fn"`
Recv struct {
State jsonRaw `json:"state"`
} `json:"recv"`
Args []interface{} `json:"args"`
Expected struct {
Result jsonRaw `json:"result"`
State jsonRaw `json:"state"`
} `json:"expected"`
}
// jsonRaw — json.RawMessage alias kept local so phaseb.go needs no extra
// import surface beyond encoding/json.
type jsonRaw = json.RawMessage
// ReplayPipeline — replay frozen cases across goroutines (each case gets
// an isolated receiver rebuilt from its recv state) and reassemble the
// results in INPUT order. Parity: every result must canonicalize to the
// frozen expected bytes; the caller compares (dispatchGap is the same
// replay used by the serial battery).
func ReplayPipeline(t *testing.T, cases []GapCase, stamp string) []replayResult {
results := make([]replayResult, len(cases))
var wg sync.WaitGroup
for i := range cases {
wg.Add(1)
go func(i int) {
defer wg.Done()
c := cases[i]
var state *BuildState
if string(c.Recv.State) != "null" && len(c.Recv.State) > 0 {
state = &BuildState{}
if err := json.Unmarshal(c.Recv.State, state); err != nil {
t.Errorf("case %d recv state: %v", i, err)
return
}
}
got, gotState := dispatchGap(t, state, c.Fn, c.Args, stamp)
results[i] = replayResult{
Name: c.Fn,
Got: mustJSON(got),
State: mustJSON(gotState),
Expected: []byte(c.Expected.Result),
}
}(i)
}
wg.Wait()
return results
}
type replayResult struct {
Name string
Got []byte
State []byte
Expected []byte
}
+186
View File
@@ -0,0 +1,186 @@
package main
// phaseb_test.go — the Phase B battery: pins the language-advantage
// guarantees without regressing parity. The registry dispatch must be
// byte-identical to the direct start_* wrappers for every frozen case;
// ReplayPipeline must reproduce the whole gap battery fan-out under -race
// with input-order reassembly; both stores satisfy StateStore at compile
// time; the FileStore's atomic Save must leave a valid ledger under
// concurrent writers.
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"testing"
)
// TestPhaseRegistryMatchesWrappers — registry dispatch ≡ direct wrappers,
// byte-for-byte, for every start_* case in the frozen battery.
func TestPhaseRegistryMatchesWrappers(t *testing.T) {
var doc gapEnvelope
if err := json.Unmarshal(gapTruth, &doc); err != nil {
t.Fatal(err)
}
stamp := doc.FrozenNow + "+00:00"
for _, c := range doc.Cases {
name := c.Fn
if _, isStart := startRegistry[name]; !isStart {
continue
}
t.Run(name, func(t *testing.T) {
rebuild := func() *BuildState {
if len(c.Recv.State) == 0 || string(c.Recv.State) == "null" {
return nil
}
s := &BuildState{}
if err := json.Unmarshal(c.Recv.State, s); err != nil {
t.Fatal(err)
}
return s
}
registryState := rebuild()
if err := StartPhase(registryState, name, stamp); err != nil {
t.Fatalf("registry dispatch: %v", err)
}
wrapperState := rebuild()
if _, gotState := dispatchGap(t, wrapperState, "BuildManager."+name, c.Args, stamp); gotState == nil {
t.Fatal("wrapper produced no state")
}
canonEq(t, "registry-vs-wrapper", registryState, mustJSON(wrapperState))
})
}
}
// TestRegistryCompleteness — every phase except the assess bootstrap has a
// starter; StartPhase rejects unknown phases (no silent no-op).
func TestRegistryCompleteness(t *testing.T) {
for _, p := range Phases {
if p == "assess" {
continue
}
if _, has := startRegistry[p]; !has {
t.Errorf("phase %q lacks a start transition", p)
}
}
s := NewBuildState("x", "y", "z")
if err := StartPhase(s, "nonexistent", "t"); err == nil {
t.Fatal("unknown phase must error, not silently no-op")
}
}
// TestMemStoreRoundTrip — the in-memory seam loads what it saved,
// unknown ids carry the oracle error text.
func TestMemStoreRoundTrip(t *testing.T) {
var want BuildState
if err := json.Unmarshal(ledgerFixture, &want); err != nil {
t.Fatal(err)
}
store := NewMemStore()
store.Put(&want)
got, err := store.Load(want.BuildID)
if err != nil {
t.Fatal(err)
}
canonEq(t, "memstore", got, ledgerFixture)
if _, err := store.Load("no-such-build"); err == nil ||
err.Error() != "Build no-such-build not found" {
t.Fatalf("missing-id error: got %v", err)
}
}
// TestFileStoreAtomicSave — concurrent writers must always leave a valid
// ledger (atomic rename), and the final bytes must equal the byte fixture
// for the same state.
func TestFileStoreAtomicSave(t *testing.T) {
var state BuildState
if err := json.Unmarshal(ledgerFixture, &state); err != nil {
t.Fatal(err)
}
store := NewFileStore(t.TempDir())
var wg sync.WaitGroup
for i := 0; i < 16; i++ {
wg.Add(1)
go func() {
defer wg.Done()
s := state // identical state from every writer: the final
// ledger must byte-match the fixture (deterministic outcome)
if err := store.Save(&s); err != nil {
t.Errorf("save: %v", err)
}
// Every intermediate read must parse (no torn ledger).
if got, err := store.Load(state.BuildID); err == nil {
var probe map[string]interface{}
if err := json.Unmarshal(mustJSON(got), &probe); err != nil {
t.Errorf("torn ledger: %v", err)
}
}
}()
}
wg.Wait()
final, err := store.Load(state.BuildID)
if err != nil {
t.Fatal(err)
}
canonEq(t, "filestore-final", final, ledgerFixture)
// No temp litter after the renames.
entries, _ := os.ReadDir(filepath.Join(store.BuildsDir, state.BuildID))
for _, e := range entries {
if e.Name() != "ledger.json" {
t.Errorf("temp litter: %s", e.Name())
}
}
}
// TestFileStoreByteParity — FileStore.Save bytes == SaveState bytes ==
// the oracle fixture (the atomic path must not change the contract).
func TestFileStoreByteParity(t *testing.T) {
var state BuildState
if err := json.Unmarshal(ledgerFixture, &state); err != nil {
t.Fatal(err)
}
store := NewFileStore(t.TempDir())
if err := store.Save(&state); err != nil {
t.Fatal(err)
}
got, err := os.ReadFile(filepath.Join(store.BuildsDir, state.BuildID, "ledger.json"))
if err != nil {
t.Fatal(err)
}
if string(got) != string(ledgerFixture) {
t.Fatalf("FileStore bytes diverge from oracle fixture (%d vs %d bytes)",
len(got), len(ledgerFixture))
}
}
// TestReplayPipelineFanOut — the WHOLE frozen battery replayed across
// goroutines, reassembled in input order, every result matching the frozen
// expected bytes (under -race this is also the concurrency proof).
func TestReplayPipelineFanOut(t *testing.T) {
var doc struct {
FrozenNow string `json:"frozen_now"`
Cases []GapCase `json:"cases"`
}
if err := json.Unmarshal(gapTruth, &doc); err != nil {
t.Fatal(err)
}
stamp := doc.FrozenNow + "+00:00"
results := ReplayPipeline(t, doc.Cases, stamp)
if len(results) != len(doc.Cases) {
t.Fatalf("reassembly lost rows: %d vs %d", len(results), len(doc.Cases))
}
for i, r := range results {
if r.Name != doc.Cases[i].Fn {
t.Fatalf("row %d misordered: %q vs %q", i, r.Name, doc.Cases[i].Fn)
}
var gotV, wantV interface{}
json.Unmarshal(r.Got, &gotV)
json.Unmarshal(r.Expected, &wantV)
gb, _ := json.Marshal(gotV)
wb, _ := json.Marshal(wantV)
if string(gb) != string(wb) {
t.Errorf("row %d (%s) diverges:\n got %s\nwant %s", i, r.Name, gb, wb)
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,257 @@
package main
// truth_buildmode_gap_test.go — gap-closing parity gate: replays
// truth_buildmode_gap.json VERBATIM (go:embed — the shared freeze_truth
// harness output, live oracle, clock pinned) through the ported functions.
// Every case carries a recv receiver (the PRE state), the call args, and
// the expected post-call state + result; the Go replay must match
// byte-for-byte after canonical JSON. Contract
// BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm.
import (
_ "embed"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
)
//go:embed truth_buildmode_gap.json
var gapTruth []byte
//go:embed ledger_load_fixture.json
var ledgerFixture []byte
type gapEnvelope struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Fn string `json:"fn"`
Recv struct {
Cls string `json:"cls"`
State json.RawMessage `json:"state"`
} `json:"recv"`
Args []interface{} `json:"args"`
Expected struct {
Result json.RawMessage `json:"result"`
State json.RawMessage `json:"state"`
} `json:"expected"`
} `json:"cases"`
}
func TestBuildModeGapParity(t *testing.T) {
var doc gapEnvelope
if err := json.Unmarshal(gapTruth, &doc); err != nil {
t.Fatalf("unparseable: %v", err)
}
stamp := doc.FrozenNow + "+00:00"
for i, c := range doc.Cases {
name := c.Fn
t.Run(name, func(t *testing.T) {
// Rebuild the receiver: recv.state null → nil state.
var state *BuildState
if string(c.Recv.State) != "null" && len(c.Recv.State) > 0 {
state = &BuildState{}
if err := json.Unmarshal(c.Recv.State, state); err != nil {
t.Fatalf("recv state unparseable: %v", err)
}
}
got, gotState := dispatchGap(t, state, c.Fn, c.Args, stamp)
canonEq(t, "result", got, c.Expected.Result)
// state: absent/null expected → no state attr or nil state;
// else canonical compare.
if len(c.Expected.State) == 0 || string(c.Expected.State) == "null" {
if len(c.Expected.State) == 0 {
return // receiver never had the attr — nothing to compare
}
if gotState != nil {
t.Fatalf("expected nil state, got one")
}
} else {
canonEq(t, "state", gotState, c.Expected.State)
}
})
_ = i
}
}
// dispatchGap — replay one frozen call through the ported function; return
// the JSON-comparable result and the post-call state pointer.
func dispatchGap(t *testing.T, state *BuildState, fn string, args []interface{}, stamp string) (result interface{}, outState *BuildState) {
t.Helper()
name := strings.TrimPrefix(fn, "BuildManager.")
arg := func(i int) interface{} {
if i < len(args) {
return args[i]
}
return nil
}
switch name {
case "assess_complexity":
return AssessComplexity(), state
case "complete_assess":
CompleteAssess(state, arg(0).(map[string]interface{}), stamp)
case "start_research":
StartResearch(state, stamp)
case "complete_research":
CompleteResearch(state, arg(0).(map[string]interface{}), stamp)
case "start_feasible":
StartFeasible(state, stamp)
case "complete_feasible":
CompleteFeasible(state, arg(0) == true, arg(1).(string),
argMap(arg(2)), stamp)
case "start_consult":
StartConsult(state, stamp)
case "complete_consult":
CompleteConsult(state, strList(arg(0)), stamp)
case "start_consent":
StartConsent(state, stamp)
case "complete_consent":
CompleteConsent(state, arg(0) == true, stamp)
case "start_plan":
StartPlan(state, stamp)
case "complete_plan":
CompletePlan(state, objList(arg(0)), stamp)
case "start_build_phase":
StartBuildPhase(state, stamp)
case "complete_build_phase":
CompleteBuildPhase(state, objList(arg(0)), stamp)
case "start_verify":
StartVerify(state, stamp)
case "complete_verify":
CompleteVerify(state, arg(0) == true, strList(arg(1)), stamp)
case "start_correct":
StartCorrect(state, stamp)
case "complete_correct":
CompleteCorrect(state, arg(0) == true, stamp)
case "start_integrate":
StartIntegrate(state, stamp)
case "complete_integrate":
CompleteIntegrate(state, arg(0) == true, strList(arg(1)), stamp)
case "start_record":
StartRecord(state, stamp)
case "complete_record":
CompleteRecord(state, stamp)
case "_save_state":
dir := t.TempDir()
if err := SaveState(state, dir); err != nil {
t.Fatalf("save: %v", err)
}
return nil, state
case "get_resume_point":
rp := ResumePoint(state)
if rp == "" {
return nil, state // Python None
}
return rp, state
case "can_resume":
return CanResume(state), state
case "get_status":
return BuildStatus(state), state
default:
t.Fatalf("unknown frozen fn %q", fn)
}
return nil, state
}
func argMap(v interface{}) map[string]interface{} {
m, _ := v.(map[string]interface{})
return m
}
// canonEq — canonical-JSON comparison (Go-built values vs the frozen
// oracle snapshot).
func canonEq(t *testing.T, what string, got interface{}, wantRaw json.RawMessage) {
t.Helper()
gb, err := json.Marshal(got)
if err != nil {
t.Fatalf("marshal got %s: %v", what, err)
}
var gotV, wantV interface{}
if err := json.Unmarshal(gb, &gotV); err != nil {
t.Fatalf("reparse got %s: %v", what, err)
}
if err := json.Unmarshal(wantRaw, &wantV); err != nil {
t.Fatalf("reparse want %s: %v", what, err)
}
gc, _ := json.Marshal(gotV)
wc, _ := json.Marshal(wantV)
if string(gc) != string(wc) {
t.Fatalf("%s divergence:\n got %s\nwant %s", what, gc, wc)
}
}
// TestLoadStateFixture — the IO seam: a build whose ledger.json holds the
// oracle's exact save bytes must load into the identical state.
func TestLoadStateFixture(t *testing.T) {
dir := t.TempDir()
buildDir := filepath.Join(dir, "20261013-022000")
if err := os.MkdirAll(buildDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(buildDir, "ledger.json"), ledgerFixture, 0o644); err != nil {
t.Fatal(err)
}
state, err := LoadState(dir, "20261013-022000")
if err != nil {
t.Fatalf("load: %v", err)
}
var want BuildState
if err := json.Unmarshal(ledgerFixture, &want); err != nil {
t.Fatal(err)
}
canonEq(t, "loadstate", state, ledgerFixture)
if _, err := LoadState(dir, "no-such-build"); err == nil ||
err.Error() != "Build no-such-build not found" {
t.Fatalf("missing-build error: got %v", err)
}
}
// TestSaveStateBytes — the byte contract: Python json.dump(asdict(state),
// indent=2) — the fixture IS those bytes; SaveState must reproduce them.
func TestSaveStateBytes(t *testing.T) {
var state BuildState
if err := json.Unmarshal(ledgerFixture, &state); err != nil {
t.Fatal(err)
}
dir := t.TempDir()
if err := SaveState(&state, dir); err != nil {
t.Fatal(err)
}
got, err := os.ReadFile(filepath.Join(dir, "20261013-022000", "ledger.json"))
if err != nil {
t.Fatal(err)
}
if string(got) != string(ledgerFixture) {
t.Fatalf("save bytes diverge from oracle fixture:\n got %d bytes\nwant %d bytes",
len(got), len(ledgerFixture))
}
// nil state → no-op, nothing written (fresh dir: nothing created).
nilDir := t.TempDir()
if err := SaveState(nil, nilDir); err != nil {
t.Fatalf("nil save: %v", err)
}
entries, _ := os.ReadDir(nilDir)
if len(entries) != 0 {
t.Fatalf("nil state must not create the build dir, found %d entries", len(entries))
}
}
// TestSaveStateRoundTrip — the phases splice must never corrupt content:
// save the fixture state, load it back, require canonical equality.
func TestSaveStateRoundTrip(t *testing.T) {
var state BuildState
if err := json.Unmarshal(ledgerFixture, &state); err != nil {
t.Fatal(err)
}
dir := t.TempDir()
if err := SaveState(&state, dir); err != nil {
t.Fatal(err)
}
back, err := LoadState(dir, state.BuildID)
if err != nil {
t.Fatal(err)
}
canonEq(t, "roundtrip", back, ledgerFixture)
}
+3
View File
@@ -0,0 +1,3 @@
module rune/inference-paths
go 1.21
+239
View File
@@ -0,0 +1,239 @@
// Package main — inference-paths: the GO port of src/rune/inference_paths.py
// (#145 inference-path census + trace wiring, #2479 dichotomy wave).
//
// Ledger verdict (docs/language-dichotomy-ledger.md): GO — the journal
// write is I/O-bound file IO (decision tree: I/O-bound → Go) and the
// census is simple counting (Law 3/7: simple operations stay in the
// caller's language; FFI overhead would exceed the compute benefit).
//
// Boundary law: the JOURNAL attempt (rune.inference_trace import +
// record_trace + the journaled flag) and the census-completeness
// obligations (the test's grep-vs-census check) stay in the Python
// facade — the Go kernel owns the record shape and census_report.
//
// No-clock law: `at` is a kernel argument — the kernel never reads the
// wall clock (the oracle renders it as
// time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())).
//
// Float note: Python renders duration_ms 0.0 as "0.0" while Go marshals
// float64 0 as "0" — the battery compares SEMANTICALLY (unmarshal both
// sides, reflect.DeepEqual), same value, same type shape.
//
// Language-advantage pass (Phase B, battery-pinned): the record is a
// typed SidePathRecord struct (schema documented in one place, JSON key
// order fixed by declaration instead of map-alphabetical accident); the
// census kind vocabulary is a Kind string type with an isExcluded
// lattice method (no bare-string comparisons); the report is a typed
// CensusReport with a struct-level Exclusion entry. Battery green
// throughout.
//
// Usage: inference-paths replay <truth.json>
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
)
// Kind — the census kind vocabulary (typed; no bare-string soup).
type Kind string
const (
KindApproval Kind = "APPROVAL" // the operator's own runs
KindCompaction Kind = "COMPACTION" // mid-assembly summarize_history
KindSide Kind = "SIDE" // raw-urllib model calls
KindEmbed Kind = "EMBED" // embedding calls
KindExcluded Kind = "EXCLUDED" // documented exclusion with reason
)
// isExcluded — EXCLUDED entries are documented exclusions, not traced.
func (k Kind) isExcluded() bool { return k == KindExcluded }
// CensusEntry — one outbound model-call site (module, function,
// endpoint, kind, note). The census is the #145 deliverable: every
// outbound model call in src/rune is ENUMERATED and each is either
// TRACED or DOCUMENTED-EXCLUDED with its reason.
type CensusEntry struct {
Module string
Function string
Endpoint string
Kind Kind
Note string
}
// census — the oracle's CENSUS table (insertion order preserved; the
// census is verified 2026-10-08 by grep for /api/generate + /api/embed
// + urlopen patterns; new call sites MUST be added here).
var census = []CensusEntry{
{"rune_operator", "_runtime_for_model", "/api/generate", KindApproval,
"approval-resume turns: fresh transport on the operator path — " +
"traced via trace_side_path since this batch"},
{"context_broker", "summarize_history", "/api/generate", KindCompaction,
"mid-assembly compaction: own transport — recorded as a compaction " +
"trace folded into the run's served sums"},
{"abstraction", "_abstract", "/api/generate", KindSide, "traced"},
{"goal", "_goal", "/api/generate", KindSide, "traced"},
{"growth_delta", "_growth", "/api/generate", KindSide, "traced"},
{"model_connect", "_connect", "/api/generate", KindSide, "traced (x2)"},
{"night_mode", "_night", "/api/generate", KindSide, "traced (x2)"},
{"provider_registry", "generate", "/api/generate", KindSide, "traced"},
{"rune_tui", "keepalive_warmup", "/api/generate", KindExcluded,
"TUI keep-alive warmup: no task linkage, no user-visible output — " +
"excluded (warmup, not inference)"},
{"sleep_time", "reflect", "/api/generate", KindSide, "traced"},
{"tiered_executor", "_execute", "/api/generate", KindSide, "traced"},
{"witness", "_witness", "/api/generate", KindSide, "traced"},
{"curator", "_embed", "/api/embed", KindEmbed, "recorded as embedding trace"},
{"memory_store", "_embed", "/api/embed", KindEmbed, "recorded as embedding trace"},
{"persona_gate", "_gate", "/api/embed", KindEmbed, "recorded as embedding trace"},
{"elastic_cognition", "_elastic", "/api/generate", KindSide, "traced"},
}
// SidePathRecord — the oracle's record dict for one side-path inference,
// as a typed struct (schema in one place; JSON key order fixed by
// declaration — mirrors the Python dict's insertion order):
//
// {"schema_version": 1, "kind": "side_path", "module", "function",
// "model", "task_id", "duration_ms", "at"}
//
// `at` is a kernel argument (no-clock law). The journal attempt and the
// journaled flag stay in the Python facade.
type SidePathRecord struct {
SchemaVersion int `json:"schema_version"`
Kind string `json:"kind"`
Module string `json:"module"`
Function string `json:"function"`
Model string `json:"model"`
TaskID string `json:"task_id"`
DurationMS float64 `json:"duration_ms"`
At string `json:"at"`
}
// TraceSidePath — build the side-path trace record.
func TraceSidePath(module, function, model, taskID string, durationMS float64, at string) SidePathRecord {
return SidePathRecord{
SchemaVersion: 1,
Kind: "side_path",
Module: module,
Function: function,
Model: model,
TaskID: taskID,
DurationMS: durationMS,
At: at,
}
}
// Exclusion — one documented-excluded census entry.
type Exclusion struct {
Module string `json:"module"`
Function string `json:"function"`
Reason string `json:"reason"`
}
// CensusReport — the census as a report: total, counts by kind, and the
// exclusion list (EXCLUDED entries carry their documented reason).
type Report struct {
Total int `json:"total"`
ByKind map[Kind]int `json:"by_kind"`
Excluded []Exclusion `json:"excluded"`
}
// CensusReportOf — fold the census into its report.
func CensusReportOf(entries []CensusEntry) Report {
byKind := map[Kind]int{}
excluded := []Exclusion{}
for _, e := range entries {
byKind[e.Kind]++
if e.Kind.isExcluded() {
excluded = append(excluded, Exclusion{
Module: e.Module,
Function: e.Function,
Reason: e.Note,
})
}
}
return Report{Total: len(entries), ByKind: byKind, Excluded: excluded}
}
// Report — the census as a report (typed; CensusReport() builds it).
func CensusReport() Report { return CensusReportOf(census) }
// replayTruth — battery driver: replay the frozen Python-oracle truth
// VERBATIM (semantic comparison — see the float note above).
func replayTruth(path string) (checked int, err error) {
raw, err := os.ReadFile(path)
if err != nil {
return 0, err
}
var doc struct {
Cases map[string][]struct {
Name string `json:"name"`
Input map[string]any `json:"input"`
Expected map[string]any `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal(raw, &doc); err != nil {
return 0, err
}
for _, c := range doc.Cases["trace_side_path"] {
checked++
got := TraceSidePath(
c.Input["module"].(string),
c.Input["function"].(string),
c.Input["model"].(string),
c.Input["task_id"].(string),
c.Input["duration_ms"].(float64),
c.Input["at"].(string),
)
if fail := compare(c.Name, got, c.Expected["record"]); fail {
return checked, fmt.Errorf("trace_side_path case %q diverged", c.Name)
}
}
for _, c := range doc.Cases["census_report"] {
checked++
if fail := compare(c.Name, CensusReport(), c.Expected); fail {
return checked, fmt.Errorf("census_report case %q diverged", c.Name)
}
}
return checked, nil
}
// compare — semantic equality (unmarshal both sides through any).
func compare(name string, got, want any) bool {
g := norm(got)
w := norm(want)
if !reflect.DeepEqual(g, w) {
gj, _ := json.Marshal(g)
wj, _ := json.Marshal(w)
fmt.Printf("case %q diverged:\n got: %s\n want: %s\n", name, gj, wj)
return true
}
return false
}
func norm(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
}
func main() {
if len(os.Args) < 2 || os.Args[1] != "replay" {
fmt.Fprintln(os.Stderr, "usage: inference-paths replay <truth.json>")
os.Exit(2)
}
checked, err := replayTruth(os.Args[2])
if err != nil {
fmt.Fprintf(os.Stderr, "PARITY FAILED: %v\n", err)
os.Exit(1)
}
fmt.Printf("PARITY OK: %d cases vs the Python oracle (record shape + census report)\n", checked)
}
+254
View File
@@ -0,0 +1,254 @@
{
"frozen": "2026-10-13T05:35:42.241015+00:00",
"oracle": "src/rune/inference_paths.py",
"pin": "time.gmtime frozen at 2026-10-12T12:34:56Z + RUNE_IT_CORE=python",
"note": "Frozen via scripts/gen_inference_paths_truth.py against the live Python oracle. Ledger verdict: GO (the journal write is I/O-bound file IO; the census is simple counting). The journal attempt (rune.inference_trace + the journaled flag) stays in the Python facade \u2014 the Go kernel owns the record shape (schema_version, kind, module, function, model, task_id, duration_ms, at; `at` is a kernel argument \u2014 no-clock law) and census_report. Battery embeds this VERBATIM; float durations compare semantically (Python renders 0.0, Go marshals 0 \u2014 same value).",
"cases": {
"trace_side_path": [
{
"name": "tsp-defaults-side-path",
"input": {
"module": "goal",
"function": "_goal",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "goal",
"function": "_goal",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "goal",
"function": "_goal",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
}
}
},
{
"name": "tsp-full-fields",
"input": {
"module": "rune_operator",
"function": "_runtime_for_model",
"model": "llama3",
"task_id": "t1",
"duration_ms": 12.5,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "rune_operator",
"function": "_runtime_for_model",
"model": "llama3",
"task_id": "t1",
"duration_ms": 12.5,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "rune_operator",
"function": "_runtime_for_model",
"model": "llama3",
"task_id": "t1",
"duration_ms": 12.5,
"at": "2026-10-12T12:34:56Z"
}
}
},
{
"name": "tsp-zero-duration",
"input": {
"module": "witness",
"function": "_witness",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "witness",
"function": "_witness",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "witness",
"function": "_witness",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
}
}
},
{
"name": "tsp-float-precision",
"input": {
"module": "tiered_executor",
"function": "_execute",
"model": "qwen2.5",
"task_id": "task-99",
"duration_ms": 123.456,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "tiered_executor",
"function": "_execute",
"model": "qwen2.5",
"task_id": "task-99",
"duration_ms": 123.456,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "tiered_executor",
"function": "_execute",
"model": "qwen2.5",
"task_id": "task-99",
"duration_ms": 123.456,
"at": "2026-10-12T12:34:56Z"
}
}
},
{
"name": "tsp-journal-failure-false",
"input": {
"module": "curator",
"function": "_embed",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "curator",
"function": "_embed",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "curator",
"function": "_embed",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
}
}
},
{
"name": "tsp-empty-module-function",
"input": {
"module": "",
"function": "",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
},
"return": {
"schema_version": 1,
"kind": "side_path",
"module": "",
"function": "",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z",
"journaled": false
},
"expected": {
"record": {
"schema_version": 1,
"kind": "side_path",
"module": "",
"function": "",
"model": "",
"task_id": "",
"duration_ms": 0.0,
"at": "2026-10-12T12:34:56Z"
}
}
}
],
"census_report": [
{
"name": "cr-full-counts-and-exclusions",
"input": {},
"return": {
"total": 16,
"by_kind": {
"APPROVAL": 1,
"COMPACTION": 1,
"SIDE": 10,
"EXCLUDED": 1,
"EMBED": 3
},
"excluded": [
{
"module": "rune_tui",
"function": "keepalive_warmup",
"reason": "TUI keep-alive warmup: no task linkage, no user-visible output \u2014 excluded (warmup, not inference)"
}
]
},
"expected": {
"total": 16,
"by_kind": {
"APPROVAL": 1,
"COMPACTION": 1,
"SIDE": 10,
"EXCLUDED": 1,
"EMBED": 3
},
"excluded": [
{
"module": "rune_tui",
"function": "keepalive_warmup",
"reason": "TUI keep-alive warmup: no task linkage, no user-visible output \u2014 excluded (warmup, not inference)"
}
]
}
}
]
}
}
+29
View File
@@ -0,0 +1,29 @@
package main
// truth_test.go — parity battery: replays the frozen Python-oracle truth
// (truth.json, frozen via scripts/gen_inference_paths_truth.py with the
// wall clock frozen and RUNE_IT_CORE=python pinned) VERBATIM. Covers
// every public function of src/rune/inference_paths.py: trace_side_path
// record shape (defaults, full fields, zero/float durations, empty
// module) and census_report (total/by_kind/excluded). The journaled
// flag and the journal attempt stay in the Python facade (boundary
// law); note the oracle's journal path currently ALWAYS yields
// journaled=False (InferenceTrace signature drift) — the frozen truth
// pins that observable behavior.
import (
"os"
"testing"
)
func TestTraceSidePathBattery(t *testing.T) {
if _, err := replayTruth("truth.json"); err != nil {
t.Fatalf("trace_side_path battery: %v", err)
}
}
func TestTruthFilePresent(t *testing.T) {
if _, err := os.Stat("truth.json"); err != nil {
t.Fatalf("frozen truth missing: %v", err)
}
}
File diff suppressed because it is too large. Load diff
+711
View File
@@ -0,0 +1,711 @@
[
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 0,
"pending": 0,
"running": 0,
"complete": 0,
"failed": 0,
"total_items": 0,
"complete_items": 0,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "load_batches",
"args": [],
"kwargs": {},
"expected": []
},
{
"fn": "load_meta",
"args": [],
"kwargs": {},
"expected": null
},
{
"fn": "save_batches",
"args": [
[]
],
"kwargs": {},
"expected": null
},
{
"fn": "load_batches",
"args": [],
"kwargs": {},
"expected": []
},
{
"fn": "group_by_file",
"args": [
[]
],
"kwargs": {},
"expected": {}
},
{
"fn": "create_batches",
"args": [
[],
"nothing"
],
"kwargs": {},
"expected": []
},
{
"fn": "create_work",
"args": [
[],
"empty task"
],
"kwargs": {},
"expected": []
},
{
"fn": "audit_to_work_items",
"args": [
{
"groups": []
}
],
"kwargs": {},
"expected": []
},
{
"fn": "audit_to_work_items",
"args": [
{
"groups": [
{
"findings": []
}
]
}
],
"kwargs": {},
"expected": []
},
{
"fn": "auto_fill_from_audit",
"args": [
{
"groups": []
}
],
"kwargs": {},
"expected": {
"batches": 0,
"items": 0,
"summary": "No findings to process."
}
},
{
"fn": "auto_fill_from_audit",
"args": [
{
"groups": [
{
"findings": [
{
"message": "bare except",
"file": "a.py",
"line": 10,
"rule": "R001",
"severity": "high"
},
{
"message": "retry wrap",
"file": "a.py",
"line": 22,
"rule": "R013",
"severity": "medium"
},
{
"message": "m1",
"file": "b.py",
"line": 5,
"rule": "R100",
"severity": "low"
},
{
"message": "m2",
"file": "c.py",
"line": 7,
"rule": "R100",
"severity": "low"
},
{
"message": "m3",
"file": "d.py",
"line": 9,
"rule": "R100",
"severity": "low"
},
{
"message": "m4",
"file": "e.py",
"line": 11,
"rule": "R100",
"severity": "low"
},
{
"message": "fallback severity",
"file": "f.py",
"line": 3,
"rule": "",
"severity": "high"
}
]
},
{
"findings": [
{
"message": "second group",
"file": "g.py",
"line": 1,
"rule": "R200",
"severity": "medium"
},
{
"message": "defaults only"
}
]
}
]
},
"audit sweep"
],
"kwargs": {},
"expected": {
"total_items": 9,
"batches": 8,
"by_severity": {
"high": 2,
"medium": 3,
"low": 4
},
"by_type": {
"R001": 1,
"R013": 1,
"R100": 4,
"": 2,
"R200": 1
},
"batch_details": [
{
"id": "B1",
"description": "Auto-fix: 2 items",
"items": 2,
"files": [
"a.py"
],
"model": "auto-fix"
},
{
"id": "B2",
"description": "R100: 1 items in b.py",
"items": 1,
"files": [
"b.py"
],
"model": "qwen3:14b"
},
{
"id": "B3",
"description": "R100: 1 items in c.py",
"items": 1,
"files": [
"c.py"
],
"model": "qwen3:14b"
},
{
"id": "B4",
"description": "R100: 1 items in d.py",
"items": 1,
"files": [
"d.py"
],
"model": "qwen3:14b"
},
{
"id": "B5",
"description": "R100: 1 items in e.py",
"items": 1,
"files": [
"e.py"
],
"model": "qwen3:14b"
},
{
"id": "B6",
"description": "high: 1 items in 1 files",
"items": 1,
"files": [
"f.py"
],
"model": "qwen3:14b"
},
{
"id": "B7",
"description": "R200: 1 items in 1 files",
"items": 1,
"files": [
"g.py"
],
"model": "qwen3:14b"
},
{
"id": "B8",
"description": "medium: 1 items in 1 files",
"items": 1,
"files": [
""
],
"model": "qwen3:14b"
}
]
}
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 8,
"pending": 8,
"running": 0,
"complete": 0,
"failed": 0,
"total_items": 9,
"complete_items": 0,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "complete_batch",
"args": [
"B1",
"auto-fixed all"
],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 8,
"pending": 7,
"running": 0,
"complete": 1,
"failed": 0,
"total_items": 9,
"complete_items": 2,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "complete_batch",
"args": [
"NOPE",
"x"
],
"kwargs": {},
"expected": null
},
{
"fn": "fail_batch",
"args": [
"B2",
"verify red"
],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 8,
"pending": 6,
"running": 0,
"complete": 1,
"failed": 1,
"total_items": 9,
"complete_items": 2,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "get_meta_status",
"args": [],
"kwargs": {},
"expected": {
"task_id": "audit",
"description": "Codebase audit",
"status": "partial",
"progress": "22%",
"batches": "1/8",
"items": "2/9",
"failed": 1,
"eta": "~14m",
"notes": []
}
},
{
"fn": "complete_batch",
"args": [
"B3",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "complete_batch",
"args": [
"B4",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "complete_batch",
"args": [
"B5",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "complete_batch",
"args": [
"B6",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "complete_batch",
"args": [
"B7",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "complete_batch",
"args": [
"B8",
"ok"
],
"kwargs": {},
"expected": null
},
{
"fn": "get_meta_status",
"args": [],
"kwargs": {},
"expected": {
"task_id": "audit",
"description": "Codebase audit",
"status": "partial",
"progress": "89%",
"batches": "7/8",
"items": "8/9",
"failed": 1,
"eta": "~2m",
"notes": []
}
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 8,
"pending": 0,
"running": 0,
"complete": 7,
"failed": 1,
"total_items": 9,
"complete_items": 8,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "clear_work",
"args": [],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 0,
"pending": 0,
"running": 0,
"complete": 0,
"failed": 0,
"total_items": 0,
"complete_items": 0,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "get_meta_status",
"args": [],
"kwargs": {},
"expected": {
"task_id": "audit",
"description": "Codebase audit",
"status": "partial",
"progress": "0%",
"batches": "0/0",
"items": "0/0",
"failed": 0,
"eta": "unknown",
"notes": []
}
},
{
"fn": "save_config",
"args": [
{
"model_routing": "cloud"
}
],
"kwargs": {},
"expected": null
},
{
"fn": "auto_fill_from_audit",
"args": [
{
"groups": [
{
"findings": [
{
"message": "m0",
"file": "big.py",
"line": 0,
"rule": "R300",
"severity": "low"
},
{
"message": "m1",
"file": "big.py",
"line": 1,
"rule": "R300",
"severity": "low"
},
{
"message": "m2",
"file": "big.py",
"line": 2,
"rule": "R300",
"severity": "low"
},
{
"message": "m3",
"file": "big.py",
"line": 3,
"rule": "R300",
"severity": "low"
},
{
"message": "m4",
"file": "big.py",
"line": 4,
"rule": "R300",
"severity": "low"
},
{
"message": "m5",
"file": "big.py",
"line": 5,
"rule": "R300",
"severity": "low"
},
{
"message": "m6",
"file": "big.py",
"line": 6,
"rule": "R300",
"severity": "low"
},
{
"message": "m7",
"file": "big.py",
"line": 7,
"rule": "R300",
"severity": "low"
},
{
"message": "m8",
"file": "big.py",
"line": 8,
"rule": "R300",
"severity": "low"
},
{
"message": "m9",
"file": "big.py",
"line": 9,
"rule": "R300",
"severity": "low"
},
{
"message": "m10",
"file": "big.py",
"line": 10,
"rule": "R300",
"severity": "low"
},
{
"message": "m11",
"file": "big.py",
"line": 11,
"rule": "R300",
"severity": "low"
},
{
"message": "m12",
"file": "big.py",
"line": 12,
"rule": "R300",
"severity": "low"
},
{
"message": "m13",
"file": "big.py",
"line": 13,
"rule": "R300",
"severity": "low"
},
{
"message": "m14",
"file": "big.py",
"line": 14,
"rule": "R300",
"severity": "low"
},
{
"message": "m15",
"file": "big.py",
"line": 15,
"rule": "R300",
"severity": "low"
},
{
"message": "m16",
"file": "big.py",
"line": 16,
"rule": "R300",
"severity": "low"
},
{
"message": "m17",
"file": "big.py",
"line": 17,
"rule": "R300",
"severity": "low"
}
]
}
]
},
"big sweep"
],
"kwargs": {},
"expected": {
"total_items": 18,
"batches": 2,
"by_severity": {
"low": 18
},
"by_type": {
"R300": 18
},
"batch_details": [
{
"id": "B1",
"description": "R300: 15 items in 1 files",
"items": 15,
"files": [
"big.py"
],
"model": "mimo-v2.5-pro"
},
{
"id": "B2",
"description": "R300: 3 items in 1 files",
"items": 3,
"files": [
"big.py"
],
"model": "qwen3:14b"
}
]
}
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"batches": 2,
"pending": 2,
"running": 0,
"complete": 0,
"failed": 0,
"total_items": 18,
"complete_items": 0,
"model_routing": "auto",
"local_model": "qwen3:14b",
"cloud_model": "mimo-v2.5-pro"
}
},
{
"fn": "get_meta_status",
"args": [],
"kwargs": {},
"expected": {
"task_id": "audit",
"description": "Codebase audit",
"status": "partial",
"progress": "0%",
"batches": "0/2",
"items": "0/18",
"failed": 0,
"eta": "unknown",
"notes": []
}
}
]
+442 -1
View File
@@ -7,12 +7,16 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
)
const (
minBatchSize = 5 // oracle MIN_BATCH_SIZE (defined, unused in batching)
maxBatchSize = 15
maxFilesPerBatch = 3
localThreshold = 10
cloudThreshold = 15 // oracle CLOUD_THRESHOLD (defined, unused in routing)
)
type WorkItem struct {
@@ -33,12 +37,98 @@ type Batch struct {
Files []string `json:"files"`
Status string `json:"status"` // batch 156: pending/running/complete/failed
Result string `json:"result"` // batch 156: completion result text
Created string `json:"created"`
Completed string `json:"completed"`
}
// size / fileCount — the oracle Batch.size / Batch.file_count properties.
func (b Batch) size() int { return len(b.Items) }
func (b Batch) fileCount() int { return len(b.Files) }
type WorkConfig struct {
ModelRouting string `json:"model_routing"` // local, cloud, auto
LocalModel string `json:"local_model"`
CloudModel string `json:"cloud_model"`
AutoVerify bool `json:"auto_verify"`
MaxRetries int `json:"max_retries"`
}
// TaskMeta — the oracle TaskMeta dataclass (meta tracker).
type TaskMeta struct {
TaskID string `json:"task_id"`
Description string `json:"description"`
Created string `json:"created"`
TotalBatches int `json:"total_batches"`
CompleteBatches int `json:"complete_batches"`
FailedBatches int `json:"failed_batches"`
TotalItems int `json:"total_items"`
CompleteItems int `json:"complete_items"`
Status string `json:"status"` // active, complete, failed, paused
Notes []string `json:"notes"`
}
// progress — the oracle TaskMeta.progress property.
func (m TaskMeta) progress() float64 {
if m.TotalItems == 0 {
return 0.0
}
return float64(m.CompleteItems) / float64(m.TotalItems)
}
// eta — the oracle TaskMeta.eta property (rough estimate: 2 min per item).
func (m TaskMeta) eta() string {
if m.CompleteItems == 0 {
return "unknown"
}
remaining := m.TotalItems - m.CompleteItems
minutes := remaining * 2
if minutes < 60 {
return fmt.Sprintf("~%dm", minutes)
}
return fmt.Sprintf("~%dh%dm", minutes/60, minutes%60)
}
// ── IO seams ─────────────────────────────────────────────────────────────────
// The oracle derives WORK_DIR/BATCH_FILE/CONFIG_FILE/META_FILE from
// expanduser("~") at import (module-level constants). Go mirrors them as
// seam vars; tests and the frozen battery repoint them via setWorkDir.
var (
workDir = defaultWorkDir()
batchFile = filepath.Join(workDir, "batches.json")
configFile = filepath.Join(workDir, "config.json")
metaFile = filepath.Join(workDir, "meta.json")
)
func defaultWorkDir() string {
home, err := os.UserHomeDir()
if err != nil {
home = "."
}
return filepath.Join(home, ".rune", "work")
}
func setWorkDir(dir string) {
workDir = dir
batchFile = filepath.Join(dir, "batches.json")
configFile = filepath.Join(dir, "config.json")
metaFile = filepath.Join(dir, "meta.json")
}
// nowUTC — datetime.now(timezone.utc).isoformat() shape
// (2026-10-13T01:46:25.123456+00:00; "-07:00" layout prints "+00:00").
func nowUTC() string {
return time.Now().UTC().Format("2006-01-02T15:04:05.000000-07:00")
}
func defaultWorkConfig() WorkConfig {
return WorkConfig{
ModelRouting: "auto",
LocalModel: "qwen3:14b",
CloudModel: "mimo-v2.5-pro",
AutoVerify: true,
MaxRetries: 2,
}
}
func groupByType(items []WorkItem) map[string][]WorkItem {
@@ -84,6 +174,7 @@ func createBatches(items []WorkItem, cfg WorkConfig) []Batch {
ID: fmt.Sprintf("B%d", id), Model: "auto-fix",
Description: fmt.Sprintf("Auto-fix: %d items", len(autoFix)),
Items: autoFix, Files: uniqueFiles(autoFix),
Created: nowUTC(), Status: "pending",
})
id++
}
@@ -124,6 +215,7 @@ func createBatches(items []WorkItem, cfg WorkConfig) []Batch {
batches = append(batches, Batch{
ID: fmt.Sprintf("B%d", id), Description: fmt.Sprintf("%s: %d items in %s", gt, len(byFile[f]), f),
Items: byFile[f], Files: []string{f},
Created: nowUTC(), Status: "pending",
})
id++
}
@@ -133,6 +225,7 @@ func createBatches(items []WorkItem, cfg WorkConfig) []Batch {
ID: fmt.Sprintf("B%d", id),
Description: fmt.Sprintf("%s: %d items in %d files", gt, len(chunk), len(files)),
Items: chunk, Files: files,
Created: nowUTC(), Status: "pending",
})
id++
}
@@ -151,11 +244,13 @@ func getNextBatch(batches []Batch) *Batch {
return nil
}
// completeBatch / failBatch — status transitions.
// completeBatch / failBatch — status transitions (oracle sets `completed`
// on complete, nothing on fail).
func completeBatch(batches []Batch, id, result string) {
for i := range batches {
if batches[i].ID == id {
batches[i].Status = "complete"
batches[i].Completed = nowUTC()
batches[i].Result = result
return
}
@@ -198,6 +293,352 @@ func routeBatch(b Batch, cfg WorkConfig) string {
}
}
// groupByFile — the oracle group_by_file (missing gap 1/13). First-seen
// key insertion order is preserved by the caller where it matters.
func groupByFile(items []WorkItem) map[string][]WorkItem {
g := map[string][]WorkItem{}
for _, it := range items {
g[it.File] = append(g[it.File], it)
}
return g
}
// ── PERSISTENCE (oracle load_config/save_config/load_batches/save_batches,
// load_meta/save_meta) — every failure suppressed exactly like the oracle's
// try/except: unreadable/absent → default/empty.
// loadConfig — oracle load_config: file missing or malformed → default
// WorkConfig; unknown keys are filtered (WorkConfig(**{known})).
func loadConfig() WorkConfig {
cfg := defaultWorkConfig()
data, err := os.ReadFile(configFile)
if err != nil {
return cfg
}
var raw map[string]any
if err := json.Unmarshal(data, &raw); err != nil {
return cfg
}
known := map[string]bool{
"model_routing": true, "local_model": true, "cloud_model": true,
"auto_verify": true, "max_retries": true,
}
filtered := map[string]any{}
for k, v := range raw {
if known[k] {
filtered[k] = v
}
}
b, err := json.Marshal(filtered)
if err != nil {
return cfg
}
if err := json.Unmarshal(b, &cfg); err != nil {
return cfg
}
return cfg
}
// saveConfig — oracle save_config: MkdirAll + indent-2 dump, suppressed.
func saveConfig(cfg WorkConfig) {
_ = os.MkdirAll(workDir, 0o755)
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return
}
_ = os.WriteFile(configFile, data, 0o644)
}
var batchKnownKeys = map[string]bool{
"id": true, "description": true, "items": true, "files": true,
"status": true, "model": true, "created": true, "completed": true,
"result": true,
}
// loadBatches — oracle load_batches: Batch(**b) rejects missing required
// keys AND unknown keys (TypeError → except → []); one bad entry empties
// the whole load.
func loadBatches() []Batch {
data, err := os.ReadFile(batchFile)
if err != nil {
return nil
}
var raw []map[string]any
if err := json.Unmarshal(data, &raw); err != nil {
return nil
}
batches := make([]Batch, 0, len(raw))
for _, m := range raw {
if m["id"] == nil || m["description"] == nil {
return nil
}
for k := range m {
if !batchKnownKeys[k] {
return nil
}
}
b, err := json.Marshal(m)
if err != nil {
return nil
}
var bt Batch
if err := json.Unmarshal(b, &bt); err != nil {
return nil
}
batches = append(batches, bt)
}
return batches
}
// saveBatches — oracle save_batches: MkdirAll + indent-2 dump of asdict
// list; nil normalizes to [] (Python has no null lists).
func saveBatches(batches []Batch) {
_ = os.MkdirAll(workDir, 0o755)
if batches == nil {
batches = []Batch{}
}
data, err := json.MarshalIndent(batches, "", " ")
if err != nil {
return
}
_ = os.WriteFile(batchFile, data, 0o644)
}
var metaKnownKeys = map[string]bool{
"task_id": true, "description": true, "created": true,
"total_batches": true, "complete_batches": true, "failed_batches": true,
"total_items": true, "complete_items": true, "status": true,
"notes": true,
}
// loadMeta — oracle load_meta: absent/malformed → None; unknown keys
// filtered (TaskMeta(**{known})); missing required keys → None.
func loadMeta() *TaskMeta {
data, err := os.ReadFile(metaFile)
if err != nil {
return nil
}
var raw map[string]any
if err := json.Unmarshal(data, &raw); err != nil {
return nil
}
if raw["task_id"] == nil || raw["description"] == nil || raw["created"] == nil {
return nil
}
filtered := map[string]any{}
for k, v := range raw {
if metaKnownKeys[k] {
filtered[k] = v
}
}
b, err := json.Marshal(filtered)
if err != nil {
return nil
}
var meta TaskMeta
if err := json.Unmarshal(b, &meta); err != nil {
return nil
}
return &meta
}
// saveMeta — oracle save_meta: MkdirAll + indent-2 dump, suppressed.
func saveMeta(meta TaskMeta) {
_ = os.MkdirAll(workDir, 0o755)
if meta.Notes == nil {
meta.Notes = []string{}
}
data, err := json.MarshalIndent(meta, "", " ")
if err != nil {
return
}
_ = os.WriteFile(metaFile, data, 0o644)
}
// ── PUBLIC API (oracle create_work / clear_work / auto-fill / meta
// tracker) — the shell over the pure core above.
// createWork — oracle create_work: load config, batch, route every batch,
// save.
func createWork(items []WorkItem, description string) []Batch {
cfg := loadConfig()
batches := createBatches(items, cfg)
for i := range batches {
batches[i].Model = routeBatch(batches[i], cfg)
}
if batches == nil {
batches = []Batch{}
}
saveBatches(batches)
return batches
}
// clearWork — oracle clear_work.
func clearWork() { saveBatches([]Batch{}) }
// getStatus — the FULL oracle get_status dict (getStatusSummary stays as
// the counts-only core the lifecycle test pins).
func getStatus() map[string]any {
batches := loadBatches()
cfg := loadConfig()
counts := getStatusSummary(batches)
totalItems, completeItems := 0, 0
for _, b := range batches {
totalItems += b.size()
if b.Status == "complete" {
completeItems += b.size()
}
}
return map[string]any{
"batches": counts["total"],
"pending": counts["pending"],
"running": counts["running"],
"complete": counts["complete"],
"failed": counts["failed"],
"total_items": totalItems,
"complete_items": completeItems,
"model_routing": cfg.ModelRouting,
"local_model": cfg.LocalModel,
"cloud_model": cfg.CloudModel,
}
}
// auditToWorkItems — oracle audit_to_work_items: groups[].findings[] →
// WorkItems (W1..Wn); R001/R013 are auto-fixable.
func auditToWorkItems(audit map[string]any) []WorkItem {
items := []WorkItem{}
groups, _ := audit["groups"].([]any)
for _, g := range groups {
gm, _ := g.(map[string]any)
findings, _ := gm["findings"].([]any)
for _, f := range findings {
fm, _ := f.(map[string]any)
rule, _ := fm["rule"].(string)
sev := "medium"
if v, ok := fm["severity"]; ok {
sev, _ = v.(string)
}
items = append(items, WorkItem{
ID: fmt.Sprintf("W%d", len(items)+1),
Description: anyString(fm["message"]),
File: anyString(fm["file"]),
Line: anyInt(fm["line"]),
Rule: rule,
Severity: sev,
AutoFixable: rule == "R001" || rule == "R013",
})
}
}
return items
}
func anyString(v any) string {
s, _ := v.(string)
return s
}
func anyInt(v any) int {
f, _ := v.(float64)
return int(f)
}
// autoFillFromAudit — oracle auto_fill_from_audit: summary for
// confirmation; empty audit short-circuits.
func autoFillFromAudit(audit map[string]any, description string) map[string]any {
items := auditToWorkItems(audit)
if len(items) == 0 {
return map[string]any{"batches": 0, "items": 0, "summary": "No findings to process."}
}
batches := createWork(items, description)
bySeverity := map[string]int{}
byType := map[string]int{}
for _, it := range items {
bySeverity[it.Severity]++
byType[it.Rule]++
}
details := make([]map[string]any, 0, len(batches))
for _, b := range batches {
files := b.Files
if files == nil {
files = []string{}
}
details = append(details, map[string]any{
"id": b.ID, "description": b.Description,
"items": b.size(), "files": files, "model": b.Model,
})
}
return map[string]any{
"total_items": len(items),
"batches": len(batches),
"by_severity": bySeverity,
"by_type": byType,
"batch_details": details,
}
}
// updateMetaFromBatches — oracle update_meta_from_batches: refresh the
// meta tracker from the on-disk batch state (create the default audit
// meta when absent; never reset status except via the two branches).
func updateMetaFromBatches() TaskMeta {
batches := loadBatches()
meta := loadMeta()
if meta == nil {
meta = &TaskMeta{
TaskID: "audit",
Description: "Codebase audit",
Created: nowUTC(),
Status: "active", // dataclass default
Notes: []string{},
}
}
meta.TotalBatches = len(batches)
meta.CompleteBatches = 0
meta.FailedBatches = 0
meta.TotalItems = 0
meta.CompleteItems = 0
for _, b := range batches {
meta.TotalItems += b.size()
switch b.Status {
case "complete":
meta.CompleteBatches++
meta.CompleteItems += b.size()
case "failed":
meta.FailedBatches++
}
}
if meta.CompleteBatches == meta.TotalBatches && meta.TotalBatches > 0 {
meta.Status = "complete"
} else if meta.FailedBatches > 0 {
meta.Status = "partial"
}
saveMeta(*meta)
return *meta
}
// getMetaStatus — oracle get_meta_status projection.
func getMetaStatus() map[string]any {
meta := updateMetaFromBatches()
notes := []string{}
if len(meta.Notes) > 0 {
last := meta.Notes
if len(last) > 5 {
last = last[len(last)-5:]
}
notes = last
}
return map[string]any{
"task_id": meta.TaskID,
"description": meta.Description,
"status": meta.Status,
"progress": fmt.Sprintf("%.0f%%", meta.progress()*100),
"batches": fmt.Sprintf("%d/%d", meta.CompleteBatches, meta.TotalBatches),
"items": fmt.Sprintf("%d/%d", meta.CompleteItems, meta.TotalItems),
"failed": meta.FailedBatches,
"eta": meta.eta(),
"notes": notes,
}
}
func main() {
if len(os.Args) < 2 || os.Args[1] != "replay" {
fmt.Fprintln(os.Stderr, "usage: work-manager replay <truth.json>")
+374
View File
@@ -0,0 +1,374 @@
package main
// parity_live_test.go — LIVE parity: Go port vs the live Python oracle
// (src/rune/work_manager.py) on the gap-closing surface, over seeded
// random scenarios. The oracle runs in a fresh subprocess with a pinned
// core (RUNE_WORK_MANAGER_CORE=python), its own empty HOME (the module
// derives its work paths from expanduser at import), and a shared
// deterministic program; both sides normalize wall-clock timestamps
// (created/completed → "<TS>").
import (
"encoding/json"
"math/rand"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
"testing"
)
const oracleExecutor = `
import dataclasses, json, os, sys
sys.path.insert(0, os.environ["WM_SRC_PATH"])
import rune.work_manager as wm
def norm(v):
if isinstance(v, dict):
return {k: ("<TS>" if k in ("created", "completed") and isinstance(x, str) else (sorted(x) if k == "files" and isinstance(x, list) else norm(x))) for k, x in v.items()}
if isinstance(v, list):
return [norm(x) for x in v]
return v
prog = json.load(sys.stdin)
out = []
for op in prog:
name = op["op"]
if name == "reset":
for f in (wm.BATCH_FILE, wm.CONFIG_FILE, wm.META_FILE):
try:
os.remove(f)
except OSError:
pass
out.append(None)
elif name == "save_config":
cfg = wm.WorkConfig(**{k: v for k, v in op["config"].items() if k in wm.WorkConfig.__dataclass_fields__})
wm.save_config(cfg)
out.append(None)
elif name == "load_config":
out.append(dataclasses.asdict(wm.load_config()))
elif name == "create_work":
items = [wm.WorkItem(**it) for it in op["items"]]
out.append([dataclasses.asdict(b) for b in wm.create_work(items, op.get("description", ""))])
elif name == "load_batches":
out.append([dataclasses.asdict(b) for b in wm.load_batches()])
elif name == "get_next_batch":
b = wm.get_next_batch()
out.append(dataclasses.asdict(b) if b is not None else None)
elif name == "complete_batch":
wm.complete_batch(op["id"], op.get("result", ""))
out.append(None)
elif name == "fail_batch":
wm.fail_batch(op["id"], op.get("result", ""))
out.append(None)
elif name == "get_status":
out.append(wm.get_status())
elif name == "update_meta_from_batches":
out.append(dataclasses.asdict(wm.update_meta_from_batches()))
elif name == "get_meta_status":
out.append(wm.get_meta_status())
elif name == "audit_to_work_items":
out.append([dataclasses.asdict(i) for i in wm.audit_to_work_items(op["audit"])])
elif name == "auto_fill_from_audit":
out.append(wm.auto_fill_from_audit(op["audit"], op.get("description", "Codebase audit")))
elif name == "clear_work":
wm.clear_work()
out.append(None)
else:
raise SystemExit("unknown op: " + name)
print(json.dumps([norm(x) for x in out]))
`
func repoRoot(t *testing.T) string {
t.Helper()
_, thisFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
return filepath.Clean(filepath.Join(filepath.Dir(thisFile), "..", "..", ".."))
}
var rules = []string{"R001", "R013", "R100", "R200", ""}
var severities = []string{"high", "medium", "low"}
var routings = []string{"local", "cloud", "auto"}
func randItems(rng *rand.Rand, n int) []WorkItem {
items := make([]WorkItem, n)
for i := range items {
items[i] = WorkItem{
ID: "1",
Description: "d" + string(rune('a'+rng.Intn(26))),
File: "f" + string(rune('a'+rng.Intn(6))) + ".py",
Line: rng.Intn(300),
Rule: rules[rng.Intn(len(rules))],
Severity: severities[rng.Intn(len(severities))],
AutoFixable: rng.Intn(10) < 3,
}
}
return items
}
func randAudit(rng *rand.Rand) map[string]any {
groups := []any{}
for g := 0; g <= rng.Intn(3); g++ {
findings := []any{}
for f := 0; f <= rng.Intn(6); f++ {
fm := map[string]any{}
if rng.Intn(10) > 0 {
fm["message"] = "m" + string(rune('a'+rng.Intn(26)))
}
if rng.Intn(10) > 1 {
fm["file"] = "f" + string(rune('a'+rng.Intn(6))) + ".py"
}
if rng.Intn(10) > 1 {
fm["line"] = float64(rng.Intn(300))
}
if rng.Intn(10) > 0 {
fm["rule"] = rules[rng.Intn(len(rules))]
}
if rng.Intn(10) > 1 {
fm["severity"] = severities[rng.Intn(len(severities))]
}
findings = append(findings, any(fm))
}
groups = append(groups, any(map[string]any{"findings": findings}))
}
return map[string]any{"groups": groups}
}
// normParity — parity normalization: (a) wall-clock timestamps → "<TS>";
// (b) `files` lists SORTED — the oracle builds them via list(set(...)),
// whose iteration order is hash-randomized per process, so no stable
// order exists to diverge from; the Go port is deterministic first-seen.
func normParity(v any) any {
switch x := v.(type) {
case map[string]any:
out := make(map[string]any, len(x))
for k, vv := range x {
if k == "created" || k == "completed" {
if _, ok := vv.(string); ok {
out[k] = "<TS>"
continue
}
}
if k == "files" {
if arr, ok := vv.([]any); ok {
strs := make([]string, len(arr))
for i, e := range arr {
strs[i], _ = e.(string)
}
sort.Strings(strs)
sorted := make([]any, len(strs))
for i, e := range strs {
sorted[i] = e
}
out[k] = sorted
continue
}
}
out[k] = normParity(vv)
}
return out
case []any:
out := make([]any, len(x))
for i, vv := range x {
out[i] = normParity(vv)
}
return out
default:
return v
}
}
// dispatchLive — the Go twin of the embedded oracle executor.
func dispatchLive(t *testing.T, workDir string, op map[string]any) any {
t.Helper()
setWorkDir(workDir)
switch op["op"] {
case "reset":
for _, f := range []string{batchFile, configFile, metaFile} {
_ = os.Remove(f)
}
return nil
case "save_config":
raw, _ := json.Marshal(op["config"])
var cfg WorkConfig
if err := json.Unmarshal(raw, &cfg); err != nil {
t.Fatalf("save_config: %v", err)
}
saveConfig(cfg)
return nil
case "load_config":
return loadConfig()
case "create_work":
raw, _ := json.Marshal(op["items"])
var items []WorkItem
if err := json.Unmarshal(raw, &items); err != nil {
t.Fatalf("create_work: %v", err)
}
desc, _ := op["description"].(string)
return createWork(items, desc)
case "load_batches":
if bs := loadBatches(); bs != nil {
return bs
}
return []Batch{}
case "get_next_batch":
if bs := loadBatches(); bs != nil {
return getNextBatch(bs)
}
return nil
case "complete_batch":
id, _ := op["id"].(string)
result, _ := op["result"].(string)
bs := loadBatches()
completeBatch(bs, id, result)
saveBatches(bs)
return nil
case "fail_batch":
id, _ := op["id"].(string)
result, _ := op["result"].(string)
bs := loadBatches()
failBatch(bs, id, result)
saveBatches(bs)
return nil
case "get_status":
return getStatus()
case "update_meta_from_batches":
return updateMetaFromBatches()
case "get_meta_status":
return getMetaStatus()
case "audit_to_work_items":
audit, _ := op["audit"].(map[string]any)
return auditToWorkItems(audit)
case "auto_fill_from_audit":
audit, _ := op["audit"].(map[string]any)
desc, _ := op["description"].(string)
return autoFillFromAudit(audit, desc)
case "clear_work":
clearWork()
return nil
default:
t.Fatalf("unknown op %v", op["op"])
return nil
}
}
func TestLiveParityPythonOracle(t *testing.T) {
if _, err := exec.LookPath("python3"); err != nil {
t.Skip("python3 unavailable")
}
repo := repoRoot(t)
srcDir := filepath.Join(repo, "src")
const seeds = 40
prog := []map[string]any{}
for seed := 0; seed < seeds; seed++ {
rng := rand.New(rand.NewSource(int64(2479 + seed)))
items := randItems(rng, rng.Intn(26))
cfg := WorkConfig{
ModelRouting: routings[rng.Intn(len(routings))],
LocalModel: "qwen3:14b",
CloudModel: "mimo-v2.5-pro",
AutoVerify: rng.Intn(2) == 0,
MaxRetries: rng.Intn(4),
}
cfgRaw, _ := json.Marshal(cfg)
var cfgMap map[string]any
_ = json.Unmarshal(cfgRaw, &cfgMap)
itemsRaw, _ := json.Marshal(items)
var itemsAny []any
_ = json.Unmarshal(itemsRaw, &itemsAny)
prog = append(prog,
map[string]any{"op": "reset"},
map[string]any{"op": "save_config", "config": cfgMap},
map[string]any{"op": "load_config"},
map[string]any{"op": "create_work", "items": itemsAny, "description": "sweep"},
map[string]any{"op": "load_batches"},
map[string]any{"op": "get_next_batch"},
map[string]any{"op": "complete_batch", "id": "B1", "result": "done"},
map[string]any{"op": "fail_batch", "id": "B2", "result": "red"},
map[string]any{"op": "get_status"},
map[string]any{"op": "update_meta_from_batches"},
map[string]any{"op": "get_meta_status"},
map[string]any{"op": "audit_to_work_items", "audit": randAudit(rng)},
map[string]any{"op": "auto_fill_from_audit", "audit": randAudit(rng), "description": "audit sweep"},
map[string]any{"op": "load_batches"},
map[string]any{"op": "get_next_batch"},
map[string]any{"op": "get_status"},
map[string]any{"op": "clear_work"},
map[string]any{"op": "load_batches"},
map[string]any{"op": "get_meta_status"},
)
}
// ── oracle side ──────────────────────────────────────────────────
progRaw, err := json.Marshal(prog)
if err != nil {
t.Fatal(err)
}
pyHome := t.TempDir()
cmd := exec.Command("python3", "-c", oracleExecutor)
cmd.Stdin = strings.NewReader(string(progRaw))
cmd.Env = append(os.Environ(),
"HOME="+pyHome,
"WM_SRC_PATH="+srcDir,
"PYTHONPATH="+srcDir,
"RUNE_WORK_MANAGER_CORE=python",
)
pyRaw, err := cmd.Output()
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
t.Fatalf("oracle executor failed: %v\n%s", err, ee.Stderr)
}
t.Fatalf("oracle executor failed: %v", err)
}
var pyOut []any
if err := json.Unmarshal(pyRaw, &pyOut); err != nil {
t.Fatalf("oracle output: %v (%q)", err, strings.TrimSpace(string(pyRaw)))
}
// ── Go side ─────────────────────────────────────────────────────
goHome := t.TempDir()
var goOut []any
for _, op := range prog {
res := dispatchLive(t, filepath.Join(goHome, ".rune", "work"), op)
raw, err := json.Marshal(res)
if err != nil {
t.Fatalf("marshal %v: %v", op["op"], err)
}
var anyRes any
_ = json.Unmarshal(raw, &anyRes)
goOut = append(goOut, normParity(anyRes))
}
// ── compare ─────────────────────────────────────────────────────
if len(goOut) != len(pyOut) {
t.Fatalf("result count: go %d vs oracle %d", len(goOut), len(pyOut))
}
fails := 0
for i := range prog {
if !reflect.DeepEqual(goOut[i], pyOut[i]) {
fails++
if fails <= 3 {
g, _ := json.Marshal(goOut[i])
p, _ := json.Marshal(pyOut[i])
gl, pl := len(g), len(p)
if gl > 400 {
g = g[:400]
}
if pl > 400 {
p = p[:400]
}
t.Errorf("op %d %v (len go=%d oracle=%d):\n go %s\n oracle %s", i, prog[i]["op"], gl, pl, g, p)
}
}
}
if fails > 0 {
t.Fatalf("LIVE PARITY FAILED: %d/%d divergences", fails, len(prog))
}
t.Logf("live parity OK: %d ops across %d seeds identical (timestamp-normalized)", len(prog), seeds)
}
+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.262.0"
__version__ = "0.267.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.262.0"' in rune_version,
'__version__ = "0.267.0"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""ctypes loader for the Rust meaningful_events core (dichotomy wave,
#2479 tranche). Mirrors broker_loader.py's contract:
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* me_should_fire({trigger, state, now}) -> {fires, reason}
* me_fire_due({state, now}) -> [trigger, ...]
* me_mark_fired({state, trigger, now}) -> state dict
The wall CLOCK is host-side by nature (now resolved by the facade —
null never crosses); the kernel owns the trigger table and the laws.
Free: capability_scoring's cs_free_string (shared process). Override the
.so with ME_RUST_LIB (a FILE path).
"""
from __future__ import annotations
import ctypes
import json
import os
from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_CRATE_DIR = _REPO / "src" / "rust" / "meaningful_events"
_LIB_PATH = Path(
os.environ.get("ME_RUST_LIB", _CRATE_DIR / "target" / "release" / "libmeaningful_events.so")
)
_ERR_TYPES = {
"ValueError": ValueError,
"KeyError": KeyError,
"AttributeError": AttributeError,
"TypeError": TypeError,
}
_lib = None
class EventsCoreUnavailable(FileNotFoundError):
"""The Rust meaningful-events core is not built. Callers fall back
to Python."""
def available() -> bool:
return _LIB_PATH.is_file()
def _load() -> ctypes.CDLL:
global _lib
if _lib is not None:
return _lib
if not _LIB_PATH.is_file():
raise EventsCoreUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
for sym in ("me_should_fire", "me_fire_due", "me_mark_fired"):
getattr(lib, sym).argtypes = [ctypes.c_void_p]
getattr(lib, sym).restype = ctypes.c_void_p
try:
lib.cs_free_string
except AttributeError:
scoring = ctypes.CDLL(str(
_REPO / "src" / "rust" / "capability_scoring" / "target" / "release" / "libcapability_scoring.so"
))
scoring.cs_free_string.argtypes = [ctypes.c_void_p]
lib._free = scoring.cs_free_string
_lib = lib
return lib
def _call(sym: str, payload: dict):
lib = _load()
data = json.dumps(payload).encode()
buf = ctypes.create_string_buffer(data)
ptr = getattr(lib, sym)(ctypes.cast(buf, ctypes.c_void_p))
if not ptr:
raise RuntimeError(f"{sym} returned null")
out = ctypes.string_at(ptr).decode()
free = getattr(lib, "_free", None)
if free is not None:
free(ptr)
doc = json.loads(out)
if not doc.get("ok"):
etype = doc.get("type", "RuntimeError")
raise _ERR_TYPES.get(etype, RuntimeError)(doc.get("err", f"{sym} failed"))
return doc["value"]
def should_fire(trigger: str, state: dict, now: float) -> dict:
return _call("me_should_fire", {"trigger": trigger, "state": state,
"now": now})
def fire_due(state: dict, now: float) -> list:
return _call("me_fire_due", {"state": state, "now": now})
def mark_fired(state: dict, trigger: str, now: float) -> dict:
return _call("me_mark_fired", {"state": state, "trigger": trigger,
"now": now})
+42 -1
View File
@@ -15,6 +15,7 @@ approaching, not because a timer fired.
from __future__ import annotations
import os
import time
# Trigger classes with (condition_key, default_rate_limit_s, stop_key)
@@ -30,10 +31,36 @@ TRIGGERS = {
}
def _kernel():
"""The Rust meaningful-events core (me_loader) when RUNE_ME_CORE
allows it, else None — the trigger table, the should_fire law, the
fire_due ordering and the mark_fired copy law delegate there first
and fall back to the Python body below (same semantics). The wall
CLOCK is host-side by nature: `now` is resolved here (never null
across FFI), and an INT now keeps the Python floor in mark_fired
(the oracle stores the value as-is; the kernel wire is float)."""
if os.environ.get("RUNE_ME_CORE", "auto") == "python":
return None
try:
from rune import me_loader
if me_loader.available():
return me_loader
except Exception: # noqa: BLE001 — kernel failure → Python floor
return None
return None
def should_fire(trigger: str, state: dict, now: float | None = None) -> dict:
"""Evaluate one trigger against current state. Returns
{fires, reason}. Rate-limited, stop-conditioned."""
now = now if now is not None else time.time()
k = _kernel()
if k is not None:
try:
return k.should_fire(trigger, state, now)
except Exception: # noqa: BLE001 — kernel floor
pass
if trigger not in TRIGGERS:
return {"fires": False, "reason": f"unknown trigger: {trigger}"}
cond_key, rate_limit, stop_key = TRIGGERS[trigger]
@@ -50,12 +77,26 @@ def should_fire(trigger: str, state: dict, now: float | None = None) -> dict:
def fire_due(state: dict, now: float | None = None) -> list:
"""All triggers due right now (the endogenous cognition tick)."""
resolved = now if now is not None else time.time()
k = _kernel()
if k is not None:
try:
return k.fire_due(state, resolved)
except Exception: # noqa: BLE001 — kernel floor
pass
return [t for t in TRIGGERS
if should_fire(t, state, now)["fires"]]
if should_fire(t, state, resolved)["fires"]]
def mark_fired(state: dict, trigger: str, now: float | None = None) -> dict:
"""Record a firing (for rate limiting). Returns the updated state."""
k = _kernel()
if k is not None and (now is None or isinstance(now, float)):
try:
return k.mark_fired(state, trigger,
now if now is not None else time.time())
except Exception: # noqa: BLE001 — kernel floor
pass
state = dict(state)
state[f"last_fired_{trigger}"] = now if now is not None else time.time()
return state
+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.262.0
Version: v0.267.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.262.0 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.267.0 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
+32
View File
@@ -8,18 +8,47 @@ for 'why' questions, contradictions, and growth.
Shape: {statements: [{text, source, weight}], budget_tokens, evidence_ref}.
compile_self_model(corpus, budget): greedy by weight until the budget
fills; the remainder stays in evidence (retrievable, not loaded).
Dichotomy wave #2479 tranche: the pure kernel (estimate_tokens /
compile_self_model / why_question) is ported to FULL Rust
(src/rust/self_model, parity oracle frozen_sm_truth.json) behind
smm_loader; the Python implementation below is the strangler fallback,
pinned with RUNE_SMM_CORE=python.
"""
from __future__ import annotations
import os
def _core():
"""The Rust self-model core when available (strangler: the Python
floor below is load-bearing). RUNE_SMM_CORE=python pins it."""
if os.environ.get("RUNE_SMM_CORE", "auto") == "python":
return None
try:
from rune import smm_loader
except Exception: # noqa: BLE001 — any loader failure means fallback
return None
try:
return smm_loader if smm_loader.available() else None
except Exception: # noqa: BLE001 — availability probe never crashes
return None
def estimate_tokens(text: str) -> int:
"""Rough token estimate (the broker estimator's shape, local)."""
core = _core()
if core is not None:
return int(core.estimate_tokens(text))
return max(1, len(text) // 4)
def compile_self_model(corpus: list, budget_tokens: int = 220) -> dict:
"""Compile corpus [{text, source, weight}] into a budgeted self-model."""
core = _core()
if core is not None:
return core.compile_self_model(corpus, budget_tokens)
ranked = sorted(corpus, key=lambda c: -c.get("weight", 0.5))
statements, evidence, used = [], [], 0
for c in ranked:
@@ -37,6 +66,9 @@ def compile_self_model(corpus: list, budget_tokens: int = 220) -> dict:
def why_question(model: dict, topic: str) -> list:
"""Retrieve the evidence behind a self-model statement ('why' path)."""
core = _core()
if core is not None:
return core.why_question(model, topic)
out = []
for s in model.get("statements", []) + model.get("evidence_ref", []):
if topic.lower() in s.get("text", "").lower():
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""ctypes loader for the Rust self_model core (dichotomy wave #2479
tranche). Mirrors broker_loader.py's contract:
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* smm_estimate_tokens({"text"}) -> token count (int)
* smm_compile_self_model({"corpus", "budget_tokens"?}) -> model dict
* smm_why_question({"model", "topic"}) -> matches list
Free: capability_scoring's cs_free_string (shared process). Override the
.so with SMM_RUST_LIB (a FILE path).
"""
from __future__ import annotations
import ctypes
import json
import os
from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_CRATE_DIR = _REPO / "src" / "rust" / "self_model"
_LIB_PATH = Path(
os.environ.get("SMM_RUST_LIB", _CRATE_DIR / "target" / "release" / "libself_model.so")
)
_lib = None
class SelfModelCoreUnavailable(FileNotFoundError):
"""The Rust self-model core is not built. Callers fall back to Python."""
def available() -> bool:
return _LIB_PATH.is_file()
def _load() -> ctypes.CDLL:
global _lib
if _lib is not None:
return _lib
if not _LIB_PATH.is_file():
raise SelfModelCoreUnavailable(str(_LIB_PATH))
lib = ctypes.CDLL(str(_LIB_PATH))
for sym in ("smm_estimate_tokens", "smm_compile_self_model", "smm_why_question"):
getattr(lib, sym).argtypes = [ctypes.c_void_p]
getattr(lib, sym).restype = ctypes.c_void_p
try:
lib.cs_free_string
except AttributeError:
scoring = ctypes.CDLL(str(
_REPO / "src" / "rust" / "capability_scoring" / "target" / "release" / "libcapability_scoring.so"
))
scoring.cs_free_string.argtypes = [ctypes.c_void_p]
lib._free = scoring.cs_free_string
_lib = lib
return lib
def _call(sym: str, payload: dict):
lib = _load()
data = json.dumps(payload).encode()
buf = ctypes.create_string_buffer(data)
ptr = getattr(lib, sym)(ctypes.cast(buf, ctypes.c_void_p))
if not ptr:
raise RuntimeError(f"{sym} returned null")
out = ctypes.string_at(ptr).decode()
free = getattr(lib, "_free", None)
if free is not None:
free(ptr)
doc = json.loads(out)
if not doc.get("ok"):
raise RuntimeError(doc.get("err", f"{sym} failed"))
return doc["value"]
def estimate_tokens(text: str) -> int:
return _call("smm_estimate_tokens", {"text": text})
def compile_self_model(corpus: list, budget_tokens: int = 220) -> dict:
return _call("smm_compile_self_model", {"corpus": corpus,
"budget_tokens": budget_tokens})
def why_question(model: dict, topic: str) -> list:
return _call("smm_why_question", {"model": model, "topic": topic})
+14
View File
@@ -0,0 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "evidence_provenance"
version = "0.1.0"
[[package]]
name = "meaningful_events"
version = "0.1.0"
dependencies = [
"evidence_provenance",
]
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "meaningful_events"
version = "0.1.0"
edition = "2021"
description = "FULL parity port of src/rune/meaningful_events.py (dichotomy wave, #2479 tranche)"
[lib]
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
evidence_provenance = { path = "../evidence_provenance" }
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,153 @@
//! branch_battery — replay the FROZEN oracle truth VERBATIM
//! (frozen_truth.json, generated by scripts/gen_meaningful_events_truth.py
//! against the LIVE Python oracle with RUNE_ME_CORE=python pinned and
//! deep-copied inputs).
use crate::{fire_due, mark_fired, should_fire};
use evidence_provenance::pyjson::{self, Json};
const TRUTH: &str = include_str!("../frozen_truth.json");
fn truth() -> Json {
pyjson::parse(TRUTH).expect("frozen truth parses")
}
fn cases(group: &str) -> Vec<Json> {
match truth().get(group) {
Some(Json::Arr(items)) => items.clone(),
_ => panic!("truth group {group} missing"),
}
}
fn at<'a>(v: &'a Json, path: &[&str]) -> Option<&'a Json> {
let mut cur = v;
for k in path {
cur = match cur {
Json::Obj(pairs) => pairs
.iter()
.find(|(k2, _)| k2 == k)
.map(|(_, x)| x)?,
_ => return None,
};
}
Some(cur)
}
fn jstr(v: Option<&Json>) -> String {
match v {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
}
}
fn now_of(v: Option<&Json>) -> Option<f64> {
match v {
Some(Json::Num(n)) | Some(Json::Float(n)) => Some(*n),
_ => None,
}
}
/// Python-value equality on Json (order-insensitive objects).
fn peq(a: &Json, b: &Json) -> bool {
match (a, b) {
(Json::Null, Json::Null) => true,
(Json::Bool(x), Json::Bool(y)) => x == y,
(Json::Num(x), Json::Num(y)) | (Json::Float(x), Json::Float(y)) => x == y,
(Json::Float(x), Json::Num(y)) | (Json::Num(x), Json::Float(y)) => x == y,
(Json::Str(x), Json::Str(y)) => x == y,
(Json::Arr(x), Json::Arr(y)) => {
x.len() == y.len() && x.iter().zip(y).all(|(a, b)| peq(a, b))
}
(Json::Obj(x), Json::Obj(y)) => {
x.len() == y.len()
&& x.iter().all(|(k, v)| {
y.iter()
.find(|(k2, _)| k2 == k)
.map(|(_, v2)| peq(v, v2))
.unwrap_or(false)
})
}
_ => false,
}
}
fn assert_case(name: &str, want: &Json, got: &Json) {
assert!(
peq(want, got),
"case {name} diverged:\n want={}\n got={}",
pyjson::dumps(want),
pyjson::dumps(got),
);
}
#[test]
fn replay_should_fire() {
for c in cases("should_fire_cases") {
let got = should_fire(
&jstr(at(&c, &["args", "trigger"])),
at(&c, &["args", "state"]).expect("state"),
now_of(at(&c, &["args", "now"])),
);
assert_case(
&jstr(at(&c, &["name"])),
at(&c, &["expect"]).expect("expect"),
&got,
);
}
}
#[test]
fn replay_fire_due() {
for c in cases("fire_due_cases") {
let got = fire_due(
at(&c, &["args", "state"]).expect("state"),
now_of(at(&c, &["args", "now"])),
);
assert_case(
&jstr(at(&c, &["name"])),
at(&c, &["expect"]).expect("expect"),
&got,
);
}
}
#[test]
fn replay_mark_fired() {
for c in cases("mark_fired_cases") {
let got = mark_fired(
at(&c, &["args", "state"]).expect("state"),
&jstr(at(&c, &["args", "trigger"])),
now_of(at(&c, &["args", "now"])),
);
assert_case(
&jstr(at(&c, &["name"])),
at(&c, &["expect"]).expect("expect"),
&got,
);
// the copy law: the kernel takes &Json and cannot mutate, but
// the truth ALSO records the oracle's input-unchanged invariant
assert!(
matches!(at(&c, &["input_unchanged"]), Some(Json::Bool(true))),
"case {} oracle input was mutated",
jstr(at(&c, &["name"])),
);
}
}
#[test]
fn all_eight_triggers_in_table_order() {
let names: Vec<&str> = crate::TRIGGERS.iter().map(|t| t.name).collect();
assert_eq!(
names,
vec![
"unresolved_commitments",
"approaching_deadlines",
"repeated_failure",
"contradictions",
"curiosity_candidates",
"prediction_mismatches",
"task_blockers",
"owner_corrections",
]
);
}
+268
View File
@@ -0,0 +1,268 @@
//! meaningful_events — endogenous meaningful-event triggers (#48).
//!
//! FULL parity port of src/rune/meaningful_events.py (dichotomy wave,
//! #2479 tranche). The wall CLOCK is host-side by nature — `now` is
//! passed per op (null never reaches the kernel; the facade resolves
//! time.time() first). The kernel owns the eight-trigger table, the
//! should_fire law, the fire_due ordering and the mark_fired copy law.
//!
//! FFI (doc-envelope law): every call takes one JSON doc and returns
//! {"ok": true, "value": ...} | {"ok": false, "err": ..., "type": ...}.
//! * me_should_fire({trigger, state, now}) -> {fires, reason}
//! * me_fire_due({state, now}) -> [trigger, ...]
//! * me_mark_fired({state, trigger, now}) -> state dict
//!
//! Python laws replicated exactly:
//! * should_fire ordering: unknown → stop → absent → rate → fires
//! * truthiness on state values (0, "", null are ABSENT/NOT-MET)
//! * last = state["last_fired_{trigger}"] or 0 (falsy → 0)
//! * rate gate is STRICTLY `now - last < rate_limit` (equal fires)
//! * remaining = int(rate_limit - (now - last)) — Python int()
//! truncation TOWARD ZERO (matches `as i64` for this domain)
//! * fire_due lists TABLE ORDER (insertion order, not sorted)
//! * mark_fired: dict(state) shallow copy + key set (unknown
//! triggers still record)
//!
//! NOTE: no me_free_string export — callers free through capability_
//! scoring's cs_free_string (shared process allocator).
use evidence_provenance::pyjson::{self, Json};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
fn obj(pairs: Vec<(&str, Json)>) -> Json {
Json::Obj(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
fn s(v: &str) -> Json {
Json::Str(v.to_string())
}
/// Phase B groundwork for the language-advantage pass: the trigger
/// table is typed records, not tuples — the compiler names every field.
pub struct Trigger {
pub name: &'static str,
pub condition_key: &'static str,
pub rate_limit_s: f64,
pub stop_key: &'static str,
}
/// The eight trigger classes, TABLE ORDER (the fire_due listing law).
pub const TRIGGERS: [Trigger; 8] = [
Trigger { name: "unresolved_commitments", condition_key: "has_open_commitments", rate_limit_s: 3600.0, stop_key: "commitments_resolved" },
Trigger { name: "approaching_deadlines", condition_key: "deadline_within_24h", rate_limit_s: 1800.0, stop_key: "deadline_passed_or_met" },
Trigger { name: "repeated_failure", condition_key: "same_failure_3x", rate_limit_s: 900.0, stop_key: "failure_pattern_broken" },
Trigger { name: "contradictions", condition_key: "contradiction_detected", rate_limit_s: 1800.0, stop_key: "contradiction_resolved" },
Trigger { name: "curiosity_candidates", condition_key: "novel_material_present", rate_limit_s: 7200.0, stop_key: "material_absorbed" },
Trigger { name: "prediction_mismatches", condition_key: "prediction_wrong", rate_limit_s: 1800.0, stop_key: "model_updated" },
Trigger { name: "task_blockers", condition_key: "task_blocked", rate_limit_s: 600.0, stop_key: "task_unblocked" },
Trigger { name: "owner_corrections", condition_key: "correction_received", rate_limit_s: 300.0, stop_key: "correction_absorbed" },
];
fn find(trigger: &str) -> Option<&'static Trigger> {
TRIGGERS.iter().find(|t| t.name == trigger)
}
/// Python truthiness on a JSON value (state.get() laws).
fn truthy(v: Option<&Json>) -> bool {
match v {
None | Some(Json::Null) => false,
Some(Json::Bool(b)) => *b,
Some(Json::Num(n)) => *n != 0.0,
Some(Json::Float(n)) => *n != 0.0,
Some(Json::Str(x)) => !x.is_empty(),
Some(Json::Arr(a)) => !a.is_empty(),
Some(Json::Obj(o)) => !o.is_empty(),
}
}
/// as_f64 over state/now values (Num and Float alike).
fn f64_of(v: Option<&Json>) -> Option<f64> {
match v {
Some(Json::Num(n)) | Some(Json::Float(n)) => Some(*n),
_ => None,
}
}
/// Phase B (language advantage): the decision is a typed verdict
/// matched EXHAUSTIVELY — the JSON envelope is built once at the edge,
/// and fire_due filters on the enum instead of re-parsing decision
/// JSON per trigger.
#[derive(Debug, Clone, Copy, PartialEq)]
enum FireDecision {
/// unreachable through should_fire (find() rules it out) but kept
/// so the match stays exhaustive over the decision lattice
#[allow(dead_code)]
Unknown,
Stopped(&'static str),
Absent(&'static str),
RateLimited(i64),
Fire(&'static str),
}
fn decide(t: &'static Trigger, state: &Json, now: f64) -> FireDecision {
if truthy(state.get(t.stop_key)) {
return FireDecision::Stopped(t.stop_key);
}
if !truthy(state.get(t.condition_key)) {
return FireDecision::Absent(t.condition_key);
}
// last = state.get(f"last_fired_{trigger}", 0) — falsy → 0
let last = f64_of(state.get(&format!("last_fired_{}", t.name))).unwrap_or(0.0);
if now - last < t.rate_limit_s {
return FireDecision::RateLimited((t.rate_limit_s - (now - last)) as i64);
}
FireDecision::Fire(t.condition_key)
}
/// should_fire law. `now` is always Some (facade-resolved clock).
pub fn should_fire(trigger: &str, state: &Json, now: Option<f64>) -> Json {
let now = now.unwrap_or(0.0);
let Some(t) = find(trigger) else {
return obj(vec![
("fires", Json::Bool(false)),
("reason", s(&format!("unknown trigger: {trigger}"))),
]);
};
match decide(t, state, now) {
FireDecision::Stopped(stop_key) => obj(vec![
("fires", Json::Bool(false)),
("reason", s(&format!("stop condition met: {stop_key}"))),
]),
FireDecision::Absent(cond_key) => obj(vec![
("fires", Json::Bool(false)),
("reason", s(&format!("condition absent: {cond_key}"))),
]),
FireDecision::RateLimited(remaining) => obj(vec![
("fires", Json::Bool(false)),
("reason", s(&format!("rate-limited ({remaining}s left)"))),
]),
FireDecision::Fire(cond_key) => obj(vec![
("fires", Json::Bool(true)),
("reason", s(&format!("condition holds: {cond_key}"))),
]),
FireDecision::Unknown => unreachable!("find() already ruled this out"),
}
}
/// fire_due law: TABLE ORDER listing of due triggers.
pub fn fire_due(state: &Json, now: Option<f64>) -> Json {
let now = now.unwrap_or(0.0);
let due: Vec<Json> = TRIGGERS
.iter()
.filter(|t| matches!(decide(t, state, now), FireDecision::Fire(_)))
.map(|t| s(t.name))
.collect();
Json::Arr(due)
}
/// mark_fired law: dict(state) shallow copy + `last_fired_{trigger}`.
pub fn mark_fired(state: &Json, trigger: &str, now: Option<f64>) -> Json {
let mut pairs: Vec<(String, Json)> = match state {
Json::Obj(pairs) => pairs.clone(),
_ => Vec::new(),
};
let stamp = Json::Float(now.unwrap_or(0.0));
let key = format!("last_fired_{trigger}");
if let Some(slot) = pairs.iter_mut().find(|(k, _)| *k == key) {
slot.1 = stamp;
} else {
pairs.push((key, stamp));
}
Json::Obj(pairs)
}
// ── FFI (doc-envelope) ───────────────────────────────────────────────────
fn envelope(result: Result<Json, (String, String)>) -> *mut c_char {
let body = match result {
Ok(value) => obj(vec![("ok", Json::Bool(true)), ("value", value)]),
Err((err, ty)) => obj(vec![
("ok", Json::Bool(false)),
("err", Json::Str(err)),
("type", Json::Str(ty)),
]),
};
let out = pyjson::dumps(&body);
match CString::new(out) {
Ok(c) => c.into_raw(),
Err(_) => CString::new(
r#"{"ok":false,"err":"nul in output","type":"RuntimeError"}"#,
)
.unwrap()
.into_raw(),
}
}
fn parse_doc(raw: &str) -> Result<Json, (String, String)> {
pyjson::parse(raw).map_err(|e| (e, "ValueError".to_string()))
}
fn read_arg(ptr: *const c_char) -> Result<String, (String, String)> {
if ptr.is_null() {
return Ok(String::new());
}
unsafe { CStr::from_ptr(ptr) }
.to_str()
.map(|s| s.to_string())
.map_err(|e| (e.to_string(), "ValueError".to_string()))
}
fn now_of(doc: &Json) -> Result<Option<f64>, (String, String)> {
match doc.get("now") {
None | Some(Json::Null) => Ok(None),
Some(v) => f64_of(Some(v))
.map(Some)
.ok_or_else(|| ("now must be a number or null".into(), "TypeError".into())),
}
}
fn state_of(doc: &Json) -> Result<&Json, (String, String)> {
match doc.get("state") {
Some(st @ Json::Obj(_)) => Ok(st),
_ => Err(("state must be an object".into(), "TypeError".into())),
}
}
macro_rules! ffi {
($name:ident, $body:expr) => {
#[no_mangle]
pub extern "C" fn $name(arg: *const c_char) -> *mut c_char {
let out: Result<Json, (String, String)> =
read_arg(arg).and_then(|raw| $body(&raw));
envelope(out)
}
};
}
ffi!(me_should_fire, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let trigger = match doc.get("trigger") {
Some(Json::Str(t)) => t.clone(),
_ => return Err(("trigger must be a string".into(), "TypeError".into())),
};
let state = state_of(&doc)?.clone();
let now = now_of(&doc)?;
Ok(should_fire(&trigger, &state, now))
});
ffi!(me_fire_due, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let state = state_of(&doc)?.clone();
let now = now_of(&doc)?;
Ok(fire_due(&state, now))
});
ffi!(me_mark_fired, |raw: &str| -> Result<Json, (String, String)> {
let doc = parse_doc(raw)?;
let state = state_of(&doc)?.clone();
let trigger = match doc.get("trigger") {
Some(Json::Str(t)) => t.clone(),
_ => return Err(("trigger must be a string".into(), "TypeError".into())),
};
let now = now_of(&doc)?;
Ok(mark_fired(&state, &trigger, now))
});
#[cfg(test)]
mod branch_battery;
+14
View File
@@ -0,0 +1,14 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "capability_scoring"
version = "0.1.0"
[[package]]
name = "self_model"
version = "0.1.0"
dependencies = [
"capability_scoring",
]
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "self_model"
version = "0.1.0"
edition = "2021"
description = "Bounded persistent self-model — dichotomy wave #2479 tranche; token estimate + greedy budgeted compile + why-retrieval in Rust; zero-dep (pyjson via capability_scoring)"
[lib]
name = "self_model"
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
capability_scoring = { path = "../capability_scoring" }
+626
View File
@@ -0,0 +1,626 @@
{
"module": "self_model",
"core_env": "RUNE_SMM_CORE=python",
"cases": [
{
"fn": "estimate_tokens",
"args": {
"text": ""
},
"expected": 1
},
{
"fn": "estimate_tokens",
"args": {
"text": "ab"
},
"expected": 1
},
{
"fn": "estimate_tokens",
"args": {
"text": "abcd"
},
"expected": 1
},
{
"fn": "estimate_tokens",
"args": {
"text": "abcde"
},
"expected": 1
},
{
"fn": "estimate_tokens",
"args": {
"text": "aaaaaaaa"
},
"expected": 2
},
{
"fn": "estimate_tokens",
"args": {
"text": "aaaaaaaaa"
},
"expected": 2
},
{
"fn": "estimate_tokens",
"args": {
"text": "aaaaaaaaaaaa"
},
"expected": 3
},
{
"fn": "estimate_tokens",
"args": {
"text": "hello \u2014 em-dash unicode"
},
"expected": 5
},
{
"fn": "estimate_tokens",
"args": {
"text": "line one\nline two\nline three"
},
"expected": 7
},
{
"fn": "compile_self_model",
"args": {
"corpus": []
},
"expected": {
"statements": [],
"budget_tokens": 220,
"used_tokens": 0,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "I speak plainly and show my work.",
"source": "persona.md",
"weight": 0.9
}
]
},
"expected": {
"statements": [
{
"text": "I speak plainly and show my work.",
"source": "persona.md",
"weight": 0.9
}
],
"budget_tokens": 220,
"used_tokens": 8,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "aaaaaaaaaaaaaaaa",
"source": "s1",
"weight": 2.0
},
{
"text": "bbbbbbbbbbbbbbbb",
"source": "s2",
"weight": 1.5
},
{
"text": "c",
"source": "s3",
"weight": 1.0
}
],
"budget_tokens": 8
},
"expected": {
"statements": [
{
"text": "aaaaaaaaaaaaaaaa",
"source": "s1",
"weight": 2.0
},
{
"text": "bbbbbbbbbbbbbbbb",
"source": "s2",
"weight": 1.5
}
],
"budget_tokens": 8,
"used_tokens": 8,
"evidence_ref": [
{
"text": "c",
"source": "s3"
}
]
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "no weight no source"
},
{
"source": "only-source"
},
{
"weight": 0.1
}
]
},
"expected": {
"statements": [
{
"text": "no weight no source",
"source": "",
"weight": 0.5
},
{
"text": "",
"source": "only-source",
"weight": 0.5
},
{
"text": "",
"source": "",
"weight": 0.1
}
],
"budget_tokens": 220,
"used_tokens": 6,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "first",
"source": "a",
"weight": 1.0
},
{
"text": "second",
"source": "b",
"weight": 1.0
},
{
"text": "third",
"source": "c",
"weight": 1.0
}
],
"budget_tokens": 3
},
"expected": {
"statements": [
{
"text": "first",
"source": "a",
"weight": 1.0
},
{
"text": "second",
"source": "b",
"weight": 1.0
},
{
"text": "third",
"source": "c",
"weight": 1.0
}
],
"budget_tokens": 3,
"used_tokens": 3,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"source": "big",
"weight": 9.9
}
],
"budget_tokens": 0
},
"expected": {
"statements": [],
"budget_tokens": 0,
"used_tokens": 0,
"evidence_ref": [
{
"text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"source": "big"
}
]
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"source": "big",
"weight": 9.9
}
],
"budget_tokens": -3
},
"expected": {
"statements": [],
"budget_tokens": -3,
"used_tokens": 0,
"evidence_ref": [
{
"text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"source": "big"
}
]
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "quarter weight",
"source": "q",
"weight": 0.25
},
{
"text": "three-quarter weight",
"source": "t",
"weight": 0.75
}
],
"budget_tokens": 50
},
"expected": {
"statements": [
{
"text": "three-quarter weight",
"source": "t",
"weight": 0.75
},
{
"text": "quarter weight",
"source": "q",
"weight": 0.25
}
],
"budget_tokens": 50,
"used_tokens": 8,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"source": "big1",
"weight": 3.0
},
{
"text": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"source": "big2",
"weight": 2.0
},
{
"text": "zzzz",
"source": "over",
"weight": 1.0
}
]
},
"expected": {
"statements": [
{
"text": "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"source": "big1",
"weight": 3.0
},
{
"text": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"source": "big2",
"weight": 2.0
},
{
"text": "zzzz",
"source": "over",
"weight": 1.0
}
],
"budget_tokens": 220,
"used_tokens": 220,
"evidence_ref": []
}
},
{
"fn": "compile_self_model",
"args": {
"corpus": [
{
"text": "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv",
"source": "huge",
"weight": 5.0
},
{
"text": "tiny",
"source": "t",
"weight": 0.4
}
],
"budget_tokens": 10
},
"expected": {
"statements": [
{
"text": "tiny",
"source": "t",
"weight": 0.4
}
],
"budget_tokens": 10,
"used_tokens": 1,
"evidence_ref": [
{
"text": "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv",
"source": "huge"
}
]
}
},
{
"fn": "why_question",
"args": {
"model": {
"statements": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
}
],
"budget_tokens": 10,
"used_tokens": 7,
"evidence_ref": [
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
"topic": "evidence"
},
"expected": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
{
"fn": "why_question",
"args": {
"model": {
"statements": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
}
],
"budget_tokens": 10,
"used_tokens": 7,
"evidence_ref": [
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
"topic": "EVIDENCE"
},
"expected": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
{
"fn": "why_question",
"args": {
"model": {
"statements": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
}
],
"budget_tokens": 10,
"used_tokens": 7,
"evidence_ref": [
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
"topic": "growth"
},
"expected": [
{
"text": "Growth is measured, not asserted.",
"source": "s3"
}
]
},
{
"fn": "why_question",
"args": {
"model": {
"statements": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
}
],
"budget_tokens": 10,
"used_tokens": 7,
"evidence_ref": [
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
"topic": "absent-topic"
},
"expected": []
},
{
"fn": "why_question",
"args": {
"model": {
"statements": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
}
],
"budget_tokens": 10,
"used_tokens": 7,
"evidence_ref": [
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
"topic": ""
},
"expected": [
{
"text": "I prefer evidence over vibes.",
"source": "s1",
"weight": 2.0
},
{
"text": "CONTRADICTIONS get surfaced loudly.",
"source": "s2"
},
{
"text": "Growth is measured, not asserted.",
"source": "s3"
},
{
"text": "quiet evidence overflow note",
"source": "s4"
}
]
},
{
"fn": "why_question",
"args": {
"model": {},
"topic": "anything"
},
"expected": []
},
{
"fn": "why_question",
"args": {
"model": {
"evidence_ref": [
{
"text": "overflowed raw note",
"source": "raw"
}
]
},
"topic": "raw"
},
"expected": [
{
"text": "overflowed raw note",
"source": "raw"
}
]
}
]
}
+83
View File
@@ -0,0 +1,83 @@
//! branch_battery — replays frozen_sm_truth.json VERBATIM (the live
//! Python oracle, frozen with RUNE_SMM_CORE=python pinned and inputs
//! deep-copied). Every case must reproduce byte-identically through the
//! Rust kernel.
use super::{pyjson, compile_self_model, estimate_tokens, why_question, Json};
const TRUTH: &str = include_str!("../frozen_sm_truth.json");
fn as_i64(v: Option<&Json>, default: i64) -> i64 {
match v {
Some(Json::Num(n)) => *n as i64,
_ => default,
}
}
#[test]
fn frozen_truth_replays_verbatim() {
let doc = pyjson::parse(TRUTH).expect("frozen_sm_truth.json parses");
let cases = match doc.get("cases") {
Some(Json::Arr(a)) => a,
_ => panic!("truth has no cases array"),
};
assert!(!cases.is_empty(), "truth is empty");
for (i, case) in cases.iter().enumerate() {
let fname = match case.get("fn") {
Some(Json::Str(s)) => s.as_str(),
_ => panic!("case {i}: missing fn"),
};
let args = case.get("args").cloned().unwrap_or(Json::Obj(vec![]));
let expected = case.get("expected").cloned().unwrap_or(Json::Null);
let got: Json = match fname {
"estimate_tokens" => {
let text = match args.get("text") {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
};
Json::Num(estimate_tokens(&text) as f64)
}
"compile_self_model" => {
let corpus: Vec<Json> = match args.get("corpus") {
Some(Json::Arr(xs)) => xs.clone(),
_ => vec![],
};
let budget = as_i64(args.get("budget_tokens"), 220);
compile_self_model(&corpus, budget)
}
"why_question" => {
let model = args.get("model").cloned().unwrap_or(Json::Obj(vec![]));
let topic = match args.get("topic") {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
};
why_question(&model, &topic)
}
other => panic!("case {i}: unknown fn {other}"),
};
let (gs, es) = (pyjson::dumps(&got), pyjson::dumps(&expected));
assert_eq!(
gs,
es,
"case {i} ({fname}) diverged:\n got: {gs}\n want: {es}"
);
}
}
#[test]
fn truth_covers_every_public_fn() {
let doc = pyjson::parse(TRUTH).expect("truth parses");
let cases = match doc.get("cases") {
Some(Json::Arr(a)) => a,
_ => panic!("truth has no cases array"),
};
let mut seen = std::collections::BTreeSet::new();
for c in cases {
if let Some(Json::Str(s)) = c.get("fn") {
seen.insert(s.clone());
}
}
for f in ["estimate_tokens", "compile_self_model", "why_question"] {
assert!(seen.contains(f), "truth missing coverage for {f}");
}
}
+210
View File
@@ -0,0 +1,210 @@
//! self_model — the bounded persistent self-model (dichotomy wave #2479
//! tranche). RUST verdict per classification: the pure kernel (token
//! estimate, greedy budgeted compile, why-retrieval) lives here.
//!
//! Oracle: src/rune/self_model.py (the facade keeps the Python floor,
//! RUNE_SMM_CORE=python pin).
//!
//! Semantics mirrored exactly:
//! * estimate_tokens(text) = max(1, char_len(text) / 4)
//! (Python `len` is CHARS, not bytes — non-ASCII truth is frozen).
//! * compile_self_model(corpus, budget_tokens=220): stable sort by
//! -weight (missing weight -> 0.5; Python `sorted` is stable, so
//! equal weights keep corpus order), then greedy fill:
//! used + tok <= budget -> statements [{text, source, weight}]
//! (missing source -> "", missing text -> ""), else evidence
//! [{text, source}]. Result key order:
//! {statements, budget_tokens, used_tokens, evidence_ref}.
//! * why_question(model, topic): statements THEN evidence_ref, keep
//! entries whose text contains topic case-insensitively; returns
//! the bare list (the oracle's return shape).
//!
//! FFI contract (doc-envelope law — every call returns {"ok","value"|"err"}):
//! * smm_estimate_tokens({"text"}) -> token count (number)
//! * smm_compile_self_model({"corpus", "budget_tokens"?}) -> model dict
//! * smm_why_question({"model", "topic"}) -> matches list
//!
//! Number boundary: pyjson numbers are f64 — the parity surface treats
//! weights as floats (Python int weights would lose their int-ness across
//! FFI; the frozen truth and fuzz corpora use floats only).
//!
//! Parity oracle: frozen_sm_truth.json (frozen from the live Python oracle
//! with RUNE_SMM_CORE=python pinned, inputs deep-copied).
pub use capability_scoring::pyjson;
#[cfg(test)]
#[path = "branch_battery.rs"]
mod branch_battery;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use pyjson::Json;
pub fn estimate_tokens(text: &str) -> i64 {
// Phase B (language advantage): ASCII input takes the O(1) byte
// length instead of a char-count walk; Python's len() is always a
// char walk. Non-ASCII keeps the exact char semantics.
let n = if text.is_ascii() {
text.len() as i64
} else {
text.chars().count() as i64
};
let tok = n / 4;
if tok < 1 {
1
} else {
tok
}
}
fn get_str(v: &Json, key: &str) -> String {
match v.get(key) {
Some(Json::Str(s)) => s.clone(),
_ => String::new(),
}
}
fn get_num(v: &Json, key: &str, default: f64) -> f64 {
match v.get(key) {
Some(Json::Num(n)) => *n,
_ => default,
}
}
fn two_field(text: &str, source: &str) -> Json {
Json::Obj(vec![
("text".into(), Json::Str(text.into())),
("source".into(), Json::Str(source.into())),
])
}
pub fn compile_self_model(corpus: &[Json], budget_tokens: i64) -> Json {
// stable sort by -weight, missing weight -> 0.5
let mut ranked: Vec<&Json> = corpus.iter().collect();
ranked.sort_by(|a, b| {
let wa = get_num(a, "weight", 0.5);
let wb = get_num(b, "weight", 0.5);
wb.partial_cmp(&wa).unwrap_or(std::cmp::Ordering::Equal)
});
let mut statements: Vec<Json> = Vec::with_capacity(ranked.len());
let mut evidence: Vec<Json> = Vec::with_capacity(ranked.len());
let mut used: i64 = 0;
for c in ranked {
let text = get_str(c, "text");
let source = get_str(c, "source");
let tok = estimate_tokens(&text);
if used + tok <= budget_tokens {
statements.push(Json::Obj(vec![
("text".into(), Json::Str(text)),
("source".into(), Json::Str(source)),
("weight".into(), Json::Num(get_num(c, "weight", 0.5))),
]));
used += tok;
} else {
evidence.push(two_field(&text, &source));
}
}
Json::Obj(vec![
("statements".into(), Json::Arr(statements)),
("budget_tokens".into(), Json::Num(budget_tokens as f64)),
("used_tokens".into(), Json::Num(used as f64)),
("evidence_ref".into(), Json::Arr(evidence)),
])
}
pub fn why_question(model: &Json, topic: &str) -> Json {
let mut matches: Vec<Json> = Vec::new();
for key in ["statements", "evidence_ref"] {
if let Some(Json::Arr(entries)) = model.get(key) {
for s in entries {
let text = get_str(s, "text");
if contains_ci(&text, topic) {
matches.push(s.clone());
}
}
}
}
Json::Arr(matches)
}
/// Case-insensitive substring test mirroring Python's
/// `topic.lower() in text.lower()` for the ASCII surface; non-ASCII
/// falls back to full Unicode lowercasing of both sides.
fn contains_ci(text: &str, topic: &str) -> bool {
if topic.is_empty() {
return true;
}
if text.is_ascii() && topic.is_ascii() {
let hay = text.as_bytes();
let needle = topic.as_bytes();
return hay.len() >= needle.len()
&& hay
.windows(needle.len())
.any(|w| w.eq_ignore_ascii_case(needle));
}
text.to_lowercase().contains(&topic.to_lowercase())
}
fn envelope(r: Result<Json, String>) -> *mut c_char {
let v = match r {
Ok(x) => Json::Obj(vec![
("ok".into(), Json::Bool(true)),
("value".into(), x),
]),
Err(e) => Json::Obj(vec![
("ok".into(), Json::Bool(false)),
("err".into(), Json::Str(e)),
]),
};
CString::new(pyjson::dumps(&v))
.map(|c| c.into_raw())
.unwrap_or(std::ptr::null_mut())
}
fn read_arg(arg: *const c_char) -> Result<Json, String> {
if arg.is_null() {
return Err("null arg".into());
}
let raw = unsafe { CStr::from_ptr(arg) }.to_bytes();
pyjson::parse(std::str::from_utf8(raw).map_err(|e| e.to_string())?)
}
#[no_mangle]
pub extern "C" fn smm_estimate_tokens(arg: *const c_char) -> *mut c_char {
let out = read_arg(arg).map(|a| {
let text = get_str(&a, "text");
Json::Num(estimate_tokens(&text) as f64)
});
envelope(out)
}
#[no_mangle]
pub extern "C" fn smm_compile_self_model(arg: *const c_char) -> *mut c_char {
let out = read_arg(arg).map(|a| {
let corpus: Vec<Json> = match a.get("corpus") {
Some(Json::Arr(xs)) => xs.clone(),
_ => vec![],
};
let budget = match a.get("budget_tokens") {
Some(Json::Num(n)) => *n as i64,
_ => 220,
};
compile_self_model(&corpus, budget)
});
envelope(out)
}
#[no_mangle]
pub extern "C" fn smm_why_question(arg: *const c_char) -> *mut c_char {
let out = read_arg(arg).map(|a| {
let model = a.get("model").cloned().unwrap_or(Json::Obj(vec![]));
let topic = get_str(&a, "topic");
why_question(&model, &topic)
});
envelope(out)
}
// Free is owned by capability_scoring's cs_free_string (shared process)
// — no free re-export here, mirroring the broker_loader contract.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T00:46:01Z-28644a-factory-batch-g
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Complete the meaningful_events dichotomy port to FULL Rust (#2479 tranche): the eight-trigger table (ordered) + should_fire law (unknown/stop/absent/rate-limited with Python int() truncation, exact reason strings) + fire_due ordering + mark_fired copy semantics as doc-envelope FFI (me_* symbols, free via capability_scoring cs_free_string — no free re-export); me_loader mirroring broker_loader.py; facade owns the wall clock (now passed per op), RUNE_ME_CORE=python pin; frozen-oracle battery (every trigger class, all branches incl. truncation cases); live parity 100%; Phase B language-advantage pass (const trigger table of typed records).
## 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-13T06:30:53Z", "contract": "BUILDER-2026-10-13T00:46:01Z-28644a-factory-batch-g", "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_meaningful_events_parity.py", "scripts/gen_meaningful_events_truth.py", "src/rune/me_loader.py", "src/rune/meaningful_events.py", "src/rust/meaningful_events/src/branch_battery.rs", "src/rust/meaningful_events/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-g
- builder:factory-batch-g
- builder:factory-batch-g
- closure-record
@@ -1,4 +1,4 @@
# Contract BUILDER-2026-10-13T05:56:22Z-3258b3-factory-gap-faf
# Contract BUILDER-2026-10-13T06:30:42Z-b381e6-factory-gap-faf
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
@@ -14,7 +14,7 @@ Close the failure_auto_filer dichotomy gap (#2479 tranche): the Go port is PARTI
- 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-13T06:05:01Z", "contract": "BUILDER-2026-10-13T05:56:22Z-3258b3-factory-gap-faf", "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_failure_auto_filer.py", "scripts/gen_failure_auto_filer_truth.py", "scripts/walk_contract_failure_auto_filer.py", "src/go/failure-filer/battery_test.go", "src/go/failure-filer/filer.go", "src/go/failure-filer/frozen_failure_auto_filer_truth.json", "src/go/failure-filer/frozen_filer_scenarios.json", "src/go/failure-filer/main.go", "src/go/failure-filer/scenario_test.go", "src/go/failure-filer/spool.go", "src/rune/failure_auto_filer.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T06:34:10Z", "contract": "BUILDER-2026-10-13T06:30:42Z-b381e6-factory-gap-faf", "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_failure_auto_filer.py", "scripts/gen_failure_auto_filer_truth.py", "scripts/walk_contract_failure_auto_filer.py", "src/go/failure-filer/battery_test.go", "src/go/failure-filer/filer.go", "src/go/failure-filer/frozen_failure_auto_filer_truth.json", "src/go/failure-filer/frozen_filer_scenarios.json", "src/go/failure-filer/main.go", "src/go/failure-filer/scenario_test.go", "src/go/failure-filer/spool.go", "src/rune/failure_auto_filer.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T06:41:01Z-4e8a36-factory-batch-f
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Port src/rune/inference_paths.py to Go (dichotomy factory, issue #2479 tranche): ledger verdict GO (I/O-bound trace journaling + simple census counting), name-preserving funcs in src/go/inference-paths, frozen-truth battery embedded verbatim, live parity 100%, Phase B language-advantage pass.
## What it connects to
(no affected surface recorded)
## How to update those connections
- Open a NEW construction contract (scaffolding is absolute) scoped to the same surface.
- Evidence trail: 4 checkpoint(s) recorded on the contract entity.
- Quality at close: {"candidate_corrections": [], "captured_at": "2026-10-13T06:42:37Z", "contract": "BUILDER-2026-10-13T06:41:01Z-4e8a36-factory-batch-f", "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/gen_inference_paths_truth.py", "src/go/inference-paths/go.mod", "src/go/inference-paths/main.go", "src/go/inference-paths/truth.json", "src/go/inference-paths/truth_test.go", "src/rune/inference_paths.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- gitea/master 251fa36d
- gitea/master 251fa36d
- gitea/master 251fa36d
- closure-record
+93
View File
@@ -0,0 +1,93 @@
"""Tests: meaningful_events.py Rust core port (dichotomy wave, #2479).
Frozen-truth battery: the 96 frozen-oracle cases replayed VERBATIM
through the facade in BOTH core modes (RUNE_ME_CORE=python floor vs the
Rust kernel), plus loader pin discipline, the fire→mark→quiet loop and
input-copy semantics.
"""
from __future__ import annotations
import copy
import json
import os
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT / "src" / "rune"))
import meaningful_events as me # noqa: E402
from rune import me_loader # noqa: E402
TRUTH = json.loads(
(ROOT / "src" / "rust" / "meaningful_events" / "frozen_truth.json")
.read_text())
@pytest.fixture()
def core_built():
if not me_loader.available():
pytest.skip("rust meaningful_events core not built")
return True
def drive(mode, fn, *args):
os.environ["RUNE_ME_CORE"] = mode
try:
return fn(*copy.deepcopy(args))
finally:
os.environ["RUNE_ME_CORE"] = "auto"
def test_loader_probe_and_pin(core_built, monkeypatch):
monkeypatch.delenv("RUNE_ME_CORE", raising=False)
assert me_loader.available()
assert me._kernel() is not None
monkeypatch.setenv("RUNE_ME_CORE", "python")
assert me._kernel() is None
def test_frozen_should_fire_both_ways(core_built):
for c in TRUTH["should_fire_cases"]:
args = (c["args"]["trigger"], c["args"]["state"], c["args"]["now"])
py = drive("python", me.should_fire, *args)
rs = drive("auto", me.should_fire, *args)
assert py == rs == c["expect"], c["name"]
def test_frozen_fire_due_both_ways(core_built):
for c in TRUTH["fire_due_cases"]:
args = (c["args"]["state"], c["args"]["now"])
py = drive("python", me.fire_due, *args)
rs = drive("auto", me.fire_due, *args)
assert py == rs == c["expect"], c["name"]
def test_frozen_mark_fired_both_ways(core_built):
for c in TRUTH["mark_fired_cases"]:
args = (c["args"]["state"], c["args"]["trigger"], c["args"]["now"])
py = drive("python", me.mark_fired, *args)
rs = drive("auto", me.mark_fired, *args)
assert py == rs == c["expect"], c["name"]
assert c["input_unchanged"] is True, c["name"]
def test_fire_mark_due_loop_both_ways(core_built):
for mode in ("python", "auto"):
state = {"task_blocked": True}
due = drive(mode, me.fire_due, state, 1000.0)
assert "task_blockers" in due
state = drive(mode, me.mark_fired, state, "task_blockers", 1000.0)
assert drive(mode, me.fire_due, state, 1000.0) == []
def test_rate_limit_string_law(core_built):
# int() truncation surfaces IN the reason string — verbatim law
r = drive("auto", me.should_fire, "task_blockers",
{"task_blocked": True, "last_fired_task_blockers": 400.5},
1000.0)
assert r == {"fires": False, "reason": "rate-limited (0s left)"}