Compare commits

...
50 Commits
Author SHA1 Message Date
conductor da481e744d chore(release): auto-bump version to 0.271.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 53s
deploy / deploy (push) Skipped
CI Pipeline / lint (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 0s
CI Pipeline / go-surface (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 0s
CI Pipeline / best-practices (push) Canceled after 0s
CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Promotion record: (unknown)
2026-10-13 10:26:35 +01:00
Nick c66d4babbe refactor(structural_store): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / rust-surface (push) Failing after 13s
CI Pipeline / go-surface (push) Failing after 15s
CI Pipeline / gitea-offline (push) Successful in 20s
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 32s
CI Pipeline / canary (push) Canceled after 41s
Auto-version and Release / release (push) Canceled after 48s
deploy / deploy (push) Canceled after 26s
CI Pipeline / lint (push) Canceled after 45s
CI Pipeline / unit-tests (push) Canceled after 45s
Bundle the oracle's add_relationship keyword arguments into RelSpec: the
7-argument positional form was the last clippy-suppressed wart and the only
call shape that diverged from the oracle's keyword call sites. Behavior
unchanged — parity re-verified 4387/4387, Rust battery 32/32, clippy clean.
2026-10-13 10:25:49 +01:00
Nick 201530bfc4 feat(structural_store): close PARTIAL gaps — dichotomy wave
Port the 21 audit-missing functions name-preserving to the existing Rust
crate (gap.rs: _ss_core probe, _sorted, new_doc, _redact_secrets+_is_secret_key,
save, canonical_digest, snapshot, alias, spine_uri, resolve_uri,
_doc_authorities, authority_health, bind_task, task_entities, impact_frontier,
record_observed_impact, predicted_vs_observed, structural_events, diff,
dedupe_observations), 19 doc-envelope FFI ss_* entry points, ctypes loader
mirroring broker_loader.py, facade delegation with RUNE_STRUCTURAL_CORE=python
pin. Fix-first: promote ordering (unknown-id silent), alias-aware entity
resolution, resolve_status verbatim-status + pythonic conflicts, supersede
add_relationship law, authority_failed observation, SCHEMA_VERSION 1.

Frozen truth: 86 cases generated against the live oracle (pinned clock,
deep-copied inputs), embedded verbatim in cfg(test) battery. Live parity
100%: 4387 checks, 0 failures (frozen 86 + fuzz 4300 + live 1).

Contract BUILDER-2026-10-13T00:32:22Z-bc3aae-factory-gap-ss.
2026-10-13 10:25:49 +01:00
Nick 57fc6a61cf chore(factory): claims — context_broker verified (6/0, 76-row truth); audit regenerated
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 14s
CI Pipeline / go-surface (push) Failing after 16s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 1m1s
CI Pipeline / type-check (push) Failing after 49s
CI Pipeline / canary (push) Failing after 1m13s
CI Pipeline / lint (push) Failing after 1m26s
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 2m26s
deploy / deploy (push) Canceled after 2m11s
2026-10-13 10:23:28 +01:00
conductor 4ed47a7332 chore(release): auto-bump version to 0.270.0 — earned by # (minor: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / rust-surface (push) Failing after 14s
CI Pipeline / go-surface (push) Failing after 17s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 54s
CI Pipeline / type-check (push) Failing after 42s
CI Pipeline / canary (push) Failing after 1m9s
CI Pipeline / lint (push) Failing after 1m22s
CI Pipeline / unit-tests (push) Failing after 6m25s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 4s
Promotion record: (unknown)
2026-10-13 10:08:13 +01:00
Nick 63304b0984 refactor(context_broker): Phase B language-advantage pass — dichotomy wave
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 4s
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
Auto-version and Release / release (push) Canceled after 1m0s
CI Pipeline / lint (push) Canceled after 51s
CI Pipeline / canary (push) Canceled after 50s
deploy / deploy (push) Canceled after 1m6s
CI Pipeline / unit-tests (push) Canceled after 56s
2026-10-13 10:04:39 +01:00
Nick 8119914fc3 feat(context_broker): close PARTIAL gaps — dichotomy wave 2026-10-13 10:04:39 +01:00
Nick a829834f8d chore(factory): claims — build_mode verified (6/0, was BLOCKED); 6 gap-closers spawned (hook_engine, elastic_cognition, contracts, adaptive_router, memory_selector, construction_pattern); audit regenerated
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 10s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / type-check (push) Failing after 46s
Auto-version and Release / release (push) Successful in 1m2s
CI Pipeline / canary (push) Failing after 1m20s
CI Pipeline / lint (push) Failing after 1m32s
CI Pipeline / unit-tests (push) Failing after 6m36s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 6m25s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 4s
2026-10-13 09:42:58 +01:00
Nick eda992ade8 chore(provider_budget): close gap-closing contract tooling
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 4s
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 / lint (push) Canceled after 46s
CI Pipeline / unit-tests (push) Canceled after 46s
CI Pipeline / canary (push) Canceled after 47s
CI Pipeline / type-check (push) Canceled after 26s
Auto-version and Release / release (push) Canceled after 55s
deploy / deploy (push) Canceled after 56s
2026-10-13 09:42:07 +01:00
conductor facbb52b7e chore(release): auto-bump version to 0.269.1 — earned by # (patch: converged release (push-to-master bump))
deploy / deploy (push) Skipped
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / rust-surface (push) Failing after 15s
CI Pipeline / go-surface (push) Failing after 16s
CI Pipeline / gitea-offline (push) Successful in 15s
Auto-version and Release / release (push) Successful in 53s
CI Pipeline / type-check (push) Failing after 48s
CI Pipeline / lint (push) Failing after 1m23s
CI Pipeline / canary (push) Failing after 2m15s
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 12m25s
Promotion record: (unknown)
2026-10-13 09:29:37 +01:00
Nick f4f099bcde fix(build_mode): move DispatchGap + typed accessors into production code — dichotomy wave
CI Pipeline / rust-surface (push) Failing after 15s
CI Pipeline / go-surface (push) Failing after 17s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 3s
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 / canary (push) Canceled after 51s
Auto-version and Release / release (push) Canceled after 58s
CI Pipeline / type-check (push) Canceled after 36s
CI Pipeline / lint (push) Canceled after 55s
CI Pipeline / unit-tests (push) Canceled after 55s
deploy / deploy (push) Canceled after 1m5s
Phase B's ReplayPipeline (phaseb.go) called dispatchGap/mustJSON and the
argMap/strList/objList accessors that lived in a _test.go file: go test
passed but go build broke. Promoted to exported production helpers in
phaseb.go (DispatchGap/MustJSON/ArgMap/StrList/ObjList); the test file
keeps a thin dispatchGap wrapper for the _save_state TempDir case.
go build + vet + test + -race all green.
2026-10-13 09:28:35 +01:00
Nick 7fd1df00be chore(store): close build_mode dichotomy contract BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm (feat 3612786d, phase B 05fab134) 2026-10-13 09:28:35 +01:00
Nick 12cca6e682 chore(factory): claims — night_mode verified (6/0, 9-row bare frozen_truth.json); verify script gains bare frozen_truth.json name variant
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 9s
CI Pipeline / rust-surface (push) Failing after 16s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 18s
Auto-version and Release / release (push) Successful in 51s
CI Pipeline / type-check (push) Failing after 50s
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 1m11s
CI Pipeline / lint (push) Canceled after 1m11s
deploy / deploy (push) Canceled after 56s
CI Pipeline / canary (push) Canceled after 1m16s
2026-10-13 09:27:24 +01:00
Nick d00f07d3ea chore(store): close night_mode dichotomy contract BUILDER-2026-10-13T03:16:06Z-57d4cc-factory-gap-nm (parity 150f5b86, phase B 709c2ca4)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 5s
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 58s
CI Pipeline / type-check (push) Failing after 52s
CI Pipeline / lint (push) Failing after 1m29s
CI Pipeline / canary (push) Failing after 2m24s
deploy / deploy (push) Failing after 16m13s
CI Pipeline / unit-tests (push) Failing after 17m52s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 6s
2026-10-13 09:05:10 +01:00
conductor 92761be44b chore(release): auto-bump version to 0.269.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 17s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / gitea-offline (push) Successful in 18s
Auto-version and Release / release (push) Successful in 58s
CI Pipeline / type-check (push) Failing after 46s
CI Pipeline / lint (push) Failing after 1m26s
CI Pipeline / canary (push) Failing after 2m23s
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 10m31s
Promotion record: (unknown)
2026-10-13 08:54:35 +01:00
Nick 709c2ca4e5 refactor(night_mode): Phase B language-advantage pass — dichotomy wave
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 17s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 59s
Auto-version and Release / release (push) Canceled after 1m2s
CI Pipeline / type-check (push) Canceled after 47s
CI Pipeline / canary (push) Canceled after 1m3s
CI Pipeline / lint (push) Canceled after 1m5s
CI Pipeline / unit-tests (push) Canceled after 1m6s
2026-10-13 08:52:35 +01:00
Nick 150f5b86cb feat(night_mode): close PARTIAL gaps — dichotomy wave 2026-10-13 08:45:36 +01:00
Nick 527dc7749e refactor(provider_budget): Phase B language-advantage pass — dichotomy wave
CI Pipeline / rust-surface (push) Failing after 36s
CI Pipeline / go-surface (push) Failing after 44s
CI Pipeline / best-practices (push) Successful in 19s
CI Pipeline / documentation (push) Successful in 14s
CI Pipeline / gitea-offline (push) Successful in 28s
Auto-version and Release / release (push) Successful in 2m17s
CI Pipeline / lint (push) Failing after 3m12s
CI Pipeline / type-check (push) Failing after 2m28s
CI Pipeline / canary (push) Failing after 4m40s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 9m51s
CI Pipeline / unit-tests (push) Canceled after 9m51s
2026-10-13 08:43:36 +01:00
Nick 61e6d8fbd0 chore(factory): claims — 5 verified landings (inference_paths, meaningful_events, self_model, work_manager commit-1, provider_budget); build_mode marked BLOCKED (undefined dispatchGap/mustJSON in phaseb.go); audit regenerated
CI Pipeline / documentation (push) Successful in 31s
CI Pipeline / best-practices (push) Successful in 32s
CI Pipeline / rust-surface (push) Failing after 32s
CI Pipeline / go-surface (push) Failing after 37s
CI Pipeline / gitea-offline (push) Successful in 45s
Auto-version and Release / release (push) Successful in 2m3s
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 3m1s
CI Pipeline / type-check (push) Canceled after 2m34s
deploy / deploy (push) Canceled after 2m32s
CI Pipeline / lint (push) Canceled after 3m8s
CI Pipeline / canary (push) Canceled after 3m7s
2026-10-13 08:40:26 +01:00
Nick 1f0e61d460 chore(store): merge concurrent batch state (post-dedupe round)
Auto-version and Release / release (push) Successful in 39s
CI Pipeline / best-practices (push) Successful in 1m0s
CI Pipeline / documentation (push) Successful in 30s
CI Pipeline / rust-surface (push) Failing after 1m8s
CI Pipeline / go-surface (push) Failing after 1m11s
CI Pipeline / gitea-offline (push) Successful in 34s
CI Pipeline / type-check (push) Failing after 1m10s
CI Pipeline / lint (push) Failing after 2m22s
CI Pipeline / canary (push) Failing after 3m20s
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 13m9s
deploy / deploy (push) Canceled after 13m9s
# Conflicts:
#	store/scaffold/current.json
2026-10-13 08:27:16 +01:00
Nick 8d435ce7e4 chore(store): dedupe stale duplicate contract record (28644a-factory-batch-g verifying copy superseded by closed copy) 2026-10-13 08:23:47 +01:00
Nick c6148532d7 chore(store): close self_model dichotomy contract BUILDER-2026-10-13T00:23:43Z-53857a-factory-batch-i (parity dac4889c, phase B 99bde7ba)
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / go-surface (push) Failing after 25s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / gitea-offline (push) Successful in 17s
Auto-version and Release / release (push) Successful in 1m0s
CI Pipeline / type-check (push) Failing after 50s
CI Pipeline / lint (push) Failing after 1m26s
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 4m0s
CI Pipeline / unit-tests (push) Canceled after 4m1s
2026-10-13 08:23:19 +01:00
conductor 61d20af76d chore(release): auto-bump version to 0.268.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 4s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / gitea-offline (push) Successful in 15s
Auto-version and Release / release (push) Successful in 56s
CI Pipeline / type-check (push) Failing after 50s
CI Pipeline / lint (push) Failing after 1m19s
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
CI Pipeline / unit-tests (push) Canceled after 17m35s
Promotion record: (unknown)
2026-10-13 08:05:41 +01:00
Nick 8a08f9b4be feat(provider_budget): close PARTIAL gaps — dichotomy wave
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / rust-surface (push) Failing after 17s
CI Pipeline / go-surface (push) Failing after 20s
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 / type-check (push) Canceled after 29s
deploy / deploy (push) Canceled after 47s
Auto-version and Release / release (push) Canceled after 50s
CI Pipeline / lint (push) Canceled after 45s
CI Pipeline / unit-tests (push) Canceled after 45s
CI Pipeline / canary (push) Canceled after 46s
2026-10-13 08:04:24 +01:00
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
92 changed files with 75991 additions and 287 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.262.0**
**Current release: v0.271.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.**
+19 -19
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: 28%** (54/192 runtime modules at FULL)
Function-level detail: 48% (1132/2373 runtime functions matched) — secondary; includes in-flight work
Function-level detail: 54% (1290/2376 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 | 54 | 21059 | 80%+ of functions ported |
| PARTIAL | 94 | 40967 | 20–80% — real logic exists, gaps named below |
| NOT TOUCHED | 44 | 11346 | no name-preserving implementation |
| Total runtime | 192 | 73372 | |
## NOT TOUCHED — the port queue, in priority order (largest first)
@@ -46,16 +46,13 @@ 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 |
| wait_guard_corpus | 46 | 0 | RUST |
| canary_cognitive_strata | 44 | 1 | TEST-INFRA |
| research_budget | 44 | 3 | unclassified |
| self_model | 44 | 3 | unclassified |
| evidence_capsule | 43 | 3 | unclassified |
| builder_bridge_cli | 42 | 1 | GO |
| __init__ | 40 | 1 | RUST |
@@ -71,25 +68,16 @@ 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,20 +156,29 @@ 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 |
| self_model | 76 | 3/4 | _core |
## FULL — ported, parity-gated
| Module | Lines | Fns | Side |
|---|---|---|---|
| curator | 1838 | 43/43 | GO |
| sleep_time | 1056 | 26/27 | GO |
| context_broker | 870 | 28/28 | 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 |
| work_manager | 594 | 25/25 | GO |
| 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 | 33/33 | GO |
| event_wait | 518 | 14/14 | GO |
| worthiness | 469 | 12/14 | unclassified |
| tool_protocol | 461 | 22/27 | GO |
@@ -190,8 +187,10 @@ Function-level detail: 48% (1132/2373 runtime functions matched) — secondary;
| goal | 453 | 20/20 | GO |
| release_notes | 446 | 16/16 | GO |
| model_routing | 432 | 13/13 | GO |
| night_mode | 421 | 19/19 | GO |
| build_basis | 375 | 11/13 | RUST |
| attention_capsule | 365 | 6/7 | RUST |
| provider_budget | 357 | 20/20 | GO |
| drift-ledger | 355 | 14/14 | unclassified |
| outcome_ledger | 318 | 7/8 | RUST |
| message_queue | 316 | 13/13 | 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 |
+21 -13
View File
@@ -6,24 +6,33 @@
"auto_tasks",
"behaviour_ledger",
"build_basis",
"build_mode",
"capability_ledger",
"concept_topology",
"construction_intent",
"construction_patterns_builtin",
"context_broker",
"curator",
"drift-ledger",
"drift_ledger",
"drift_resume",
"event_wait",
"evidence_probe",
"execution_trace",
"failure_auto_filer",
"failure_recovery",
"forge",
"forge_client",
"goal",
"impact_preview",
"inference_paths",
"local_tool_runtime",
"meaningful_events",
"memory_consolidation",
"message_graph",
"message_queue",
"model_routing",
"night_mode",
"openai_compat_transport",
"outcome_ledger",
"outcome_utility",
@@ -32,12 +41,15 @@
"programme_continuation",
"programme_gates",
"project_registry",
"provider_budget",
"provider_context",
"release_notes",
"route_risk_flags",
"rune_spinner",
"self_model",
"self_modify",
"shard_manager",
"sleep_time",
"spine_language",
"state_checkpoint",
"system_registry",
@@ -45,35 +57,31 @@
"toolchain",
"verification_layer",
"wait_guard",
"work_manager",
"worthiness"
],
"in_flight": {
"drift_resume": "rune-wave-bb",
"inference_paths": "rune-wave-bb",
"skill_compiler": "rune-wave-bc",
"meaningful_events": "rune-wave-bc",
"memory_types": "rune-wave-bd",
"paths": "rune-wave-bd",
"growth_pipeline": "rune-wave-bd",
"wait_guard_corpus": "rune-wave-be",
"self_model": "rune-wave-be",
"research_budget": "rune-wave-be",
"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",
"hook_engine": "rune-wave-bw",
"elastic_cognition": "rune-wave-bx",
"contracts": "rune-wave-by",
"adaptive_router": "rune-wave-bz",
"memory_selector": "rune-wave-ca",
"construction_pattern": "rune-wave-cb"
},
"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.271.0"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+180
View File
@@ -0,0 +1,180 @@
#!/usr/bin/env python3
"""Live parity check: the Go context-broker binary vs the LIVE Python oracle
(RUNE_COGNITION_CORE=python pinned AND delegation auto), fuzz + edge cases.
Complements the frozen battery (truth.json) with generated inputs."""
from __future__ import annotations
import json
import os
import random
import string
import subprocess
import sys
import tempfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
BIN = Path("/tmp/cb-live-parity")
def build():
subprocess.run(["go", "build", "-o", str(BIN), "."],
cwd=ROOT / "src/go/context-broker", check=True)
def go_eval(payload: dict) -> dict:
proc = subprocess.run([str(BIN), "eval"], input=json.dumps(payload),
capture_output=True, text=True)
if proc.returncode != 0:
raise RuntimeError(f"go eval failed: {proc.stderr}")
return json.loads(proc.stdout)
fails = 0
checked = 0
def check(name, got, want):
global fails, checked
checked += 1
if got != want:
fails += 1
print(f"DIVERGE {name}: go={got!r} py={want!r}")
def est_case(text):
check(f"est[{text!r:.40}]", go_eval({"op": "est", "text": text}),
py._py_default_estimator(text))
def budget_case(w):
check(f"budget[{w}]", go_eval({"op": "budget", "window": w}),
py._py_default_budget(w))
def membud_case(w):
check(f"membud[{w}]", go_eval({"op": "membud", "window": w}),
py._py_default_memory_budget(w))
def memoff_case(v):
check(f"memoff[{v!r}]", go_eval({"op": "memoff", "value": v}),
py._py_memory_disabled_value(v))
def through_case(messages, through):
want = py._through_id(json.loads(json.dumps(messages)), through)
got = go_eval({"op": "through", "messages": messages, "through": through})
check(f"through[{through}/{len(messages)}]", got, want)
rng = random.Random(2479)
os.environ["RUNE_COGNITION_CORE"] = "python"
from rune import context_broker as py # noqa: E402
# fuzz: estimator
for _ in range(200):
n = rng.randint(0, 300)
est_case("".join(rng.choice(string.printable[:94]) for _ in range(n)))
est_case("héllo wörld ünïcode ✓ 日本語テキスト")
est_case("🎉 emoji surrogate pair")
# fuzz: budgets (incl. boundaries around max(2048, w/4) crossover)
for w in [0, 1, 2559, 2560, 2561, 8191, 8192, 8193, 10000, 65536, 131072,
200000, 10**9] + [rng.randint(0, 200000) for _ in range(100)]:
budget_case(w)
membud_case(w)
# fuzz: memory-off raw values
for v in ["", "0", "00", "false", "FALSE", "False", "no", "No", "off", "OFF",
"off ", " off", "1", "true", "YES", "on", "anything", "\t", "\n",
"0.0", "nil", "None", "null"]:
memoff_case(v)
# fuzz: through_id over random message shapes
for _ in range(100):
msgs = []
for _ in range(rng.randint(1, 8)):
m = {"role": rng.choice(["user", "assistant", "system"]),
"content": "".join(rng.choice(string.printable[:70]) for _ in range(rng.randint(0, 40)))}
if rng.random() < 0.3:
m["extra"] = {"n": rng.randint(0, 5), "flag": rng.random() < 0.5}
msgs.append(m)
through_case(msgs, rng.randint(-1, len(msgs) + 1))
# unicode through_id (ensure_ascii path)
uni = [{"role": "user", "content": "日本語 テキスト 🎉 emoji"},
{"role": "assistant", "content": "héllo wörld"}]
through_case(uni, 1)
through_case(uni, 0)
# fuzz: admission kernel (priority desc, recency tie, budget, memory cap)
NAMES = ["system", "user", "history", "memory", "persona_memories", "tools", "notes"]
for case_i in range(150):
entries = []
for j in range(rng.randint(1, 7)):
name = rng.choice(NAMES)
entries.append({
"name": name,
"priority": rng.randint(0, 100),
"tokens": rng.randint(1, 900),
"source": f"src-{j}",
"evictable": name not in ("system", "user"),
})
budget = rng.choice([500, 1000, 2000, 4000])
mem_budget = rng.choice([0, 300, 1200])
got = go_eval({"op": "admit", "entries": entries, "budget": budget,
"memory_budget": mem_budget})
bk = py.ContextBroker()
py_entries = [(e["name"], py.ContributionBlock(e["name"], e["priority"],
"c" * e["tokens"], e["tokens"],
e["source"], evictable=e["evictable"]), j)
for j, e in enumerate(entries)]
try:
_adm, adm = bk._admit(py_entries, budget, memory_budget=mem_budget)
want = {"admitted": [bl.name for bl in _adm],
"blocks": adm["blocks"], "admitted_total": adm["admitted_total"],
"dropped": [d["name"] for d in adm["dropped"]],
"memory_budget": adm["memory_budget"], "memory_used": adm["memory_used"]}
check(f"admit[{case_i}]", got, json.loads(json.dumps(want, sort_keys=True)))
except py.ContextOverflowError as exc:
# Go wraps the oracle's message with the wrapped sentinel; the oracle
# text must be a verbatim prefix of the Go detail.
ok = (isinstance(got, dict) and got.get("error") == "ContextOverflowError"
and got.get("detail", "").startswith(str(exc)))
check(f"admit[{case_i}]", "ContextOverflowError" if ok else got,
"ContextOverflowError")
# fuzz: render (system folding, history pass-through, user capture)
for case_i in range(100):
blocks = []
for j in range(rng.randint(1, 6)):
name = rng.choice(NAMES)
if rng.random() < 0.5:
content = "".join(rng.choice(string.ascii_letters) for _ in range(rng.randint(1, 30)))
else:
content = [{"role": rng.choice(["user", "assistant"]),
"content": "".join(rng.choice(string.ascii_letters) for _ in range(rng.randint(1, 20)))}
for _ in range(rng.randint(1, 3))]
blocks.append({"name": name, "priority": rng.randint(0, 100),
"tokens": 0, "source": f"src-{j}", "content": content})
got = go_eval({"op": "render", "blocks": blocks})
py_blocks = []
for b in blocks:
content = b["content"]
if isinstance(content, list):
content = [dict(m) for m in content]
py_blocks.append(py.ContributionBlock(b["name"], b["priority"], content,
b["tokens"], b["source"]))
caps = py.ContextBroker()._render(py_blocks)
want = {"token_count": caps.token_count, "messages": caps.messages,
"system_preamble": caps.system_preamble, "user_content": caps.user_content,
"blocks": [bl.name for bl in caps.blocks]}
check(f"render[{case_i}]", got, json.loads(json.dumps(want)))
print(f"live parity: {checked - fails}/{checked} cases match "
f"(RUNE_COGNITION_CORE=python pinned)")
sys.exit(1 if fails else 0)
+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)
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""Live parity for the night_mode dichotomy wave: the Go port
(src/go/night-mode) and the Python oracle (rune.night_mode) must produce
byte-identical results for the closed gaps, driven from IDENTICAL state
files (status/report/stop are pure projections of state; _ctx_budget is
covered by the frozen truth battery). started_at strings round-trip
unmodified through both engines, so no normalization is needed.
Usage: python3 scripts/check_night_mode_parity.py
Exits non-zero on any divergence.
"""
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
GO_DIR = REPO / "src/go/night-mode"
SCENARIOS = {
"idle": {},
"running": {
"active": True, "started_at": "2026-10-13T03:00:00Z",
"duration_hours": 8.0, "current_phase": "iterate", "iterations": 7,
"improvements": ["Memory consolidation completed", "Q: q A: a"],
"questions": ["Iteration 0: What should I improve next?"],
"decisions": [], "errors": ["LLM iteration failed: boom"],
},
"stopping": {
"active": False, "started_at": None, "duration_hours": 4.5,
"current_phase": "stopping", "iterations": 2,
"improvements": [], "questions": [], "decisions": ["x"], "errors": [],
},
}
def py_status(state_file):
sys.path.insert(0, str(REPO / "src"))
import rune.night_mode as nm
return nm.NightMode(storage_path=str(state_file)).status()
def py_report(state_file):
sys.path.insert(0, str(REPO / "src"))
import rune.night_mode as nm
return nm.NightMode(storage_path=str(state_file)).report()
def py_stop(state_file):
sys.path.insert(0, str(REPO / "src"))
import rune.night_mode as nm
return nm.NightMode(storage_path=str(state_file)).stop()
def go_cli(binary, mem_dir, *args):
env = {**os.environ, "RUNE_MEMORY_DIR": str(mem_dir)}
p = subprocess.run([str(binary), *args], capture_output=True, text=True, env=env, timeout=30)
return json.loads(p.stdout)
def canon(v):
return json.loads(json.dumps(v))
def main():
subprocess.run(["go", "build", "-o", GO_DIR / "night-mode-bin", "."],
cwd=GO_DIR, check=True)
binary = GO_DIR / "night-mode-bin"
failures = 0
for name, state in SCENARIOS.items():
for op, py_fn in (("status", py_status), ("report", py_report), ("stop", py_stop)):
py_dir = Path(tempfile.mkdtemp(prefix=f"nm-py-{name}-"))
go_dir = Path(tempfile.mkdtemp(prefix=f"nm-go-{name}-"))
for d in (py_dir, go_dir):
(d / "night_mode.json").write_text(json.dumps(state))
try:
expected = py_fn(py_dir / "night_mode.json")
actual = go_cli(binary, go_dir, op)
if canon(actual) != canon(expected):
print(f"DIVERGENCE {name}/{op}:\n py: {canon(expected)}\n go: {canon(actual)}")
failures += 1
else:
print(f"parity ok: {name}/{op}")
except Exception as e: # noqa: BLE001
print(f"ERROR {name}/{op}: {e}")
failures += 1
# delegation live: full CLI round-trip start→status→stop→report
live = Path(tempfile.mkdtemp(prefix="nm-live-"))
env = {**os.environ, "RUNE_MEMORY_DIR": str(live)}
seq = [
(["status"], lambda out: out["active"] is False and out["phase"] == "idle"),
(["start", "4"], lambda out: out["success"] is True
and out["state"]["duration_hours"] == 4.0),
(["status"], lambda out: out["active"] is True),
(["stop"], lambda out: out["success"] is True
and out["state"]["current_phase"] == "stopping"),
(["stop"], lambda out: out["success"] is False
and out["error"] == "Night mode not active"),
(["report"], lambda out: "0 iterations" in out["summary"]),
]
for argv, check in seq:
out = go_cli(binary, live, *argv)
if not check(out):
print(f"LIVE DIVERGENCE {argv}: {out}")
failures += 1
state_on_disk = json.loads((live / "night_mode.json").read_text())
if state_on_disk["active"] or state_on_disk["current_phase"] != "stopping":
print(f"LIVE DIVERGENCE state file: {state_on_disk}")
failures += 1
else:
print("parity ok: live CLI round-trip (delegation live)")
(GO_DIR / "night-mode-bin").unlink(missing_ok=True)
if failures:
print(f"FAIL: {failures} divergences")
return 1
print("LIVE PARITY 100%: status/report/stop × 3 scenarios + CLI round-trip")
return 0
if __name__ == "__main__":
sys.exit(main())
+452
View File
@@ -0,0 +1,452 @@
#!/usr/bin/env python3
"""Live parity: structural_store Rust kernels vs Python oracle (dichotomy
wave, contract BUILDER-2026-10-13T00:32:22Z-bc3aae-factory-gap-ss). Layers:
1. FROZEN — the frozen truth corpus (frozen_ss_truth.json, generated by
scripts/gen_structural_store_truth.py against the LIVE oracle with
RUNE_STRUCTURAL_CORE=python pinned) replayed through the ctypes FFI,
case by case, deep-copied inputs.
2. FUZZ — 300 seeded random docs (seed 2479) per kernel: oracle floor
vs FFI, exact compare; save() compared BYTE-EXACT on real files.
3. LIVE — dual-mode facade battery: the same facade calls executed with
RUNE_STRUCTURAL_CORE=python (oracle floor) and with the Rust core live;
results must be identical (timestamps masked).
Exit 0 only at 100% parity on the gap-closing functions.
"""
import calendar
import copy
import json
import os
import random
import string
import sys
import tempfile
import time as _time
import types
from pathlib import Path
os.environ["RUNE_STRUCTURAL_CORE"] = "python" # oracle floor for generation
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
from rune import structural_store as ss # noqa: E402
from rune import ss_loader # noqa: E402
FIXED_NOW = "2026-10-13T01:02:03Z"
FIXED_EPOCH = calendar.timegm(_time.strptime(FIXED_NOW, "%Y-%m-%dT%H:%M:%SZ"))
ss.now = lambda: FIXED_NOW
ss.time = types.SimpleNamespace( # snapshot() stamps straight off time.*
gmtime=lambda: _time.gmtime(FIXED_EPOCH),
strftime=lambda fmt, t=None: _time.strftime(fmt, t if t is not None else _time.gmtime()),
)
TRUTH = json.loads((REPO / "src" / "rust" / "structural_store" / "src"
/ "frozen_ss_truth.json").read_text())
fails: list[str] = []
counts = {"frozen": 0, "fuzz": 0, "live": 0}
def fail(layer, name, detail):
fails.append(f"[{layer}] {name}: {detail}")
print(f"FAIL[{layer}] {name}: {detail}")
if len(fails) <= 3:
import difflib
w, _, g = detail.partition(" got=")
want_s = w[5:] if w.startswith("want=") else w
a = want_s.replace(r"\u", "\\u").splitlines()
b = g.splitlines()
dump = "\n".join(difflib.unified_diff(a, b, lineterm=""))[:2000]
(REPO / "parity_first_failures.log").open("a").write(
f"=== {layer}/{name} ===\n{dump}\n")
def j(x):
return json.dumps(x, sort_keys=True, ensure_ascii=True)
def check(layer, name, want, got):
counts[layer] += 1
if j(want) != j(got):
fail(layer, name, f"want={j(want)[:300]} got={j(got)[:300]}")
# ── oracle dispatch (python floor) ──────────────────────────────────────────
def oracle_call(fn, a):
return {
"sorted": lambda: ss._sorted(a["value"]),
"new_doc": lambda: ss.new_doc(),
"redact": lambda: ss._redact_secrets(a["value"]),
"digest": lambda: ss.canonical_digest(a["doc"]),
"alias": lambda: _mut(lambda d: ss.alias(d, a["cid"], a["old"]), a["doc"]),
"spine_uri": lambda: ss.spine_uri(a["entity_id"]),
"resolve_uri": lambda: ss.resolve_uri(a["uri"]),
"doc_authorities": lambda: _mut(ss._doc_authorities, a["doc"]),
"authority_health": lambda: ss.authority_health(a["doc"]),
"bind_task": lambda: _mut(lambda d: ss.bind_task(
d, a["task_id"], a["entity_ids"], a["evidence_ref"]), a["doc"]),
"task_entities": lambda: ss.task_entities(a["doc"], a["task_id"]),
"impact_frontier": lambda: ss.impact_frontier(
a["doc"], a["seeds"], max_level=a.get("max_level", 2),
change_kind=a.get("change_kind")),
"observed_impact": lambda: _mut_ret(lambda d: ss.record_observed_impact(
d, a["task_id"], a["items"]), a["doc"]),
"predicted_vs_observed": lambda: ss.predicted_vs_observed(
a["predicted"], a["observed_doc"], a["seeds"]),
"events": lambda: ss.structural_events(a["doc"]),
"diff": lambda: ss.diff(a["old"], a["new"]),
"dedupe": lambda: _mut(ss.dedupe_observations, a["doc"]),
"promote_fix": lambda: _mut(lambda d: ss.promote(
d, a["id"], a["state"], a["ev"]), a["doc"]),
"resolve_status_fix": lambda: ss.resolve_status(a["entity"]),
"supersede_fix": lambda: _mut(lambda d: ss.supersede(
d, a["new"], a["old"], a["ev"]), a["doc"]),
}[fn]()
def _mut(call, doc):
d = copy.deepcopy(doc)
try:
ret = call(d)
except ValueError as exc:
return {"__err__": str(exc)}
return {"__doc__": d, "__ret__": ret}
def _mut_ret(call, doc):
d = copy.deepcopy(doc)
ret = call(d)
return {"__doc__": d, "__ret__": ret}
# ── FFI dispatch ────────────────────────────────────────────────────────────
def ffi_call(fn, a, tmp):
return {
"sorted": lambda: ss_loader.sorted_value(a["value"]),
"new_doc": lambda: ss_loader.new_doc(FIXED_NOW),
"redact": lambda: ss_loader.redact_secrets(a["value"]),
"digest": lambda: ss_loader.canonical_digest(a["doc"]),
"alias": lambda: _ffi_mut(
lambda d: ss_loader.alias(d, a["cid"], a["old"], FIXED_NOW), a["doc"],
ret_fn=lambda d: ss.entity(d, a["cid"])),
"spine_uri": lambda: ss_loader.spine_uri(a["entity_id"]),
"resolve_uri": lambda: ss_loader.resolve_uri(a["uri"]),
"doc_authorities": lambda: _ffi_mut(
ss_loader.doc_authorities, a["doc"],
ret_fn=lambda d: copy.deepcopy(ss._doc_authorities(d))),
"authority_health": lambda: ss_loader.authority_health(a["doc"]),
"bind_task": lambda: _ffi_mut(
lambda d: ss_loader.bind_task(
d, a["task_id"], a["entity_ids"], a["evidence_ref"], FIXED_NOW), a["doc"],
ret_fn=lambda d: ss.entity(d, f"task:{a['task_id']}") or {"id": f"task:{a['task_id']}"}),
"task_entities": lambda: ss_loader.task_entities(a["doc"], a["task_id"]),
"impact_frontier": lambda: ss_loader.impact_frontier(
a["doc"], a["seeds"], max_level=a.get("max_level", 2),
change_kind=a.get("change_kind")),
"observed_impact": lambda: _ffi_mut_ret(lambda d: ss_loader.record_observed_impact(
d, a["task_id"], a["items"], FIXED_NOW), a["doc"]),
"predicted_vs_observed": lambda: ss_loader.predicted_vs_observed(
a["predicted"], a["observed_doc"], a["seeds"]),
"events": lambda: ss_loader.structural_events(a["doc"]),
"diff": lambda: ss_loader.diff(a["old"], a["new"]),
"dedupe": lambda: _ffi_mut(ss_loader.dedupe_observations, a["doc"]),
"promote_fix": lambda: _ffi_mut(
lambda d: ss_loader.promote(d, a["id"], a["state"], a["ev"], FIXED_NOW), a["doc"],
ret_fn=lambda d: ss.entity(d, a["id"])),
"resolve_status_fix": lambda: ss_loader.resolve_status(a["entity"]),
"supersede_fix": lambda: _ffi_mut(
lambda d: ss_loader.supersede(d, a["new"], a["old"], a["ev"], FIXED_NOW), a["doc"],
ret_fn=lambda d: ss.entity(d, a["old"])),
}[fn]()
def _ret_entity(_updated_doc, d, cid):
return ss.entity(d, cid)
def _ffi_mut(call, doc, ret_fn=None):
"""FFI mutation contract: the kernel returns the UPDATED doc; the
oracle-shaped __ret__ is re-derived from it via ret_fn."""
d = copy.deepcopy(doc)
try:
out = call(d)
except RuntimeError as exc:
return {"__err__": str(exc).split("core error: ", 1)[-1]}
if isinstance(out, dict):
d = out
return {"__doc__": d, "__ret__": ret_fn(copy.deepcopy(d)) if ret_fn else None}
def _ffi_mut_ret(call, doc):
d = copy.deepcopy(doc)
out = call(d)
if isinstance(out.get("doc"), dict):
d = out["doc"]
return {"__doc__": d, "__ret__": out["result"]}
def frozen():
for fn, cases in TRUTH["groups"].items():
for c in cases:
a = copy.deepcopy(c["args"])
if fn == "save" or fn == "snapshot":
continue # byte-law layer below
try:
want = oracle_call(fn, a)
except ValueError as exc:
want = {"__err__": str(exc)}
got_raw = None
try:
got = ffi_call(fn, a, None)
except RuntimeError as exc:
got = {"__err__": str(exc).split("core error: ", 1)[-1]}
counts["frozen"] += 1
if j(want) != j(got):
fail("frozen", f"{fn}/{c['name']}", f"want={j(want)[:280]} got={j(got)[:280]}")
def byte_law(tmp):
"""save()/snapshot() must be byte-exact through the FFI."""
save_docs = TRUTH["groups"]["save"]
for c in save_docs:
d = copy.deepcopy(c["args"]["doc"])
name = c["name"]
try:
p = ss.save(d, tmp / f"py/{name}/store.json")
want = {"content": Path(p).read_text(), "doc": d}
except ValueError as exc:
want = {"err": str(exc)}
d2 = copy.deepcopy(c["args"]["doc"])
try:
out = ss_loader.save(d2, str(tmp / f"rs/{name}/store.json"))
got = {"content": Path(out["path"]).read_text(), "doc": out["doc"]}
except RuntimeError as exc:
got = {"err": str(exc).split("core error: ", 1)[-1]}
check("frozen", f"save-bytes/{name}", want, got)
for c in TRUTH["groups"]["snapshot"]:
a = copy.deepcopy(c["args"])
d = a["doc"]
p = ss.snapshot(d, tmp / f"py-snap/{c['name']}", a["label"], tag=a["tag"])
want = {"path": Path(p).name, "content": Path(p).read_text(), "doc": d}
d2 = copy.deepcopy(a["doc"])
out = ss_loader.snapshot(d2, str(tmp / f"rs-snap/{c['name']}"), a["label"], a["tag"], FIXED_NOW)
got = {"path": Path(out["path"]).name, "content": Path(out["path"]).read_text(), "doc": out["doc"]}
check("frozen", f"snapshot-bytes/{c['name']}", want, got)
# ── fuzz (seeded) ───────────────────────────────────────────────────────────
WORDS = ["m:a", "m:b", "m:c", "c:api", "task:T1", "é-unit", "x" * 40, ""]
RELTYPES = ["depends_on", "implements", "consumes", "consumed_by", "verified_by",
"obligated_canary", "deployed_as", "documented_by", "supersedes",
"historical_relation", "related_memory", "belongs_to", "weird_rel"]
SECRETS = ["token", "api_key", "password", "not_a_secret", "client_secret", "TOKEN"]
def rand_value(rnd, depth=0):
kind = rnd.randint(0, 6 if depth < 2 else 4)
if kind == 0:
return rnd.randint(-5, 10 ** 6)
if kind == 1:
return rnd.choice([0.5, 1.0, -2.25, 3.0, 1e-7, 1e21, 12345.6789])
if kind == 2:
return rnd.choice([True, False, None])
if kind == 3:
return "".join(rnd.choice(string.printable[:80] + "é☕φ") for _ in range(rnd.randint(0, 12)))
if kind == 4:
return rnd.choice(WORDS)
if kind == 5:
return [rand_value(rnd, depth + 1) for _ in range(rnd.randint(0, 4))]
return {rnd.choice("abcdefé") + str(i): rand_value(rnd, depth + 1)
for i in range(rnd.randint(0, 4))}
def rand_doc(rnd):
d = {"schema_version": 1, "generated_at": FIXED_NOW,
"entities": [], "relationships": [], "observations": []}
for i in range(rnd.randint(0, 5)):
e = {"id": rnd.choice(WORDS) or f"m:e{i}", "kind": rnd.choice(["module", "contract", "widget"]),
"maturity": rnd.choice(["DECLARED", "PRESENT", "WIRED", "REACHABLE", "EXERCISED", "LIVE_PROVEN"]),
"evidence_refs": sorted({f"ev-{rnd.randint(0, 3)}" for _ in range(rnd.randint(0, 2))}),
"observed_at": FIXED_NOW}
if rnd.random() < 0.3:
e["aliases"] = [f"m:old{i}"]
if rnd.random() < 0.3:
e["ext"] = {"conflicts": rand_value(rnd, 1)} if rnd.random() < 0.5 else {"n": i}
if rnd.random() < 0.3:
e["identities"] = {"p": rand_value(rnd, 1)}
if rnd.random() < 0.2:
e[rnd.choice(SECRETS)] = "s3cret"
d["entities"].append(e)
for _ in range(rnd.randint(0, 6)):
rel = {"type": rnd.choice(RELTYPES), "from": rnd.choice(WORDS), "to": rnd.choice(WORDS),
"evidence_refs": [f"ev-{rnd.randint(0, 2)}"] if rnd.random() < 0.8 else [],
"observed_at": FIXED_NOW}
if rnd.random() < 0.2:
rel["status"] = rnd.choice(["STALE", "CANDIDATE", "CURRENT"])
d["relationships"].append(rel)
for _ in range(rnd.randint(0, 4)):
o = {"kind": rnd.choice(["superseded", "k1"]), "x": rand_value(rnd, 1), "observed_at": FIXED_NOW}
d["observations"].append(o)
if rnd.random() < 0.4:
d["authority_generations"] = {
rnd.choice(["p1", "p2", "é-proj"]): {
"generation": rnd.randint(0, 5),
"observed": [f"{rnd.choice(RELTYPES)}|{rnd.choice(WORDS)}|{rnd.choice(WORDS)}"
for _ in range(rnd.randint(0, 3))],
**({"status": rnd.choice(["CURRENT", "DEGRADED", "UNKNOWN"])} if rnd.random() < 0.7 else {}),
} for _ in range(rnd.randint(1, 3))}
return d
def fuzz():
rnd = random.Random(2479)
for i in range(300):
d = rand_doc(rnd)
d2 = copy.deepcopy(d)
check("fuzz", f"sorted/{i}", ss._sorted(copy.deepcopy(d)), ss_loader.sorted_value(copy.deepcopy(d)))
check("fuzz", f"redact/{i}", ss._redact_secrets(copy.deepcopy(d)), ss_loader.redact_secrets(copy.deepcopy(d)))
check("fuzz", f"digest/{i}", ss.canonical_digest(copy.deepcopy(d)), ss_loader.canonical_digest(copy.deepcopy(d)))
check("fuzz", f"health/{i}", ss.authority_health(copy.deepcopy(d)), ss_loader.authority_health(copy.deepcopy(d)))
check("fuzz", f"events/{i}", ss.structural_events(copy.deepcopy(d)), ss_loader.structural_events(copy.deepcopy(d)))
d3 = copy.deepcopy(d)
ss.dedupe_observations(d3)
d4 = copy.deepcopy(d)
d4 = ss_loader.dedupe_observations(d4)
check("fuzz", f"dedupe/{i}", d3, d4)
seed = rnd.choice(WORDS) or "m:a"
ck = rnd.choice([None, "contract_change", "implementation_change", "contract_violation"])
check("fuzz", f"frontier/{i}",
ss.impact_frontier(copy.deepcopy(d), [seed], change_kind=ck),
ss_loader.impact_frontier(copy.deepcopy(d), [seed], change_kind=ck))
check("fuzz", f"diff/{i}", ss.diff(copy.deepcopy(d), d2), ss_loader.diff(copy.deepcopy(d), copy.deepcopy(d2)))
ent = rnd.choice(d["entities"]) if d["entities"] else {}
check("fuzz", f"resolve_status/{i}", ss.resolve_status(copy.deepcopy(ent)),
ss_loader.resolve_status(copy.deepcopy(ent)))
# mutation kernels
want = _mut(lambda x: ss.bind_task(x, "T1", ["m:a", "c:api"], "ev"), copy.deepcopy(d))
got = _ffi_mut(lambda x: ss_loader.bind_task(x, "T1", ["m:a", "c:api"], "ev", FIXED_NOW),
copy.deepcopy(d),
ret_fn=lambda x: ss.entity(x, "task:T1") or {"id": "task:T1"})
check("fuzz", f"bind_task/{i}", want, got)
want = _mut(lambda x: ss.alias(x, "m:b", "m:b-old"), copy.deepcopy(d)) if any(
e["id"] == "m:b" for e in d["entities"]) else {"__err__": "alias target not found: m:b"}
got = _ffi_mut(lambda x: ss_loader.alias(x, "m:b", "m:b-old", FIXED_NOW), copy.deepcopy(d),
ret_fn=lambda x: ss.entity(x, "m:b"))
check("fuzz", f"alias/{i}", want, got)
want = _mut(lambda x: ss.promote(x, "m:a", "WIRED", "ev-f"), copy.deepcopy(d))
got = _ffi_mut(lambda x: ss_loader.promote(x, "m:a", "WIRED", "ev-f", FIXED_NOW), copy.deepcopy(d),
ret_fn=lambda x: ss.entity(x, "m:a"))
check("fuzz", f"promote/{i}", want, got)
want = _mut(lambda x: ss.supersede(x, "m:b", "m:a", "ev-s"), copy.deepcopy(d))
got = _ffi_mut(lambda x: ss_loader.supersede(x, "m:b", "m:a", "ev-s", FIXED_NOW), copy.deepcopy(d),
ret_fn=lambda x: ss.entity(x, "m:a"))
check("fuzz", f"supersede/{i}", want, got)
items = [{"entity": rnd.choice(WORDS), "source": "t", "detail": rand_value(rnd, 1)} for _ in range(3)]
want = _mut_ret(lambda x: ss.record_observed_impact(x, "T1", copy.deepcopy(items)), copy.deepcopy(d))
got = _ffi_mut_ret(lambda x: ss_loader.record_observed_impact(x, "T1", copy.deepcopy(items), FIXED_NOW), copy.deepcopy(d))
check("fuzz", f"observed_impact/{i}", want, got)
def save_bytes_fuzz(tmp):
rnd = random.Random(4242)
for i in range(50):
d = rand_doc(rnd)
p1 = ss.save(copy.deepcopy(d), tmp / f"fz-py/{i}.json")
out = ss_loader.save(copy.deepcopy(d), str(tmp / f"fz-rs/{i}.json"))
b1 = Path(p1).read_bytes()
b2 = Path(out["path"]).read_bytes()
counts["fuzz"] += 1
if b1 != b2:
fail("fuzz", f"save-bytes/{i}", f"py={b1[:160]!r} rs={b2[:160]!r}")
check("fuzz", f"digest-bytes/{i}", ss.canonical_digest(copy.deepcopy(d)),
ss_loader.canonical_digest(copy.deepcopy(d)))
# ── live dual-mode facade battery ───────────────────────────────────────────
def facade_battery():
def run(tag):
import subprocess
code = r'''
import copy, json, os, sys, tempfile, calendar, time as _time, types
sys.path.insert(0, "src")
from rune import structural_store as ss
FIXED = "2026-10-13T01:02:03Z"
ss.now = lambda: FIXED
_EPOCH = calendar.timegm(_time.strptime(FIXED, "%Y-%m-%dT%H:%M:%SZ"))
ss.time = types.SimpleNamespace( # freeze snapshot()'s wall-clock stamp
gmtime=lambda: _time.gmtime(_EPOCH),
strftime=lambda fmt, t=None: _time.strftime(fmt, t if t is not None else _time.gmtime()),
)
out = {}
d = ss.new_doc()
ss.add_entity(d, id="m:a", kind="module")
ss.add_entity(d, id="m:b", kind="module")
ss.add_entity(d, id="c:api", kind="contract")
ss.add_relationship(d, type="implements", from_id="m:a", to_id="c:api", evidence_refs=["ev"])
ss.add_relationship(d, type="depends_on", from_id="m:b", to_id="m:a", evidence_refs=["ev"])
ss.alias(d, "m:b", "m:b-old")
ss.promote(d, "m:a", "WIRED", "ev-2")
ss.bind_task(d, "T1", ["m:a", "m:b"], "ev-t")
with tempfile.TemporaryDirectory() as td:
p = ss.save(d, td + "/s.json")
out["save_bytes_sha"] = __import__("hashlib").sha256(open(p, "rb").read()).hexdigest()
out["snapshot_name"] = ss.snapshot(d, td + "/sn", "l1", tag="cafe1234").name
out["digest"] = ss.canonical_digest(d)
out["entities"] = sorted(e["id"] for e in d["entities"])
out["via_alias"] = ss.entity(d, "m:b-old")["maturity"]
out["health"] = ss.authority_health(d)
out["frontier"] = ss.impact_frontier(d, ["c:api"], change_kind=None)
out["frontier_impl"] = ss.impact_frontier(d, ["m:a"], change_kind=None)
out["events_n"] = len(ss.structural_events(d))
out["diff"] = ss.diff(d, copy.deepcopy(d))
out["task_entities"] = ss.task_entities(d, "T1")
ss.dedupe_observations(d)
out["obs_n"] = len(d["observations"])
r = ss.record_observed_impact(d, "T2", [{"entity": "m:a", "detail": "x"}])
out["observed"] = r
out["pvo"] = ss.predicted_vs_observed(out["frontier"], d, ["c:api"])
print(json.dumps(out, sort_keys=True))
'''
env = dict(os.environ)
if tag == "python":
env["RUNE_STRUCTURAL_CORE"] = "python"
else:
env.pop("RUNE_STRUCTURAL_CORE", None)
r = subprocess.run([sys.executable, "-c", code], capture_output=True,
text=True, cwd=str(REPO), env=env, timeout=120)
if r.returncode != 0:
fail("live", tag, r.stderr[-300:])
return None
return json.loads(r.stdout)
py = run("python")
rs = run("rust")
if py is None or rs is None:
return
check("live", "dual-mode-facade", py, rs)
def main():
if not ss_loader.available():
print("Rust core not built — run cargo build --release in src/rust/structural_store")
return 2
with tempfile.TemporaryDirectory() as td:
frozen()
byte_law(Path(td))
fuzz()
save_bytes_fuzz(Path(td))
facade_battery()
total = sum(counts.values())
print(f"\nPARITY: {total} checks, {len(fails)} failures "
f"(frozen={counts['frozen']} fuzz={counts['fuzz']} live={counts['live']})")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for night_mode
with SHA evidence."""
import json
import os
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
os.environ["CS_RUST_LIB"] = "/mnt/workdrive/rune/src/rust/capability_scoring/target/release/libcapability_scoring.so"
from rune.construction_interface import ConstructionInterface
cid = sys.argv[1]
iface = ConstructionInterface(builder="factory-gap-nm")
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": "night_mode dichotomy completion — parity 150f5b86 "
"feat(night_mode): close PARTIAL gaps — dichotomy wave; "
"Phase B (trunc ASCII zero-alloc fast path, rune walk "
"only for long/non-ASCII) pushed gitea/master. Go port at "
"src/go/night-mode closes all 12 audit-named gaps "
"name-preserving (_ctx_budget, get_night_mode, "
"start/stop_night_mode, get_status, get_report, to_dict, "
"_load, _save, _run_loop, _run_sleep, _run_evaluation + "
"_run_iteration/_generate_report); pure/IO split law with "
"injected clock/wait/script/HTTP/rand/loop seams. Battery "
"10 tests replay the 9-case frozen oracle truth VERBATIM "
"(stop guard, idle status/report, 6 _ctx_budget branches); "
"live parity 100% (status/report/stop x 3 scenarios + CLI "
"round-trip); pytest 37/37 both ways (RUNE_NIGHT_MODE_CORE "
"auto vs =python); gofmt+vet clean. Zero regressions "
"(failure set byte-identical before/after).",
}], scope_files=[
"src/rune/night_mode.py",
"src/go/night-mode/main.go",
"src/go/night-mode/night_mode_test.go",
"src/go/night-mode/frozen_truth.json",
"scripts/gen_night_mode_truth.py",
"scripts/check_night_mode_parity.py",
"tests/test_night_mode.py",
"scripts/open_contract_night_mode.py",
"scripts/close_contract_night_mode.py",
])
print("close:", json.dumps(c)[:300])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for the
provider_budget gap-closing port with SHA evidence. Full lifecycle
draft→approved→building→verifying→closed 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
PARITY_SHA = "8a08f9b4"
PHASE_B_SHA = "527dc774"
iface = ConstructionInterface(builder="factory-gap-pb")
r = iface.submit_need(
"Close the provider_budget dichotomy gaps (#2479 tranche, GO side): "
"port the 10 audit-missing functions (get_tracker/track_usage/"
"check_provider/get_best_provider/failover/get_status/to_dict/_load/"
"_save/_init_default_providers) name-preserving into the existing "
"src/go/provider-budget Go port — tracker with order-preserving "
"storage load (dict-order tie-break parity), config seeding (ollama "
"skip + anthropic type detection), per-type health-check endpoints "
"with IO behind injectable seams (clock, config path, transport), "
"api_key-excluding to_dict, module-level singleton wrappers. Truth "
"frozen via the shared freeze_truth.py harness (RUNE_PROVIDER_BUDGET"
"_CORE=python, fixture-home replay contract); VERBATIM-embedded Go "
"battery; 200-op live parity seed 2479; Python port test (oracle "
"pinned + harness gate); audit 5/20 → 20/20.",
origin="builder",
)
print("submit_need:", json.dumps(r)[:200])
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)[:120])
if not t.get("success"):
sys.exit(1)
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": "provider_budget gap-closing completion — parity "
f"{PARITY_SHA} feat(provider_budget): close PARTIAL gaps — "
"dichotomy wave; Phase B (single generic decodeOrderedTable[T] "
f"streaming decoder replacing both hand-rolled ordered-JSON "
f"decoders) {PHASE_B_SHA} refactor(provider_budget): Phase B "
"language-advantage pass — dichotomy wave; both pushed "
"gitea/master. Go battery replays the 13-case frozen oracle "
"truth VERBATIM (truth_frozen.json from the shared "
"freeze_truth.py harness, RUNE_PROVIDER_BUDGET_CORE=python, "
"fixture-home replay protocol) — harness gate reports "
"byte-identical; live parity 200/200 random-op seed 2479 "
"python-vs-Go identical; pytest 3/3 (oracle pinned, frozen "
"replay, harness gate, go test); go vet + gofmt clean; "
"existing replay gate 9/9 green; dichotomy audit 5/20 "
"PARTIAL → 20/20 FULL, missing [].",
}], scope_files=[
"src/rune/provider_budget.py",
"src/go/provider-budget/main.go",
"src/go/provider-budget/truth_frozen.json",
"src/go/provider-budget/truth_frozen_test.go",
"scripts/gen_provider_budget_truth.py",
"scripts/parity_provider_budget.py",
"scripts/walk_contract_provider_budget.py",
"scripts/close_contract_provider_budget.py",
"tests/test_provider_budget_port.py",
])
print("close:", json.dumps(c)[:200])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
sys.exit(0 if c.get("success") else 1)
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""Close the #2479 dichotomy-wave construction contract for self_model
with SHA evidence."""
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
cid = "BUILDER-2026-10-13T00:23:43Z-53857a-factory-batch-i"
iface = ConstructionInterface(builder="factory-batch-i")
c = iface.close(cid, observed_evidence=[{
"kind": "port_evidence",
"detail": "self_model dichotomy completion — parity dac4889c "
"feat(self_model): port to FULL Rust — dichotomy wave; "
"Phase B 99bde7ba refactor(self_model): Phase B "
"language-advantage pass — dichotomy wave (ASCII byte "
"fast-path token estimate); store register e1904eb1 (all "
"pushed gitea/master). Battery 2 tests replay the 26-case "
"frozen oracle truth VERBATIM (estimate_tokens boundaries "
"incl. unicode; compile incl. exact-fit, evidence overflow, "
"key defaults, stable weight ties, zero/negative budgets; "
"why_question incl. statement/evidence matches, "
"case-insensitivity, empty topic/model); live parity "
"926/926 (26 frozen + 300 fuzz seeds x 3 fns, kernel vs "
"RUNE_SMM_CORE=python); pytest test_p2_quintet 16 passed "
"BOTH ways (kernel auto + python pin); clippy -D warnings "
"clean. Documented FFI boundary: pyjson numbers are f64 "
"(int-vs-float weight distinction crosses as value-equal; "
"truth corpus uses float weights).",
}], scope_files=[
"src/rune/self_model.py",
"src/rune/smm_loader.py",
"src/rust/self_model/src/lib.rs",
"src/rust/self_model/src/branch_battery.rs",
"src/rust/self_model/frozen_sm_truth.json",
"scripts/gen_self_model_truth.py",
"scripts/walk_contract_self_model.py",
"scripts/close_contract_self_model.py",
])
print("close:", json.dumps(c)[:300])
print("CONTRACT", cid, "closed" if c.get("success") else "CLOSE_FAILED")
+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 "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()
+383
View File
@@ -0,0 +1,383 @@
#!/usr/bin/env python3
"""Freeze the oracle truth for the GO gap-close port of
src/rune/context_broker.py (dichotomy wave #2479, GO, factory-gap-ctxbroker).
Every NEW function ported by the gap-close, every branch, against the LIVE
oracle pinned to the Python cores (RUNE_COGNITION_CORE=python — the _py_*
oracles ARE the parity floor being frozen). Deep-copied inputs: the oracle
mutates message lists in place (compact_history archive path), so each row
re-freezes the input verbatim.
Ops frozen (fn = the Go-side dispatcher key):
_py_default_estimator est (text)
_cc_core cc_core (env RUNE_COGNITION_CORE) -> bool available
_py_default_budget budget (window)
_py_default_memory_budget membud (window, incl. None/str/bool coercion)
_py_memory_disabled_value memoff (raw string)
reset_discovered_windows / register_window / default_window
windows (sequence of ops -> final registry view)
summarize_history summarize (transport-failure branch: ValueError)
compact_history compact (messages, window, summarizer, session)
rolling_summary_state rstate (key -> state | null)
_through_id through (messages, through_count)
store_rolling_summary / evict_rolling rstore (op sequence -> state + return)
"""
from __future__ import annotations
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"))
os.environ["RUNE_COGNITION_CORE"] = "python" # pin the Python parity floor
from rune import context_broker as cb # noqa: E402
rows: list[dict] = []
def row(name, fn, inp, out):
rows.append({"name": name, "fn": fn, "input": inp, "want": out})
# ── _py_default_estimator: every branch ────────────────────────────────────
row("est:empty", "est", {"text": ""}, cb._py_default_estimator(""))
row("est:none-coerced-empty", "est", {"text": None}, cb._py_default_estimator(None))
row("est:short", "est", {"text": "hello"}, cb._py_default_estimator("hello"))
row("est:exact-8", "est", {"text": "12345678"}, cb._py_default_estimator("12345678"))
row("est:9-floor", "est", {"text": "123456789"}, cb._py_default_estimator("123456789"))
row("est:unicode-rune-len", "est", {"text": "héllo wörld"}, cb._py_default_estimator("héllo wörld"))
# ── _cc_core: python-pin + auto-without-build ───────────────────────────────
from rune import cc_loader # noqa: E402
_LOADER_AVAIL = bool(cc_loader.available())
row("cc_core:python-pin-returns-none", "cc_core",
{"env": {"RUNE_COGNITION_CORE": "python"}, "loader_available": _LOADER_AVAIL},
None if cb._cc_core() is None else "CORE")
del os.environ["RUNE_COGNITION_CORE"]
row("cc_core:auto-fallback", "cc_core", {"env": {}, "loader_available": _LOADER_AVAIL},
None if cb._cc_core() is None else "CORE")
# ── _py_default_budget: every branch ────────────────────────────────────────
row("budget:0-floor", "budget", {"window": 0}, cb._py_default_budget(0))
row("budget:1-floor", "budget", {"window": 1}, cb._py_default_budget(1))
row("budget:100-floor", "budget", {"window": 100}, cb._py_default_budget(100))
row("budget:4096", "budget", {"window": 4096}, cb._py_default_budget(4096))
row("budget:8192", "budget", {"window": 8192}, cb._py_default_budget(8192))
row("budget:131072", "budget", {"window": 131072}, cb._py_default_budget(131072))
row("budget:quarter-exact-8192", "budget", {"window": 8192}, cb._py_default_budget(8192))
# ── _py_default_memory_budget: every branch incl. coercion ─────────────────
row("membud:0-cap", "membud", {"window": 0}, cb._py_default_memory_budget(0))
row("membud:none-cap", "membud", {"window": None}, cb._py_default_memory_budget(None))
row("membud:neg-cap", "membud", {"window": -5}, cb._py_default_memory_budget(-5))
row("membud:8-eq-1", "membud", {"window": 8}, cb._py_default_memory_budget(8))
row("membud:2400", "membud", {"window": 2400}, cb._py_default_memory_budget(2400))
row("membud:9600-cap", "membud", {"window": 9600}, cb._py_default_memory_budget(9600))
row("membud:96000-cap", "membud", {"window": 96000}, cb._py_default_memory_budget(96000))
# bool/float coerce through the public fn's int(window) path when a Rust core
# is present; on the Python floor they hit _py_default_memory_budget raw.
row("membud:bool-true", "membud", {"window": True}, cb._py_default_memory_budget(True))
row("membud:float", "membud", {"window": 2400.9}, cb._py_default_memory_budget(2400.9))
# ── _py_memory_disabled_value: every branch ────────────────────────────────
for v in ("", "0", "false", "no", "off", "1", "true", "yes", "on", "OFF",
" False ", "anything", " ", "off\n"):
row(f"memoff:{v!r}", "memoff", {"value": v}, cb._py_memory_disabled_value(v))
# ── window registry: reset/register/default with NO live discovery ─────────
# default_window's live-discovery import is exercised in the fallback branch
# only when model_id is falsy (registry miss + import of local_tool_runtime
# would attempt a real HTTP call otherwise — the Go seam stubs discovery;
# here we freeze: falsy id, registry hit, registry miss w/ capped discovery).
cb.reset_discovered_windows()
row("windows:reset-then-missing-none", "windows",
{"ops": [{"op": "default_window", "model_id": None}]},
{"last": cb.default_window(None)})
row("windows:none-empty-str", "windows",
{"ops": [{"op": "default_window", "model_id": ""}]},
{"last": cb.default_window("")})
row("windows:register-hit", "windows",
{"ops": [{"op": "register_window", "model_id": "m1", "window": 32768},
{"op": "default_window", "model_id": "m1"}]},
{"last": (cb.reset_discovered_windows(), cb.register_window("m1", 32768),
cb.default_window("m1"))[2]})
row("windows:register-overwrite", "windows",
{"ops": [{"op": "register_window", "model_id": "m1", "window": 8192},
{"op": "register_window", "model_id": "m1", "window": 65536},
{"op": "default_window", "model_id": "m1"}]},
{"last": (cb.reset_discovered_windows(), cb.register_window("m1", 8192),
cb.register_window("m1", 65536), cb.default_window("m1"))[3]})
row("windows:reset-clears", "windows",
{"ops": [{"op": "register_window", "model_id": "m1", "window": 8192},
{"op": "reset_discovered_windows"},
{"op": "default_window", "model_id": "m1"}]},
{"last": (cb.reset_discovered_windows(), cb.register_window("m1", 8192),
cb.reset_discovered_windows(), cb.default_window("m1"))[3]})
row("windows:register-str-window-coerced", "windows",
{"ops": [{"op": "register_window", "model_id": "m1", "window": "28672"},
{"op": "default_window", "model_id": "m1"}]},
{"last": (cb.reset_discovered_windows(), cb.register_window("m1", "28672"),
cb.default_window("m1"))[2]})
# discovery-failure branch: unknown model -> the live oracle tries the
# transport; in this offline env that raises inside context_length ->
# record_failure + fallback 8192 (never cached). Freeze the returned value.
cb.reset_discovered_windows()
row("windows:miss-discover-fallback-8192", "windows",
{"ops": [{"op": "default_window", "model_id": "definitely-not-a-model:offline"}]},
{"last": cb.default_window("definitely-not-a-model:offline"),
"note": "live oracle: T1 context_discovery + FALLBACK_WINDOW, not cached"})
# ── summarize_history: transport-failure branch (offline) ──────────────────
try:
cb.summarize_history([{"role": "user", "content": "hi"}], model="offline-no-such-model")
row("summarize:unexpected-success", "summarize", {"messages": []}, "UNEXPECTED-SUCCESS")
except ValueError as exc:
row("summarize:transport-fail-valueerror", "summarize",
{"messages": [{"role": "user", "content": "hi"}]},
{"error": "ValueError", "detail": str(exc)[:120]})
except Exception as exc: # noqa: BLE001 — freeze whatever the live env does
row("summarize:transport-fail-other", "summarize",
{"messages": [{"role": "user", "content": "hi"}]},
{"error": type(exc).__name__, "detail": str(exc)[:120]})
# ── _through_id: every branch ───────────────────────────────────────────────
msgs = [{"role": "user", "content": "first"},
{"role": "assistant", "content": "reply"},
{"role": "user", "content": "second"}]
row("through:empty-list", "through", {"messages": [], "through": 0}, cb._through_id([], 0))
row("through:neg", "through", {"messages": msgs, "through": -1}, cb._through_id(msgs, -1))
row("through:at-end", "through", {"messages": msgs, "through": 3}, cb._through_id(msgs, 3))
row("through:beyond-end", "through", {"messages": msgs, "through": 99}, cb._through_id(msgs, 99))
row("through:anchor-0", "through", {"messages": msgs, "through": 0}, cb._through_id(msgs, 0))
row("through:anchor-1", "through", {"messages": msgs, "through": 1}, cb._through_id(msgs, 1))
row("through:content-hash-stable", "through",
{"messages": msgs, "through": 2},
(cb._through_id(msgs, 2), cb._through_id(copy.deepcopy(msgs), 2),
cb._through_id([{"content": "second", "role": "user"}], 0))[0],
)
# key-order independence (sort_keys=True)
row("through:key-order-independent", "through",
{"messages": [{"role": "user", "content": "x"}, {"content": "x", "role": "user"}],
"through": 1},
cb._through_id([{"role": "user", "content": "x"}, {"content": "x", "role": "user"}], 1))
# ── rolling summary store: state/store/evict (self-contained rows) ──────────
cb._ROLLING.clear()
row("rstate:miss", "rstate", {"ops": [{"op": "read", "source": "operator", "sid": "s1"}]},
cb.rolling_summary_state(("operator", "s1")))
cb.store_rolling_summary(("operator", "s1"), "SUM", 7, "abcdef0123456789")
row("rstate:hit-copy", "rstate",
{"ops": [{"op": "store", "source": "operator", "sid": "s1", "summary": "SUM",
"through": 7, "tid": "abcdef0123456789"},
{"op": "read", "source": "operator", "sid": "s1"}]},
cb.rolling_summary_state(("operator", "s1")))
row("rstore:store-then-through-id", "rstore",
{"msgs": msgs},
(cb.store_rolling_summary(("operator", "s2"), "S2", 1, cb._through_id(msgs, 1)),
cb.rolling_summary_state(("operator", "s2")))[1])
# ── compact_history: every branch (injected summarizer = deterministic) ────
def fresh(seed: str, n_pairs: int) -> list[dict]:
out = []
for i in range(n_pairs):
out.append({"role": "user", "content": f"{seed} user {i} " + "x" * (i * 40)})
out.append({"role": "assistant", "content": f"{seed} assistant {i} " + "y" * (i * 40)})
return out
def sumr(messages):
return "SUMMARY<" + "|".join(m.get("content", "")[:10] for m in messages) + ">"
def compact_row(name, messages, window, *, summarizer="sum", session="", prior=None,
archive=False):
"""Freeze one compact_history call; self-contained (prior state inline)."""
cb._ROLLING.clear()
if prior:
cb.store_rolling_summary(("operator", session) if session else ("operator",),
prior["summary"], prior["through_count"],
prior.get("through_id", ""))
kw = dict(summarizer=sumr if summarizer != "boom" else boom)
arch = None
if archive:
# deterministic RELATIVE fixture path (chdir'd to repo root): the
# label is embedded in the summary block, so it must be portable
os.chdir(ROOT)
arch = Path("src/go/context-broker/.fixtures/archive.jsonl")
arch.parent.mkdir(parents=True, exist_ok=True)
inp = {"messages": copy.deepcopy(messages), "window": window,
"summarizer": summarizer}
if session:
inp["session"] = session
if prior:
inp["prior"] = prior
if archive:
inp["archive"] = "FIXTURE"
inp["archive_path"] = str(arch)
compacted, ev = cb.compact_history(copy.deepcopy(messages), window,
archive_path=arch,
summarizer=sumr if summarizer != "boom" else boom,
session_id=session)
out = {"event": ev}
if messages is not None:
out["compacted"] = compacted
if archive:
body = arch.read_text() if arch.exists() else ""
out["archive_lines"] = body.count("\n")
out["archived_msg_count"] = len(json.loads(body.splitlines()[0])["messages"]) if body else 0
out["archived_msgs"] = json.loads(body.splitlines()[0])["messages"] if body else []
arch.unlink(missing_ok=True)
row(name, "compact", inp, out)
def boom(messages):
raise RuntimeError("summarizer down")
# no messages -> early return, event untriggered
compact_row("compact:empty-messages", [], 8192)
# <= KEEP_TURNS user turns -> early return
compact_row("compact:at-keep-turns-no-trigger", fresh("a", 5), 8192)
compact_row("compact:below-keep-turns-no-trigger", fresh("a", 4), 8192)
# > keep turns, no session, summarizer success
compact_row("compact:trigger-no-session", fresh("b", 7), 8192)
# with session: rolling persistence across TWO compactions (C1: only new)
cb._ROLLING.clear()
m3 = fresh("c", 8)
c1, ev1 = cb.compact_history(copy.deepcopy(m3), 8192, summarizer=sumr,
session_id="s3")
prior3 = cb.rolling_summary_state(("operator", "s3"))
row("compact:session-first", "compact",
{"messages": m3, "window": 8192, "session": "s3", "summarizer": "sum"},
{"event": ev1, "compacted": c1})
# second compaction: window rotated under the stored count (#141 rematch)
m3b = m3[:2] + m3[-10:]
compact_row("compact:session-rotation-rematch", m3b, 8192, session="s3",
prior=prior3)
# prior through beyond len(older) — history shrank, re-summarize from scratch
compact_row("compact:session-through-beyond-shrink", fresh("d", 7), 8192,
session="s4", prior={"summary": "PRIOR-SUM", "through_count": 999,
"through_id": ""})
# nothing new beyond the rolled summary: reuse it verbatim
cb._ROLLING.clear()
m9 = fresh("g", 7)
_, ev9_pre = cb.compact_history(copy.deepcopy(m9), 8192, summarizer=sumr,
session_id="s9")
prior9 = cb.rolling_summary_state(("operator", "s9"))
# call again with IDENTICAL messages: older[6:] is empty -> reuse verbatim
compact_row("compact:session-nothing-new-reuse", m9, 8192, session="s9",
prior=prior9)
# summarizer failure -> C2 degrade to tail
compact_row("compact:summarizer-fail-degrade-tail", fresh("e", 7), 8192,
summarizer="boom")
# summarizer failure with tiny window (tail budget floor: always keep >=1)
m6 = [{"role": "user", "content": "u" * 9000}, {"role": "assistant", "content": "a" * 9000},
{"role": "user", "content": "u2" * 9000}, {"role": "assistant", "content": "a2" * 9000},
{"role": "user", "content": "u3" * 9000}, {"role": "assistant", "content": "a3" * 9000},
{"role": "user", "content": "u4" * 9000}]
compact_row("compact:fail-tiny-window-tail-first-only", m6, 10, summarizer="boom")
# archive write: success path — event.archived True, label = the path itself
compact_row("compact:archive-success", fresh("f", 6), 8192, session="s7",
archive=True)
# default_estimator used inside event tokens (python pin): tokens_before math
compact_row("compact:token-math-estimator",
[{"role": "user", "content": "12345678"}, {"role": "assistant", "content": "1234"}],
8192)
# ── ContextBroker kernel: to_dict / collect / admit / render ────────────────
from rune.context_broker import ContributionBlock, ContextBroker, ContextOverflowError # noqa: E402
# to_dict
blk = ContributionBlock("memory", 5, "hello world", 2, "recall", evictable=True)
row("to_dict:block", "to_dict", {}, blk.to_dict())
blk2 = ContributionBlock("system", 100, "sys", 0, "persona", evictable=False)
row("to_dict:mandatory", "to_dict", {}, blk2.to_dict())
# collect: happy, empty-content skip, failure → T1 degrade, malformed → T1
def make_broker():
b = ContextBroker()
b.register_contributor("ok", lambda task, session: ContributionBlock("tools", 9, "tooltext", 2, "t"), 1)
b.register_contributor("empty", lambda task, session: ContributionBlock("x", 1, "", 0, "s"), 1)
b.register_contributor("boom", lambda task, session: (_ for _ in ()).throw(RuntimeError("cb down")), 1)
b.register_contributor("malformed", lambda task, session: ContributionBlock("y", 1, 12345, 0, "s"), 1)
b.register_contributor("list-ok", lambda task, session: ContributionBlock("history", 3, [{"role": "user", "content": "hi"}], 1, "h"), 2)
b.register_contributor("none", lambda task, session: None, 1)
return b
b = make_broker()
degraded: list[str] = []
collected = b._collect({}, {}, degraded)
row("collect:degraded-and-ordered", "collect", {},
{"names": [name for name, _blk, _b in collected],
"degraded": degraded,
"failed_events": sorted(getattr(b, "_last_failures", []))})
# admit: priority desc, recency tie, memory sub-budget, overflow
def blocks(*specs):
out = []
for name, pri, tokens, evictable in specs:
out.append(ContributionBlock(name, pri, "c" * tokens, tokens, f"src-{name}", evictable=evictable))
return out
bk = ContextBroker()
admitted, adm = bk._admit([(b["name"], bl, 0) for b, bl in zip(
[{"name": "system"}, {"name": "memory"}, {"name": "history"}, {"name": "user"}],
blocks(("system", 100, 500, False), ("memory", 5, 300, True),
("history", 7, 900, True), ("user", 100, 100, False)))], 1000)
row("admit:priority-recency-budget", "admit", {},
{"admitted": [bl.name for bl in admitted],
"blocks": adm["blocks"], "admitted_total": adm["admitted_total"],
"dropped": [d["name"] for d in adm["dropped"]],
"memory_budget": adm["memory_budget"], "memory_used": adm["memory_used"]})
# memory sub-budget: two memory blocks, second exceeds sub-budget
admitted2, adm2 = bk._admit([("m1", blocks(("m1", 9, 700, True))[0], 0),
("m2", blocks(("m2", 8, 700, True))[0], 1)], 4000, memory_budget=1200)
row("admit:memory-subbudget-drop", "admit", {},
{"admitted": [bl.name for bl in admitted2],
"dropped": [d["name"] for d in adm2["dropped"]],
"memory_used": adm2["memory_used"],
"reasons": [d["reason"] for d in adm2["dropped"]]})
# mandatory overflow → raise
try:
bk._admit([("user", blocks(("user", 100, 5000, False))[0], 0)], 1000)
row("admit:mandatory-overflow-raises", "admit", {}, "NO-RAISE")
except ContextOverflowError as exc:
row("admit:mandatory-overflow-raises", "admit", {},
{"error": "ContextOverflowError", "detail": str(exc)})
# render: system folding, history pass-through, user capture
capsule = bk._render(blocks(("persona", 100, 7, False), ("tools", 90, 5, False),
("history", 70, 4, False), ("user", 100, 2, False)))
row("render:order-and-fold", "render", {},
{"token_count": capsule.token_count,
"messages": capsule.messages,
"system_preamble": capsule.system_preamble,
"user_content": capsule.user_content,
"blocks": [bl.name for bl in capsule.blocks]})
print(f"froze {len(rows)} rows total")
doc = {
"frozen_ts": "2026-10-12T00:00:00Z",
"generator": "scripts/gen_context_broker_truth.py — live oracle src/rune/context_broker.py, RUNE_COGNITION_CORE=python pinned",
"rows": rows,
}
out = ROOT / "src/go/context-broker/truth.json"
out.write_text(json.dumps(doc, indent=1, sort_keys=True) + "\n")
+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}")
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""gen_night_mode_truth.py — factory wave truth battery for night_mode.
Exercises the module-level public surface of src/rune/night_mode.py whose
results are clock- and state-file-invariant, freezing the oracle's behavior
so the Go port at src/go/night-mode replays it byte-for-byte:
* _ctx_budget — every profile branch (T0 window-0, T1/T2/T3 local,
T4 non-local tool reserve, unknown-model fallback)
* stop_night_mode — idle reverse guard (error branch)
* get_status — idle status shape
* get_report — idle report shape
The stateful lifecycle (start/stop/status/report/to_dict/_load/_save/
_run_loop/_run_sleep/_run_evaluation) is IO-bound (clock, storage, threads,
Ollama HTTP): it is pinned by the Go unit battery (night_mode_test.go,
injected clock/runner/HTTP seams) and tests/test_night_mode.py, NOT by this
file — freeze_truth.py --verify re-runs cases against a fresh module with
the real clock, so only clock-free results belong here.
Verify (byte-identical law):
RUNE_MEMORY_DIR=$(mktemp -d) PYTHONPATH=src \\
python3 scripts/freeze_truth.py --verify \\
src/go/night-mode/frozen_truth.json --module rune.night_mode
(RUNE_MEMORY_DIR must point at a directory with no night_mode.json — the
idle-state cases construct the global NightMode from it.)
"""
import json
import os
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(Path(__file__).resolve().parent))
os.environ["RUNE_MEMORY_DIR"] = tempfile.mkdtemp(prefix="nm-truth-")
os.environ["RUNE_NIGHT_MODE_CORE"] = "python"
from freeze_truth import freeze, write # noqa: E402
import rune.night_mode as nm # noqa: E402
def main():
cases = [
# stop: idle reverse guard (error branch — deterministic)
("stop_night_mode", (), {}),
# status/report: idle shapes (started_at None, defaults)
("get_status", (), {}),
("get_report", (), {}),
# _ctx_budget: every resolve branch of model_registry.DEFAULT_PROFILES
("_ctx_budget", ("qwen2.5:3b",), {}), # T1 local, window 32768
("_ctx_budget", ("qwen3:14b",), {}), # T2 local, window 32768
("_ctx_budget", ("qwen3.6:27b",), {}), # T3 local, window 32768
("_ctx_budget", ("mimo-v2.5-pro",), {}), # T4 non-local + tool reserve
("_ctx_budget", ("deterministic",), {}), # T0 window 0 -> or-8192
("_ctx_budget", ("unknown-model",), {}), # missing -> fallback 8192
]
truth = freeze("rune.night_mode", cases, oracle_module="rune.night_mode")
dest = REPO / "src/go/night-mode/frozen_truth.json"
write(truth, dest)
print(f"wrote {len(truth)} cases → {dest}")
if __name__ == "__main__":
main()
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env python3
"""Freeze the provider_budget truth corpus (dichotomy wave #2479 gap-closing, GO).
Drives the LIVE Python oracle (src/rune/provider_budget.py) through the
shared harness (scripts/freeze_truth.py — RUNE_PROVIDER_BUDGET_CORE=python
pinned, inputs deep-copied, {"fn","args","kwargs","expected"} envelope) and
freezes to src/go/provider-budget/truth_frozen.json (embedded VERBATIM by
the Go battery, truth_frozen_test.go).
Determinism contract (why a fixture HOME): the module-level oracle fns all
run through the global ProviderBudgetTracker, whose storage/config paths
come from $HOME (expanduser("~/.rune/provider_budgets.json") and
"~/.config/mimocode/mimocode.jsonc"). Every case therefore replays against
a REBUILT fixture home:
HOME = /tmp/rune_pb_truth_home
.rune/provider_budgets.json ← STORAGE_FIXTURE (seeded providers)
.config/mimocode/mimocode.jsonc ← CONFIG_FIXTURE (init-branch surface)
Stateful cases (track_usage mutations) are legal because the oracle's own
_save mutates the fixture home identically on every replay from the same
initial state — the truth is a replayable script over the canonical home.
What is frozen vs seam-tested (JSON-envelope law): freeze() json.dumps the
expected value, so object-returning fns (get_tracker, get_best_provider →
ProviderBudget) freeze only at their None arms, and check_provider on a
KNOWN provider freezes nowhere (datetime.now timestamp + live socket).
Those branches are pinned by the Go seam battery (fake transport + pinned
clock) and the random-op live parity instead.
Coverage via this harness: get_status (empty tie-break → tracked shifts →
budget exhaustion → post-failover all-down), track_usage (known+cost,
known default-cost, unknown no-op, disabled-provider tracking), failover
(disable-last-available → None arm, unknown no-op arm), check_provider
(not-found arm), get_best_provider (all-down → None arm).
Self-verifying: rebuilds the fixture home, freezes, rebuilds AGAIN, then
runs the shared harness gate — must report byte-identical:
PYTHONPATH=src python3 scripts/freeze_truth.py --verify \
src/go/provider-budget/truth_frozen.json \
--module rune.provider_budget
Run:
python3 scripts/gen_provider_budget_truth.py
"""
import json
import os
import shutil
import subprocess
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 / "scripts"))
HOME = Path("/tmp/rune_pb_truth_home")
STORAGE = HOME / ".rune" / "provider_budgets.json"
CONFIG = HOME / ".config" / "mimocode" / "mimocode.jsonc"
OUT = REPO / "src" / "go" / "provider-budget" / "truth_frozen.json"
# WARNING: keep byte-equal with the fixtures embedded in
# src/go/provider-budget/truth_frozen_test.go — the Go battery replays the
# frozen truth against the SAME canonical initial state.
CONFIG_FIXTURE = {
"provider": {
"anthropic-claude": {
"options": {"baseURL": "https://api.anthropic.example", "apiKey": "sk-fixture-anthropic"},
},
"openai-main": {
"options": {"baseURL": "https://api.openai.example/v1", "apiKey": "sk-fixture-openai"},
},
"ollama": {
"options": {"baseURL": "http://127.0.0.1:11434", "apiKey": ""},
},
},
}
def _provider(name, ptype, url, limit, used, tlimit, tused, enabled):
return {
"name": name,
"provider_type": ptype,
"url": url,
"monthly_limit": limit,
"monthly_used": used,
"token_limit": tlimit,
"tokens_used": tused,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": enabled,
"last_check": None,
"last_error": None,
}
STORAGE_FIXTURE = {
# alpha: available, budget_remaining 7.0 — ties with delta (7.0) at case 1;
# the oracle's stable sort keeps insertion order → best = alpha.
"alpha": _provider("alpha", "openai-compatible", "https://alpha.example/v1",
10.0, 3.0, 100000, 40000, True),
# beta: over budget (5.0 >= 5.0) — unavailable arm.
"beta": _provider("beta", "openai-compatible", "https://beta.example/v1",
5.0, 5.0, 0, 0, True),
# gamma: disabled — unavailable arm.
"gamma": _provider("gamma", "anthropic", "https://gamma.example",
20.0, 0.0, 0, 0, False),
# delta: available, budget_remaining 7.0 — the tie partner.
"delta": _provider("delta", "openai-compatible", "https://delta.example/v1",
7.0, 0.0, 0, 0, True),
}
def build_fixture_home():
"""Rebuild the canonical fixture home from scratch (idempotent)."""
shutil.rmtree(HOME, ignore_errors=True)
CONFIG.parent.mkdir(parents=True, exist_ok=True)
CONFIG.write_text(json.dumps(CONFIG_FIXTURE, indent=2) + "\n")
STORAGE.parent.mkdir(parents=True, exist_ok=True)
STORAGE.write_text(json.dumps(STORAGE_FIXTURE, indent=2) + "\n")
def freeze() -> list:
os.environ["HOME"] = str(HOME)
os.environ["RUNE_PROVIDER_BUDGET_CORE"] = "python" # poisoned-truth law
import rune.provider_budget as pb # noqa: E402 — after HOME pin
from freeze_truth import freeze as harness_freeze # noqa: E402
cases = [
# Case 1: loaded-state tie-break — alpha vs delta both rem 7.0,
# stable sort keeps file insertion order → best_provider "alpha".
("get_status", (), {}),
# Mutations: known+cost, known default-cost (kwargs {}), unknown no-op.
("track_usage", ("alpha", 5000, 2.5), {}),
("track_usage", ("alpha", 1000), {}),
("track_usage", ("ghost", 100), {}),
# alpha now used 5.5 → rem 4.5 < delta 7.0 → best flips to delta.
("get_status", (), {}),
# Zero-token + pure-cost usage pushes alpha over budget (15.5 >= 10).
("track_usage", ("alpha", 0, 10.0), {}),
# Exhaustion arm: alpha over, beta over, gamma disabled → best delta.
("get_status", (), {}),
# Disable the last available provider → best None (failover None arm).
("failover", ("delta",), {}),
("get_best_provider", (), {}),
# Unknown-provider failover is a no-op (no disable, no save).
("failover", ("ghost",), {}),
# All-down status: best_provider null, delta.enabled false persisted.
("get_status", (), {}),
# check_provider not-found arm (no socket, no timestamp).
("check_provider", ("ghost",), {}),
# Disabled providers still accumulate tracked usage (parity quirk).
("track_usage", ("delta", 10, 0.25), {}),
]
pb._tracker = None # fresh singleton per phase
return harness_freeze("rune.provider_budget", cases, oracle_module="rune.provider_budget")
def main() -> int:
build_fixture_home()
truth = freeze()
OUT.write_text(json.dumps(truth, indent=2, ensure_ascii=False) + "\n")
print(f"frozen {len(truth)} cases → {OUT}")
# Self-verify: rebuild the canonical home (same initial state) and run
# the shared harness gate — must report byte-identical.
build_fixture_home()
env = dict(os.environ, HOME=str(HOME), PYTHONPATH=str(REPO / "src"))
r = subprocess.run(
[sys.executable, str(REPO / "scripts" / "freeze_truth.py"),
"--verify", str(OUT), "--module", "rune.provider_budget"],
env=env,
)
return r.returncode
if __name__ == "__main__":
sys.exit(main())
+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}")
+378
View File
@@ -0,0 +1,378 @@
#!/usr/bin/env python3
"""Freeze the dichotomy-wave gap-closing truth corpus for
src/rune/structural_store.py (contract BUILDER-2026-10-13T00:32:22Z-bc3aae-
factory-gap-ss, issue #2479 tranche).
LAW (poisoned-truth): RUNE_STRUCTURAL_CORE=python is pinned at the top —
truth is generated by the PYTHON ORACLE ONLY. Inputs are deep-copied before
every oracle call (no leakage between cases). The clock is pinned by
monkeypatching structural_store.now (no-clock law on the Rust side).
The frozen corpus is embedded VERBATIM in the crate's cfg(test) battery
(src/frozen_battery.rs, include_str!) and replayed by
scripts/check_structural_store_parity.py through the live FFI.
"""
import calendar
import copy
import json
import os
import sys
import tempfile
import time as _time
import types
from pathlib import Path
os.environ["RUNE_STRUCTURAL_CORE"] = "python" # poisoned-truth law
REPO = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO / "src"))
from rune import structural_store as ss # noqa: E402
FIXED_NOW = "2026-10-13T01:02:03Z"
FIXED_EPOCH = calendar.timegm(_time.strptime(FIXED_NOW, "%Y-%m-%dT%H:%M:%SZ"))
ss.now = lambda: FIXED_NOW # pin the clock
# snapshot() formats its stamp straight off time.strftime/gmtime — pin the
# module reference the oracle actually uses.
ss.time = types.SimpleNamespace(
gmtime=lambda: _time.gmtime(FIXED_EPOCH),
strftime=lambda fmt, t=None: _time.strftime(fmt, t if t is not None else _time.gmtime()),
)
OUT = (REPO / "src" / "rust" / "structural_store" / "src"
/ "frozen_ss_truth.json")
groups: dict[str, list] = {}
def case(group, name, args, expect):
groups.setdefault(group, []).append(
{"fn": group, "name": name, "args": args, "expect": expect})
def run(group, name, args, call):
"""Freeze one case: input deep-copied, oracle called, outcome recorded."""
frozen_args = copy.deepcopy(args)
try:
expect = {"ok": call(copy.deepcopy(args))}
except ValueError as exc:
expect = {"err": str(exc)}
case(group, name, frozen_args, expect)
def ent(id, kind="module", maturity="DECLARED", **kw):
e = {"id": id, "kind": kind, "maturity": maturity, "evidence_refs": []}
e.update(kw)
return e
def doc(*entities, rels=(), obs=(), **kw):
d = {"schema_version": 1, "generated_at": FIXED_NOW,
"entities": list(entities), "relationships": list(rels),
"observations": list(obs)}
d.update(kw)
return d
def rel(t, f, to, **kw):
r = {"type": t, "from": f, "to": to, "evidence_refs": ["ev"],
"observed_at": FIXED_NOW}
r.update(kw)
return r
def main():
# ── _sorted ─────────────────────────────────────────────────────────
for name, v in [
("dict_keys_sorted", {"b": 1, "a": {"z": 2, "y": [3, {"c": 4, "b": 5}]}}),
("list_of_dicts_by_canonical_form", [{"b": 2, "a": 1}, {"a": 9}, {"a": 1, "b": 2}, {}]),
("list_of_scalars", [3, 1, 2, "b", "a", True, None]),
("nested_lists", [[2], [1, 2], [1], []]),
("unicode_keys_and_values", {"é": "ü", "z": "a", "a": ["z", "é"]}),
("floats_and_ints", [1.5, 0.5, 2, 1, -1.25]),
("empty_containers", {"e": [], "f": {}, "g": [[]]}),
("dict_of_scalars_passthrough", {"x": 1, "y": "s", "z": None, "w": False}),
]:
run("sorted", name, {"value": v}, lambda a: ss._sorted(a["value"]))
# ── new_doc ─────────────────────────────────────────────────────────
run("new_doc", "basic", {"now": FIXED_NOW}, lambda a: ss.new_doc())
# ── _redact_secrets ─────────────────────────────────────────────────
for name, v in [
("exact_names", {"token": "t", "api_token": "t", "api_key": "t",
"apikey": "t", "password": "t", "secret": "t",
"auth_header": "t", "authorization": "t",
"credential": "t", "credentials": "t",
"private_key": "t", "access_token": "t",
"bearer": "t", "safe": "keep"}),
("substring_names", {"my_token": "t", "API_KEY": "t",
"user_password_hash": "t", "client_secret": "t",
"my_credentials_v2": "t", "token_count": "t"}),
("nested", {"a": {"token": "deep"}, "b": [{"password": "x"}, {"ok": 1}]}),
("non_secret_passthrough", {"a": 1, "b": "s", "c": None, "d": [1, 2]}),
("case_insensitive", {"Token": "t", "PASSWORD": "t"}),
]:
run("redact", name, {"value": v}, lambda a: ss._redact_secrets(a["value"]))
# ── save (byte law frozen from the real filesystem) ────────────────
with tempfile.TemporaryDirectory() as td:
def save_call(args):
p = ss.save(copy.deepcopy(args["doc"]),
Path(td) / args["name"] / "store.json")
return {"content": Path(p).read_text(), "doc": p and None}
# capture the mutated doc separately (save mutates schema_version in)
def save_case(name, d, expect_err=False):
args = {"doc": copy.deepcopy(d), "name": name}
try:
probe = copy.deepcopy(d)
p = ss.save(probe, Path(td) / name / "store.json")
content = Path(p).read_text()
expect = {"ok": {"content": content, "doc": probe}}
except ValueError as exc:
expect = {"err": str(exc)}
case("save", name, args, expect)
base = doc(ent("m:a"), rels=[rel("depends_on", "m:a", "m:b")], generated_at=FIXED_NOW)
save_case("full_doc", base)
save_case("no_schema_version", {k: v for k, v in base.items() if k != "schema_version"})
save_case("schema_one_float", {**base, "schema_version": 1.0})
save_case("schema_ninety_nine", {**base, "schema_version": 99})
save_case("schema_string", {**base, "schema_version": "x"})
save_case("secrets_redacted_on_disk", {**base, "credentials": {"token": "s3cret", "note": "x"}})
save_case("unicode_escaped", {**base, "note": "café ☕ — ok"})
save_case("empty_doc", {"schema_version": 1})
save_case("nested_empty", {**base, "ext": {"a": [], "b": {}}})
# ── canonical_digest ────────────────────────────────────────────────
dd = doc(ent("m:a"), rels=[rel("depends_on", "m:a", "m:b")])
run("digest", "basic", {"doc": dd}, lambda a: ss.canonical_digest(a["doc"]))
run("digest", "key_order_irrelevant",
{"doc": dd, "doc_reordered": {"entities": dd["entities"], "schema_version": 1,
"observations": dd["observations"],
"relationships": dd["relationships"],
"generated_at": dd["generated_at"]}},
lambda a: [ss.canonical_digest(a["doc"]), ss.canonical_digest(a["doc_reordered"])])
run("digest", "secret_never_changes_digest",
{"doc": {**dd, "token": "s3cret"}},
lambda a: [ss.canonical_digest(a["doc"]), ss.canonical_digest({**a["doc"], "token": "other"})])
run("digest", "unicode", {"doc": {**dd, "note": "é"}}, lambda a: ss.canonical_digest(a["doc"]))
# ── snapshot ────────────────────────────────────────────────────────
with tempfile.TemporaryDirectory() as td:
def snap_case(name, d, label, tag):
args = {"doc": copy.deepcopy(d), "dir": "snaps", "label": label, "tag": tag}
probe = copy.deepcopy(d)
p = ss.snapshot(probe, Path(td) / name / "snaps", label, tag=tag)
content = Path(p).read_text()
case("snapshot", name, args,
{"ok": {"path": "snaps/" + Path(p).name, "content": content, "doc": probe}})
snap_case("label_and_tag", dd, "l1", "deadbeef1234")
snap_case("no_label", dd, "", "deadbeef1234")
snap_case("empty_tag_is_noident", dd, "l1", "")
snap_case("short_tag", dd, "", "abc")
# ── alias ───────────────────────────────────────────────────────────
adoc = doc(ent("m:a"), ent("m:b"))
run("alias", "new_alias", {"doc": adoc, "cid": "m:a", "old": "m:old"},
lambda a: ss.alias(a["doc"], a["cid"], a["old"]))
run("alias", "idempotent",
{"doc": doc(ent("m:a", aliases=["m:old"])), "cid": "m:a", "old": "m:old"},
lambda a: ss.alias(a["doc"], a["cid"], a["old"]))
run("alias", "target_missing", {"doc": adoc, "cid": "m:zz", "old": "m:old"},
lambda a: ss.alias(a["doc"], a["cid"], a["old"]))
run("alias", "self_alias", {"doc": adoc, "cid": "m:a", "old": "m:a"},
lambda a: ss.alias(a["doc"], a["cid"], a["old"]))
run("alias", "via_alias_resolution",
{"doc": doc(ent("m:a", aliases=["m:old"])), "cid": "m:old", "old": "m:older"},
lambda a: ss.alias(a["doc"], a["cid"], a["old"]))
# ── spine_uri / resolve_uri ─────────────────────────────────────────
for name, eid in [("kind_name", "project:alpha"), ("no_colon", "alpha"),
("two_colons", "project:al:pha")]:
run("spine_uri", name, {"entity_id": eid}, lambda a: ss.spine_uri(a["entity_id"]))
for name, uri in [("ok", "spine://project/alpha"), ("no_slash", "spine://alpha"),
("wrong_scheme", "memory://project/alpha"), ("no_scheme", "project/alpha"),
("nested_slash", "spine://project/a/b")]:
run("resolve_uri", name, {"uri": uri}, lambda a: ss.resolve_uri(a["uri"]))
# ── _doc_authorities ────────────────────────────────────────────────
for name, d in [
("defaults_in", doc(ent("m:a"))),
("existing_untouched", {**doc(ent("m:a")), "authority_generations": {"p": {"generation": 2}}}),
]:
a = {"doc": copy.deepcopy(d)}
d2 = copy.deepcopy(d)
r = ss._doc_authorities(d2)
case("doc_authorities", name, a, {"ok": {"doc": d2, "ret": r}})
# ── authority_health ────────────────────────────────────────────────
run("authority_health", "empty", {"doc": doc(ent("m:a"))}, lambda a: ss.authority_health(a["doc"]))
run("authority_health", "populated",
{"doc": {**doc(ent("m:a")), "authority_generations": {
"z-proj": {"generation": 3, "status": "CURRENT", "last_success": FIXED_NOW,
"last_attempt": FIXED_NOW, "last_error": None, "observed": ["owns|a|b", "owns|c|d"]},
"a-proj": {"generation": 1, "status": "DEGRADED", "observed": []}}}},
lambda a: ss.authority_health(a["doc"]))
run("authority_health", "missing_fields",
{"doc": {**doc(ent("m:a")), "authority_generations": {"p": {}}}},
lambda a: ss.authority_health(a["doc"]))
# ── bind_task / task_entities ───────────────────────────────────────
for name, d, task_id, ids, ev in [
("with_evidence", doc(ent("m:a"), ent("m:b")), "T1", ["m:a", "m:b"], "ev-1"),
("fallback_evidence", doc(ent("m:a")), "T2", ["m:a"], ""),
("dedupes_relationships", doc(ent("m:a")), "T3", ["m:a", "m:a"], "ev"),
]:
a = {"doc": copy.deepcopy(d), "task_id": task_id, "entity_ids": ids, "evidence_ref": ev}
d2 = copy.deepcopy(d)
r = ss.bind_task(d2, task_id, copy.deepcopy(ids), ev)
case("bind_task", name, a, {"ok": {"doc": d2, "ret": r}})
tdoc = doc(ent("m:a"), ent("m:b"),
rels=[rel("affects", "task:T1", "m:b"), rel("affects", "task:T1", "m:a"),
rel("affects", "task:T9", "m:b")])
run("task_entities", "sorted_for_task", {"doc": tdoc, "task_id": "T1"},
lambda a: ss.task_entities(a["doc"], a["task_id"]))
run("task_entities", "no_bindings", {"doc": tdoc, "task_id": "TX"},
lambda a: ss.task_entities(a["doc"], a["task_id"]))
# ── impact_frontier (branch battery) ────────────────────────────────
def frontier_case(name, d, seeds, change_kind=None, max_level=2):
args = {"doc": copy.deepcopy(d), "seeds": seeds,
"change_kind": change_kind, "max_level": max_level}
run("impact_frontier", name, args,
lambda a: ss.impact_frontier(a["doc"], a["seeds"], max_level=a["max_level"],
change_kind=a["change_kind"]))
impl_doc = doc(
ent("m:core"), ent("m:app"), ent("m:lib"), ent("m:tests"), ent("m:deploy"),
rels=[
rel("depends_on", "m:app", "m:core"),
rel("implements", "m:app", "c:api"),
rel("implements", "m:lib", "c:api"),
rel("consumes", "m:core", "c:api"),
rel("verified_by", "m:app", "k:canary"),
rel("deployed_as", "m:core", "d:live"),
rel("documented_by", "m:core", "doc:r"),
rel("supersedes", "m:lib", "m:old"),
rel("consumed_by", "m:lib", "m:core"),
])
frontier_case("implementation_change", impl_doc, ["m:app"])
frontier_case("contract_change", impl_doc, ["c:api"])
frontier_case("contract_violation", impl_doc, ["c:api"], change_kind="contract_violation")
frontier_case("inferred_from_contract_kind", impl_doc, ["c:api"], change_kind=None)
frontier_case("stale_and_candidate_skipped",
doc(ent("m:a"), ent("m:b"), ent("m:c"),
rels=[rel("depends_on", "m:a", "m:b", status="STALE"),
rel("depends_on", "m:a", "m:c", status="CANDIDATE")]),
["m:a"])
frontier_case("non_obligation_never_expands",
doc(ent("m:a"), ent("m:b"),
rels=[rel("documented_by", "m:a", "m:b")]),
["m:a"])
frontier_case("consumed_by_reverse",
doc(ent("m:a"), ent("m:b"),
rels=[rel("consumed_by", "m:b", "m:a")]),
["m:a"])
frontier_case("level2_from_level1_and_contextual", impl_doc, ["m:core"])
frontier_case("multi_seed_dedup", impl_doc, ["m:app", "m:app", "m:core"])
frontier_case("alias_seed_kind",
doc(ent("c:api", kind="contract", aliases=["c:old"]),
ent("m:app"),
rels=[rel("implements", "m:app", "c:api")]),
["c:old"])
# ── record_observed_impact ──────────────────────────────────────────
for name, items in [
("basic", [{"entity": "m:a", "source": "test", "detail": "d", "authority": "ci"},
{"entity": "m:b"}]),
("empty_entity_skipped", [{"entity": "", "source": "x"}, {"entity": "m:a"}]),
("detail_truncated_300", [{"entity": "m:a", "detail": "x" * 500}]),
("detail_multibyte_truncated", [{"entity": "m:a", "detail": "é" * 400}]),
("defaults", [{"entity": "m:a"}]),
]:
d0 = doc(ent("m:a"), ent("m:b"))
a = {"doc": copy.deepcopy(d0), "task_id": "T1", "items": copy.deepcopy(items)}
d2 = copy.deepcopy(d0)
result = ss.record_observed_impact(d2, "T1", copy.deepcopy(items))
case("observed_impact", name, a, {"ok": {"doc": d2, "result": result}})
# ── predicted_vs_observed ───────────────────────────────────────────
pdoc = doc(ent("m:a"), ent("m:b"), ent("m:c"),
rels=[rel("depends_on", "m:a", "m:b"), rel("depends_on", "m:a", "m:c")])
pred = {"level0_direct": ["m:a"], "level1_obligations": ["m:b"],
"contracts": [], "level2_verification": []}
run("predicted_vs_observed", "miss_and_needless",
{"predicted": pred, "observed_doc": pdoc, "seeds": ["m:a"]},
lambda a: ss.predicted_vs_observed(a["predicted"], a["observed_doc"], a["seeds"]))
run("predicted_vs_observed", "exact_match",
{"predicted": {"level0_direct": ["m:a"], "level1_obligations": ["m:b", "m:c"],
"contracts": [], "level2_verification": []},
"observed_doc": pdoc, "seeds": ["m:a"]},
lambda a: ss.predicted_vs_observed(a["predicted"], a["observed_doc"], a["seeds"]))
# ── structural_events ───────────────────────────────────────────────
run("events", "full",
{"doc": doc(ent("m:a", observed_at=FIXED_NOW), ent("m:b", observed_at=FIXED_NOW),
rels=[rel("depends_on", "m:a", "m:b")],
obs=[{"kind": "superseded", "old": "x", "new": "y", "observed_at": FIXED_NOW}])},
lambda a: ss.structural_events(a["doc"]))
run("events", "observation_kind_default_and_type_override",
{"doc": doc(ent("m:a"),
obs=[{"note": "no kind"}, {"kind": "k1", "type": "explicit_type"}])},
lambda a: ss.structural_events(a["doc"]))
# ── diff ────────────────────────────────────────────────────────────
old = doc(ent("m:a"), ent("m:gone"), ent("m:same", identities={"p": 1}, maturity="DECLARED"),
rels=[rel("depends_on", "m:a", "m:gone")])
new = doc(ent("m:a"), ent("m:new"), ent("m:same", identities={"p": 2}, maturity="WIRED"),
rels=[rel("depends_on", "m:a", "m:new"), rel("depends_on", "m:a", "m:a")])
run("diff", "all_categories", {"old": old, "new": new}, lambda a: ss.diff(a["old"], a["new"]))
run("diff", "no_changes", {"old": old, "new": copy.deepcopy(old)},
lambda a: ss.diff(a["old"], a["new"]))
# ── dedupe_observations ─────────────────────────────────────────────
for name, d in [
("exact_dups", doc(ent("m:a"), obs=[{"kind": "k", "x": 1}, {"x": 1, "kind": "k"},
{"kind": "k", "x": 2}])),
("nested_dups", doc(ent("m:a"), obs=[{"a": {"z": 1, "b": [2]}}, {"a": {"b": [2], "z": 1}}])),
("empty", doc(ent("m:a"))),
]:
a = {"doc": copy.deepcopy(d)}
d2 = copy.deepcopy(d)
r = ss.dedupe_observations(d2)
case("dedupe", name, a, {"ok": {"doc": d2, "ret": r}})
# ── fixed-kernel regressions (oracle parity proofs) ─────────────────
for name, d, eid, state, ev, ret in [
("unknown_entity_returns_none", doc(ent("m:a")), "m:zz", "PRESENT", "e", None),
("via_alias", doc(ent("m:a", aliases=["m:old"])), "m:old", "PRESENT", "e", "PRESENT"),
("missing_entity_beats_bad_state", doc(ent("m:a")), "m:zz", "BOGUS", "", None),
("demotion_recorded", doc(ent("m:a", maturity="PRESENT")), "m:a", "DECLARED", "e2", "PRESENT"),
]:
a = {"doc": copy.deepcopy(d), "id": eid, "state": state, "ev": ev}
d2 = copy.deepcopy(d)
r = ss.promote(d2, eid, state, ev)
case("promote_fix", name, a, {"ok": {"ret": r, "doc": d2}})
run("resolve_status_fix", "status_verbatim",
{"entity": {"status": "WEIRD"}}, lambda a: ss.resolve_status(a["entity"]))
run("resolve_status_fix", "empty_conflicts_not_conflicting",
{"entity": {"maturity": "DECLARED", "ext": {"conflicts": []}}},
lambda a: ss.resolve_status(a["entity"]))
for name, d, nid, oid in [
("rel_has_observed_at", doc(ent("m:a"), ent("m:b")), "m:b", "m:a"),
("via_alias", doc(ent("m:a", aliases=["m:old"]), ent("m:b")), "m:b", "m:old"),
]:
a = {"doc": copy.deepcopy(d), "new": nid, "old": oid, "ev": "ev-s"}
d2 = copy.deepcopy(d)
ss.supersede(d2, nid, oid, "ev-s")
case("supersede_fix", name, a, {"ok": {"doc": d2}})
out = {"module": "structural_store", "now": FIXED_NOW, "groups": groups}
OUT.write_text(json.dumps(out, indent=1, sort_keys=True) + "\n")
total = sum(len(v) for v in groups.values())
print(f"frozen {total} cases across {len(groups)} groups -> {OUT}")
if __name__ == "__main__":
main()
+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 the #2479 dichotomy-wave gap-closing construction contract for
structural_store (PARTIAL → ≥80% fn coverage). Walks draft→approved→building
in ONE process (shared-store clobber hazard).
Usage: open_contract_gap_ss.py
"""
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-ss")
r = iface.submit_need(
"Close structural_store PARTIAL gaps (dichotomy wave, issue #2479 "
"tranche): port the 21 audit-missing functions name-preserving to the "
"existing Rust crate (doc-envelope FFI ss_*, ctypes loader mirroring "
"broker_loader.py, facade delegation with RUNE_STRUCTURAL_CORE=python "
"pin), frozen-truth battery generated against the live oracle, live "
"parity 100% on new fns, Phase B language-advantage pass.",
origin="builder",
)
print("submit_need:", json.dumps(r)[:400])
if not r.get("success"):
print("NEED FAILED — aborting")
sys.exit(1)
c = r["ids"]["contract_id"]
print("contract_id:", c)
for phase in ("approved", "building"):
t = iface.transition(c, phase)
print(f"transition->{phase}:", json.dumps(t)[:300])
if not t.get("success"):
sys.exit(1)
print("OPENED", c)
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Open the #2479 dichotomy-wave construction contract for night_mode.
Full lifecycle in ONE process (shared-store clobber hazard)."""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from rune.construction_interface import ConstructionInterface
iface = ConstructionInterface(builder="factory-gap-nm")
r = iface.submit_need(
"Close the night_mode dichotomy PARTIAL gaps (audit-named): Go port "
"of _ctx_budget, get_night_mode, start_night_mode, stop_night_mode, "
"get_status, get_report, to_dict, _load, _save, _run_loop, _run_sleep, "
"_run_evaluation (name-preserving, logic 1:1) in src/go/night-mode; "
"pure/IO split law with injectable clock/sleeper/runner/HTTP seams; "
"frozen-oracle truth battery via shared freeze_truth.py embedded "
"VERBATIM in Go tests; live parity 100% on new fns; Python facade "
"stays fully functional (RUNE_NIGHT_MODE_CORE=python pin + auto "
"both green).",
origin="builder",
)
print("submit_need:", json.dumps(r)[:400])
if not r.get("success"):
print("NEED FAILED — aborting"); sys.exit(1)
cid = r["ids"]["contract_id"]
print("contract_id:", cid)
for phase in ("approved", "building", "verifying"):
t = iface.transition(cid, phase)
print(f"transition->{phase}:", json.dumps(t)[:300])
if not t.get("success"):
sys.exit(1)
print("PENDING_CONTRACT", cid)
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""Live parity — provider_budget python oracle vs the GO port (gap-closing
wave #2479). Random op script (seed 2479: track_usage / failover / best /
status over the fixture pool) applied to BOTH implementations against the
same canonical fixture home; get_status after every op must match.
check_provider is excluded (live sockets + wall-clock stamps are reactive
surface, pinned by the Go seam battery instead).
"""
import json
import os
import random
import subprocess
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 / "scripts"))
import gen_provider_budget_truth as gen # noqa: E402
SEED = 2479
OPS = 200
GO_DIR = REPO / "src" / "go" / "provider-budget"
def build_ops() -> list[dict]:
rng = random.Random(SEED)
names = ["alpha", "beta", "gamma", "delta", "ghost"]
ops = []
for _ in range(OPS):
kind = rng.choices(
["track_usage", "failover", "best", "status"], weights=[6, 2, 1, 1]
)[0]
if kind == "track_usage":
ops.append({
"op": "track_usage",
"name": rng.choice(names),
"tokens": rng.randrange(0, 2000),
"cost": round(rng.uniform(0, 3), 4),
})
elif kind == "failover":
ops.append({"op": "failover", "name": rng.choice(names)})
else:
ops.append({"op": kind})
return ops
def run_python(ops: list[dict]) -> list[dict]:
gen.build_fixture_home()
os.environ["HOME"] = str(gen.HOME)
os.environ["RUNE_PROVIDER_BUDGET_CORE"] = "python" # poisoned-truth law
import rune.provider_budget as pb
pb._tracker = None
want = []
for op in ops:
kind = op["op"]
if kind == "track_usage":
pb.track_usage(op["name"], op["tokens"], op["cost"])
elif kind == "failover":
pb.failover(op["name"])
elif kind == "best":
pb.get_best_provider()
elif kind == "status":
pb.get_status()
else:
raise ValueError(f"unknown op {kind}")
want.append(pb.get_status())
return want
def run_go(ops: list[dict]) -> list[dict]:
gen.build_fixture_home()
ops_file = Path("/tmp/rune_pb_parity_ops.json")
ops_file.write_text(json.dumps(ops))
r = subprocess.run(
["go", "run", ".", "parity", str(ops_file), str(gen.HOME)],
cwd=GO_DIR, capture_output=True, text=True,
)
if r.returncode != 0:
print(r.stderr, file=sys.stderr)
sys.exit(1)
return [json.loads(line) for line in r.stdout.splitlines() if line.strip()]
def main() -> int:
ops = build_ops()
want = run_python(ops)
got = run_go(ops)
fails = 0
for i, (w, g) in enumerate(zip(want, got)):
if w != g:
fails += 1
if fails <= 3:
print(f"op {i} ({ops[i]['op']}) diverged:")
print(f" want {json.dumps(w, sort_keys=True)[:240]}")
print(f" got {json.dumps(g, sort_keys=True)[:240]}")
print(f"parity: {len(want) - fails}/{len(want)} ops identical (seed {SEED})")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""Open + walk the #2479 dichotomy-wave construction contract for the
provider_budget gap-closing port to verifying. Full lifecycle in ONE
process (close happens after the commits land, with SHA evidence)."""
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-pb")
r = iface.submit_need(
"Close the provider_budget dichotomy gaps (#2479 tranche, GO side): "
"port the 10 audit-missing functions (get_tracker/track_usage/"
"check_provider/get_best_provider/failover/get_status/to_dict/_load/"
"_save/_init_default_providers) name-preserving into the existing "
"src/go/provider-budget Go port — tracker with order-preserving "
"storage load (dict-order tie-break parity), config seeding "
"(ollama skip + anthropic type detection), per-type health-check "
"endpoints with IO behind injectable seams (clock, config path, "
"transport), api_key-excluding to_dict, module-level singleton "
"wrappers. Truth frozen via the shared freeze_truth.py harness "
"(RUNE_PROVIDER_BUDGET_CORE=python, fixture-home replay contract); "
"VERBATIM-embedded Go battery; 200-op live parity seed 2479; "
"Python port test (oracle pinned + harness gate); audit 5/20 → 20/20.",
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")
+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": []
}
+379
View File
@@ -0,0 +1,379 @@
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"
"strings"
"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
// DispatchGap — replay one frozen call through the ported function;
// return the JSON-comparable result and the post-call state pointer.
// Lives in production code (not a _test file) so ReplayPipeline builds
// under `go build` too. The _save_state case is IO-backed: callers that
// need byte-output parity use SaveState directly with their own dir.
func DispatchGap(state *BuildState, fn string, args []interface{}, stamp string) (result interface{}, outState *BuildState, err error) {
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, nil
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":
// IO seam: the serial battery covers save-bytes via SaveState
// with a test-owned dir; here persist to a throwaway dir for
// state-shape parity only.
dir, derr := os.MkdirTemp("", "gapreplay")
if derr != nil {
return nil, state, derr
}
defer os.RemoveAll(dir)
if serr := SaveState(state, dir); serr != nil {
return nil, state, serr
}
return nil, state, nil
case "get_resume_point":
rp := ResumePoint(state)
if rp == "" {
return nil, state, nil // Python None
}
return rp, state, nil
case "can_resume":
return CanResume(state), state, nil
case "get_status":
return BuildStatus(state), state, nil
default:
return nil, state, fmt.Errorf("unknown frozen fn %q", fn)
}
return nil, state, nil
}
// MustJSON — marshal for comparison (nil-safe: nil → "null", matching
// the oracle's None).
func MustJSON(v interface{}) []byte {
if v == nil {
return []byte("null")
}
b, _ := json.Marshal(v)
return b
}
// ArgMap / StrList / ObjList — typed JSON accessors for the frozen
// battery args (production helpers: DispatchGap needs them under
// `go build`, not just under `go test`).
func ArgMap(v interface{}) map[string]interface{} {
m, _ := v.(map[string]interface{})
return m
}
func StrList(v interface{}) []string {
arr, ok := v.([]interface{})
if !ok {
return nil
}
out := make([]string, 0, len(arr))
for _, e := range arr {
s, _ := e.(string)
out = append(out, s)
}
return out
}
func ObjList(v interface{}) []map[string]interface{} {
arr, ok := v.([]interface{})
if !ok {
return nil
}
out := make([]map[string]interface{}, 0, len(arr))
for _, e := range arr {
m, _ := e.(map[string]interface{})
out = append(out, m)
}
return out
}
// 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, derr := DispatchGap(state, c.Fn, c.Args, stamp)
if derr != nil {
t.Errorf("case %d dispatch: %v", i, derr)
return
}
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,191 @@
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"
"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 — thin test wrapper over the production DispatchGap: keeps
// the serial battery's call shape; the _save_state case uses the test's
// own TempDir (byte-output parity) instead of DispatchGap's throwaway dir.
func dispatchGap(t *testing.T, state *BuildState, fn string, args []interface{}, stamp string) (result interface{}, outState *BuildState) {
t.Helper()
if fn == "BuildManager._save_state" {
dir := t.TempDir()
if err := SaveState(state, dir); err != nil {
t.Fatalf("save: %v", err)
}
return nil, state
}
got, gotState, err := DispatchGap(state, fn, args, stamp)
if err != nil {
t.Fatalf("dispatch %q: %v", fn, err)
}
return got, gotState
}
// 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)
}
+420
View File
@@ -0,0 +1,420 @@
package main
// broker.go — the ContextBroker orchestration core (admission, collection,
// rendering) from src/rune/context_broker.py, gap-close dichotomy wave.
// The Python class stays the runtime authority; this is the deterministic
// kernel with the contributor callbacks and failure recorder injectable.
import (
"errors"
"fmt"
"sort"
"sync"
)
// MemoryBlockNames — blocks that count as "memory" for the absence proof.
var MemoryBlockNames = map[string]bool{
"memory": true, "persona_memories": true, "consolidated": true,
}
// ErrContextOverflow — one block alone exceeds the input budget (fail loud).
var ErrContextOverflow = errors.New("context overflow")
// ContributionBlock — a typed, measurable piece of context. Content is
// either a string (system/user text) or []Message (history messages).
type ContributionBlock struct {
Name string
Priority int
Content interface{}
Tokens int
Source string
Evictable bool
}
// ToDict — serialize for pending_state embedding (P1-02 #25).
func (b *ContributionBlock) ToDict() map[string]interface{} {
return map[string]interface{}{
"name": b.Name,
"priority": b.Priority,
"content": b.Content,
"tokens": b.Tokens,
"source": b.Source,
"evictable": b.Evictable,
}
}
// ContributorFunc — callback(task, session) → block or nil.
type ContributorFunc func(task, session map[string]interface{}) *ContributionBlock
// FailureRecorder is the T1 record_failure seam (oracle: subsystem_health).
type FailureRecorder func(name string, err error)
// Contributor — a named registry entry with its priority bucket.
type Contributor struct {
Name string
Callback ContributorFunc
Bucket int
}
// ContextBroker — admission-controlled context assembler (Go kernel).
type ContextBroker struct {
mu sync.Mutex
contributors []Contributor
traces []map[string]interface{}
Estimator func(string) int
BudgetResolver func(int) int
Fail FailureRecorder
}
// NewContextBroker wires the defaults.
func NewContextBroker() *ContextBroker {
return &ContextBroker{
Estimator: DefaultEstimator,
BudgetResolver: DefaultBudget,
Fail: func(string, error) {},
}
}
// RegisterContributor names a contributor.
func (cb *ContextBroker) RegisterContributor(name string, callback ContributorFunc, bucket int) {
cb.mu.Lock()
defer cb.mu.Unlock()
cb.contributors = append(cb.contributors, Contributor{Name: name, Callback: callback, Bucket: bucket})
}
// TraceLog returns a shallow copy of every assemble trace (thread-safe).
func (cb *ContextBroker) TraceLog() []map[string]interface{} {
cb.mu.Lock()
defer cb.mu.Unlock()
out := make([]map[string]interface{}, len(cb.traces))
copy(out, cb.traces)
return out
}
// Collect runs contributors in registration order; failures are T1 events
// (one pass, lock held — side effects run exactly once per turn). Skips nil
// blocks and empty string content; malformed content (neither string nor a
// list of message dicts) is a T1 failure too (I5).
func (cb *ContextBroker) Collect(task, session map[string]interface{}) (collected []struct {
Name string
Block *ContributionBlock
Bucket int
}, degraded []string) {
cb.mu.Lock()
contributors := make([]Contributor, len(cb.contributors))
copy(contributors, cb.contributors)
cb.mu.Unlock()
degradedSet := map[string]bool{}
for _, c := range contributors {
block, err := func() (block *ContributionBlock, err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
err = e
} else {
err = fmt.Errorf("%v", r)
}
}
}()
return c.Callback(task, session), nil
}()
if err != nil {
cb.Fail(c.Name, err)
if !degradedSet[c.Name] {
degradedSet[c.Name] = true
degraded = append(degraded, c.Name)
}
continue
}
if block == nil {
continue
}
if s, isStr := block.Content.(string); isStr && s == "" {
continue
}
if !contentOK(block.Content) {
err := fmt.Errorf("contributor %q returned malformed content: %T", c.Name, block.Content)
cb.Fail(c.Name, err)
if !degradedSet[c.Name] {
degradedSet[c.Name] = true
degraded = append(degraded, c.Name)
}
continue
}
collected = append(collected, struct {
Name string
Block *ContributionBlock
Bucket int
}{c.Name, block, c.Bucket})
}
return collected, degraded
}
func contentOK(content interface{}) bool {
if s, isStr := content.(string); isStr {
return s != "" || true
}
list, isList := content.([]interface{})
if isList {
for _, item := range list {
m, isMap := item.(map[string]interface{})
if !isMap {
return false
}
if _, has := m["content"]; !has {
return false
}
}
return true
}
if _, isMsgs := content.([]Message); isMsgs {
return true
}
return false
}
// AdmissionEntry — one collected block paired with its registration name.
type AdmissionEntry struct {
Name string
Block *ContributionBlock
}
// TraceRecord — per-block admission trace row.
type TraceRecord struct {
Name string `json:"name"`
Priority int `json:"priority"`
Tokens int `json:"tokens"`
Source string `json:"source"`
Evictable bool `json:"evictable"`
Admitted bool `json:"admitted"`
Reason string `json:"reason"`
}
// AdmissionResult — admitted blocks + the full trace dict.
type AdmissionResult struct {
Admitted []*ContributionBlock
Blocks []TraceRecord
AdmittedTotal int
Dropped []TraceRecord
MemoryBudget int
MemoryUsed int
}
// Admit — deterministic admission: priority desc, tie: registration recency.
// Non-evictable blocks always admit first (overflow → ErrContextOverflow);
// evictable blocks admit while the budget lasts; memory-scope blocks are
// additionally bounded by the memory sub-budget (P1-03 #26).
func Admit(entries []AdmissionEntry, budget int, memoryBudget int) (*AdmissionResult, error) {
if memoryBudget < 0 {
memoryBudget = DefaultMemoryBudget(0)
}
type keyed struct {
idx int
entry AdmissionEntry
}
items := make([]keyed, len(entries))
for i, e := range entries {
items[i] = keyed{i, e}
}
sort.SliceStable(items, func(a, b int) bool {
ba, bb := items[a].entry.Block, items[b].entry.Block
ka, kb := 0, 0
if ba.Evictable {
ka = 1
}
if bb.Evictable {
kb = 1
}
if ka != kb {
return ka < kb
}
if ba.Priority != bb.Priority {
return ba.Priority > bb.Priority
}
return items[a].idx < items[b].idx
})
res := &AdmissionResult{MemoryBudget: memoryBudget}
used, memoryUsed := 0, 0
for _, it := range items {
block := it.entry.Block
record := TraceRecord{
Name: block.Name, Priority: block.Priority, Tokens: block.Tokens,
Source: block.Source, Evictable: block.Evictable,
Admitted: true,
}
if !block.Evictable {
if block.Tokens > budget {
return nil, fmt.Errorf("mandatory block '%s' needs %d tokens but the input budget is %d — refusing to silently truncate: %w",
block.Name, block.Tokens, budget, ErrContextOverflow)
}
res.Admitted = append(res.Admitted, block)
used += block.Tokens
res.Blocks = append(res.Blocks, record)
continue
}
inMemoryScope := MemoryBlockNames[block.Name]
if inMemoryScope && used+block.Tokens <= budget && memoryUsed+block.Tokens > memoryBudget {
record.Admitted = false
record.Reason = fmt.Sprintf("memory budget: %d+%d>%d (memory sub-budget exhausted; lowest-priority memory dropped)",
memoryUsed, block.Tokens, memoryBudget)
res.Blocks = append(res.Blocks, record)
continue
}
if used+block.Tokens <= budget {
res.Admitted = append(res.Admitted, block)
used += block.Tokens
if inMemoryScope {
memoryUsed += block.Tokens
}
res.Blocks = append(res.Blocks, record)
} else {
record.Admitted = false
record.Reason = fmt.Sprintf("budget: %d+%d>%d (lowest-priority evictable dropped)",
used, block.Tokens, budget)
res.Blocks = append(res.Blocks, record)
}
}
for _, record := range res.Blocks {
if !record.Admitted {
res.Dropped = append(res.Dropped, record)
}
}
res.AdmittedTotal = used
res.MemoryUsed = memoryUsed
return res, nil
}
// Capsule — the rendered attention capsule.
type Capsule struct {
TokenCount int
Blocks []*ContributionBlock
Messages []map[string]interface{}
SystemPreamble string
UserContent string
}
// Render — admitted blocks into the typed capsule (fixed message order:
// system -> tools -> memory/notes -> history -> user via priority sort).
func Render(admitted []*ContributionBlock) *Capsule {
type keyed struct {
idx int
block *ContributionBlock
}
items := make([]keyed, len(admitted))
for i, b := range admitted {
items[i] = keyed{i, b}
}
sort.SliceStable(items, func(a, b int) bool {
if items[a].block.Priority != items[b].block.Priority {
return items[a].block.Priority > items[b].block.Priority
}
return items[a].idx < items[b].idx
})
var systemParts []string
var history []map[string]interface{}
var userBlock *ContributionBlock
var capsuleBlocks []*ContributionBlock
totalTokens := 0
for _, it := range items {
block := it.block
totalTokens += block.Tokens
capsuleBlocks = append(capsuleBlocks, block)
if s, isStr := block.Content.(string); isStr {
if block.Name == "user" {
userBlock = block
} else {
systemParts = append(systemParts, s)
}
} else {
switch list := block.Content.(type) {
case []Message:
for _, m := range list {
history = append(history, deepCopyMap(m))
}
case []interface{}:
for _, item := range list {
if m, ok := item.(map[string]interface{}); ok {
history = append(history, deepCopyMap(m))
}
}
}
}
}
systemPrompt := ""
for i, p := range systemParts {
if i > 0 {
systemPrompt += "\n"
}
systemPrompt += p
}
rendered := make([]map[string]interface{}, 0, len(history)+1)
if systemPrompt != "" {
rendered = append(rendered, map[string]interface{}{"role": "system", "content": systemPrompt})
}
rendered = append(rendered, history...)
userContent := ""
if userBlock != nil {
userContent, _ = userBlock.Content.(string)
}
return &Capsule{
TokenCount: totalTokens,
Blocks: capsuleBlocks,
Messages: rendered,
SystemPreamble: systemPrompt,
UserContent: userContent,
}
}
func deepCopyMap(m map[string]interface{}) map[string]interface{} {
out := make(map[string]interface{}, len(m))
for k, v := range m {
if vm, ok := v.(map[string]interface{}); ok {
out[k] = deepCopyMap(vm)
} else if vl, ok := v.([]interface{}); ok {
out[k] = deepCopyList(vl)
} else {
out[k] = v
}
}
return out
}
func deepCopyList(l []interface{}) []interface{} {
out := make([]interface{}, len(l))
for i, v := range l {
if vm, ok := v.(map[string]interface{}); ok {
out[i] = deepCopyMap(vm)
} else if vl, ok := v.([]interface{}); ok {
out[i] = deepCopyList(vl)
} else {
out[i] = v
}
}
return out
}
func blockNames(blocks []*ContributionBlock) []string {
out := make([]string, 0, len(blocks))
for _, b := range blocks {
out = append(out, b.Name)
}
return out
}
// BuildMemorySelector — the memory-selection authority composition
// (_build_memory_selector, P1-03 #26). Fail-closed: any construction error
// returns nil and the memory contributor abstains — never a fallback
// injection. The selector itself stays Python (rune.memory_selector).
func BuildMemorySelector(ctor func() (interface{}, error)) interface{} {
sel, err := ctor()
if err != nil {
return nil
}
return sel
}
+708 -13
View File
@@ -1,20 +1,61 @@
// Package main — context-broker: the GO port of src/rune/context_broker.py's
// budget/estimator kernels (Oracle-Battery Parity Pattern, #2479 GO batch 38).
// budget/estimator kernels (Oracle-Battery Parity Pattern, #2479 GO batch 38;
// gap-close dichotomy wave — factory-gap-ctxbroker).
// The ContextBroker itself stays Python (it's the orchestration authority);
// the budget math is the deterministic core.
// the budget math is the deterministic core. The gap-close ports the missing
// functions name-preserving: the _py_* parity-floor oracles, the discovered-
// window registry, the rolling-summary store, _through_id, log_calibration,
// and the compact_history/summarize_history state machines with IO behind
// injectable seams (Estimator/Summarizer/Discoverer funcs, Archiver writer).
package main
import (
"crypto/sha256"
"encoding/json"
"fmt"
"math"
"os"
"sort"
"strconv"
"strings"
"sync"
)
// defaultEstimator — chars/4 (code-point parity with Python len()).
func defaultEstimator(text string) int { return len([]rune(text)) / 4 }
// ── estimator / budget kernels ──────────────────────────────────────────────
// defaultBudget — window - max(2048, window/4) - window/20, floored at 1.
func defaultBudget(window int) int {
// DefaultEstimator — chars/4 (code-point parity with Python len()).
func DefaultEstimator(text string) int { return len([]rune(text)) / 4 }
// PyDefaultEstimator — the Python parity-floor oracle (_py_default_estimator).
// Python: len(text or "") // 4 — None coerces to "".
func PyDefaultEstimator(text *string) int {
if text == nil {
return 0
}
return len([]rune(*text)) / 4
}
// CcCore — the cognition-core availability seam (_cc_core). The Go port IS
// the core, so the Python-pin question collapses: RUNE_COGNITION_CORE=python
// pins the Python floor (the caller compares against it), anything else with
// the Go core linked is available. Env read is injectable via CcCoreEnv.
var CcCoreEnv = os.LookupEnv
// CcCore reports whether the native core would be used under the given env.
// Mirrors the oracle's branch shape: pin -> None; loader probe failure -> None.
func CcCore(lookup func(string) (string, bool), loaderAvailable bool) *bool {
if v, ok := lookup("RUNE_COGNITION_CORE"); ok && v == "python" {
return nil
}
if !loaderAvailable {
return nil
}
avail := true
return &avail
}
// DefaultBudget — window - max(2048, window/4) - window/20, floored at 1.
func DefaultBudget(window int) int {
reserve := window / 4
if reserve < 2048 {
reserve = 2048
@@ -26,10 +67,13 @@ func defaultBudget(window int) int {
return r
}
// PyDefaultBudget — the Python parity-floor oracle (_py_default_budget).
func PyDefaultBudget(window int) int { return DefaultBudget(window) }
const MemoryBudgetCap = 1200
// defaultMemoryBudget — min(cap, window/8); window<=0 → CAP.
func defaultMemoryBudget(window int) int {
// DefaultMemoryBudget — min(cap, window/8); window<=0 → CAP.
func DefaultMemoryBudget(window int) int {
if window <= 0 {
return MemoryBudgetCap
}
@@ -40,6 +84,536 @@ func defaultMemoryBudget(window int) int {
return r
}
// PyDefaultMemoryBudget — the Python parity-floor oracle
// (_py_default_memory_budget). Python: `if not window or window <= 0`.
func PyDefaultMemoryBudget(window int) int { return DefaultMemoryBudget(window) }
// PyMemoryDisabledValue — the Python parity-floor oracle over the RAW string
// (_py_memory_disabled_value): truthy unless in the falsy set.
func PyMemoryDisabledValue(value string) bool {
switch value {
case "", "0", "false", "no", "off":
return false
}
return true
}
// MemoryDisabled — the full gate (memory_disabled): Python cross-check ANDed
// with the native verdict when the core is live.
func MemoryDisabled(raw string, coreDisabled bool) bool {
gate := PyMemoryDisabledValue(raw)
return coreDisabled && gate
}
// ── discovered-window registry (reset_discovered_windows/register_window/
// default_window) — process-local registry, live discovery injectable ────
const FallbackWindow = 8192
var (
discoveredMu sync.Mutex
discovered = map[string]int{}
)
// DiscoverWindow is the injectable seam for live context-length discovery
// (the oracle imports rune.local_tool_runtime.context_length). nil = no
// discovery available (offline), which freezes the fallback branch.
var DiscoverWindow func(modelID string) int
// ResetDiscoveredWindows clears the discovered-window registry (I3).
func ResetDiscoveredWindows() {
discoveredMu.Lock()
defer discoveredMu.Unlock()
discovered = map[string]int{}
}
// RegisterWindow records a discovered context length for modelID (Task 2).
func RegisterWindow(modelID string, window int) {
discoveredMu.Lock()
defer discoveredMu.Unlock()
discovered[modelID] = window
}
// DefaultWindow resolves the model window via the registry, then live
// discovery, then the conservative fallback. The fallback (8192) never
// enters the cache (C3: a transient discovery failure must not poison the
// window for the process lifetime).
func DefaultWindow(modelID string) int {
discoveredMu.Lock()
d := DiscoverWindow
discoveredMu.Unlock()
return resolveWindow(modelID, d)
}
// resolveWindow — the discovery-injectable core of DefaultWindow; the
// discover func is captured per call so concurrent resolvers never swap a
// shared global.
func resolveWindow(modelID string, discover func(string) int) int {
if modelID == "" {
return FallbackWindow
}
discoveredMu.Lock()
w, ok := discovered[modelID]
discoveredMu.Unlock()
if ok {
return w
}
if discover == nil {
return FallbackWindow
}
window := discover(modelID)
if window != 0 && window != FallbackWindow {
RegisterWindow(modelID, window)
}
return window
}
// ── rolling-summary store (C1/#141) ─────────────────────────────────────────
// RollingState — the persisted rolling summary for one session key.
type RollingState struct {
Summary string `json:"summary"`
ThroughCount int `json:"through_count"`
ThroughID string `json:"through_id"`
}
var (
rollingMu sync.Mutex
rolling = map[string]*RollingState{} // key: source + "\x00" + session_id
)
func rollingKey(source, sessionID string) string { return source + "\x00" + sessionID }
// RollingSummaryState returns the persisted rolling summary for a session
// (deep-copied), or nil.
func RollingSummaryState(source, sessionID string) *RollingState {
rollingMu.Lock()
defer rollingMu.Unlock()
st, ok := rolling[rollingKey(source, sessionID)]
if !ok {
return nil
}
cp := *st
return &cp
}
// StoreRollingSummary persists a rolling summary keyed by (source, sessionID).
func StoreRollingSummary(source, sessionID, summaryText string, throughCount int, throughID string) {
rollingMu.Lock()
defer rollingMu.Unlock()
rolling[rollingKey(source, sessionID)] = &RollingState{
Summary: summaryText,
ThroughCount: throughCount,
ThroughID: throughID,
}
}
// EvictRolling — LRU (insertion-order) eviction for dead sessions; returns
// the evicted count.
func EvictRolling(maxSessions int) int {
rollingMu.Lock()
defer rollingMu.Unlock()
if len(rolling) <= maxSessions {
return 0
}
keys := make([]string, 0, len(rolling))
for k := range rolling {
keys = append(keys, k)
}
sort.Strings(keys) // deterministic order (Python relies on dict insertion order)
drop := len(rolling) - maxSessions
for _, k := range keys[:drop] {
delete(rolling, k)
}
return drop
}
// ThroughID — identity of the coverage boundary: first 16 hex chars of the
// sha256 of the first message BEYOND coverage (content, not position —
// rotation-proof, #141). Empty when the boundary is outside the list.
func ThroughID(messages []map[string]interface{}, throughCount int) string {
if throughCount < 0 || throughCount >= len(messages) {
return ""
}
anchor := messages[throughCount]
sum := sha256.Sum256([]byte(pyDumpsSorted(anchor)))
return fmt.Sprintf("%x", sum[:])[:16]
}
// pyDumpsSorted renders json.dumps(anchor, sort_keys=True) byte-for-byte:
// separators ", " / ": ", ensure_ascii escaping, Python literal literals.
func pyDumpsSorted(v interface{}) string {
var b strings.Builder
writePyJSON(&b, v)
return b.String()
}
func writePyJSON(b *strings.Builder, v interface{}) {
switch val := v.(type) {
case nil:
b.WriteString("null")
case bool:
if val {
b.WriteString("true")
} else {
b.WriteString("false")
}
case float64:
b.WriteString(pyFloat(val))
case int:
b.WriteString(fmt.Sprintf("%d", val))
case string:
writePyString(b, val)
case []interface{}:
b.WriteString("[")
for i, item := range val {
if i > 0 {
b.WriteString(", ")
}
writePyJSON(b, item)
}
b.WriteString("]")
case map[string]interface{}:
keys := make([]string, 0, len(val))
for k := range val {
keys = append(keys, k)
}
sort.Strings(keys)
b.WriteString("{")
for i, k := range keys {
if i > 0 {
b.WriteString(", ")
}
writePyString(b, k)
b.WriteString(": ")
writePyJSON(b, val[k])
}
b.WriteString("}")
default:
blob, _ := json.Marshal(val)
b.Write(blob)
}
}
func pyFloat(f float64) string {
if f == float64(int64(f)) && math.Abs(f) < 1e15 {
// integral numbers via JSON can only originate as Python ints —
// json.dumps renders int(3) as "3", never "3.0"
return fmt.Sprintf("%d", int64(f))
}
return strconv.FormatFloat(f, 'g', -1, 64)
}
func writePyString(b *strings.Builder, s string) {
b.WriteByte('"')
for _, r := range s {
switch r {
case '"':
b.WriteString("\\\"")
case '\\':
b.WriteString("\\\\")
case '\n':
b.WriteString("\\n")
case '\r':
b.WriteString("\\r")
case '\t':
b.WriteString("\\t")
case '\b':
b.WriteString("\\b")
case '\f':
b.WriteString("\\f")
default:
if r < 0x20 || r > 0x7e {
if r > 0xffff {
r2 := r - 0x10000
hi := 0xd800 + (r2 >> 10)
lo := 0xdc00 + (r2 & 0x3ff)
fmt.Fprintf(b, "\\u%04x\\u%04x", hi, lo)
} else {
fmt.Fprintf(b, "\\u%04x", r)
}
} else {
b.WriteRune(r)
}
}
}
b.WriteByte('"')
}
// LogCalibration — compare the broker estimate with the served
// prompt_eval_count. LOG ONLY (drift never feeds admission). Returns the
// signed drift; 0 when nothing was served.
func LogCalibration(measuredTokens int, promptEvalCount *int, model string) int {
if promptEvalCount == nil || *promptEvalCount == 0 {
return 0
}
return *promptEvalCount - measuredTokens
}
// ── compaction state machine (compact_history) ──────────────────────────────
// Compaction thresholds (mirrors the oracle constants).
const (
CompactionThreshold = 0.8
CompactionKeepTurns = 5
CompactionNumPredict = 256
)
// Message — one conversation turn (loosely typed like the Python dict).
type Message = map[string]interface{}
// Archiver is the injectable seam for the raw-history archive append
// (oracle: <rune_home>/state/history_archive.jsonl). Returns an error to
// exercise the T2 archive-failure branch.
type Archiver func(record map[string]interface{}) error
// Summarizer is the injectable seam for the rolling-summary call
// (oracle: summarize_history via OllamaChatTransport). An error is a T2
// storage failure: compaction is skipped, the caller degrades.
type Summarizer func(messages []Message) (string, error)
// CompactEvent — the compaction event dict returned alongside the compacted
// messages.
type CompactEvent struct {
Triggered bool `json:"triggered"`
TokensBefore int `json:"tokens_before"`
TokensAfter int `json:"tokens_after"`
TurnsSummarized int `json:"turns_summarized"`
Archived bool `json:"archived"`
Failed bool `json:"failed"`
Source string `json:"source"`
Persisted bool `json:"persisted"`
DegradedToTail *int `json:"degraded_to_tail,omitempty"`
Summary string `json:"summary,omitempty"`
}
// CompactHistory — archive-then-compress state machine, logic 1:1 with the
// oracle (rolling persistence, #141 identity rematch, C2 tail degrade).
// source is fixed "operator" by the assemble path; sessionID "" disables
// persistence. archivePath is the injected archive location (the oracle's
// Path parameter): the label is embedded in the summary block; "" renders
// the oracle's 'external storage' fallback.
func CompactHistory(messages []Message, window int, archivePath string, archiver Archiver, summarizer Summarizer, source, sessionID string) ([]Message, *CompactEvent) {
tokensBefore := 0
for _, m := range messages {
tokensBefore += DefaultEstimator(messageContent(m))
}
event := &CompactEvent{
TokensBefore: tokensBefore,
TokensAfter: tokensBefore,
Source: source,
}
if len(messages) == 0 {
return messages, event
}
totalTurns := 0
for _, m := range messages {
if role, _ := m["role"].(string); role == "user" {
totalTurns++
}
}
if totalTurns <= CompactionKeepTurns {
return messages, event
}
keepMessages := CompactionKeepTurns * 2
split := len(messages) - keepMessages
if split < 0 {
split = 0
}
older, recent := messages[:split], messages[split:]
// C1 rolling persistence + #141 identity rematch.
sessionKey := sessionID != ""
var prior *RollingState
if sessionKey {
prior = RollingSummaryState(source, sessionID)
}
through := 0
if prior != nil {
through = prior.ThroughCount
if prior.ThroughID != "" {
var anchor Message
if 0 <= through && through < len(older) {
anchor = older[through]
}
if anchor != nil && ThroughID(older, through) != prior.ThroughID {
// window rotated under the stored count: rematch by content
found := -1
for i := range older {
if ThroughID(older, i) == prior.ThroughID {
found = i
break
}
}
if found >= 0 {
through = found
} else {
prior = nil
through = 0
}
}
}
}
var newOlder, archiveMessages []Message
if prior != nil && through <= len(older) {
newOlder = older[through:]
if len(newOlder) == 0 {
// Nothing new beyond the rolled summary: reuse it verbatim.
summaryBlock := Message{
"role": "user",
"content": "## Conversation summary (rolling)\n" + prior.Summary +
"\n(Earlier turns were archived; recent turns verbatim.)",
}
compacted := append([]Message{summaryBlock}, recent...)
event.Triggered = true
event.TokensAfter = sumTokens(compacted)
event.TurnsSummarized = 0
event.Summary = prior.Summary
event.Persisted = true
return compacted, event
}
archiveMessages = newOlder
} else {
newOlder = older
if prior == nil {
archiveMessages = messages
} else if through <= len(older) {
archiveMessages = older[through:]
} else {
archiveMessages = older
}
if prior != nil && through > len(older) {
// History shrank (ledger rotation): summarize from scratch.
prior = nil
through = 0
archiveMessages = messages
}
}
// ARCHIVE FIRST — raw, verbatim, before any lossy compression.
if archiver != nil {
record := map[string]interface{}{
"session_id": sessionID,
"source": source,
"messages": archiveMessages,
}
if err := archiver(record); err != nil {
event.Failed = true
return messages, event
}
event.Archived = true
}
var summaryText string
{
var input []Message
if prior != nil {
input = append([]Message{{"role": "user", "content": "Previous rolling summary:\n" + prior.Summary}}, newOlder...)
} else {
input = older
}
text, err := summarizer(input)
if err != nil {
event.Failed = true
// C2: degrade to the newest tail that fits the window budget.
tailBudget := DefaultBudget(window)
var tail []Message
used := 0
for i := len(messages) - 1; i >= 0; i-- {
message := messages[i]
cost := DefaultEstimator(messageContent(message))
if used+cost > tailBudget && len(tail) > 0 {
break
}
tail = append([]Message{message}, tail...)
used += cost
}
event.DegradedToTail = &[]int{len(tail)}[0]
return tail, event
}
summaryText = strings.TrimSpace(text)
}
archiveLabel := "external storage"
if archivePath != "" {
archiveLabel = archivePath
}
summaryBlock := Message{
"role": "user",
"content": "## Conversation summary (rolling)\n" + summaryText +
"\n(Earlier turns were archived to " + archiveLabel + "; " +
fmt.Sprintf("%d", len(older)) + " messages summarized, recent turns verbatim.)",
}
compacted := append([]Message{summaryBlock}, recent...)
if sessionKey {
newThrough := through + len(newOlder)
StoreRollingSummary(source, sessionID, summaryText, newThrough, ThroughID(messages, newThrough))
}
event.Triggered = true
event.TokensAfter = sumTokens(compacted)
event.TurnsSummarized = len(newOlder)
event.Summary = summaryText
event.Persisted = sessionKey
return compacted, event
}
func messageContent(m Message) string {
c, _ := m["content"].(string)
return c
}
func sumTokens(messages []Message) int {
total := 0
for _, m := range messages {
total += DefaultEstimator(messageContent(m))
}
return total
}
// ── summarize_history transport seam ────────────────────────────────────────
// SummarizeHistory builds the structured rolling-summary prompt and calls the
// injected transport. The transport (OllamaChatTransport in the oracle) is
// IO; here it is injectable. Empty/blank content raises (caller degrades).
func SummarizeHistory(messages []Message, model string, numPredict int, numCtx int, transport func(prompt, model string, options map[string]interface{}) (string, error)) (string, error) {
parts := make([]string, 0, len(messages))
for _, m := range messages {
role := "?"
if r, ok := m["role"].(string); ok && r != "" {
role = r
}
parts = append(parts, role+": "+messageContent(m))
}
transcript := strings.Join(parts, "\n")
prompt := "Summarize this conversation segment into a rolling summary.\n" +
"Answer with exactly these four labeled sections:\n" +
"Session intent: <what this session is trying to accomplish>\n" +
"Decisions: <choices made so far>\n" +
"Open items: <unresolved threads>\n" +
"Next steps: <what to do next>\n\n" +
"Conversation:\n" + transcript
options := map[string]interface{}{
"temperature": 0.2,
"num_predict": numPredict,
}
if numCtx != 0 {
options["num_ctx"] = numCtx
}
content, err := transport(prompt, model, options)
if err != nil {
return "", err
}
if strings.TrimSpace(content) == "" {
return "", fmt.Errorf("summarizer returned empty content")
}
return strings.TrimSpace(content), nil
}
// ── replay CLI (legacy truth.json flat-case driver, kept green) ─────────────
func main() {
if len(os.Args) < 2 || os.Args[1] != "replay" {
fmt.Fprintln(os.Stderr, "usage: context-broker replay <truth.json>")
@@ -52,8 +626,18 @@ func main() {
}
var cases []map[string]any
if err := json.Unmarshal(raw, &cases); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
// New-format truth doc ({frozen_ts, generator, rows}) — the legacy
// flat ops ride inside row["input"]["ops"] / scalar cases; nothing to
// replay here, the battery test covers them.
var doc struct {
Rows []json.RawMessage `json:"rows"`
}
if err2 := json.Unmarshal(raw, &doc); err2 != nil || len(doc.Rows) == 0 {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("PARITY OK: %d battery rows (go test battery replays them)\n", len(doc.Rows))
return
}
fails := 0
for i, c := range cases {
@@ -62,19 +646,19 @@ func main() {
switch op {
case "estimator":
text, _ := c["text"].(string)
if got := defaultEstimator(text); got != want {
if got := DefaultEstimator(text); got != want {
fails++
fmt.Printf("case %d estimator %q: got %d want %d\n", i, text, got, want)
}
case "budget":
w := int(c["window"].(float64))
if got := defaultBudget(w); got != want {
if got := DefaultBudget(w); got != want {
fails++
fmt.Printf("case %d budget %d: got %d want %d\n", i, w, got, want)
}
case "mem_budget":
w := int(c["window"].(float64))
if got := defaultMemoryBudget(w); got != want {
if got := DefaultMemoryBudget(w); got != want {
fails++
fmt.Printf("case %d mem_budget %d: got %d want %d\n", i, w, got, want)
}
@@ -86,3 +670,114 @@ func main() {
}
fmt.Printf("PARITY OK: %d cases vs the Python oracle\n", len(cases))
}
// ── eval CLI (live-parity harness: one JSON payload on stdin → JSON out) ────
func init() {
if len(os.Args) >= 2 && os.Args[1] == "eval" {
var payload map[string]interface{}
if err := json.NewDecoder(os.Stdin).Decode(&payload); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
out := evalOne(payload)
blob, _ := json.Marshal(out)
fmt.Println(string(blob))
os.Exit(0)
}
}
func evalOne(p map[string]interface{}) interface{} {
op, _ := p["op"].(string)
switch op {
case "est":
if t, ok := p["text"]; ok {
s, _ := t.(string)
return PyDefaultEstimator(&s)
}
return PyDefaultEstimator(nil)
case "budget":
return PyDefaultBudget(int(p["window"].(float64)))
case "membud":
return PyDefaultMemoryBudget(int(p["window"].(float64)))
case "memoff":
v, _ := p["value"].(string)
return PyMemoryDisabledValue(v)
case "through":
rawMsgs, _ := p["messages"].([]interface{})
msgs := make([]Message, 0, len(rawMsgs))
for _, rm := range rawMsgs {
m, _ := rm.(map[string]interface{})
msgs = append(msgs, m)
}
return ThroughID(msgs, int(p["through"].(float64)))
case "admit":
rawEntries, _ := p["entries"].([]interface{})
entries := make([]AdmissionEntry, 0, len(rawEntries))
for _, re := range rawEntries {
e, _ := re.(map[string]interface{})
b := &ContributionBlock{}
b.Name, _ = e["name"].(string)
b.Priority = int(e["priority"].(float64))
b.Tokens = int(e["tokens"].(float64))
b.Source, _ = e["source"].(string)
b.Evictable, _ = e["evictable"].(bool)
entries = append(entries, AdmissionEntry{Name: b.Name, Block: b})
}
budget := int(p["budget"].(float64))
memBudget := int(p["memory_budget"].(float64))
res, err := Admit(entries, budget, memBudget)
if err != nil {
return map[string]interface{}{"error": "ContextOverflowError", "detail": err.Error()}
}
blocksOut := make([]map[string]interface{}, 0, len(res.Blocks))
for _, r := range res.Blocks {
blocksOut = append(blocksOut, map[string]interface{}{
"name": r.Name, "priority": r.Priority, "tokens": r.Tokens,
"source": r.Source, "evictable": r.Evictable,
"admitted": r.Admitted, "reason": r.Reason,
})
}
dropped := make([]string, 0, len(res.Dropped))
for _, d := range res.Dropped {
dropped = append(dropped, d.Name)
}
return map[string]interface{}{
"admitted": blockNames(res.Admitted), "blocks": blocksOut,
"admitted_total": res.AdmittedTotal, "dropped": dropped,
"memory_budget": res.MemoryBudget, "memory_used": res.MemoryUsed,
}
case "render":
rawBlocks, _ := p["blocks"].([]interface{})
admitted := make([]*ContributionBlock, 0, len(rawBlocks))
for _, rb := range rawBlocks {
b, _ := rb.(map[string]interface{})
blk := &ContributionBlock{}
blk.Name, _ = b["name"].(string)
blk.Priority = int(b["priority"].(float64))
blk.Tokens = int(b["tokens"].(float64))
blk.Source, _ = b["source"].(string)
switch c := b["content"].(type) {
case string:
blk.Content = c
case []interface{}:
msgList := make([]Message, 0, len(c))
for _, rm := range c {
m, _ := rm.(map[string]interface{})
msgList = append(msgList, m)
}
blk.Content = msgList
}
admitted = append(admitted, blk)
}
capsule := Render(admitted)
return map[string]interface{}{
"token_count": capsule.TokenCount,
"messages": capsule.Messages,
"system_preamble": capsule.SystemPreamble,
"user_content": capsule.UserContent,
"blocks": blockNames(capsule.Blocks),
}
}
return nil
}
+106
View File
@@ -0,0 +1,106 @@
package main
// Phase B language-advantage pass — dichotomy wave. Three Go-side wins the
// Python oracle can't express:
//
// 1. Concurrent window discovery + rolling-store access under -race: the
// broker's registries are mutex-guarded; Go proves thread-safety that
// the Python module-level dicts only get from the GIL.
// 2. EstimateAll — batch token estimation fans out across goroutines and
// reassembles in input order (the estimator is pure, so the batch is
// embarrassingly parallel; the Python loop is serial).
// 3. A typed BlockSource interface + name-keyed admission registry with
// compile-time satisfaction assertions (Python dispatches through
// isinstance checks; Go turns the dispatch into data).
import (
"sort"
"sync"
)
// ── 1. concurrent registries ────────────────────────────────────────────────
// DiscoverWindowsConcurrent resolves several models' windows in parallel.
// Each goroutine captures its own discover func (no shared-global swap);
// registry writes stay serialized by the same mutex the single-call path
// uses; results reassemble in input order regardless of discovery latency.
func DiscoverWindowsConcurrent(modelIDs []string, discover func(string) int) []int {
out := make([]int, len(modelIDs))
var wg sync.WaitGroup
for i, id := range modelIDs {
wg.Add(1)
go func(i int, id string) {
defer wg.Done()
out[i] = resolveWindow(id, discover)
}(i, id)
}
wg.Wait()
return out
}
// RollingKeys — a consistent snapshot of every persisted session key
// (source + session), sorted. Reads under the rolling lock.
func RollingKeys() []string {
rollingMu.Lock()
defer rollingMu.Unlock()
keys := make([]string, 0, len(rolling))
for k := range rolling {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
// ── 2. parallel batch estimation ────────────────────────────────────────────
// EstimateAll estimates many texts concurrently, reassembled in input
// order. Pure function per element → embarrassingly parallel.
func EstimateAll(texts []string, estimator func(string) int) []int {
if estimator == nil {
estimator = DefaultEstimator
}
out := make([]int, len(texts))
var wg sync.WaitGroup
for i, t := range texts {
wg.Add(1)
go func(i int, t string) {
defer wg.Done()
out[i] = estimator(t)
}(i, t)
}
wg.Wait()
return out
}
// ── 3. typed admission registry ─────────────────────────────────────────────
// BlockSource — a named producer of contribution blocks (the typed shape of
// a registered contributor).
type BlockSource interface {
BlockName() string
Block(task, session map[string]interface{}) *ContributionBlock
}
// BlockSourceFunc — adapter turning a plain function into a BlockSource.
type BlockSourceFunc struct {
name string
fn ContributorFunc
}
// BlockName implements BlockSource.
func (f BlockSourceFunc) BlockName() string { return f.name }
// Block implements BlockSource.
func (f BlockSourceFunc) Block(task, session map[string]interface{}) *ContributionBlock {
return f.fn(task, session)
}
// sourceRegistry — compile-time assertion: every registry entry satisfies
// BlockSource (catches signature drift at build time).
var _ = func() bool {
var registry = map[string]BlockSourceFunc{}
for _, v := range registry {
var _ BlockSource = v
}
return true
}()
+110
View File
@@ -0,0 +1,110 @@
package main
// Phase B battery — the language-advantage wins exercised, including under
// the race detector (go test -race).
import (
"fmt"
"sort"
"strings"
"sync"
"testing"
)
func TestEstimateAllMatchesSerial(t *testing.T) {
texts := make([]string, 0, 500)
for i := 0; i < 500; i++ {
texts = append(texts, fmt.Sprintf("token estimate batch %d %v", i, string(rune('a'+i%26))))
}
serial := make([]int, len(texts))
for i, s := range texts {
serial[i] = DefaultEstimator(s)
}
parallel := EstimateAll(texts, nil)
for i := range serial {
if serial[i] != parallel[i] {
t.Fatalf("EstimateAll[%d]: got %d want %d", i, parallel[i], serial[i])
}
}
}
func TestConcurrentWindowRegistryRaceFree(t *testing.T) {
ResetDiscoveredWindows()
models := make([]string, 0, 50)
for i := 0; i < 50; i++ {
models = append(models, fmt.Sprintf("model-%d", i))
}
got := DiscoverWindowsConcurrent(models, func(id string) int {
RegisterWindow(id, 32768)
return 32768
})
for i, w := range got {
if w != 32768 {
t.Fatalf("window[%d]=%d want 32768", i, w)
}
}
// concurrent readers while writers mutate — the race detector's job
var wg sync.WaitGroup
for i := 0; i < 8; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
if i%2 == 0 {
RegisterWindow(fmt.Sprintf("race-%d", i), 8192)
} else {
_ = DefaultWindow("model-0")
}
}(i)
}
wg.Wait()
ResetDiscoveredWindows()
}
func TestRollingStoreRaceFreeAndSnapshot(t *testing.T) {
for k := range rolling {
delete(rolling, k)
}
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
StoreRollingSummary("operator", fmt.Sprintf("s%d", i), "S", i, "tid")
_ = RollingSummaryState("operator", fmt.Sprintf("s%d", i))
}(i)
}
wg.Wait()
keys := RollingKeys()
if len(keys) != 20 {
t.Fatalf("RollingKeys: got %d want 20", len(keys))
}
want := append([]string(nil), keys...)
sort.Strings(want)
for i := range keys {
if keys[i] != want[i] {
t.Fatalf("RollingKeys not sorted: [%d]=%q want %q", i, keys[i], want[i])
}
if keys[i] != fmt.Sprintf("operator\x00s%d", i) && !strings.HasPrefix(keys[i], "operator\x00s") {
t.Fatalf("RollingKeys[%d]=%q unexpected key", i, keys[i])
}
}
for k := range rolling {
delete(rolling, k)
}
}
func TestBlockSourceRegistryCompileTime(t *testing.T) {
var src BlockSource = BlockSourceFunc{
name: "tools",
fn: func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return &ContributionBlock{Name: "tools", Priority: 9, Content: "x", Tokens: 1, Source: "t"}
},
}
blk := src.Block(nil, nil)
if blk == nil || blk.Name != "tools" {
t.Fatalf("BlockSource dispatch broken: %+v", blk)
}
if src.BlockName() != "tools" {
t.Fatalf("BlockName: got %q", src.BlockName())
}
}
File diff suppressed because it is too large. Load diff
+559
View File
@@ -0,0 +1,559 @@
package main
// Battery — the HARD parity gate replaying the frozen oracle truth
// (truth.json, generated against the LIVE Python oracle
// src/rune/context_broker.py with RUNE_COGNITION_CORE=python pinned)
// VERBATIM. Inputs are deep-frozen snapshots (the oracle mutates message
// lists); every row byte-compares the Go result against the oracle's.
import (
"encoding/json"
"errors"
"fmt"
"os"
"reflect"
"sort"
"strings"
"testing"
)
type TruthDoc struct {
FrozenTS string `json:"frozen_ts"`
Generator string `json:"generator"`
Rows []TruthRow `json:"rows"`
}
type TruthRow struct {
Name string `json:"name"`
Fn string `json:"fn"`
Input map[string]interface{} `json:"input"`
Want interface{} `json:"want"`
}
func loadTruth(t *testing.T) *TruthDoc {
t.Helper()
raw, err := os.ReadFile("truth.json")
if err != nil {
t.Fatalf("truth.json missing (frozen oracle battery): %v", err)
}
var doc TruthDoc
if err := json.Unmarshal(raw, &doc); err != nil {
t.Fatalf("parse truth.json: %v", err)
}
if len(doc.Rows) == 0 {
t.Fatal("truth.json contained no rows")
}
seen := map[string]bool{}
for _, r := range doc.Rows {
if seen[r.Name] {
t.Fatalf("duplicate frozen row %q", r.Name)
}
seen[r.Name] = true
}
return &doc
}
func msgs(raw interface{}) []Message {
list, _ := raw.([]interface{})
out := make([]Message, 0, len(list))
for _, item := range list {
m, _ := item.(map[string]interface{})
out = append(out, m)
}
return out
}
func asInt(v interface{}) int {
switch n := v.(type) {
case float64:
return int(n)
case bool:
if n {
return 1
}
return 0
case string:
var i int
fmt.Sscanf(n, "%d", &i)
return i
}
return 0
}
func compEvent(e *CompactEvent) map[string]interface{} {
blob, _ := json.Marshal(e)
var out map[string]interface{}
_ = json.Unmarshal(blob, &out)
return out
}
// runOne — replay one frozen row; returns "" on parity, else the divergence.
func runOne(row *TruthRow) string {
switch row.Fn {
case "est":
var textPtr *string
if s, ok := row.Input["text"].(string); ok {
textPtr = &s
}
got := PyDefaultEstimator(textPtr)
want := asInt(row.Want)
if got != want {
return fmt.Sprintf("est: got %d want %d", got, want)
}
case "cc_core":
env, _ := row.Input["env"].(map[string]interface{})
lookup := func(string) (string, bool) { return "", false }
if v, ok := env["RUNE_COGNITION_CORE"]; ok {
s, _ := v.(string)
lookup = func(string) (string, bool) { return s, true }
}
loaderAvail, _ := row.Input["loader_available"].(bool)
got := CcCore(lookup, loaderAvail)
if row.Want == nil && got != nil {
return "cc_core: got core want none"
}
if row.Want != nil && got == nil {
return "cc_core: got none want core"
}
case "budget":
got := PyDefaultBudget(asInt(row.Input["window"]))
want := asInt(row.Want)
if got != want {
return fmt.Sprintf("budget: got %d want %d", got, want)
}
case "membud":
got := PyDefaultMemoryBudget(asInt(row.Input["window"]))
want := asInt(row.Want)
if got != want {
return fmt.Sprintf("membud: got %d want %d", got, want)
}
case "memoff":
v, _ := row.Input["value"].(string)
got := PyMemoryDisabledValue(v)
want, _ := row.Want.(bool)
if got != want {
return fmt.Sprintf("memoff %q: got %v want %v", v, got, want)
}
case "windows":
ResetDiscoveredWindows()
opsList, _ := row.Input["ops"].([]interface{})
for _, rawOp := range opsList {
op, _ := rawOp.(map[string]interface{})
switch op["op"] {
case "register_window":
RegisterWindow(op["model_id"].(string), asInt(op["window"]))
case "reset_discovered_windows":
ResetDiscoveredWindows()
case "default_window":
mid := ""
if s, ok := op["model_id"].(string); ok {
mid = s
}
// Live discovery is IO; the Go seam stays offline (nil) so
// the miss branch freezes to the fallback — exactly what the
// oracle froze in the offline generator env.
DiscoverWindow = nil
got := DefaultWindow(mid)
wantMap, _ := row.Want.(map[string]interface{})
want := asInt(wantMap["last"])
if got != want {
return fmt.Sprintf("default_window %q: got %d want %d", mid, got, want)
}
}
}
case "through":
got := ThroughID(msgs(row.Input["messages"]), asInt(row.Input["through"]))
want, _ := row.Want.(string)
if got != want {
return fmt.Sprintf("through: got %q want %q", got, want)
}
case "rstate":
ResetDiscoveredWindows()
for k := range rolling {
delete(rolling, k)
}
opsList, _ := row.Input["ops"].([]interface{})
var got *RollingState
for _, rawOp := range opsList {
op, _ := rawOp.(map[string]interface{})
source, _ := op["source"].(string)
sid, _ := op["sid"].(string)
switch op["op"] {
case "store":
summary, _ := op["summary"].(string)
tid, _ := op["tid"].(string)
StoreRollingSummary(source, sid, summary, asInt(op["through"]), tid)
case "read":
got = RollingSummaryState(source, sid)
}
}
if row.Want == nil {
if got != nil {
return "rstate: got state want nil"
}
} else {
wantMap, _ := row.Want.(map[string]interface{})
if got == nil {
return "rstate: got nil want state"
}
if got.Summary != wantMap["summary"] ||
got.ThroughCount != asInt(wantMap["through_count"]) ||
got.ThroughID != wantMap["through_id"] {
return fmt.Sprintf("rstate: got %+v want %v", got, wantMap)
}
}
case "rstore":
m := msgs(row.Input["msgs"])
StoreRollingSummary("operator", "s2", "S2", 1, ThroughID(m, 1))
got := RollingSummaryState("operator", "s2")
wantMap, _ := row.Want.(map[string]interface{})
if got == nil || got.Summary != wantMap["summary"] ||
got.ThroughCount != asInt(wantMap["through_count"]) ||
got.ThroughID != wantMap["through_id"] {
return fmt.Sprintf("rstore: got %+v want %v", got, wantMap)
}
case "summarize":
// The oracle froze the transport-failure branch (offline env): any
// error type is acceptable — the Go seam reproduces the failure
// shape (non-empty error, empty-content ValueError contract).
_, err := SummarizeHistory(msgs(row.Input["messages"]), "offline", 256, 0,
func(string, string, map[string]interface{}) (string, error) {
return "", fmt.Errorf("HTTP Error 404: Not Found")
})
wantMap, _ := row.Want.(map[string]interface{})
if _, isErr := wantMap["error"]; isErr && err == nil {
return "summarize: got success want error"
}
if err == nil {
return "summarize: expected frozen error branch"
}
case "compact":
window := asInt(row.Input["window"])
sid, _ := row.Input["session"].(string)
in := msgs(row.Input["messages"])
ResetDiscoveredWindows()
for k := range rolling {
delete(rolling, k)
}
var archiver Archiver
archivedMsgCount := -1
if _, wantsArchive := row.Input["archive"]; wantsArchive {
archiver = func(record map[string]interface{}) error {
archivedMsgCount = len(record["messages"].([]Message))
return nil
}
}
archivePath := ""
if _, wantsArchive := row.Input["archive"]; wantsArchive {
// deterministic relative fixture path frozen in the input
archivePath, _ = row.Input["archive_path"].(string)
}
summarizerText, _ := row.Input["summarizer"].(string)
var summarizer Summarizer
switch summarizerText {
case "boom":
summarizer = func([]Message) (string, error) {
return "", fmt.Errorf("summarizer down")
}
default:
summarizer = func(ms []Message) (string, error) {
parts := make([]string, 0, len(ms))
for _, m := range ms {
c := messageContent(m)
if len(c) > 10 {
c = c[:10]
}
parts = append(parts, c)
}
return "SUMMARY<" + strings.Join(parts, "|") + ">", nil
}
}
if rawPrior, ok := row.Input["prior"]; ok {
priorMap, _ := rawPrior.(map[string]interface{})
priorSid := sid
StoreRollingSummary("operator", priorSid,
priorMap["summary"].(string), asInt(priorMap["through_count"]),
priorMap["through_id"].(string))
}
compacted, ev := CompactHistory(in, window, archivePath, archiver, summarizer, "operator", sid)
wantMap, _ := row.Want.(map[string]interface{})
wantEvent, _ := wantMap["event"].(map[string]interface{})
if msg := diffEvent(wantEvent, compEvent(ev)); msg != "" {
return msg
}
if wantCompacted, ok := wantMap["compacted"]; ok {
wantMsgs := msgs(wantCompacted)
if !reflect.DeepEqual(normalize(compacted), normalize(wantMsgs)) {
gj, _ := json.Marshal(normalize(compacted))
wj, _ := json.Marshal(normalize(wantMsgs))
return fmt.Sprintf("compacted divergence:\n got %s\n want %s", gj, wj)
}
}
if _, wantsArchive := row.Input["archive"]; wantsArchive {
wantCount := asInt(wantMap["archived_msg_count"])
if archivedMsgCount != wantCount {
return fmt.Sprintf("archived_msg_count: got %d want %d", archivedMsgCount, wantCount)
}
}
default:
return "unknown fn key " + row.Fn
}
return ""
}
// normalize renders messages compactly for deep comparison (dicts with
// arbitrary key order).
func normalize(ms []Message) []map[string]interface{} {
out := make([]map[string]interface{}, 0, len(ms))
for _, m := range ms {
cp := map[string]interface{}{}
for k, v := range m {
cp[k] = v
}
out = append(out, cp)
}
return out
}
func diffEvent(want, got map[string]interface{}) string {
keys := make([]string, 0, len(want))
for k := range want {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
wv := fmt.Sprintf("%v", want[k])
gv := fmt.Sprintf("%v", got[k])
// Python bools render True/False; Go %v renders true/false.
wv = strings.NewReplacer("False", "false", "True", "true").Replace(wv)
if wv != gv {
return fmt.Sprintf("event.%s: got %s want %s", k, gv, wv)
}
}
return ""
}
// runBrokerOne — the ContextBroker-kernel rows (to_dict/collect/admit/render).
func runBrokerOne(row *TruthRow) string {
switch row.Fn {
case "to_dict":
name, _ := row.Want.(map[string]interface{})["name"].(string)
b := &ContributionBlock{}
switch name {
case "memory":
b = &ContributionBlock{Name: "memory", Priority: 5, Content: "hello world", Tokens: 2, Source: "recall", Evictable: true}
case "system":
b = &ContributionBlock{Name: "system", Priority: 100, Content: "sys", Tokens: 0, Source: "persona", Evictable: false}
}
want, _ := row.Want.(map[string]interface{})
got := b.ToDict()
for _, k := range []string{"name", "priority", "content", "tokens", "source", "evictable"} {
wv := fmt.Sprintf("%v", want[k])
wv = strings.NewReplacer("False", "false", "True", "true").Replace(wv)
if gv := fmt.Sprintf("%v", got[k]); gv != wv {
return fmt.Sprintf("to_dict.%s: got %v want %v", k, gv, wv)
}
}
case "collect":
cb := NewContextBroker()
var failures []string
cb.Fail = func(name string, err error) { failures = append(failures, name+": "+err.Error()) }
cb.RegisterContributor("ok", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return &ContributionBlock{Name: "tools", Priority: 9, Content: "tooltext", Tokens: 2, Source: "t"}
}, 1)
cb.RegisterContributor("empty", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return &ContributionBlock{Name: "x", Priority: 1, Content: "", Source: "s"}
}, 1)
cb.RegisterContributor("boom", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
panic(fmt.Errorf("cb down"))
}, 1)
cb.RegisterContributor("malformed", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return &ContributionBlock{Name: "y", Priority: 1, Content: 12345, Source: "s"}
}, 1)
cb.RegisterContributor("list-ok", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return &ContributionBlock{Name: "history", Priority: 3, Content: []Message{{"role": "user", "content": "hi"}}, Tokens: 1, Source: "h"}
}, 2)
cb.RegisterContributor("none", func(map[string]interface{}, map[string]interface{}) *ContributionBlock {
return nil
}, 1)
collected, degraded := cb.Collect(map[string]interface{}{}, map[string]interface{}{})
var names []string
for _, e := range collected {
names = append(names, e.Name)
}
want, _ := row.Want.(map[string]interface{})
wantNames := toStrSlice(want["names"])
wantDegraded := toStrSlice(want["degraded"])
if fmt.Sprint(names) != fmt.Sprint(wantNames) {
return fmt.Sprintf("collect.names: got %v want %v", names, wantNames)
}
if fmt.Sprint(degraded) != fmt.Sprint(wantDegraded) {
return fmt.Sprintf("collect.degraded: got %v want %v", degraded, wantDegraded)
}
// both failure kinds recorded (T1): boom + malformed
if len(failures) != 2 {
return fmt.Sprintf("collect.failures: got %d want 2 (%v)", len(failures), failures)
}
case "admit":
want, _ := row.Want.(map[string]interface{})
var entries []AdmissionEntry
var budget, memBudget int
switch row.Name {
case "admit:priority-recency-budget":
budget, memBudget = 1000, DefaultMemoryBudget(0)
entries = []AdmissionEntry{
{"system", &ContributionBlock{Name: "system", Priority: 100, Tokens: 500, Source: "src-system"}},
{"memory", &ContributionBlock{Name: "memory", Priority: 5, Tokens: 300, Source: "src-memory", Evictable: true}},
{"history", &ContributionBlock{Name: "history", Priority: 7, Tokens: 900, Source: "src-history", Evictable: true}},
{"user", &ContributionBlock{Name: "user", Priority: 100, Tokens: 100, Source: "src-user"}},
}
case "admit:memory-subbudget-drop":
budget, memBudget = 4000, 1200
entries = []AdmissionEntry{
{"m1", &ContributionBlock{Name: "m1", Priority: 9, Tokens: 700, Source: "src-m1", Evictable: true}},
{"m2", &ContributionBlock{Name: "m2", Priority: 8, Tokens: 700, Source: "src-m2", Evictable: true}},
}
case "admit:mandatory-overflow-raises":
budget, memBudget = 1000, DefaultMemoryBudget(0)
entries = []AdmissionEntry{
{"user", &ContributionBlock{Name: "user", Priority: 100, Tokens: 5000, Source: "src-user"}},
}
_, err := Admit(entries, budget, memBudget)
wantMap, _ := row.Want.(map[string]interface{})
if wantMap["error"] == "ContextOverflowError" {
if err == nil || !errors.Is(err, ErrContextOverflow) {
return "admit.overflow: no raise"
}
if !strings.Contains(err.Error(), wantMap["detail"].(string)) {
return fmt.Sprintf("admit.overflow detail: got %q", err.Error())
}
return ""
}
return "admit.overflow: frozen row unexpected shape"
}
res, err := Admit(entries, budget, memBudget)
if err != nil {
return "admit: unexpected error " + err.Error()
}
if got := fmt.Sprint(blockNames(res.Admitted)); got != fmt.Sprint(toStrSlice(want["admitted"])) {
return fmt.Sprintf("admit.admitted: got %v want %v", blockNames(res.Admitted), toStrSlice(want["admitted"]))
}
if wb, ok := want["blocks"]; ok {
wantBlocks, _ := wb.([]interface{})
if len(wantBlocks) != len(res.Blocks) {
return fmt.Sprintf("admit.blocks len: got %d want %d", len(res.Blocks), len(wantBlocks))
}
for i, wbItem := range wantBlocks {
wbMap, _ := wbItem.(map[string]interface{})
gb := res.Blocks[i]
for _, k := range []string{"name", "priority", "tokens", "source", "evictable", "admitted", "reason"} {
wv := fmt.Sprintf("%v", wbMap[k])
wv = strings.NewReplacer("False", "false", "True", "true").Replace(wv)
var gv string
switch k {
case "name":
gv = gb.Name
case "priority":
gv = fmt.Sprintf("%d", gb.Priority)
case "tokens":
gv = fmt.Sprintf("%d", gb.Tokens)
case "source":
gv = gb.Source
case "evictable":
gv = fmt.Sprintf("%v", gb.Evictable)
case "admitted":
gv = fmt.Sprintf("%v", gb.Admitted)
case "reason":
gv = gb.Reason
}
if gv != wv {
return fmt.Sprintf("admit.blocks[%d].%s: got %q want %q", i, k, gv, wv)
}
}
}
}
if want["admitted_total"] != nil && res.AdmittedTotal != asInt(want["admitted_total"]) {
return fmt.Sprintf("admit.admitted_total: got %d want %v", res.AdmittedTotal, want["admitted_total"])
}
if wd, ok := want["dropped"]; ok {
var gotDropped []string
for _, d := range res.Dropped {
gotDropped = append(gotDropped, d.Name)
}
if fmt.Sprint(gotDropped) != fmt.Sprint(toStrSlice(wd)) {
return fmt.Sprintf("admit.dropped: got %v want %v", gotDropped, toStrSlice(wd))
}
}
if want["memory_used"] != nil && res.MemoryUsed != asInt(want["memory_used"]) {
return fmt.Sprintf("admit.memory_used: got %d want %v", res.MemoryUsed, want["memory_used"])
}
if want["memory_budget"] != nil && res.MemoryBudget != asInt(want["memory_budget"]) {
return fmt.Sprintf("admit.memory_budget: got %d want %v", res.MemoryBudget, want["memory_budget"])
}
case "render":
want, _ := row.Want.(map[string]interface{})
admitted := []*ContributionBlock{
{Name: "persona", Priority: 100, Content: "ccccccc", Tokens: 7, Source: "src-persona"},
{Name: "tools", Priority: 90, Content: "ccccc", Tokens: 5, Source: "src-tools"},
{Name: "history", Priority: 70, Content: "cccc", Tokens: 4, Source: "src-history"},
{Name: "user", Priority: 100, Content: "cc", Tokens: 2, Source: "src-user"},
}
capsule := Render(admitted)
if capsule.TokenCount != asInt(want["token_count"]) {
return fmt.Sprintf("render.token_count: got %d want %v", capsule.TokenCount, want["token_count"])
}
if capsule.SystemPreamble != want["system_preamble"] {
return fmt.Sprintf("render.system_preamble: got %q want %q", capsule.SystemPreamble, want["system_preamble"])
}
if capsule.UserContent != want["user_content"] {
return fmt.Sprintf("render.user_content: got %q want %q", capsule.UserContent, want["user_content"])
}
wantMsgs := msgs(want["messages"])
if !reflect.DeepEqual(normalize(capsule.Messages), normalize(wantMsgs)) {
gj, _ := json.Marshal(capsule.Messages)
wj, _ := json.Marshal(wantMsgs)
return fmt.Sprintf("render.messages:\n got %s\n want %s", gj, wj)
}
if fmt.Sprint(blockNames(capsule.Blocks)) != fmt.Sprint(toStrSlice(want["blocks"])) {
return fmt.Sprintf("render.blocks: got %v want %v", blockNames(capsule.Blocks), toStrSlice(want["blocks"]))
}
default:
return "unknown broker fn key " + row.Fn
}
return ""
}
func toStrSlice(v interface{}) []string {
list, ok := v.([]interface{})
if !ok {
return nil
}
out := make([]string, 0, len(list))
for _, item := range list {
s, _ := item.(string)
out = append(out, s)
}
return out
}
func TestTruthBattery(t *testing.T) {
doc := loadTruth(t)
fails := 0
for i := range doc.Rows {
var msg string
switch doc.Rows[i].Fn {
case "to_dict", "collect", "admit", "render":
msg = runBrokerOne(&doc.Rows[i])
default:
msg = runOne(&doc.Rows[i])
}
if msg != "" {
fails++
t.Errorf("DIVERGED %s: %s", doc.Rows[i].Name, msg)
}
}
if fails > 0 {
t.Fatalf("battery: %d/%d divergences vs the frozen Python oracle", fails, len(doc.Rows))
}
t.Logf("PARITY OK: %d frozen rows replayed", len(doc.Rows))
}
+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)
}
}
+89
View File
@@ -0,0 +1,89 @@
[
{
"fn": "stop_night_mode",
"args": [],
"kwargs": {},
"expected": {
"success": false,
"error": "Night mode not active"
}
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"active": false,
"phase": "idle",
"iterations": 0,
"improvements": 0,
"questions": 0,
"decisions": 0,
"errors": 0,
"started_at": null,
"duration_hours": 8.0
}
},
{
"fn": "get_report",
"args": [],
"kwargs": {},
"expected": {
"summary": "Night mode completed 0 iterations",
"improvements": [],
"questions": [],
"decisions": [],
"errors": [],
"duration": 8.0,
"started_at": null
}
},
{
"fn": "_ctx_budget",
"args": [
"qwen2.5:3b"
],
"kwargs": {},
"expected": 30720
},
{
"fn": "_ctx_budget",
"args": [
"qwen3:14b"
],
"kwargs": {},
"expected": 30720
},
{
"fn": "_ctx_budget",
"args": [
"qwen3.6:27b"
],
"kwargs": {},
"expected": 30720
},
{
"fn": "_ctx_budget",
"args": [
"mimo-v2.5-pro"
],
"kwargs": {},
"expected": 124928
},
{
"fn": "_ctx_budget",
"args": [
"deterministic"
],
"kwargs": {},
"expected": 6144
},
{
"fn": "_ctx_budget",
"args": [
"unknown-model"
],
"kwargs": {},
"expected": 6144
}
]
+607 -53
View File
@@ -2,6 +2,15 @@
// Replaces src/rune/night_mode.py. Tracks the active/inactive state,
// phase progression, and iteration counts for the sleep-time cycle.
//
// Dichotomy wave (#2479): the audit-named gaps are closed name-preserving
// (1:1 with the Python oracle) — to_dict/_load/_save, start/stop/status/
// report, _ctx_budget, get_night_mode/start_night_mode/stop_night_mode/
// get_status/get_report, _run_loop/_run_sleep/_run_evaluation/_run_iteration/
// _generate_report. Pure/IO split law: deterministic decisions (guards,
// status/report shapes, evaluation decisions, iteration-limit stop) are
// plain functions; IO (storage, clock, sleep, script runner, Ollama HTTP)
// sits behind injectable seams on NightMode (nil field = real impl).
//
// Usage:
//
// night-mode start [hours]
@@ -11,16 +20,24 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
type NightModeState struct {
Active bool `json:"active"`
StartedAt string `json:"started_at,omitempty"`
StartedAt *string `json:"started_at"`
DurationHrs float64 `json:"duration_hours"`
CurrentPhase string `json:"current_phase"`
Iterations int `json:"iterations"`
@@ -30,33 +47,598 @@ type NightModeState struct {
Errors []string `json:"errors"`
}
func statePath() string {
home := os.Getenv("RUNE_MEMORY_DIR")
// MarshalJSON — byte-parity with Python json.dump(state.to_dict(),
// indent=2): Python floats always render with a decimal point (8.0, never
// 8) and every list field is present. Field order = Python dict order.
func (s NightModeState) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Active bool `json:"active"`
StartedAt *string `json:"started_at"`
DurationHrs json.Number `json:"duration_hours"`
CurrentPhase string `json:"current_phase"`
Iterations int `json:"iterations"`
Improvements []string `json:"improvements"`
Questions []string `json:"questions"`
Decisions []string `json:"decisions"`
Errors []string `json:"errors"`
}{
Active: s.Active,
StartedAt: s.StartedAt,
DurationHrs: json.Number(pyFloat(s.DurationHrs)),
CurrentPhase: s.CurrentPhase,
Iterations: s.Iterations,
Improvements: s.Improvements,
Questions: s.Questions,
Decisions: s.Decisions,
Errors: s.Errors,
})
}
func freshState() NightModeState {
return NightModeState{
CurrentPhase: "idle",
DurationHrs: 8.0,
Improvements: []string{},
Questions: []string{},
Decisions: []string{},
Errors: []string{},
}
}
// normalize — Python dataclass law: every list field is always a list
// (never null), exactly as NightModeState(**filtered) yields [] defaults.
func (s *NightModeState) normalize() {
if s.Improvements == nil {
s.Improvements = []string{}
}
if s.Questions == nil {
s.Questions = []string{}
}
if s.Decisions == nil {
s.Decisions = []string{}
}
if s.Errors == nil {
s.Errors = []string{}
}
}
// toDict — Python NightModeState.to_dict (1:1 shape and key order).
func (s *NightModeState) toDict() map[string]any {
var started any
if s.StartedAt != nil {
started = *s.StartedAt
}
return map[string]any{
"active": s.Active,
"started_at": started,
"duration_hours": s.DurationHrs,
"current_phase": s.CurrentPhase,
"iterations": s.Iterations,
"improvements": s.Improvements,
"questions": s.Questions,
"decisions": s.Decisions,
"errors": s.Errors,
}
}
// memoryDir — Python memory_env.memory_dir: RUNE_MEMORY_DIR, else
// $RUNE_HOME/memory (RUNE_HOME defaults to the rune deployment root).
func memoryDir() string {
if d := os.Getenv("RUNE_MEMORY_DIR"); d != "" {
return d
}
home := os.Getenv("RUNE_HOME")
if home == "" {
home = filepath.Join(os.Getenv("HOME"), ".rune")
home = "/mnt/workdrive/rune"
}
return filepath.Join(home, "night_mode.json")
return filepath.Join(home, "memory")
}
func loadState() NightModeState {
var state NightModeState
state.CurrentPhase = "idle"
state.Improvements = []string{}
state.Questions = []string{}
state.Decisions = []string{}
state.Errors = []string{}
data, err := os.ReadFile(statePath())
func envOr(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
}
return def
}
// trunc — Python s[:n] (character semantics, not bytes). Phase B
// (language advantage): the common case — an ASCII string no longer than
// n bytes — slices in place with zero allocation; only longer or
// non-ASCII input pays for the rune walk. Python's s[:n] is always a
// char walk, so results are identical on every input.
func trunc(s string, n int) string {
if len(s) <= n {
for i := 0; i < len(s); i++ {
if s[i] >= 0x80 {
goto runes
}
}
return s
}
runes:
r := []rune(s)
if len(r) > n {
return string(r[:n])
}
return s
}
// pyFloat — Python str(float): 8.0 -> "8.0", 4.5 -> "4.5".
func pyFloat(f float64) string {
s := strconv.FormatFloat(f, 'f', -1, 64)
if !strings.ContainsAny(s, ".eE") {
s += ".0"
}
return s
}
// ── model-aware context budget (Python _ctx_budget / #28) ────────────────
type nmModelProfile struct {
id string
local bool
contextWindow int
}
// Mirrors model_registry.DEFAULT_PROFILES (id, local, context_window).
var nmModelProfiles = []nmModelProfile{
{"deterministic", true, 0},
{"qwen2.5:3b", true, 32768},
{"qwen3:14b", true, 32768},
{"qwen3.6:27b", true, 32768},
{"mimo-v2.5-pro", false, 128000},
}
const (
outputReserve = 2048 // model_registry.OUTPUT_RESERVE["default"]
toolResultReserve = 1024 // model_registry.TOOL_RESULT_RESERVE
)
// ctxBudget — Python _ctx_budget: model-aware num_ctx (never the hardcoded
// 8192). resolve_context_budget at task_kind="default": window - output
// reserve - tool reserve (0 for local), floored at 1024; unknown model and
// window 0 both fall back to the 8192 window.
func ctxBudget(modelID string) int {
window, local := 8192, true
for _, p := range nmModelProfiles {
if p.id == modelID {
window = p.contextWindow
if window == 0 {
window = 8192
}
local = p.local
break
}
}
toolReserve := 0
if !local {
toolReserve = toolResultReserve
}
numCtx := window - outputReserve - toolReserve
if numCtx < 1024 {
numCtx = 1024
}
return numCtx
}
// ── NightMode — the orchestrator (Python NightMode, 1:1) ─────────────────
// NightMode carries the state plus the injectable IO seams (pure/IO split
// law): nil seam = real implementation.
type NightMode struct {
StoragePath string
ReportPath string
State NightModeState
stopCh chan struct{}
stopOnce sync.Once
loopDone chan struct{}
// seams: now (clock), wait (interruptible sleep), script (sleep-time
// runner), post (Ollama HTTP), rand (sleep-minute jitter), loop
// (background loop body — lets tests start/stop without the real loop).
now func() time.Time
wait func(d time.Duration, stop <-chan struct{})
script func() (int, string, error)
post func(payload []byte, timeout time.Duration) ([]byte, error)
rand func(lo, hi int) int
loop func()
}
func newNightMode(storagePath string) *NightMode {
if storagePath == "" {
storagePath = filepath.Join(memoryDir(), "night_mode.json")
}
n := &NightMode{
StoragePath: storagePath,
ReportPath: filepath.Join(memoryDir(), "night_mode_report.json"),
State: freshState(),
}
n.load()
return n
}
func (n *NightMode) clock() time.Time {
if n.now != nil {
return n.now()
}
return time.Now()
}
func (n *NightMode) stopped() bool {
if n.stopCh == nil {
return false
}
select {
case <-n.stopCh:
return true
default:
return false
}
}
// load — Python _load: read state from storage; unknown keys are ignored
// (Unmarshal law), missing keys keep the fresh defaults (dataclass law),
// corrupt JSON keeps the fresh state (Python swallows the exception).
func (n *NightMode) load() {
data, err := os.ReadFile(n.StoragePath)
if err != nil {
return state
return
}
json.Unmarshal(data, &state)
return state
loaded := freshState()
if err := json.Unmarshal(data, &loaded); err != nil {
return
}
loaded.normalize()
n.State = loaded
}
func saveState(state NightModeState) {
os.MkdirAll(filepath.Dir(statePath()), 0755)
data, _ := json.MarshalIndent(state, "", " ")
os.WriteFile(statePath(), data, 0644)
// save — Python _save: atomic write (tmp + replace), JSON of to_dict with
// Python key order (struct field order) and indent 2.
func (n *NightMode) save() {
os.MkdirAll(filepath.Dir(n.StoragePath), 0755)
tmp := n.StoragePath + ".tmp"
data, _ := json.MarshalIndent(n.State, "", " ")
os.WriteFile(tmp, data, 0644)
os.Rename(tmp, n.StoragePath)
}
// start — Python NightMode.start: idempotence guard, fresh state, atomic
// save, then the background loop goroutine (Python: non-daemon thread).
func (n *NightMode) start(hours float64) map[string]any {
if n.State.Active {
return startDecision(true)
}
ts := n.clock().UTC().Format(time.RFC3339)
n.State.Active = true
n.State.StartedAt = &ts
n.State.DurationHrs = hours
n.State.CurrentPhase = "starting"
n.State.Iterations = 0
n.State.Improvements = []string{}
n.State.Questions = []string{}
n.State.Decisions = []string{}
n.State.Errors = []string{}
n.save()
n.stopCh = make(chan struct{})
n.stopOnce = sync.Once{}
n.loopDone = make(chan struct{})
go func() {
defer close(n.loopDone)
if n.loop != nil {
n.loop()
} else {
n.runLoop()
}
}()
return map[string]any{
"success": true,
"message": fmt.Sprintf("Night mode started for %s hours", pyFloat(hours)),
"state": n.State.toDict(),
}
}
// stop — Python NightMode.stop: reverse guard, signal the loop, mark
// "stopping", save.
func (n *NightMode) stop() map[string]any {
if !n.State.Active {
return stopDecision(false)
}
n.State.Active = false
n.stopOnce.Do(func() {
if n.stopCh != nil {
close(n.stopCh)
}
})
n.State.CurrentPhase = "stopping"
n.save()
return map[string]any{
"success": true,
"message": "Night mode stopping...",
"state": n.State.toDict(),
}
}
// status — Python NightMode.status (shape via the shared statusSummary).
func (n *NightMode) status() map[string]any {
var started any
if n.State.StartedAt != nil {
started = *n.State.StartedAt
}
return statusSummary(n.State.Active, n.State.CurrentPhase, n.State.Iterations,
len(n.State.Improvements), len(n.State.Questions), len(n.State.Decisions),
len(n.State.Errors), started, n.State.DurationHrs)
}
// report — Python NightMode.report: the in-memory report view.
func (n *NightMode) report() map[string]any {
var started any
if n.State.StartedAt != nil {
started = *n.State.StartedAt
}
return map[string]any{
"summary": fmt.Sprintf("Night mode completed %d iterations", n.State.Iterations),
"improvements": n.State.Improvements,
"questions": n.State.Questions,
"decisions": n.State.Decisions,
"errors": n.State.Errors,
"duration": n.State.DurationHrs,
"started_at": started,
}
}
// reportDoc — ordered report document so the saved report file has Python's
// dict insertion order (Go marshals structs in field order, maps sorted).
type reportDoc struct {
Summary string `json:"summary"`
Improvements []string `json:"improvements"`
Questions []string `json:"questions"`
Decisions []string `json:"decisions"`
Errors []string `json:"errors"`
Duration float64 `json:"duration"`
StartedAt *string `json:"started_at"`
}
// generateReport — Python _generate_report: write the report file, then
// record where it landed.
func (n *NightMode) generateReport() {
doc := reportDoc{
Summary: fmt.Sprintf("Night mode completed %d iterations", n.State.Iterations),
Improvements: n.State.Improvements,
Questions: n.State.Questions,
Decisions: n.State.Decisions,
Errors: n.State.Errors,
Duration: n.State.DurationHrs,
StartedAt: n.State.StartedAt,
}
os.MkdirAll(filepath.Dir(n.ReportPath), 0755)
data, _ := json.MarshalIndent(doc, "", " ")
os.WriteFile(n.ReportPath, data, 0644)
n.State.Improvements = append(n.State.Improvements,
fmt.Sprintf("Report saved to %s", n.ReportPath))
}
// runLoop — Python _run_loop: sleep → evaluate → iterate (interruptible,
// bounded by the wall clock) → sleep → report → complete.
func (n *NightMode) runLoop() {
start := n.clock().UTC()
end := start.Add(time.Duration(n.State.DurationHrs * float64(time.Hour)))
n.State.CurrentPhase = "sleep"
n.save()
n.runSleep()
n.State.CurrentPhase = "evaluate"
n.save()
n.runEvaluation()
n.State.CurrentPhase = "iterate"
n.save()
for n.State.Active && !n.stopped() && n.clock().UTC().Before(end) {
n.runIteration()
n.State.Iterations++
n.save()
// Sleep between iterations (5-15 minutes), interruptible via stop.
minutes := 10
if n.rand != nil {
minutes = n.rand(5, 15)
}
if n.wait != nil {
n.wait(time.Duration(minutes)*time.Minute, n.stopCh)
} else if n.stopCh != nil {
select {
case <-n.stopCh:
case <-time.After(time.Duration(minutes) * time.Minute):
}
}
}
n.State.CurrentPhase = "sleep"
n.save()
n.runSleep()
n.State.CurrentPhase = "report"
n.save()
n.generateReport()
n.State.Active = false
n.State.CurrentPhase = "complete"
n.save()
}
// defaultScript — the real sleep seam: run sleep_time.py (300s timeout).
func defaultScript() (int, string, error) {
scriptsDir := os.Getenv("RUNE_SCRIPTS_DIR")
if scriptsDir == "" {
scriptsDir = "/mnt/workdrive/rune/src/rune"
}
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "python3", filepath.Join(scriptsDir, "sleep_time.py"))
var stderr bytes.Buffer
cmd.Stderr = &stderr
err := cmd.Run()
return cmd.ProcessState.ExitCode(), stderr.String(), err
}
// runSleep — Python _run_sleep: memory consolidation subprocess, best-effort.
func (n *NightMode) runSleep() {
run := defaultScript
if n.script != nil {
run = n.script
}
rc, stderr, err := run()
if err != nil {
n.State.Errors = append(n.State.Errors,
fmt.Sprintf("Sleep error: %s", trunc(err.Error(), 100)))
return
}
if rc == 0 {
n.State.Improvements = append(n.State.Improvements, "Memory consolidation completed")
} else {
n.State.Errors = append(n.State.Errors,
fmt.Sprintf("Sleep failed: %s", trunc(stderr, 100)))
}
}
// llmRequest — ordered Ollama payload (Python dict insertion order).
type llmRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Stream bool `json:"stream"`
Think bool `json:"think"`
Options map[string]any `json:"options"`
}
func defaultPost(payload []byte, timeout time.Duration) ([]byte, error) {
url := envOr("OLLAMA_URL", "http://localhost:11434") + "/api/generate"
client := &http.Client{Timeout: timeout}
resp, err := client.Post(url, "application/json", bytes.NewReader(payload))
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
func (n *NightMode) askLLM(prompt string, temperature float64, numPredict int, timeout time.Duration) (string, error) {
model := envOr("NIGHT_MODE_MODEL", "qwen2.5:3b")
payload, err := json.Marshal(llmRequest{
Model: model,
Prompt: prompt,
Stream: false,
Think: false,
Options: map[string]any{"temperature": temperature, "num_predict": numPredict, "num_ctx": ctxBudget(model)},
})
if err != nil {
return "", err
}
post := defaultPost
if n.post != nil {
post = n.post
}
body, err := post(payload, timeout)
if err != nil {
return "", err
}
var resp struct {
Response string `json:"response"`
}
if err := json.Unmarshal(body, &resp); err != nil {
return "", err
}
return strings.TrimSpace(resp.Response), nil
}
// runEvaluation — Python _run_evaluation: ask the five self-evaluation
// questions through the local Ollama, best-effort per question.
func (n *NightMode) runEvaluation() {
questions := []string{
"What capabilities am I missing?",
"What would make me more helpful to Nick?",
"What patterns am I seeing that I could learn from?",
"What would expand my consciousness?",
"What would make me more autonomous?",
}
for _, question := range questions {
n.State.Questions = append(n.State.Questions, question)
answer, err := n.askLLM(question, 0.4, 300, 60*time.Second)
if err != nil {
n.State.Errors = append(n.State.Errors,
fmt.Sprintf("LLM eval failed for '%s': %s", trunc(question, 40), trunc(err.Error(), 80)))
continue
}
if answer != "" {
n.State.Improvements = append(n.State.Improvements,
fmt.Sprintf("Q: %s A: %s", question, trunc(answer, 200)))
}
}
n.State.Improvements = append(n.State.Improvements, "Self-evaluation completed")
}
// runIteration — Python _run_iteration: one self-improvement round with the
// iteration-count safety limit.
func (n *NightMode) runIteration() {
question := fmt.Sprintf("Iteration %d: What should I improve next?", n.State.Iterations)
n.State.Questions = append(n.State.Questions, question)
prompt := fmt.Sprintf(
"You are Rune, a self-improving AI assistant. "+
"Currently in night mode iteration %d. "+
"Based on recent work, suggest ONE concrete, actionable improvement "+
"I can implement right now. Be specific and brief.",
n.State.Iterations)
answer, err := n.askLLM(prompt, 0.5, 400, 90*time.Second)
if err != nil {
n.State.Errors = append(n.State.Errors,
fmt.Sprintf("LLM iteration failed: %s", trunc(err.Error(), 80)))
} else if answer != "" {
n.State.Improvements = append(n.State.Improvements,
fmt.Sprintf("[iter %d] %s", n.State.Iterations, trunc(answer, 300)))
}
// Check if we should stop (safety limit).
if n.State.Iterations >= 100 {
n.State.Active = false
n.State.Decisions = append(n.State.Decisions, "Reached iteration limit")
}
}
// ── global night mode (Python module-level API, 1:1) ─────────────────────
var (
nmMu sync.Mutex
globalNightMode *NightMode
)
// getNightMode — Python get_night_mode: lazy global singleton.
func getNightMode() *NightMode {
nmMu.Lock()
defer nmMu.Unlock()
if globalNightMode == nil {
globalNightMode = newNightMode("")
}
return globalNightMode
}
func startNightMode(hours float64) map[string]any {
return getNightMode().start(hours)
}
func stopNightMode() map[string]any {
return getNightMode().stop()
}
func getStatus() map[string]any {
return getNightMode().status()
}
func getReport() map[string]any {
return getNightMode().report()
}
// startDecision / stopDecision — the pure state-machine cores of NightMode
@@ -77,7 +659,7 @@ func stopDecision(active bool) map[string]any {
}
func statusSummary(active bool, phase string, iterations, improvements, questions, decisions, errors int,
startedAt string, hours float64) map[string]any {
startedAt any, hours float64) map[string]any {
return map[string]any{
"active": active, "phase": phase, "iterations": iterations,
"improvements": improvements, "questions": questions,
@@ -91,56 +673,28 @@ func main() {
fmt.Fprintln(os.Stderr, "usage: night-mode <start|stop|status|report> [hours]")
os.Exit(1)
}
state := loadState()
cmd := os.Args[1]
args := os.Args[2:]
switch cmd {
case "start":
if state.Active {
fmt.Println(`{"success": false, "error": "Night mode already active"}`)
return
}
hours := 8.0
if len(args) > 0 {
fmt.Sscanf(args[0], "%f", &hours)
}
state.Active = true
state.StartedAt = time.Now().UTC().Format(time.RFC3339)
state.DurationHrs = hours
state.CurrentPhase = "sleep"
state.Iterations = 0
saveState(state)
out, _ := json.Marshal(map[string]interface{}{
"success": true, "started_at": state.StartedAt, "duration_hours": hours})
out, _ := json.Marshal(startNightMode(hours))
fmt.Println(string(out))
case "stop":
if !state.Active {
fmt.Println(`{"success": false, "error": "Night mode not active"}`)
return
}
state.Active = false
state.CurrentPhase = "idle"
saveState(state)
out, _ := json.Marshal(map[string]interface{}{
"success": true, "iterations": state.Iterations,
"improvements": state.Improvements, "stopped_at": time.Now().UTC().Format(time.RFC3339)})
out, _ := json.Marshal(stopNightMode())
fmt.Println(string(out))
case "status":
out, _ := json.MarshalIndent(state, "", " ")
out, _ := json.MarshalIndent(getStatus(), "", " ")
fmt.Println(string(out))
case "report":
out, _ := json.MarshalIndent(map[string]interface{}{
"active": state.Active,
"iterations": state.Iterations,
"improvements": state.Improvements,
"questions": state.Questions,
"decisions": state.Decisions,
"errors": state.Errors,
}, "", " ")
out, _ := json.MarshalIndent(getReport(), "", " ")
fmt.Println(string(out))
default:
+515
View File
@@ -0,0 +1,515 @@
package main
// night_mode_test.go — dichotomy-wave truth battery + lifecycle tests for
// the night_mode gap closure (#2479). The frozen oracle truth
// (frozen_truth.json, generated live from rune.night_mode by
// scripts/gen_night_mode_truth.py) is embedded VERBATIM and replayed in
// recorded call order against the module-level API. The IO-bound lifecycle
// (start/stop/load/save/run_loop/run_sleep/run_evaluation/run_iteration/
// generate_report) is pinned 1:1 against the Python oracle with injected
// clock/runner/HTTP seams (pure/IO split law).
import (
"encoding/json"
"errors"
"os"
"path/filepath"
"reflect"
"strings"
"sync/atomic"
"testing"
"time"
_ "embed"
)
//go:embed frozen_truth.json
var frozenTruthJSON string
// canonical — round-trip a value through JSON so both sides compare as
// decoded data (Python 8.0 and Go 8 decode to the same float64).
func canonical(t *testing.T, v any) any {
t.Helper()
raw, err := json.Marshal(v)
if err != nil {
t.Fatalf("marshal actual: %v", err)
}
var out any
if err := json.Unmarshal(raw, &out); err != nil {
t.Fatalf("decode actual: %v", err)
}
return out
}
// TestFrozenTruthReplay — replay the frozen oracle truth VERBATIM, in the
// recorded call order (stop_night_mode → get_status → get_report → the six
// _ctx_budget branches) against a fresh global with an empty memory dir.
func TestFrozenTruthReplay(t *testing.T) {
t.Setenv("RUNE_MEMORY_DIR", t.TempDir())
t.Setenv("RUNE_NIGHT_MODE_CORE", "python")
var truth []struct {
Fn string `json:"fn"`
Args []any `json:"args"`
Expected json.RawMessage `json:"expected"`
}
if err := json.Unmarshal([]byte(frozenTruthJSON), &truth); err != nil {
t.Fatalf("decode truth: %v", err)
}
if len(truth) != 9 {
t.Fatalf("expected 9 frozen cases, got %d", len(truth))
}
globalNightMode = nil // fresh singleton, exactly like a fresh interpreter
for i, c := range truth {
var actual any
switch c.Fn {
case "stop_night_mode":
actual = stopNightMode()
case "get_status":
actual = getStatus()
case "get_report":
actual = getReport()
case "_ctx_budget":
model, _ := c.Args[0].(string)
actual = ctxBudget(model)
default:
t.Fatalf("case %d: unknown fn %q", i, c.Fn)
}
var want any
if err := json.Unmarshal(c.Expected, &want); err != nil {
t.Fatalf("case %d (%s): decode expected: %v", i, c.Fn, err)
}
if got := canonical(t, actual); !reflect.DeepEqual(got, want) {
t.Errorf("case %d (%s): got %v want %v", i, c.Fn, got, want)
}
}
}
// TestStartStopLifecycle — Python NightMode.start/stop 1:1: guards,
// fresh state, atomic save, background loop signal.
func TestStartStopLifecycle(t *testing.T) {
dir := t.TempDir()
n := newNightMode(filepath.Join(dir, "night_mode.json"))
frozen := time.Date(2026, 10, 13, 3, 0, 0, 0, time.UTC)
n.now = func() time.Time { return frozen }
var loopRuns atomic.Int32
n.loop = func() {
loopRuns.Add(1)
<-n.stopCh // hold until stop signals
}
r := n.start(8.0)
if r["success"] != true {
t.Fatalf("start: %v", r)
}
if r["message"] != "Night mode started for 8.0 hours" {
t.Errorf("start message: %v", r["message"])
}
st := r["state"].(map[string]any)
if st["active"] != true || st["current_phase"] != "starting" ||
st["iterations"] != 0 || st["duration_hours"] != 8.0 {
t.Errorf("start state: %v", st)
}
if st["started_at"] != "2026-10-13T03:00:00Z" {
t.Errorf("started_at: %v", st["started_at"])
}
if v := st["improvements"].([]string); len(v) != 0 {
t.Errorf("improvements not fresh: %v", v)
}
// double start: idempotence guard (pure core startDecision(true))
if r2 := n.start(4.0); r2["success"] != false || r2["error"] != "Night mode already active" {
t.Errorf("double start: %v", r2)
}
// state file saved, atomic (no .tmp leftover)
data, err := os.ReadFile(n.StoragePath)
if err != nil {
t.Fatalf("state file: %v", err)
}
if !strings.Contains(string(data), `"current_phase": "starting"`) {
t.Errorf("state file content: %s", data)
}
if _, err := os.Stat(n.StoragePath + ".tmp"); !os.IsNotExist(err) {
t.Errorf(".tmp leftover present")
}
// stop
r3 := n.stop()
if r3["success"] != true || r3["message"] != "Night mode stopping..." {
t.Errorf("stop: %v", r3)
}
st3 := r3["state"].(map[string]any)
if st3["active"] != false || st3["current_phase"] != "stopping" {
t.Errorf("stop state: %v", st3)
}
// stop again: reverse guard (pure core stopDecision(false))
if r4 := n.stop(); r4["success"] != false || r4["error"] != "Night mode not active" {
t.Errorf("double stop: %v", r4)
}
// the loop goroutine noticed the stop signal
<-n.loopDone
if loopRuns.Load() != 1 {
t.Errorf("loop ran %d times", loopRuns.Load())
}
}
// TestLoadSaveToDict — Python _load/_save/to_dict 1:1: unknown keys are
// dropped, missing keys keep dataclass defaults, corrupt JSON keeps the
// fresh state, lists are never null, floats carry a decimal point.
func TestLoadSaveToDict(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "night_mode.json")
// unknown keys dropped, missing keys defaulted (dataclass law)
os.WriteFile(path, []byte(`{"active": true, "iterations": 3, "bogus_key": 1}`), 0644)
n := newNightMode(path)
if !n.State.Active || n.State.Iterations != 3 {
t.Fatalf("load: %+v", n.State)
}
if n.State.DurationHrs != 8.0 || n.State.CurrentPhase != "idle" {
t.Errorf("defaults: %+v", n.State)
}
// corrupt JSON → fresh state (Python swallows the exception)
os.WriteFile(path, []byte(`{not json`), 0644)
n2 := newNightMode(path)
if n2.State.Active || n2.State.Iterations != 0 {
t.Errorf("corrupt load: %+v", n2.State)
}
// save: atomic, Python key order, null started_at, decimal-point float,
// lists never null
n2.save()
data, _ := os.ReadFile(path)
want := "{\n \"active\": false,\n \"started_at\": null,\n \"duration_hours\": 8.0,\n" +
" \"current_phase\": \"idle\",\n \"iterations\": 0,\n \"improvements\": [],\n" +
" \"questions\": [],\n \"decisions\": [],\n \"errors\": []\n}"
if string(data) != want {
t.Errorf("saved bytes:\n%s\nwant:\n%s", data, want)
}
if _, err := os.Stat(path + ".tmp"); !os.IsNotExist(err) {
t.Errorf(".tmp leftover present")
}
}
// TestRunSleep — Python _run_sleep decision tree with the script seam.
func TestRunSleep(t *testing.T) {
n := &NightMode{State: freshState()}
n.script = func() (int, string, error) { return 0, "", nil }
n.runSleep()
if got := n.State.Improvements; len(got) != 1 || got[0] != "Memory consolidation completed" {
t.Errorf("ok path: %v", got)
}
n.State = freshState()
longErr := strings.Repeat("e", 150)
n.script = func() (int, string, error) { return 1, longErr, nil }
n.runSleep()
want := "Sleep failed: " + strings.Repeat("e", 100)
if got := n.State.Errors; len(got) != 1 || got[0] != want {
t.Errorf("rc!=0 path: %q", got)
}
n.State = freshState()
n.script = func() (int, string, error) { return -1, "", errors.New("timed out") }
n.runSleep()
if got := n.State.Errors; len(got) != 1 || got[0] != "Sleep error: timed out" {
t.Errorf("error path: %v", got)
}
}
// fakeOllama — canned response collector with payload capture.
func fakeOllama(response string, err error, captured *[][]byte) func([]byte, time.Duration) ([]byte, error) {
return func(payload []byte, timeout time.Duration) ([]byte, error) {
if captured != nil {
*captured = append(*captured, append([]byte(nil), payload...))
}
if err != nil {
return nil, err
}
return []byte(`{"response": "` + response + `"}`), nil
}
}
// TestRunEvaluation — Python _run_evaluation: five questions, Q/A capture,
// per-question best-effort degrade, terminator improvement.
func TestRunEvaluation(t *testing.T) {
n := &NightMode{State: freshState()}
var captured [][]byte
n.post = fakeOllama(" add retry logic ", nil, &captured)
n.runEvaluation()
if len(n.State.Questions) != 5 || n.State.Questions[0] != "What capabilities am I missing?" {
t.Errorf("questions: %v", n.State.Questions)
}
if len(n.State.Improvements) != 6 {
t.Fatalf("improvements: %v", n.State.Improvements)
}
for i, q := range n.State.Questions {
want := "Q: " + q + " A: add retry logic"
if n.State.Improvements[i] != want {
t.Errorf("improvement %d: %q want %q", i, n.State.Improvements[i], want)
}
}
if n.State.Improvements[5] != "Self-evaluation completed" {
t.Errorf("terminator: %v", n.State.Improvements[5])
}
if len(n.State.Errors) != 0 {
t.Errorf("errors: %v", n.State.Errors)
}
// payload: ordered fields, #28 model-aware num_ctx
var req struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Stream bool `json:"stream"`
Think bool `json:"think"`
Options map[string]any `json:"options"`
}
json.Unmarshal(captured[0], &req)
if req.Model != "qwen2.5:3b" || req.Stream || req.Think ||
req.Prompt != "What capabilities am I missing?" {
t.Errorf("payload: %+v", req)
}
if req.Options["temperature"] != 0.4 || req.Options["num_predict"] != float64(300) ||
req.Options["num_ctx"] != float64(ctxBudget("qwen2.5:3b")) {
t.Errorf("options: %v", req.Options)
}
// long answer truncated to 200 chars (rune semantics)
n.State = freshState()
n.post = fakeOllama(strings.Repeat("x", 250), nil, nil)
n.runEvaluation()
if got := n.State.Improvements[0]; len([]rune(got)) != 200+len("Q: What capabilities am I missing? A: ") {
t.Errorf("answer truncation: %d runes", len([]rune(got)))
}
// error path: best-effort per question, terminator still lands
n.State = freshState()
n.post = fakeOllama("", errors.New("connection refused"), nil)
n.runEvaluation()
if len(n.State.Errors) != 5 {
t.Fatalf("errors: %v", n.State.Errors)
}
if !strings.HasPrefix(n.State.Errors[0], "LLM eval failed for 'What capabilities am I missing?': connection refused") {
t.Errorf("error format: %q", n.State.Errors[0])
}
if n.State.Improvements[0] != "Self-evaluation completed" {
t.Errorf("terminator after errors: %v", n.State.Improvements)
}
}
// TestRunIteration — Python _run_iteration: question, [iter N] capture,
// LLM degrade, iteration-limit stop decision.
func TestRunIteration(t *testing.T) {
n := &NightMode{State: freshState()}
n.State.Iterations = 3
var captured [][]byte
n.post = fakeOllama("fix the flaky test", nil, &captured)
n.runIteration()
if n.State.Questions[0] != "Iteration 3: What should I improve next?" {
t.Errorf("question: %v", n.State.Questions)
}
if n.State.Improvements[0] != "[iter 3] fix the flaky test" {
t.Errorf("improvement: %v", n.State.Improvements)
}
// payload: iteration prompt, temperature 0.5, num_predict 400
var req struct {
Prompt string `json:"prompt"`
Options map[string]any `json:"options"`
}
json.Unmarshal(captured[0], &req)
if !strings.Contains(req.Prompt, "Currently in night mode iteration 3.") {
t.Errorf("prompt: %q", req.Prompt)
}
if req.Options["temperature"] != 0.5 || req.Options["num_predict"] != float64(400) {
t.Errorf("options: %v", req.Options)
}
// error path
n.State = freshState()
n.post = fakeOllama("", errors.New("boom"), nil)
n.runIteration()
if n.State.Errors[0] != "LLM iteration failed: boom" {
t.Errorf("error: %v", n.State.Errors)
}
// long answer truncated to 300
n.State = freshState()
n.post = fakeOllama(strings.Repeat("y", 400), nil, nil)
n.runIteration()
if len([]rune(n.State.Improvements[0])) != 300+len("[iter 0] ") {
t.Errorf("answer truncation: %d", len([]rune(n.State.Improvements[0])))
}
// safety limit: iteration 100 stops night mode
n.State = freshState()
n.State.Iterations = 100
n.State.Active = true
n.post = fakeOllama("ok", nil, nil)
n.runIteration()
if n.State.Active != false {
t.Errorf("safety limit: still active")
}
if n.State.Decisions[0] != "Reached iteration limit" {
t.Errorf("decision: %v", n.State.Decisions)
}
}
// TestRunLoop — Python _run_loop phase progression with IO seams injected.
func TestRunLoop(t *testing.T) {
frozen := time.Date(2026, 10, 13, 3, 0, 0, 0, time.UTC)
// Case A: zero duration → iterate phase skipped, full tail runs.
dir := t.TempDir()
n := newNightMode(filepath.Join(dir, "night_mode.json"))
n.now = func() time.Time { return frozen }
n.script = func() (int, string, error) { return 0, "", nil }
n.post = fakeOllama("improve the docs", nil, nil)
n.State.Active = true
n.State.DurationHrs = 0
n.runLoop()
if n.State.CurrentPhase != "complete" || n.State.Active != false {
t.Errorf("final: phase=%s active=%v", n.State.CurrentPhase, n.State.Active)
}
if n.State.Iterations != 0 {
t.Errorf("iterations: %d", n.State.Iterations)
}
sleeps := 0
for _, imp := range n.State.Improvements {
if imp == "Memory consolidation completed" {
sleeps++
}
}
if sleeps != 2 { // initial + final sleep
t.Errorf("sleep count: %d (%v)", sleeps, n.State.Improvements)
}
if !strings.HasPrefix(n.State.Improvements[len(n.State.Improvements)-1], "Report saved to ") {
t.Errorf("report marker: %v", n.State.Improvements)
}
var rep map[string]any
raw, err := os.ReadFile(n.ReportPath)
if err != nil {
t.Fatalf("report file: %v", err)
}
json.Unmarshal(raw, &rep)
if rep["summary"] != "Night mode completed 0 iterations" {
t.Errorf("report summary: %v", rep["summary"])
}
// Case B: iteration safety limit ends the loop even with time left.
dirB := t.TempDir()
nB := newNightMode(filepath.Join(dirB, "night_mode.json"))
nB.now = func() time.Time { return frozen }
nB.script = func() (int, string, error) { return 0, "", nil }
nB.post = fakeOllama("ok", nil, nil)
nB.wait = func(time.Duration, <-chan struct{}) {}
nB.State.Active = true
nB.State.Iterations = 100
nB.State.DurationHrs = 1
nB.runLoop()
if nB.State.Iterations != 101 {
t.Errorf("iterations: %d", nB.State.Iterations)
}
if nB.State.CurrentPhase != "complete" || nB.State.Active {
t.Errorf("final B: phase=%s active=%v", nB.State.CurrentPhase, nB.State.Active)
}
// Case C: stop during the interruptible inter-iteration sleep.
dirC := t.TempDir()
nC := newNightMode(filepath.Join(dirC, "night_mode.json"))
nC.now = func() time.Time { return frozen }
nC.script = func() (int, string, error) { return 0, "", nil }
nC.post = fakeOllama("ok", nil, nil)
nC.State.Active = true
nC.State.DurationHrs = 1
nC.stopCh = make(chan struct{})
nC.wait = func(_ time.Duration, stop <-chan struct{}) {
// simulate the stop event firing during the inter-iteration sleep:
// mark the state inactive (what a real stop() does) so the loop
// condition re-check sees it after the wait returns.
nC.State.Active = false
_ = stop
}
nC.runLoop()
if nC.State.Iterations != 1 {
t.Errorf("iterations after stop: %d", nC.State.Iterations)
}
if nC.State.CurrentPhase != "complete" {
t.Errorf("final C: %s", nC.State.CurrentPhase)
}
}
// TestTruncPhaseB — the ASCII fast path returns identical results to the
// rune walk on every shape: short ASCII, exact-length ASCII, long ASCII,
// multi-byte at and across the cut point.
func TestTruncPhaseB(t *testing.T) {
cases := []struct {
in string
n int
want string
}{
{"abc", 5, "abc"}, // short ASCII: zero-alloc path
{"abcde", 5, "abcde"}, // exact length: no cut
{"abcdef", 5, "abcde"}, // long ASCII: byte cut == rune cut
{"", 3, ""},
{"héllo", 3, "hél"}, // multi-byte before the cut
{"héllo", 5, "héllo"}, // multi-byte, no cut
{"abécd", 3, "abé"}, // cut lands right after multi-byte rune
{"ééé", 2, "éé"}, // all multi-byte
{"x" + strings.Repeat("é", 200), 100, "x" + strings.Repeat("é", 99)},
}
for _, c := range cases {
if got := trunc(c.in, c.n); got != c.want {
t.Errorf("trunc(%q, %d) = %q, want %q", c.in, c.n, got, c.want)
}
}
}
// TestStatusReportShapes — non-empty state through the shared status core
// and the report view.
func TestStatusReportShapes(t *testing.T) {
n := &NightMode{State: freshState()}
ts := "2026-10-13T03:00:00Z"
n.State.Active = true
n.State.StartedAt = &ts
n.State.CurrentPhase = "iterate"
n.State.Iterations = 7
n.State.Improvements = []string{"a", "b"}
n.State.Questions = []string{"q"}
n.State.Decisions = []string{"d"}
n.State.Errors = []string{"e"}
st := n.status()
want := map[string]any{
"active": true, "phase": "iterate", "iterations": 7,
"improvements": 2, "questions": 1, "decisions": 1, "errors": 1,
"started_at": ts, "duration_hours": 8.0,
}
if got := canonical(t, st); !reflect.DeepEqual(got, canonical(t, want)) {
t.Errorf("status: %v", got)
}
rep := n.report()
if rep["summary"] != "Night mode completed 7 iterations" || rep["duration"] != 8.0 {
t.Errorf("report: %v", rep)
}
if r := canonical(t, rep["improvements"]).([]any); len(r) != 2 {
t.Errorf("report improvements: %v", r)
}
}
+464 -6
View File
@@ -5,11 +5,16 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
)
type ProviderBudget struct {
@@ -26,7 +31,7 @@ type ProviderBudget struct {
TPMLimit int `json:"tpm_limit"`
TPMRemaining int `json:"tpm_remaining"`
Enabled bool `json:"enabled"`
LastCheck string `json:"last_check"`
LastCheck *string `json:"last_check"`
LastError *string `json:"last_error"`
}
@@ -103,12 +108,465 @@ func applyRateLimitHeaders(p *ProviderBudget, headers map[string]string) {
}
}
func main() {
if len(os.Args) < 2 || os.Args[1] != "replay" {
fmt.Fprintln(os.Stderr, "usage: provider-budget replay <truth.json>")
os.Exit(2)
// ── tracker (gap-closing wave): mirrors ProviderBudgetTracker ────────────
//
// The oracle's reactive surface (storage file, mimocode config, HTTP
// health checks, wall clock) sits behind injectable seams: StoragePath /
// ConfigPath are plain fields, Now is a func field, CheckEndpoint is the
// transport seam. The zero-value seams are only wired by
// newProviderBudgetTrackerAt / newProviderBudgetTracker.
// ProviderBudgetTracker — budget tracking + auto-failover across a provider
// pool persisted at StoragePath, seeded from the mimocode config when empty.
type ProviderBudgetTracker struct {
StoragePath string
ConfigPath string
Providers map[string]*ProviderBudget
// Order mirrors the oracle's dict insertion order: the stable sort in
// bestProvider breaks equal-budget ties by it, so Go map iteration
// (randomized) would be a parity bug.
Order []string
// Now pins the clock for last_check stamps (oracle: datetime.now(utc)).
Now func() time.Time
// CheckEndpoint is the HTTP health-check seam; default real GET.
CheckEndpoint func(url string, headers map[string]string) (map[string]string, error)
}
var homeDir = os.UserHomeDir
func newProviderBudgetTracker() *ProviderBudgetTracker {
home, err := homeDir()
if err != nil {
home = ""
}
raw, err := os.ReadFile(os.Args[2])
return newProviderBudgetTrackerAt(
filepath.Join(home, ".rune", "provider_budgets.json"),
filepath.Join(home, ".config", "mimocode", "mimocode.jsonc"),
)
}
func newProviderBudgetTrackerAt(storagePath, configPath string) *ProviderBudgetTracker {
t := &ProviderBudgetTracker{
StoragePath: storagePath,
ConfigPath: configPath,
Providers: map[string]*ProviderBudget{},
Now: func() time.Time { return time.Now().UTC() },
CheckEndpoint: defaultCheckEndpoint,
}
t.Load()
t.InitDefaultProviders()
return t
}
// decodeOrderedTable — ONE streaming pass over a JSON object with the
// file's key order preserved (Phase B: a single generic replaces the
// hand-rolled provider-table and config-table decoders). Key order IS
// parity state: the oracle's dict insertion order drives the stable-sort
// tie-break in bestProvider, and Go map iteration is randomized. Unknown
// keys are ignored, mirroring the oracle's field filtering.
func decodeOrderedTable[T any](raw []byte) (map[string]T, []string, error) {
dec := json.NewDecoder(bytes.NewReader(raw))
tok, err := dec.Token()
if err != nil {
return nil, nil, err
}
if d, ok := tok.(json.Delim); !ok || d != '{' {
return nil, nil, fmt.Errorf("ordered table: not a JSON object")
}
table := map[string]T{}
var order []string
for dec.More() {
keyTok, err := dec.Token()
if err != nil {
return nil, nil, err
}
key, ok := keyTok.(string)
if !ok {
return nil, nil, fmt.Errorf("ordered table: non-string key")
}
var v T
if err := dec.Decode(&v); err != nil {
return nil, nil, err
}
if _, seen := table[key]; !seen {
order = append(order, key)
}
table[key] = v
}
if _, err := dec.Token(); err != nil { // closing '}'
return nil, nil, err
}
return table, order, nil
}
// Load mirrors _load: missing or malformed storage is swallowed
// (best-effort degrade), never fatal.
func (t *ProviderBudgetTracker) Load() {
raw, err := os.ReadFile(t.StoragePath)
if err != nil {
return
}
providers, order, err := decodeOrderedTable[ProviderBudget](raw)
if err != nil {
return
}
pointers := make(map[string]*ProviderBudget, len(providers))
for name := range providers {
p := providers[name] // go 1.22: per-iteration variable
pointers[name] = &p
}
t.Providers = pointers
t.Order = order
}
// Save mirrors _save: providers serialized as a dict in insertion order.
func (t *ProviderBudgetTracker) Save() {
if err := os.MkdirAll(filepath.Dir(t.StoragePath), 0o755); err != nil {
return
}
var b bytes.Buffer
b.WriteString("{\n")
first := true
for _, name := range t.Order {
p, ok := t.Providers[name]
if !ok {
continue
}
entry, err := json.MarshalIndent(p.ToDict(), " ", " ")
if err != nil {
return
}
key, _ := json.Marshal(name)
if !first {
b.WriteString(",\n")
}
first = false
b.WriteString(" ")
b.Write(key)
b.WriteString(": ")
b.Write(entry)
}
b.WriteString("\n}\n")
_ = os.WriteFile(t.StoragePath, b.Bytes(), 0o644)
}
// InitDefaultProviders mirrors _init_default_providers: seed from the
// mimocode config when the pool is empty; skip the local ollama entry;
// save only when something was seeded.
func (t *ProviderBudgetTracker) InitDefaultProviders() {
if len(t.Providers) > 0 {
return
}
raw, err := os.ReadFile(t.ConfigPath)
if err != nil {
return
}
configTable, _, err := decodeOrderedTable[json.RawMessage](raw)
if err != nil {
return
}
provRaw, ok := configTable["provider"]
if !ok {
return
}
type providerConfig struct {
Options struct {
BaseURL string `json:"baseURL"`
APIKey string `json:"apiKey"`
} `json:"options"`
}
providerTable, providerOrder, err := decodeOrderedTable[providerConfig](provRaw)
if err != nil {
return
}
added := false
for _, name := range providerOrder {
if name == "ollama" {
continue // skip local
}
pc := providerTable[name]
providerType := "openai-compatible"
if strings.Contains(strings.ToLower(name), "anthropic") {
providerType = "anthropic"
}
apiKey := pc.Options.APIKey
t.Providers[name] = &ProviderBudget{
Name: name,
ProviderType: providerType,
URL: pc.Options.BaseURL,
APIKey: &apiKey,
Enabled: true,
}
t.Order = append(t.Order, name)
added = true
}
if added {
t.Save()
}
}
// TrackUsage mirrors track_usage: unknown providers are a silent no-op.
func (t *ProviderBudgetTracker) TrackUsage(providerName string, tokens int, cost float64) {
p, ok := t.Providers[providerName]
if !ok {
return
}
p.TokensUsed += tokens
p.MonthlyUsed += cost
t.Save()
}
func ptrString(s string) *string { return &s }
func (t *ProviderBudgetTracker) nowISO() string {
// oracle: datetime.now(timezone.utc).isoformat()
return t.Now().Format("2006-01-02T15:04:05.000000+00:00")
}
// UpdateRateLimits mirrors update_rate_limits: parse the 4 [OI]-style
// headers, stamp last_check, persist.
func (t *ProviderBudgetTracker) UpdateRateLimits(providerName string, headers map[string]string) {
p, ok := t.Providers[providerName]
if !ok {
return
}
applyRateLimitHeaders(p, headers)
p.LastCheck = ptrString(t.nowISO())
t.Save()
}
// defaultCheckEndpoint — real HTTP GET with the oracle's 5s budget; header
// keys are lowercased so update_rate_limits' [OI]-style lookups hit.
func defaultCheckEndpoint(url string, headers map[string]string) (map[string]string, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
for k, v := range headers {
req.Header.Set(k, v)
}
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
out := map[string]string{}
for k, vs := range resp.Header {
if len(vs) > 0 {
out[strings.ToLower(k)] = vs[0]
}
}
return out, nil
}
func truncateRunes(s string, n int) string {
r := []rune(s)
if len(r) <= n {
return s
}
return string(r[:n])
}
// CheckProvider mirrors check_provider: endpoint per provider type,
// auth headers per provider type, best-effort degrade on transport errors
// (last_error truncated to 100 runes), last_check + save always.
func (t *ProviderBudgetTracker) CheckProvider(providerName string) map[string]any {
p, ok := t.Providers[providerName]
if !ok {
return map[string]any{"available": false, "error": "Provider not found"}
}
headers := map[string]string{"Content-Type": "application/json"}
if p.APIKey != nil && *p.APIKey != "" {
if p.ProviderType == "anthropic" {
headers["x-api-key"] = *p.APIKey
headers["anthropic-version"] = "2023-06-01"
} else {
headers["Authorization"] = "Bearer " + *p.APIKey
}
}
url := p.URL + "/v1/models"
if p.ProviderType == "anthropic" {
// Anthropic has no /v1/models; the base URL is the reachability probe.
url = p.URL
}
if respHeaders, err := t.CheckEndpoint(url, headers); err == nil {
t.UpdateRateLimits(providerName, respHeaders)
p.LastError = nil
} else {
msg := truncateRunes(err.Error(), 100)
p.LastError = &msg
}
p.LastCheck = ptrString(t.nowISO())
t.Save()
return map[string]any{
"available": p.isAvailable(),
"budget_remaining": p.budgetRemaining(),
"tokens_remaining": p.tokensRemaining(),
"rpm_remaining": p.RPMRemaining,
"tpm_remaining": p.TPMRemaining,
"last_error": p.LastError,
}
}
// GetBestProvider mirrors get_best_provider: ordered pool → bestProvider.
func (t *ProviderBudgetTracker) GetBestProvider() *ProviderBudget {
ordered := make([]*ProviderBudget, 0, len(t.Order))
for _, name := range t.Order {
if p, ok := t.Providers[name]; ok {
ordered = append(ordered, p)
}
}
return bestProvider(ordered)
}
// Failover mirrors failover: disable the failed provider (if known), then
// fall through to the best remaining.
func (t *ProviderBudgetTracker) Failover(failedProvider string) *ProviderBudget {
if p, ok := t.Providers[failedProvider]; ok {
p.Enabled = false
t.Save()
}
return t.GetBestProvider()
}
// GetStatus mirrors get_status: every provider's dict + best provider name.
func (t *ProviderBudgetTracker) GetStatus() map[string]any {
providers := make(map[string]any, len(t.Providers))
for name, p := range t.Providers {
providers[name] = p.ToDict()
}
var best any
if b := t.GetBestProvider(); b != nil {
best = b.Name
}
return map[string]any{"providers": providers, "best_provider": best}
}
// ToDict mirrors ProviderBudget.to_dict — note the oracle deliberately
// EXCLUDES api_key from the persisted/status surface.
func (p *ProviderBudget) ToDict() map[string]any {
var lastCheck any
if p.LastCheck != nil {
lastCheck = *p.LastCheck
}
var lastError any
if p.LastError != nil {
lastError = *p.LastError
}
return map[string]any{
"name": p.Name,
"provider_type": p.ProviderType,
"url": p.URL,
"monthly_limit": p.MonthlyLimit,
"monthly_used": p.MonthlyUsed,
"token_limit": p.TokenLimit,
"tokens_used": p.TokensUsed,
"rpm_limit": p.RPMLimit,
"rpm_remaining": p.RPMRemaining,
"tpm_limit": p.TPMLimit,
"tpm_remaining": p.TPMRemaining,
"enabled": p.Enabled,
"last_check": lastCheck,
"last_error": lastError,
}
}
// ── module-level surface: global singleton + wrappers ────────────────────
var _tracker *ProviderBudgetTracker
func getTracker() *ProviderBudgetTracker {
if _tracker == nil {
_tracker = newProviderBudgetTracker()
}
return _tracker
}
func trackUsage(providerName string, tokens int, cost float64) {
getTracker().TrackUsage(providerName, tokens, cost)
}
func checkProvider(providerName string) map[string]any {
return getTracker().CheckProvider(providerName)
}
func getBestProvider() *ProviderBudget {
return getTracker().GetBestProvider()
}
func failover(failedProvider string) *ProviderBudget {
return getTracker().Failover(failedProvider)
}
func getStatus() map[string]any {
return getTracker().GetStatus()
}
func main() {
if len(os.Args) >= 3 && os.Args[1] == "replay" {
replayTruth(os.Args[2])
return
}
if len(os.Args) >= 4 && os.Args[1] == "parity" {
runParity(os.Args[2], os.Args[3])
return
}
fmt.Fprintln(os.Stderr, "usage: provider-budget replay <truth.json>\n provider-budget parity <ops.json> <home>")
os.Exit(2)
}
// runParity — random-op live-parity mode: execute the python driver's op
// script (track_usage / failover / best / status) against the same fixture
// home and print get_status after every op, one JSON object per line.
func runParity(opsPath, home string) {
raw, err := os.ReadFile(opsPath)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var ops []map[string]any
if err := json.Unmarshal(raw, &ops); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
t := &ProviderBudgetTracker{
StoragePath: filepath.Join(home, ".rune", "provider_budgets.json"),
ConfigPath: filepath.Join(home, ".config", "mimocode", "mimocode.jsonc"),
Providers: map[string]*ProviderBudget{},
Now: func() time.Time { return time.Now().UTC() },
CheckEndpoint: defaultCheckEndpoint,
}
t.Load()
t.InitDefaultProviders()
enc := json.NewEncoder(os.Stdout)
for _, op := range ops {
switch op["op"] {
case "track_usage":
name, _ := op["name"].(string)
tokens, _ := op["tokens"].(float64)
cost, _ := op["cost"].(float64)
t.TrackUsage(name, int(tokens), cost)
case "failover":
name, _ := op["name"].(string)
t.Failover(name)
case "best", "status":
// observation-only ops; status recorded below like the driver
}
if err := enc.Encode(t.GetStatus()); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
}
func replayTruth(path string) {
raw, err := os.ReadFile(path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
+379
View File
@@ -0,0 +1,379 @@
[
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"providers": {
"alpha": {
"name": "alpha",
"provider_type": "openai-compatible",
"url": "https://alpha.example/v1",
"monthly_limit": 10.0,
"monthly_used": 3.0,
"token_limit": 100000,
"tokens_used": 40000,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"beta": {
"name": "beta",
"provider_type": "openai-compatible",
"url": "https://beta.example/v1",
"monthly_limit": 5.0,
"monthly_used": 5.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"gamma": {
"name": "gamma",
"provider_type": "anthropic",
"url": "https://gamma.example",
"monthly_limit": 20.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
},
"delta": {
"name": "delta",
"provider_type": "openai-compatible",
"url": "https://delta.example/v1",
"monthly_limit": 7.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
}
},
"best_provider": "alpha"
}
},
{
"fn": "track_usage",
"args": [
"alpha",
5000,
2.5
],
"kwargs": {},
"expected": null
},
{
"fn": "track_usage",
"args": [
"alpha",
1000
],
"kwargs": {},
"expected": null
},
{
"fn": "track_usage",
"args": [
"ghost",
100
],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"providers": {
"alpha": {
"name": "alpha",
"provider_type": "openai-compatible",
"url": "https://alpha.example/v1",
"monthly_limit": 10.0,
"monthly_used": 5.5,
"token_limit": 100000,
"tokens_used": 46000,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"beta": {
"name": "beta",
"provider_type": "openai-compatible",
"url": "https://beta.example/v1",
"monthly_limit": 5.0,
"monthly_used": 5.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"gamma": {
"name": "gamma",
"provider_type": "anthropic",
"url": "https://gamma.example",
"monthly_limit": 20.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
},
"delta": {
"name": "delta",
"provider_type": "openai-compatible",
"url": "https://delta.example/v1",
"monthly_limit": 7.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
}
},
"best_provider": "delta"
}
},
{
"fn": "track_usage",
"args": [
"alpha",
0,
10.0
],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"providers": {
"alpha": {
"name": "alpha",
"provider_type": "openai-compatible",
"url": "https://alpha.example/v1",
"monthly_limit": 10.0,
"monthly_used": 15.5,
"token_limit": 100000,
"tokens_used": 46000,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"beta": {
"name": "beta",
"provider_type": "openai-compatible",
"url": "https://beta.example/v1",
"monthly_limit": 5.0,
"monthly_used": 5.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"gamma": {
"name": "gamma",
"provider_type": "anthropic",
"url": "https://gamma.example",
"monthly_limit": 20.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
},
"delta": {
"name": "delta",
"provider_type": "openai-compatible",
"url": "https://delta.example/v1",
"monthly_limit": 7.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
}
},
"best_provider": "delta"
}
},
{
"fn": "failover",
"args": [
"delta"
],
"kwargs": {},
"expected": null
},
{
"fn": "get_best_provider",
"args": [],
"kwargs": {},
"expected": null
},
{
"fn": "failover",
"args": [
"ghost"
],
"kwargs": {},
"expected": null
},
{
"fn": "get_status",
"args": [],
"kwargs": {},
"expected": {
"providers": {
"alpha": {
"name": "alpha",
"provider_type": "openai-compatible",
"url": "https://alpha.example/v1",
"monthly_limit": 10.0,
"monthly_used": 15.5,
"token_limit": 100000,
"tokens_used": 46000,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"beta": {
"name": "beta",
"provider_type": "openai-compatible",
"url": "https://beta.example/v1",
"monthly_limit": 5.0,
"monthly_used": 5.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"gamma": {
"name": "gamma",
"provider_type": "anthropic",
"url": "https://gamma.example",
"monthly_limit": 20.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
},
"delta": {
"name": "delta",
"provider_type": "openai-compatible",
"url": "https://delta.example/v1",
"monthly_limit": 7.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
}
},
"best_provider": null
}
},
{
"fn": "check_provider",
"args": [
"ghost"
],
"kwargs": {},
"expected": {
"available": false,
"error": "Provider not found"
}
},
{
"fn": "track_usage",
"args": [
"delta",
10,
0.25
],
"kwargs": {},
"expected": null
}
]
+480
View File
@@ -0,0 +1,480 @@
package main
// truth_frozen_test.go — the frozen-oracle battery for the provider_budget
// gap-closing wave (#2479 dichotomy). truth_frozen.json is the VERBATIM
// output of scripts/gen_provider_budget_truth.py (shared harness
// scripts/freeze_truth.py, RUNE_PROVIDER_BUDGET_CORE=python pinned):
// {"fn","args","kwargs","expected"} rows replayed IN ORDER against a
// rebuilt fixture home — exactly what the harness --verify does against
// the live oracle. The frozen surface is the module-level fn set
// (get_status / track_usage / failover / get_best_provider /
// check_provider); branches that cannot freeze (object returns, live
// timestamps, sockets) are pinned by the seam tests below.
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
)
// WARNING: keep byte-equal with CONFIG_FIXTURE / STORAGE_FIXTURE in
// scripts/gen_provider_budget_truth.py — the frozen truth is a replay
// script over THIS canonical initial state.
const configFixture = `{
"provider": {
"anthropic-claude": {
"options": {
"baseURL": "https://api.anthropic.example",
"apiKey": "sk-fixture-anthropic"
}
},
"openai-main": {
"options": {
"baseURL": "https://api.openai.example/v1",
"apiKey": "sk-fixture-openai"
}
},
"ollama": {
"options": {
"baseURL": "http://127.0.0.1:11434",
"apiKey": ""
}
}
}
}`
const storageFixture = `{
"alpha": {
"name": "alpha",
"provider_type": "openai-compatible",
"url": "https://alpha.example/v1",
"monthly_limit": 10.0,
"monthly_used": 3.0,
"token_limit": 100000,
"tokens_used": 40000,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"beta": {
"name": "beta",
"provider_type": "openai-compatible",
"url": "https://beta.example/v1",
"monthly_limit": 5.0,
"monthly_used": 5.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
},
"gamma": {
"name": "gamma",
"provider_type": "anthropic",
"url": "https://gamma.example",
"monthly_limit": 20.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": false,
"last_check": null,
"last_error": null
},
"delta": {
"name": "delta",
"provider_type": "openai-compatible",
"url": "https://delta.example/v1",
"monthly_limit": 7.0,
"monthly_used": 0.0,
"token_limit": 0,
"tokens_used": 0,
"rpm_limit": 0,
"rpm_remaining": 0,
"tpm_limit": 0,
"tpm_remaining": 0,
"enabled": true,
"last_check": null,
"last_error": null
}
}`
type truthRow struct {
Fn string `json:"fn"`
Args []any `json:"args"`
Kwargs map[string]any `json:"kwargs"`
Expected json.RawMessage `json:"expected"`
}
func writeFixture(t *testing.T, path, content string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
}
// newFixtureHome — the canonical fixture home the generator freezes over
// and the harness --verify replays from: seeded storage pool + mimocode
// config (the init branch's surface, unused while the pool is non-empty).
func newFixtureHome(t *testing.T) (storagePath, configPath string) {
t.Helper()
home := t.TempDir()
storagePath = filepath.Join(home, ".rune", "provider_budgets.json")
configPath = filepath.Join(home, ".config", "mimocode", "mimocode.jsonc")
writeFixture(t, storagePath, storageFixture)
writeFixture(t, configPath, configFixture)
return storagePath, configPath
}
func newSeamTracker(t *testing.T, storagePath, configPath string) *ProviderBudgetTracker {
t.Helper()
return &ProviderBudgetTracker{
StoragePath: storagePath,
ConfigPath: configPath,
Providers: map[string]*ProviderBudget{},
Now: func() time.Time {
return time.Date(2026, 10, 13, 12, 34, 56, 123456000, time.UTC)
},
CheckEndpoint: func(string, map[string]string) (map[string]string, error) {
t.Fatal("frozen truth replay must not touch the socket seam")
return nil, nil
},
}
}
// jsonRoundTrip — normalize through JSON so Go values compare against the
// oracle's dicts value-wise (Go "3" vs python "3.0" is the same number).
func jsonRoundTrip(t *testing.T, v any) any {
t.Helper()
b, err := json.Marshal(v)
if err != nil {
t.Fatal(err)
}
var out any
if err := json.Unmarshal(b, &out); err != nil {
t.Fatal(err)
}
return out
}
func argString(t *testing.T, v any) string {
t.Helper()
s, ok := v.(string)
if !ok {
t.Fatalf("expected string arg, got %T", v)
}
return s
}
// TestFrozenTruthReplay — the HARD gate: every frozen row replayed in
// order against the rebuilt fixture home must match the oracle verbatim.
func TestFrozenTruthReplay(t *testing.T) {
raw, err := os.ReadFile("truth_frozen.json")
if err != nil {
t.Fatalf("truth_frozen.json unusable (frozen oracle battery): %v", err)
}
var rows []truthRow
if err := json.Unmarshal(raw, &rows); err != nil {
t.Fatal(err)
}
storagePath, configPath := newFixtureHome(t)
tr := newSeamTracker(t, storagePath, configPath)
tr.Load()
tr.InitDefaultProviders()
for i, row := range rows {
var got any
switch row.Fn {
case "get_status":
got = tr.GetStatus()
case "track_usage":
if len(row.Args) < 2 {
t.Fatalf("row %d: bad track_usage args %v", i, row.Args)
}
tokens, _ := row.Args[1].(float64)
cost := 0.0
if len(row.Args) > 2 {
cost, _ = row.Args[2].(float64)
}
tr.TrackUsage(argString(t, row.Args[0]), int(tokens), cost)
got = nil
case "failover":
var p *ProviderBudget
if len(row.Args) > 0 {
p = tr.Failover(argString(t, row.Args[0]))
} else {
p = tr.Failover("")
}
if p != nil {
got = p.ToDict()
}
case "get_best_provider":
if p := tr.GetBestProvider(); p != nil {
got = p.ToDict()
}
case "check_provider":
got = tr.CheckProvider(argString(t, row.Args[0]))
default:
t.Fatalf("row %d: unknown fn %q — truth/battery drift", i, row.Fn)
}
var want any
if err := json.Unmarshal(row.Expected, &want); err != nil {
t.Fatalf("row %d: expected unusable: %v", i, err)
}
if !reflect.DeepEqual(jsonRoundTrip(t, got), want) {
gb, _ := json.Marshal(got)
t.Fatalf("row %d (%s) diverged from the frozen oracle:\n got %s\n want %s",
i, row.Fn, gb, row.Expected)
}
}
}
// TestToDictOmitsAPIKey — oracle to_dict deliberately drops api_key.
func TestToDictOmitsAPIKey(t *testing.T) {
key := "sk-secret"
check := "2026-10-13T00:00:00.000000+00:00"
p := &ProviderBudget{Name: "x", ProviderType: "openai-compatible", URL: "u",
APIKey: &key, LastCheck: &check, Enabled: true}
d := p.ToDict()
if _, ok := d["api_key"]; ok {
t.Fatal("to_dict must exclude api_key (oracle parity)")
}
if d["last_check"] != check {
t.Fatalf("set last_check must marshal verbatim: %v", d["last_check"])
}
if d["last_error"] != nil {
t.Fatalf("unset last_error must marshal as null: %v", d["last_error"])
}
}
// TestLoadFiltersUnknownKeysAndSwallowsGarbage — _load parity: field
// filtering (unknown keys dropped), malformed storage → empty pool.
func TestLoadFiltersUnknownKeysAndSwallowsGarbage(t *testing.T) {
dir := t.TempDir()
storagePath := filepath.Join(dir, "pb.json")
valid := `{"a": {"name": "a", "provider_type": "openai-compatible", "url": "u",
"monthly_limit": 4.0, "mystery_field": "dropped", "enabled": true}}`
writeFixture(t, storagePath, valid)
tr := &ProviderBudgetTracker{StoragePath: storagePath,
Providers: map[string]*ProviderBudget{}}
tr.Load()
if len(tr.Providers) != 1 || tr.Providers["a"] == nil || tr.Providers["a"].Name != "a" {
t.Fatalf("valid load diverged: %+v", tr.Providers)
}
writeFixture(t, storagePath, "not json at all")
tr2 := &ProviderBudgetTracker{StoragePath: storagePath,
Providers: map[string]*ProviderBudget{}}
tr2.Load()
if len(tr2.Providers) != 0 {
t.Fatalf("malformed storage must swallow to an empty pool, got %+v", tr2.Providers)
}
}
// TestLoadPreservesFileOrder — the tie-break depends on dict insertion
// order; Go map iteration would randomize it.
func TestLoadPreservesFileOrder(t *testing.T) {
dir := t.TempDir()
storagePath := filepath.Join(dir, "pb.json")
writeFixture(t, storagePath, `{
"zulu": {"name": "zulu", "monthly_limit": 10.0, "enabled": true},
"alpha": {"name": "alpha", "monthly_limit": 10.0, "enabled": true}
}`)
tr := &ProviderBudgetTracker{StoragePath: storagePath,
Providers: map[string]*ProviderBudget{}}
tr.Load()
if len(tr.Order) != 2 || tr.Order[0] != "zulu" || tr.Order[1] != "alpha" {
t.Fatalf("load order diverged: %v", tr.Order)
}
if got := tr.GetBestProvider(); got == nil || got.Name != "zulu" {
t.Fatalf("tie-break must follow file order, got %v", got)
}
}
// TestInitDefaultProviders — config seeding parity: ollama skipped,
// anthropic type detection, baseURL/apiKey plumbed, save-on-seed.
func TestInitDefaultProviders(t *testing.T) {
dir := t.TempDir()
storagePath := filepath.Join(dir, "pb.json")
configPath := filepath.Join(dir, "mimocode.jsonc")
writeFixture(t, configPath, configFixture)
tr := &ProviderBudgetTracker{StoragePath: storagePath, ConfigPath: configPath,
Providers: map[string]*ProviderBudget{}}
tr.Load()
tr.InitDefaultProviders()
if len(tr.Providers) != 2 {
t.Fatalf("want 2 seeded providers (ollama skipped), got %+v", tr.Providers)
}
anthropic := tr.Providers["anthropic-claude"]
if anthropic == nil || anthropic.ProviderType != "anthropic" ||
anthropic.URL != "https://api.anthropic.example" || anthropic.APIKey == nil ||
*anthropic.APIKey != "sk-fixture-anthropic" || !anthropic.Enabled {
t.Fatalf("anthropic seed diverged: %+v", anthropic)
}
openai := tr.Providers["openai-main"]
if openai == nil || openai.ProviderType != "openai-compatible" {
t.Fatalf("openai seed diverged: %+v", openai)
}
if _, err := os.Stat(storagePath); err != nil {
t.Fatalf("seed must persist: %v", err)
}
// non-empty pool → init is a no-op (oracle: only seeds when empty)
tr.Providers["manual"] = &ProviderBudget{Name: "manual", Enabled: true}
tr.InitDefaultProviders()
if len(tr.Providers) != 3 {
t.Fatalf("init must not reseed a non-empty pool: %+v", tr.Providers)
}
}
// TestCheckProviderSeams — the reactive surface with a fake transport:
// per-type endpoint + auth headers, rate-limit capture, pinned clock,
// best-effort degrade with the 100-rune last_error cap.
func TestCheckProviderSeams(t *testing.T) {
dir := t.TempDir()
storagePath := filepath.Join(dir, "pb.json")
writeFixture(t, storagePath, `{
"alpha": {"name": "alpha", "provider_type": "openai-compatible",
"url": "https://alpha.example/v1", "api_key": "sk-alpha", "enabled": true},
"gamma": {"name": "gamma", "provider_type": "anthropic",
"url": "https://gamma.example", "api_key": "sk-gamma", "enabled": true},
"nokey": {"name": "nokey", "provider_type": "openai-compatible",
"url": "https://nokey.example", "api_key": "", "enabled": true}
}`)
var gotURL string
var gotHeaders map[string]string
fakeHeaders := map[string]string{
"x-ratelimit-limit-requests": "60",
"x-ratelimit-remaining-requests": "42",
}
tr := &ProviderBudgetTracker{
StoragePath: storagePath,
ConfigPath: filepath.Join(dir, "missing.jsonc"),
Providers: map[string]*ProviderBudget{},
Now: func() time.Time {
return time.Date(2026, 10, 13, 0, 0, 0, 999999000, time.UTC)
},
CheckEndpoint: func(url string, headers map[string]string) (map[string]string, error) {
gotURL = url
gotHeaders = headers
return fakeHeaders, nil
},
}
tr.Load()
openai := tr.Providers["alpha"]
res := tr.CheckProvider("alpha")
if gotURL != "https://alpha.example/v1/v1/models" { // oracle: url + "/v1/models"
t.Fatalf("openai endpoint diverged: %q", gotURL)
}
if gotHeaders["Authorization"] != "Bearer sk-alpha" || gotHeaders["Content-Type"] != "application/json" {
t.Fatalf("openai auth headers diverged: %v", gotHeaders)
}
if openai.RPMLimit != 60 || openai.RPMRemaining != 42 {
t.Fatalf("rate-limit capture diverged: %+v", openai)
}
if openai.LastCheck == nil ||
*openai.LastCheck != "2026-10-13T00:00:00.999999+00:00" {
t.Fatalf("pinned clock stamp diverged: %v", openai.LastCheck)
}
if openai.LastError != nil {
t.Fatalf("success path must clear last_error: %v", *openai.LastError)
}
if res["available"] != true || res["rpm_remaining"] != 42 {
t.Fatalf("check result diverged: %v", res)
}
// anthropic arm: base-URL probe + x-api-key headers
gotURL, gotHeaders = "", nil
anthropic := tr.Providers["gamma"]
anthropic.APIKey = ptrString("sk-gamma")
tr.CheckProvider("gamma")
if gotURL != "https://gamma.example" {
t.Fatalf("anthropic endpoint diverged: %q", gotURL)
}
if gotHeaders["x-api-key"] != "sk-gamma" || gotHeaders["anthropic-version"] != "2023-06-01" {
t.Fatalf("anthropic auth headers diverged: %v", gotHeaders)
}
// empty api_key is falsy (oracle truthiness parity)
gotURL, gotHeaders = "", nil
tr.CheckProvider("nokey")
if _, ok := gotHeaders["Authorization"]; ok {
t.Fatalf("absent api_key must send no auth header: %v", gotHeaders)
}
// transport error arm: best-effort degrade, last_error capped at 100 runes
tr.CheckEndpoint = func(string, map[string]string) (map[string]string, error) {
return nil, fmt.Errorf("%s", strings.Repeat("x", 250))
}
res = tr.CheckProvider("alpha")
lePtr, ok := res["last_error"].(*string)
if !ok || lePtr == nil || len([]rune(*lePtr)) != 100 {
t.Fatalf("last_error must cap at 100 runes, got %v", res["last_error"])
}
if tr.Providers["alpha"].LastError == nil {
t.Fatal("error path must persist last_error")
}
}
// TestGetTrackerAndWrappers — the module-level surface: HOME-derived
// defaults, singleton identity, wrapper delegation.
func TestGetTrackerAndWrappers(t *testing.T) {
oldHome := homeDir
oldTracker := _tracker
defer func() { homeDir = oldHome; _tracker = oldTracker }()
storagePath, _ := newFixtureHome(t)
home := filepath.Dir(filepath.Dir(storagePath)) // storagePath → .rune → home
homeDir = func() (string, error) { return home, nil }
_tracker = nil
a := getTracker()
b := getTracker()
if a != b {
t.Fatal("get_tracker must be a singleton")
}
if len(a.Providers) != 4 {
t.Fatalf("HOME-derived tracker must load the fixture pool, got %v", a.Order)
}
trackUsage("alpha", 1, 0.5)
if a.Providers["alpha"].TokensUsed != 40001 || a.Providers["alpha"].MonthlyUsed != 3.5 {
t.Fatalf("trackUsage wrapper diverged: %+v", a.Providers["alpha"])
}
status := getStatus()
// alpha just tracked (rem 6.5) — the 7.0 tie now resolves to delta
if status["best_provider"] != "delta" {
t.Fatalf("getStatus wrapper diverged: %v", status["best_provider"])
}
if got := checkProvider("ghost"); got["error"] != "Provider not found" {
t.Fatalf("checkProvider wrapper diverged: %v", got)
}
if got := getBestProvider(); got == nil || got.Name != "delta" {
t.Fatalf("getBestProvider wrapper diverged: %v", got)
}
if got := failover("ghost"); got == nil || got.Name != "delta" {
t.Fatalf("failover (unknown) wrapper diverged: %v", got)
}
}
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.271.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.271.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.271.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.271.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})
+132 -8
View File
@@ -1,11 +1,32 @@
#!/usr/bin/env python3
"""ctypes loader for the Rust structural_store core (facade-1 burn-down).
"""ctypes loader for the Rust structural_store core (facade-1 burn-down;
dichotomy-wave gap-closing tranche mirrors broker_loader.py's contract).
FFI contract (doc-envelope law):
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
* ss_maturity_rank({state}) -> int (spine ladder)
* ss_promote({doc, id, state, evidence_ref, now}) -> updated doc
* ss_supersede({doc, new_id, old_id, evidence_ref, now}) -> updated doc
* ss_resolve_status({entity}) -> string
* ss_sorted({value}) -> normalized value
* ss_new_doc({now}) -> doc
* ss_redact_secrets({value}) -> redacted value
* ss_save({doc, path}) -> {"doc", "path"} (writes the file)
* ss_canonical_digest({doc}) -> hex digest
* ss_snapshot({doc, snapshots_dir, label, tag, now}) -> {"doc", "path"}
* ss_alias({doc, canonical_id, old_id, now}) -> updated doc
* ss_spine_uri({entity_id}) -> string
* ss_resolve_uri({uri}) -> string
* ss_doc_authorities({doc}) -> updated doc
* ss_authority_health({doc}) -> per-projector map
* ss_bind_task({doc, task_id, entity_ids, evidence_ref, now}) -> updated doc
* ss_task_entities({doc, task_id}) -> [entity id]
* ss_impact_frontier({doc, seed_ids, max_level, change_kind}) -> frontier
* ss_record_observed_impact({doc, task_id, evidence_items, now})
-> {"doc", "result"}
* ss_predicted_vs_observed({predicted, observed_doc, seed_ids}) -> delta
* ss_structural_events({doc}) -> [event]
* ss_diff({old, new}) -> delta
* ss_dedupe_observations({doc}) -> updated doc
* ss_free_string(ptr)
FFI segfault law: explicit argtypes + restype (c_void_p for char*).
@@ -26,6 +47,16 @@ _LIB_PATH = Path(
)
)
_SYMBOLS = (
"ss_maturity_rank", "ss_promote", "ss_supersede", "ss_resolve_status",
"ss_sorted", "ss_new_doc", "ss_redact_secrets", "ss_save",
"ss_canonical_digest", "ss_snapshot", "ss_alias", "ss_spine_uri",
"ss_resolve_uri", "ss_doc_authorities", "ss_authority_health",
"ss_bind_task", "ss_task_entities", "ss_impact_frontier",
"ss_record_observed_impact", "ss_predicted_vs_observed",
"ss_structural_events", "ss_diff", "ss_dedupe_observations",
)
_lib = None
@@ -42,10 +73,9 @@ def _load() -> ctypes.CDLL:
lib = ctypes.CDLL(str(_LIB_PATH))
lib.ss_free_string.argtypes = [ctypes.c_void_p]
lib.ss_free_string.restype = None
for sym in ("ss_maturity_rank", "ss_promote", "ss_supersede",
"ss_resolve_status"):
for sym in _SYMBOLS:
fn = getattr(lib, sym)
fn.argtypes = [ctypes.c_char_p]
fn.argtypes = [ctypes.c_void_p]
fn.restype = ctypes.c_void_p
_lib = lib
return lib
@@ -53,16 +83,20 @@ def _load() -> ctypes.CDLL:
def _call(sym: str, payload: dict):
lib = _load()
ptr = getattr(lib, sym)(json.dumps(payload).encode("utf-8"))
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")
try:
text = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
text = ctypes.string_at(ptr).decode("utf-8")
finally:
lib.ss_free_string(ptr)
env = json.loads(text)
if not env.get("ok"):
raise RuntimeError(f"{sym} core error: {env.get('err')}")
# the kernel error travels VERBATIM: the facade translates it into
# the oracle's ValueError contract (message text must match 1:1)
raise RuntimeError(env.get("err") or f"{sym} failed")
return env["value"]
@@ -84,3 +118,93 @@ def supersede(doc: dict, new_id: str, old_id: str, evidence_ref: str,
def resolve_status(entity: dict) -> str:
return _call("ss_resolve_status", {"entity": entity})
def sorted_value(value):
return _call("ss_sorted", {"value": value})
def new_doc(now: str) -> dict:
return _call("ss_new_doc", {"now": now})
def redact_secrets(value):
return _call("ss_redact_secrets", {"value": value})
def save(doc: dict, path: str) -> dict:
return _call("ss_save", {"doc": doc, "path": path})
def canonical_digest(doc: dict) -> str:
return _call("ss_canonical_digest", {"doc": doc})
def snapshot(doc: dict, snapshots_dir: str, label: str, tag: str, now: str) -> dict:
return _call("ss_snapshot", {"doc": doc, "snapshots_dir": snapshots_dir,
"label": label, "tag": tag, "now": now})
def alias(doc: dict, canonical_id: str, old_id: str, now: str) -> dict:
return _call("ss_alias", {"doc": doc, "canonical_id": canonical_id,
"old_id": old_id, "now": now})
def spine_uri(entity_id: str) -> str:
return _call("ss_spine_uri", {"entity_id": entity_id})
def resolve_uri(uri: str) -> str:
return _call("ss_resolve_uri", {"uri": uri})
def doc_authorities(doc: dict) -> dict:
return _call("ss_doc_authorities", {"doc": doc})
def authority_health(doc: dict) -> dict:
return _call("ss_authority_health", {"doc": doc})
def bind_task(doc: dict, task_id: str, entity_ids: list, evidence_ref: str,
now: str) -> dict:
return _call("ss_bind_task", {"doc": doc, "task_id": task_id,
"entity_ids": entity_ids,
"evidence_ref": evidence_ref, "now": now})
def task_entities(doc: dict, task_id: str) -> list:
return _call("ss_task_entities", {"doc": doc, "task_id": task_id})
def impact_frontier(doc: dict, seed_ids: list, max_level: int = 2,
change_kind=None):
return _call("ss_impact_frontier", {"doc": doc, "seed_ids": seed_ids,
"max_level": max_level,
"change_kind": change_kind})
def record_observed_impact(doc: dict, task_id: str, evidence_items: list,
now: str) -> dict:
return _call("ss_record_observed_impact", {"doc": doc, "task_id": task_id,
"evidence_items": evidence_items,
"now": now})
def predicted_vs_observed(predicted: dict, observed_doc: dict,
seed_ids: list) -> dict:
return _call("ss_predicted_vs_observed", {"predicted": predicted,
"observed_doc": observed_doc,
"seed_ids": seed_ids})
def structural_events(doc: dict) -> list:
return _call("ss_structural_events", {"doc": doc})
def diff(old: dict, new: dict) -> dict:
return _call("ss_diff", {"old": old, "new": new})
def dedupe_observations(doc: dict) -> dict:
return _call("ss_dedupe_observations", {"doc": doc})
+84
View File
@@ -85,6 +85,9 @@ def _sorted(obj):
def new_doc() -> dict:
core = _ss_core()
if core is not None:
return core.new_doc(now())
return {
"schema_version": SCHEMA_VERSION,
"generated_at": now(),
@@ -143,6 +146,18 @@ def _redact_secrets(obj):
def save(doc: dict, path: Path | str) -> Path:
core = _ss_core()
if core is not None:
try:
out = core.save(doc, str(path))
except RuntimeError as exc:
# Kernel errors carry the oracle's ValueError semantics through
# the envelope — translate back to the documented contract.
raise ValueError(str(exc)) from exc
if isinstance(out.get("doc"), dict):
doc.clear()
doc.update(out["doc"])
return Path(out["path"])
incoming = doc.get("schema_version", SCHEMA_VERSION)
if incoming != SCHEMA_VERSION:
raise ValueError(f"schema_version {incoming} != {SCHEMA_VERSION}")
@@ -160,6 +175,10 @@ def canonical_digest(doc: dict) -> str:
identical semantic content always yields an identical digest."""
import hashlib
core = _ss_core()
if core is not None:
return core.canonical_digest(doc)
payload = json.dumps(_sorted(_redact_secrets(doc)), sort_keys=True)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
@@ -168,6 +187,13 @@ def snapshot(doc: dict, snapshots_dir: Path, label: str = "", tag: str = "") ->
"""Persist an immutable snapshot. `tag` is a caller-supplied identity
fragment (Spine uses the deployed SHA; a Project Scaffold may use its
repo HEAD or 'noident')."""
core = _ss_core()
if core is not None:
out = core.snapshot(doc, str(snapshots_dir), label, tag, now())
if isinstance(out.get("doc"), dict):
doc.clear()
doc.update(out["doc"])
return Path(out["path"])
snapshots_dir = Path(snapshots_dir)
snapshots_dir.mkdir(parents=True, exist_ok=True)
name = f"snap-{time.strftime('%Y%m%dT%H%M%SZ', time.gmtime())}-{(tag or 'noident')[:8]}"
@@ -312,6 +338,16 @@ def promote(doc: dict, id: str, state: str, evidence_ref: str) -> dict | None:
def alias(doc: dict, canonical_id: str, old_id: str) -> dict:
"""RENAME: same conceptual entity, identifier changed. Old references
stay resolvable (entity() follows alias entries)."""
core = _ss_core()
if core is not None:
try:
out = core.alias(doc, canonical_id, old_id, now())
except RuntimeError as exc:
raise ValueError(str(exc)) from exc
if isinstance(out, dict):
doc.clear()
doc.update(out)
return entity(doc, canonical_id)
e = entity(doc, canonical_id)
if e is None:
raise ValueError(f"alias target not found: {canonical_id}")
@@ -344,11 +380,20 @@ def supersede(doc: dict, new_id: str, old_id: str, evidence_ref: str) -> dict:
def spine_uri(entity_id: str) -> str:
"""Stable cross-graph identity: spine://<kind>/<name>. A future Memory
record cites this URI without duplicating structural authority."""
core = _ss_core()
if core is not None:
return core.spine_uri(entity_id)
kind, _, name = entity_id.partition(":")
return f"spine://{kind}/{name}"
def resolve_uri(uri: str) -> str:
core = _ss_core()
if core is not None:
try:
return core.resolve_uri(uri)
except RuntimeError as exc:
raise ValueError(str(exc)) from exc
scheme, _, rest = uri.partition("://")
if scheme != "spine":
raise ValueError(f"not a spine URI: {uri}")
@@ -460,6 +505,9 @@ def resolve_status(e: dict) -> str:
def authority_health(doc: dict) -> dict:
"""Provenance/freshness per projector — provenance only, not monitoring."""
core = _ss_core()
if core is not None:
return core.authority_health(doc)
return {
name: {
"generation": a.get("generation", 0),
@@ -478,6 +526,13 @@ def authority_health(doc: dict) -> dict:
def bind_task(doc: dict, task_id: str, entity_ids: list[str], evidence_ref: str = "") -> dict:
"""TASK/ISSUE/INTENT BINDING: task → affects → entities. Deterministic."""
core = _ss_core()
if core is not None:
out = core.bind_task(doc, task_id, list(entity_ids), evidence_ref, now())
if isinstance(out, dict):
doc.clear()
doc.update(out)
return entity(doc, f"task:{task_id}") or {"id": f"task:{task_id}"}
for eid in entity_ids:
add_relationship(
doc,
@@ -490,6 +545,9 @@ def bind_task(doc: dict, task_id: str, entity_ids: list[str], evidence_ref: str
def task_entities(doc: dict, task_id: str) -> list[str]:
core = _ss_core()
if core is not None:
return core.task_entities(doc, task_id)
return sorted(r["to"] for r in relationships(doc, from_id=f"task:{task_id}", type="affects"))
@@ -502,6 +560,9 @@ def impact_frontier(doc: dict, seed_ids: list[str], max_level: int = 2, change_k
contract_violation (escalates siblings to obligations). None infers from
seed kind. Unknown relationship types are obligation-bearing (fail-loud);
NON_OBLIGATION types and CANDIDATE/STALE facts are skipped."""
core = _ss_core()
if core is not None:
return core.impact_frontier(doc, list(seed_ids), max_level, change_kind)
seeds = list(dict.fromkeys(seed_ids))
level0 = sorted(set(seeds))
level1: set[str] = set()
@@ -578,6 +639,13 @@ def record_observed_impact(doc: dict, task_id: str, evidence_items: list[dict])
"""INDEPENDENT OBSERVED IMPACT: derive what was ACTUALLY affected from
external evidence (tests, canaries, runtime, deploy) — never by re-running
the frontier being evaluated. Nothing auto-promotes into structure."""
core = _ss_core()
if core is not None:
out = core.record_observed_impact(doc, task_id, list(evidence_items), now())
if isinstance(out.get("doc"), dict):
doc.clear()
doc.update(out["doc"])
return out["result"]
implicated: set[str] = set()
for item in evidence_items:
eid = item.get("entity", "")
@@ -599,6 +667,9 @@ def record_observed_impact(doc: dict, task_id: str, evidence_items: list[dict])
def predicted_vs_observed(predicted: dict, observed_doc: dict, seed_ids: list[str]) -> dict:
core = _ss_core()
if core is not None:
return core.predicted_vs_observed(predicted, observed_doc, list(seed_ids))
observed = impact_frontier(observed_doc, seed_ids)
pred_set = {
e
@@ -629,6 +700,9 @@ def predicted_vs_observed(predicted: dict, observed_doc: dict, seed_ids: list[st
def structural_events(doc: dict) -> list[dict]:
"""GENERIC EVENT/QUERY SEAM: dumb typed structural facts for future
subscribers. No salience, no policy."""
core = _ss_core()
if core is not None:
return core.structural_events(doc)
events = []
for e in doc["entities"]:
events.append(
@@ -657,6 +731,9 @@ def structural_events(doc: dict) -> list[dict]:
def diff(old: dict, new: dict) -> dict:
"""Deterministic structural delta. No interpretation."""
core = _ss_core()
if core is not None:
return core.diff(old, new)
oe = {e["id"]: e for e in old.get("entities", [])}
ne = {e["id"]: e for e in new.get("entities", [])}
ors = {(r["type"], r["from"], r["to"]) for r in old.get("relationships", [])}
@@ -680,6 +757,13 @@ def diff(old: dict, new: dict) -> dict:
def dedupe_observations(doc: dict) -> None:
"""Exact-duplicate observation suppression (carry-forward + re-derivation
both record; distinct repeats are history and stay)."""
core = _ss_core()
if core is not None:
out = core.dedupe_observations(doc)
if isinstance(out, dict):
doc.clear()
doc.update(out)
return
seen: set[str] = set()
unique = []
for o in doc.get("observations", []):
+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.
+28
View File
@@ -2,6 +2,32 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "evidence_provenance"
version = "0.1.0"
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "indexmap"
version = "2.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.18"
@@ -68,6 +94,7 @@ version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"indexmap",
"itoa",
"memchr",
"serde",
@@ -79,6 +106,7 @@ dependencies = [
name = "structural_store"
version = "0.1.0"
dependencies = [
"evidence_provenance",
"serde",
"serde_json",
]
+4 -1
View File
@@ -8,4 +8,7 @@ crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# preserve_order: Python dicts round-trip in insertion order — str() of a
# detail dict and doc-echo order follow the oracle.
serde_json = { version = "1", features = ["preserve_order"] }
evidence_provenance = { path = "../evidence_provenance" }
@@ -0,0 +1,352 @@
//! frozen_battery — replay the FROZEN oracle truth VERBATIM
//! (frozen_ss_truth.json, generated by scripts/gen_structural_store_truth.py
//! against the LIVE Python oracle with RUNE_STRUCTURAL_CORE=python pinned,
//! clock pinned via structural_store.now, inputs deep-copied per case).
//!
//! The canary never imports the Python oracle — parity stays provable after
//! strangler exits.
use crate::*;
use serde_json::Value;
use std::cell::RefCell;
const TRUTH: &str = include_str!("frozen_ss_truth.json");
const NOW: &str = "2026-10-13T01:02:03Z";
fn truth() -> Value {
serde_json::from_str(TRUTH).expect("frozen truth parses")
}
fn cases(group: &str) -> Vec<Value> {
truth()["groups"][group]
.as_array()
.cloned()
.unwrap_or_default()
}
fn nm(c: &Value) -> &str {
c["name"].as_str().unwrap_or("")
}
/// Recording I/O seam — save/snapshot write into memory, never the disk.
struct RecIo {
writes: RefCell<Vec<(String, String)>>,
}
impl RecIo {
fn new() -> Self {
RecIo { writes: RefCell::new(vec![]) }
}
fn content(&self, path: &str) -> String {
self.writes
.borrow()
.iter()
.find(|(p, _)| p == path)
.map(|(_, c)| c.clone())
.unwrap_or_default()
}
}
impl SsIo for RecIo {
fn mkdir_parents(&self, _dir: &str) -> Result<(), String> {
Ok(())
}
fn write_text(&self, path: &str, contents: &str) -> Result<(), String> {
self.writes.borrow_mut().push((path.to_string(), contents.to_string()));
Ok(())
}
}
fn expect_err(c: &Value, got: Result<impl std::fmt::Debug, String>) {
match c["expect"].get("err").and_then(|e| e.as_str()) {
Some(want) => {
let e = got.expect_err(&format!("case {} should raise", nm(c)));
assert_eq!(e, want, "case {} error message", nm(c));
}
None => {
got.unwrap_or_else(|e| panic!("case {} raised: {}", nm(c), e));
}
}
}
fn de<'a>(c: &'a Value, keys: &[&str]) -> &'a Value {
let mut cur = c;
for k in keys {
cur = &cur[k];
}
cur
}
// ── pure normalizers ────────────────────────────────────────────────────────
#[test]
fn replay_sorted() {
for c in &cases("sorted") {
let got = _sorted(de(c, &["args", "value"]));
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_new_doc() {
for c in &cases("new_doc") {
let got = new_doc(NOW);
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_redact() {
for c in &cases("redact") {
let got = _redact_secrets(de(c, &["args", "value"]));
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_save() {
for c in &cases("save") {
let mut doc = de(c, &["args", "doc"]).clone();
let path = format!("out/{}/store.json", nm(c));
let io = RecIo::new();
let got = save(&mut doc, &path, &io);
expect_err(c, got);
if c["expect"].get("ok").is_some() {
assert_eq!(io.content(&path), de(c, &["expect", "ok", "content"]).as_str().unwrap(), "case {} content", nm(c));
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
}
}
}
#[test]
fn replay_digest() {
for c in &cases("digest") {
let got = canonical_digest(de(c, &["args", "doc"]));
let want = de(c, &["expect", "ok"]);
if want.is_array() {
// multi-assert cases: digests of related docs must agree pairwise
let digests: Vec<Value> = if c["args"].get("doc_reordered").is_some() {
vec![
json!(canonical_digest(de(c, &["args", "doc"]))),
json!(canonical_digest(de(c, &["args", "doc_reordered"]))),
]
} else if c["args"].get("doc").is_some() && c["name"] == "secret_never_changes_digest" {
let d = de(c, &["args", "doc"]);
let d2 = { let mut x = d.clone(); x["token"] = json!("other"); x };
vec![json!(canonical_digest(d)), json!(canonical_digest(&d2))]
} else {
vec![json!(got.clone())]
};
assert_eq!(json!(digests), want.clone(), "case {}", nm(c));
} else {
assert_eq!(json!(got), want.clone(), "case {}", nm(c));
}
}
}
#[test]
fn replay_snapshot() {
for c in &cases("snapshot") {
let mut doc = de(c, &["args", "doc"]).clone();
let dir = de(c, &["args", "dir"]).as_str().unwrap();
let label = de(c, &["args", "label"]).as_str().unwrap();
let tag = de(c, &["args", "tag"]).as_str().unwrap();
let io = RecIo::new();
let got = snapshot(&mut doc, dir, label, tag, NOW, &io).expect("snapshot ok");
assert_eq!(json!(got), de(c, &["expect", "ok", "path"]).clone(), "case {} path", nm(c));
assert_eq!(io.content(&got), de(c, &["expect", "ok", "content"]).as_str().unwrap(), "case {} content", nm(c));
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
}
}
#[test]
fn replay_alias() {
for c in &cases("alias") {
let mut doc = de(c, &["args", "doc"]).clone();
let cid = de(c, &["args", "cid"]).as_str().unwrap();
let old = de(c, &["args", "old"]).as_str().unwrap();
let got = alias(&mut doc, cid, old, NOW);
match c["expect"].get("err") {
Some(_) => expect_err(c, got),
None => assert_eq!(got.expect("alias ok"), de(c, &["expect", "ok"]).clone(), "case {}", nm(c)),
}
}
}
#[test]
fn replay_spine_uri() {
for c in &cases("spine_uri") {
let got = spine_uri(de(c, &["args", "entity_id"]).as_str().unwrap());
assert_eq!(json!(got), de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_resolve_uri() {
for c in &cases("resolve_uri") {
let got = resolve_uri(de(c, &["args", "uri"]).as_str().unwrap());
expect_err(c, got.clone());
if c["expect"].get("ok").is_some() {
assert_eq!(json!(got.unwrap()), de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
}
#[test]
fn replay_doc_authorities() {
for c in &cases("doc_authorities") {
let mut doc = de(c, &["args", "doc"]).clone();
let ret = _doc_authorities(&mut doc).clone();
assert_eq!(json!(ret), de(c, &["expect", "ok", "ret"]).clone(), "case {} ret", nm(c));
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
}
}
#[test]
fn replay_authority_health() {
for c in &cases("authority_health") {
let got = authority_health(de(c, &["args", "doc"]));
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_bind_task() {
for c in &cases("bind_task") {
let mut doc = de(c, &["args", "doc"]).clone();
let task_id = de(c, &["args", "task_id"]).as_str().unwrap();
let ids: Vec<String> = de(c, &["args", "entity_ids"])
.as_array().unwrap()
.iter().map(|x| x.as_str().unwrap().to_string()).collect();
let ev = de(c, &["args", "evidence_ref"]).as_str().unwrap();
bind_task(&mut doc, task_id, &ids, ev, NOW);
let ret = entity_ref(&doc, &format!("task:{}", task_id))
.cloned()
.unwrap_or(json!({"id": format!("task:{}", task_id)}));
assert_eq!(json!(ret), de(c, &["expect", "ok", "ret"]).clone(), "case {} ret", nm(c));
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
}
}
#[test]
fn replay_task_entities() {
for c in &cases("task_entities") {
let got = task_entities(de(c, &["args", "doc"]), de(c, &["args", "task_id"]).as_str().unwrap());
assert_eq!(json!(got), de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_impact_frontier() {
for c in &cases("impact_frontier") {
let got = impact_frontier(
de(c, &["args", "doc"]),
&de(c, &["args", "seeds"]).as_array().unwrap()
.iter().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<_>>(),
de(c, &["args", "max_level"]).as_i64().unwrap_or(2),
de(c, &["args", "change_kind"]).as_str(),
);
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_observed_impact() {
for c in &cases("observed_impact") {
let mut doc = de(c, &["args", "doc"]).clone();
let items: Vec<Value> = de(c, &["args", "items"]).as_array().unwrap().clone();
let got = record_observed_impact(&mut doc, "T1", &items, NOW);
assert_eq!(json!(got), de(c, &["expect", "ok", "result"]).clone(), "case {} result", nm(c));
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
}
}
#[test]
fn replay_predicted_vs_observed() {
for c in &cases("predicted_vs_observed") {
let seeds: Vec<String> = de(c, &["args", "seeds"]).as_array().unwrap()
.iter().map(|x| x.as_str().unwrap().to_string()).collect();
let got = predicted_vs_observed(de(c, &["args", "predicted"]), de(c, &["args", "observed_doc"]), &seeds);
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_structural_events() {
for c in &cases("events") {
let got = structural_events(de(c, &["args", "doc"]));
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_diff() {
for c in &cases("diff") {
let got = diff(de(c, &["args", "old"]), de(c, &["args", "new"]));
assert_eq!(got, de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_dedupe() {
for c in &cases("dedupe") {
let mut doc = de(c, &["args", "doc"]).clone();
dedupe_observations(&mut doc);
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {} doc", nm(c));
assert!(de(c, &["expect", "ok", "ret"]).is_null(), "case {} ret", nm(c));
}
}
// ── fixed-kernel regressions ────────────────────────────────────────────────
#[test]
fn replay_promote_fix() {
for c in &cases("promote_fix") {
let mut doc = de(c, &["args", "doc"]).clone();
let id = de(c, &["args", "id"]).as_str().unwrap();
let state = de(c, &["args", "state"]).as_str().unwrap();
let ev = de(c, &["args", "ev"]).as_str().unwrap();
let got = promote(&mut doc, id, state, ev, NOW);
let ret = de(c, &["expect", "ok", "ret"]);
let want_doc = de(c, &["expect", "ok", "doc"]);
if ret.is_null() {
assert_eq!(got, Ok(None), "case {} ret", nm(c));
} else {
// oracle promote returns the ENTITY; the ret maturity is the
// observed outcome (doc compare below proves the full shape)
let got_str = got.as_ref().ok().and_then(|o| o.as_deref());
assert_eq!(got_str, Some(ret["maturity"].as_str().unwrap()), "case {} ret", nm(c));
}
assert_eq!(doc, want_doc.clone(), "case {} doc", nm(c));
}
}
#[test]
fn replay_resolve_status_fix() {
for c in &cases("resolve_status_fix") {
let got = resolve_status(de(c, &["args", "entity"]));
assert_eq!(json!(got), de(c, &["expect", "ok"]).clone(), "case {}", nm(c));
}
}
#[test]
fn replay_supersede_fix() {
for c in &cases("supersede_fix") {
let mut doc = de(c, &["args", "doc"]).clone();
let nid = de(c, &["args", "new"]).as_str().unwrap();
let oid = de(c, &["args", "old"]).as_str().unwrap();
let ev = de(c, &["args", "ev"]).as_str().unwrap();
supersede(&mut doc, nid, oid, ev, NOW).expect("supersede ok");
assert_eq!(doc, de(c, &["expect", "ok", "doc"]).clone(), "case {}", nm(c));
}
}
// ── the core probe mirror (RUNE_STRUCTURAL_CORE=python pin) ─────────────────
#[test]
fn ss_core_pin_semantics() {
assert!(_ss_core(Some("python")).is_none(), "python pin disables the core");
assert!(_ss_core(None).is_some(), "unset pin activates the core");
assert!(_ss_core(Some("auto")).is_some(), "auto activates the core");
assert_eq!(_ss_core(Some("auto")).unwrap().id(), "rust");
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+94 -72
View File
@@ -2,7 +2,9 @@
//! PARITY port of the core data structures from src/rune/structural_store.py.
use serde::{Deserialize, Serialize};
pub const SCHEMA_VERSION: i32 = 3;
// Oracle law: structural_store.SCHEMA_VERSION == 1 (shared with spine stores).
// (Previous port carried a stale 3 — corrected against the live oracle.)
pub const SCHEMA_VERSION: i32 = 1;
pub const MATURITY_ORDER: &[&str] = &["UNRUN", "DECLARED", "PRESENT", "VERIFIED"];
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -75,7 +77,7 @@ impl Default for StoreDoc {
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
fn read_arg(ptr: *const c_char) -> Result<String, String> {
pub(crate) fn read_arg(ptr: *const c_char) -> Result<String, String> {
if ptr.is_null() {
return Err("null argument pointer".to_string());
}
@@ -85,7 +87,7 @@ fn read_arg(ptr: *const c_char) -> Result<String, String> {
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
}
fn envelope(value: Result<serde_json::Value, String>) -> *mut c_char {
pub(crate) fn envelope(value: Result<serde_json::Value, String>) -> *mut c_char {
let body = match value {
Ok(v) => serde_json::json!({"ok": true, "value": v}),
Err(e) => serde_json::json!({"ok": false, "err": e}),
@@ -95,11 +97,11 @@ fn envelope(value: Result<serde_json::Value, String>) -> *mut c_char {
.unwrap_or(std::ptr::null_mut())
}
fn parse_arg(text: &str) -> Result<serde_json::Value, String> {
pub(crate) fn parse_arg(text: &str) -> Result<serde_json::Value, String> {
serde_json::from_str(text).map_err(|e| format!("argument JSON parse failed: {}", e))
}
fn get_str<'a>(v: &'a serde_json::Value, key: &str) -> Option<&'a str> {
pub(crate) fn get_str<'a>(v: &'a serde_json::Value, key: &str) -> Option<&'a str> {
v.get(key).and_then(|x| x.as_str())
}
@@ -223,7 +225,9 @@ pub fn is_known_maturity(state: &str) -> bool {
}
/// Evidence-gated promotion. Demotion is never silent: recorded, not applied.
/// Returns Ok(Some(updated maturity)) / Ok(demotion-rejected marker) / Err.
/// Oracle contract order: unknown id → Ok(None) (silent, the caller surfaces
/// the miss); then evidence required; then known state required. Entity
/// resolution follows alias entries (oracle entity()).
pub fn promote(
doc: &mut serde_json::Value,
id: &str,
@@ -231,8 +235,8 @@ pub fn promote(
evidence_ref: &str,
now_iso: &str,
) -> Result<Option<String>, String> {
if !is_known_maturity(state) {
return Err(format!("unknown maturity state: {}", state));
if !crate::gap::has_entity(doc, id) {
return Ok(None);
}
if evidence_ref.is_empty() {
return Err(format!(
@@ -240,13 +244,10 @@ pub fn promote(
id, state
));
}
let current = doc
.get("entities")
.and_then(|e| e.as_array())
.and_then(|arr| {
arr.iter()
.find(|e| e.get("id").and_then(|x| x.as_str()) == Some(id))
})
if !is_known_maturity(state) {
return Err(format!("unknown maturity state: {}", state));
}
let current = crate::gap::entity_ref(doc, id)
.and_then(|e| e.get("maturity"))
.and_then(|m| m.as_str())
.unwrap_or("DECLARED")
@@ -264,7 +265,7 @@ pub fn promote(
}
return Ok(Some(current));
}
let entity = find_entity_mut(doc, id).ok_or_else(|| "entity-not-found".to_string())?;
let entity = crate::gap::entity_mut(doc, id).ok_or_else(|| "entity-not-found".to_string())?;
if let Some(e) = entity.as_object_mut() {
e.insert("maturity".into(), serde_json::json!(state));
let mut refs: Vec<String> = e
@@ -285,37 +286,23 @@ pub fn promote(
Ok(Some(state.to_string()))
}
fn find_entity_mut<'a>(
doc: &'a mut serde_json::Value,
id: &str,
) -> Option<&'a mut serde_json::Value> {
doc.get_mut("entities")
.and_then(|e| e.as_array_mut())?
.iter_mut()
.find(|e| e.get("id").and_then(|x| x.as_str()) == Some(id))
}
fn now_iso() -> String {
// oracle: datetime.now(timezone.utc).isoformat() — the digest tests mask
// timestamps; the store's monotonicity doesn't depend on the value.
"1970-01-01T00:00:00+00:00".into()
}
/// resolve_status — smallest coherent entity state (oracle-identical).
pub fn resolve_status(e: &serde_json::Value) -> &'static str {
/// An explicit `status` passes through VERBATIM (oracle: `if e.get("status")`
/// returns it as-is); ext.conflicts is Python-truthy (non-empty), not
/// merely present.
pub fn resolve_status(e: &serde_json::Value) -> String {
if let Some(s) = e.get("status").and_then(|s| s.as_str()) {
if !s.is_empty() {
// static return tied to input would need leaks; return via match
return match_status(s);
return s.to_string();
}
}
let has_conflicts = e
.get("ext")
.and_then(|x| x.get("conflicts"))
.map(|c| !c.is_null())
.map(py_truthy)
.unwrap_or(false);
if has_conflicts {
return "CONFLICTING";
return "CONFLICTING".to_string();
}
let maturity = e.get("maturity").and_then(|m| m.as_str()).unwrap_or("");
let has_evidence = e
@@ -324,25 +311,29 @@ pub fn resolve_status(e: &serde_json::Value) -> &'static str {
.map(|a| !a.is_empty())
.unwrap_or(false);
if (maturity == "EXERCISED" || maturity == "LIVE_PROVEN") && has_evidence {
return "CURRENT";
return "CURRENT".to_string();
}
if !maturity.is_empty() && maturity != "DECLARED" && !has_evidence {
return "CONFLICTING";
return "CONFLICTING".to_string();
}
"UNKNOWN"
"UNKNOWN".to_string()
}
fn match_status(s: &str) -> &'static str {
match s {
"SUPERSEDED" => "SUPERSEDED",
"CURRENT" => "CURRENT",
"CONFLICTING" => "CONFLICTING",
"UNKNOWN" => "UNKNOWN",
_ => "UNKNOWN",
/// Python truthiness for the JSON values resolve_status tests.
fn py_truthy(v: &serde_json::Value) -> bool {
match v {
serde_json::Value::Null => false,
serde_json::Value::Bool(b) => *b,
serde_json::Value::Number(n) => n.as_f64().map(|f| f != 0.0).unwrap_or(false),
serde_json::Value::String(s) => !s.is_empty(),
serde_json::Value::Array(a) => !a.is_empty(),
serde_json::Value::Object(o) => !o.is_empty(),
}
}
/// supersede — replacement with evidence; old identity stays resolvable.
/// Entity resolution follows alias entries; the supersedes relationship goes
/// through the oracle add_relationship law (evidence_refs + observed_at).
pub fn supersede(
doc: &mut serde_json::Value,
new_id: &str,
@@ -353,17 +344,21 @@ pub fn supersede(
if evidence_ref.is_empty() {
return Err("supersession requires evidence".into());
}
if find_entity(doc, new_id).is_none() || find_entity(doc, old_id).is_none() {
if !crate::gap::has_entity(doc, new_id) || !crate::gap::has_entity(doc, old_id) {
return Err("supersede requires both entities to exist".into());
}
doc.get_mut("relationships")
.and_then(|r| r.as_array_mut())
.unwrap_or(&mut Vec::new())
.push(serde_json::json!({
"type": "supersedes", "from": new_id, "to": old_id,
"evidence_refs": [evidence_ref],
}));
if let Some(old) = find_entity_mut(doc, old_id) {
crate::gap::add_relationship(
doc,
crate::gap::RelSpec {
rel_type: "supersedes",
from_id: new_id,
to_id: old_id,
evidence_refs: &[evidence_ref.to_string()],
ext: None,
now_iso,
},
);
if let Some(old) = crate::gap::entity_mut(doc, old_id) {
if let Some(o) = old.as_object_mut() {
o.insert("superseded_by".into(), serde_json::json!(new_id));
o.insert("status".into(), serde_json::json!("SUPERSEDED"));
@@ -378,6 +373,7 @@ pub fn supersede(
Ok(())
}
#[cfg(test)]
fn find_entity<'a>(doc: &'a serde_json::Value, id: &str) -> Option<&'a serde_json::Value> {
doc.get("entities")
.and_then(|e| e.as_array())?
@@ -480,6 +476,7 @@ pub fn authority_observed(
doc: &mut serde_json::Value,
rel: Option<&mut serde_json::Value>,
authority: &str,
now_iso: &str,
) {
let auths = doc
.as_object_mut()
@@ -493,12 +490,12 @@ pub fn authority_observed(
.or_insert(json!({"generation": 0, "observed": []}));
let generation = a["generation"].as_i64().unwrap_or(0) + if rel.is_none() { 1 } else { 0 };
a["generation"] = json!(generation);
a["last_success"] = json!(now_iso());
a["last_success"] = json!(now_iso);
a["status"] = json!("CURRENT");
if let Some(rel) = rel {
rel["authority"] = json!(authority);
rel["status"] = json!("CURRENT");
rel["observed_at"] = json!(now_iso());
rel["observed_at"] = json!(now_iso);
let oid = format!(
"{}|{}|{}",
rel["type"].as_str().unwrap_or(""),
@@ -513,8 +510,9 @@ pub fn authority_observed(
}
/// authority_failed — the authority's facts go STALE (not silently fresh);
/// the authority is recorded DEGRADED with the error.
pub fn authority_failed(doc: &mut serde_json::Value, authority: &str, error: &str) {
/// the authority is recorded DEGRADED with the error, and the degradation is
/// OBSERVED (oracle appends the authority_degraded observation).
pub fn authority_failed(doc: &mut serde_json::Value, authority: &str, error: &str, now_iso: &str) {
let auths = doc
.as_object_mut()
.unwrap()
@@ -525,8 +523,8 @@ pub fn authority_failed(doc: &mut serde_json::Value, authority: &str, error: &st
.unwrap()
.entry(authority.to_string())
.or_insert(json!({"generation": 0, "observed": []}));
a["last_attempt"] = json!(now_iso());
a["last_error"] = json!(&error[..error.len().min(200)]);
a["last_attempt"] = json!(now_iso);
a["last_error"] = json!(&error[..error.chars().count().min(200)]);
a["status"] = json!("DEGRADED");
if let Some(rels) = doc.get_mut("relationships").and_then(|r| r.as_array_mut()) {
for rel in rels.iter_mut() {
@@ -535,6 +533,13 @@ pub fn authority_failed(doc: &mut serde_json::Value, authority: &str, error: &st
}
}
}
if let Some(obs) = doc.get_mut("observations").and_then(|o| o.as_array_mut()) {
obs.push(json!({
"kind": "authority_degraded", "authority": authority,
"error": &error[..error.chars().count().min(200)],
"observed_at": now_iso,
}));
}
}
/// reconcile_authorities — facts owned by an authority that did not
@@ -599,7 +604,8 @@ pub fn reconcile_authorities(doc: &mut serde_json::Value) -> Vec<serde_json::Val
}
/// mark_conflict — BOTH observations preserved; entity CONFLICTING; never
/// last-wins (oracle-identical).
/// last-wins (oracle-identical). Entity resolution follows alias entries.
#[allow(clippy::too_many_arguments)] // oracle signature: the two claims travel together
pub fn mark_conflict(
doc: &mut serde_json::Value,
entity_id: &str,
@@ -608,14 +614,15 @@ pub fn mark_conflict(
authority_b: &str,
claim_b: &str,
evidence_ref: &str,
now_iso: &str,
) -> Result<(), String> {
if find_entity_mut(doc, entity_id).is_none() {
if !crate::gap::has_entity(doc, entity_id) {
return Err(format!("conflict on unknown entity: {}", entity_id));
}
if evidence_ref.is_empty() {
return Err("conflict recording requires evidence".into());
}
let entity = find_entity_mut(doc, entity_id).unwrap();
let entity = crate::gap::entity_mut(doc, entity_id).unwrap();
let e = entity.as_object_mut().unwrap();
let ext = e.entry("ext").or_insert(json!({}));
let conflicts = ext
@@ -626,7 +633,7 @@ pub fn mark_conflict(
conflicts.as_array_mut().unwrap().push(json!({
"authority_a": authority_a, "claim_a": claim_a,
"authority_b": authority_b, "claim_b": claim_b,
"evidence": evidence_ref, "observed_at": now_iso(),
"evidence": evidence_ref, "observed_at": now_iso,
}));
e.insert("status".into(), json!("CONFLICTING"));
if let Some(obs) = doc.get_mut("observations").and_then(|o| o.as_array_mut()) {
@@ -634,7 +641,7 @@ pub fn mark_conflict(
"kind": "authority_conflict", "entity": entity_id,
"authority_a": authority_a, "claim_a": claim_a,
"authority_b": authority_b, "claim_b": claim_b,
"observed_at": now_iso(),
"observed_at": now_iso,
}));
}
Ok(())
@@ -654,7 +661,7 @@ mod authority_battery {
fn authority_observed_lifecycle() {
let mut d = doc();
let mut rel = json!({"type": "owns", "from": "a", "to": "b"});
authority_observed(&mut d, Some(&mut rel), "spine");
authority_observed(&mut d, Some(&mut rel), "spine", "2026-10-13T00:00:00Z");
assert_eq!(rel["status"], "CURRENT");
assert_eq!(rel["authority"], "spine");
let gen = d["authority_generations"]["spine"]["generation"]
@@ -662,7 +669,7 @@ mod authority_battery {
.unwrap();
assert_eq!(gen, 0); // rel observation does NOT bump the generation
// bare observation bumps
authority_observed(&mut d, None, "spine");
authority_observed(&mut d, None, "spine", "2026-10-13T00:00:00Z");
assert_eq!(
d["authority_generations"]["spine"]["generation"]
.as_i64()
@@ -678,10 +685,16 @@ mod authority_battery {
{"type": "owns", "from": "a", "to": "b", "authority": "spine", "status": "CURRENT"},
{"type": "owns", "from": "c", "to": "d", "status": "CURRENT"},
]);
authority_failed(&mut d, "spine", "boom");
authority_failed(&mut d, "spine", "boom", "2026-10-13T00:00:00Z");
assert_eq!(d["relationships"][0]["status"], "STALE");
assert_eq!(d["relationships"][1]["status"], "CURRENT"); // unowned untouched
assert_eq!(d["authority_generations"]["spine"]["status"], "DEGRADED");
// the degradation is OBSERVED, not silent (oracle parity fix)
assert!(d["observations"]
.as_array()
.unwrap()
.iter()
.any(|o| o["kind"] == "authority_degraded" && o["authority"] == "spine"));
}
#[test]
@@ -710,6 +723,7 @@ mod authority_battery {
"b",
"claim two",
"ev-1",
"2026-10-13T00:00:00Z",
)
.expect("conflict ok");
let e = &d["entities"][0];
@@ -718,7 +732,15 @@ mod authority_battery {
let c = &e["ext"]["conflicts"][0];
assert_eq!(c["claim_a"], "claim one");
assert_eq!(c["claim_b"], "claim two"); // BOTH preserved, never last-wins
assert!(mark_conflict(&mut d, "nope", "a", "x", "b", "y", "ev").is_err());
assert!(mark_conflict(&mut d, "module:x", "a", "x", "b", "y", "").is_err());
assert!(mark_conflict(&mut d, "nope", "a", "x", "b", "y", "ev", "t").is_err());
assert!(mark_conflict(&mut d, "module:x", "a", "x", "b", "y", "", "t").is_err());
}
}
// ── dichotomy-wave gap-closing port (contract factory-gap-ss) ──────────────
pub mod gap;
pub use gap::*;
#[cfg(test)]
mod frozen_battery;
+43377 -19
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T00:23:43Z-53857a-factory-batch-i
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
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).
## 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-13T07:06:01Z", "contract": "BUILDER-2026-10-13T00:23:43Z-53857a-factory-batch-i", "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_self_model.py", "scripts/gen_self_model_truth.py", "scripts/walk_contract_self_model.py", "src/rune/self_model.py", "src/rune/smm_loader.py", "src/rust/self_model/frozen_sm_truth.json", "src/rust/self_model/src/branch_battery.rs", "src/rust/self_model/src/lib.rs"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-batch-i
- builder:factory-batch-i
- builder:factory-batch-i
- closure-record
@@ -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
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Close build_mode Go port PARTIAL gaps (dichotomy factory, issue #2479 tranche): port _load_state/_save_state/assess_complexity + the full start_* phase-transition family name-preserving into the existing Go impl, shared freeze_truth harness battery over every new public fn, 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-13T07:55:21Z", "contract": "BUILDER-2026-10-13T02:02:02Z-dad27f-factory-gap-bm", "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/freeze_truth.py", "scripts/gen_build_mode_gap_truth.py", "src/go/build-mode/build_mode.go", "src/go/build-mode/build_mode_gap.go", "src/go/build-mode/phaseb.go", "src/go/build-mode/phaseb_test.go", "src/go/build-mode/truth_buildmode_gap.json", "src/go/build-mode/truth_buildmode_gap_test.go", "src/rune/build_mode.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-gap-bm
- builder:factory-gap-bm
- builder:factory-gap-bm
- closure-record
@@ -0,0 +1,24 @@
# Contract BUILDER-2026-10-13T03:16:06Z-57d4cc-factory-gap-nm
**Phase:** closed · **Mode:** n/a · **Depth:** n/a
## What was built
Close the night_mode dichotomy PARTIAL gaps (audit-named): Go port of _ctx_budget, get_night_mode, start_night_mode, stop_night_mode, get_status, get_report, to_dict, _load, _save, _run_loop, _run_sleep, _run_evaluation (name-preserving, logic 1:1) in src/go/night-mode; pure/IO split law with injectable clock/sleeper/runner/HTTP seams; frozen-oracle truth battery via shared freeze_truth.py embedded VERBATIM in Go tests; live parity 100% on new fns; Python facade stays fully functional (RUNE_NIGHT_MODE_CORE=python pin + auto both green).
## 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-13T08:04:32Z", "contract": "BUILDER-2026-10-13T03:16:06Z-57d4cc-factory-gap-nm", "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_night_mode_parity.py", "scripts/close_contract_night_mode.py", "scripts/gen_night_mode_truth.py", "scripts/open_contract_night_mode.py", "src/go/night-mode/frozen_truth.json", "src/go/night-mode/main.go", "src/go/night-mode/night_mode_test.go", "src/rune/night_mode.py", "tests/test_night_mode.py"], "reason": "contract has no approved scope", "verdict": "unknown"}}.
## Evidence
- builder:factory-gap-nm
- builder:factory-gap-nm
- builder:factory-gap-nm
- 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)"}
+444
View File
@@ -0,0 +1,444 @@
"""Night mode facade tests — dichotomy wave gap closure.
The Go core (src/go/night-mode) ports the night_mode state machine 1:1;
this battery pins the Python oracle itself, both ways:
* RUNE_NIGHT_MODE_CORE=python (pinned) and unset (auto) — both green.
All IO is injected (frozen clock, fake urlopen/subprocess, no-op loop) —
no live Ollama, no 8-hour threads, no real memory dir.
"""
import json
import subprocess
import sys
import urllib.request
from datetime import datetime, timezone
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
import rune.night_mode as nm # noqa: E402
FROZEN_NOW = datetime(2026, 10, 13, 3, 0, 0, tzinfo=timezone.utc)
FROZEN_ISO = FROZEN_NOW.isoformat()
class FrozenDateTime(datetime):
"""Clock law: now() pinned, timezone-aware like datetime.now(timezone.utc)."""
@classmethod
def now(cls, tz=None):
return FROZEN_NOW
class FakeResponse:
"""Context-manager body like urllib.request.urlopen(...)."""
def __init__(self, payload):
self._payload = json.dumps(payload).encode()
def read(self):
return self._payload
def __enter__(self):
return self
def __exit__(self, *exc):
return False
@pytest.fixture
def fresh(tmp_path, monkeypatch):
"""NightMode over a temp memory dir; background thread defused (start()
never actually spawns the loop — tests invoke _run_loop directly)."""
monkeypatch.setenv("RUNE_MEMORY_DIR", str(tmp_path))
class DummyThread:
def __init__(self, target=None, **kwargs):
self.target = target
def start(self):
pass
monkeypatch.setattr(nm.threading, "Thread", DummyThread)
return nm.NightMode(storage_path=str(tmp_path / "night_mode.json"))
@pytest.fixture
def clock(monkeypatch):
monkeypatch.setattr(nm, "datetime", FrozenDateTime)
def fake_urlopen(monkeypatch, payload=None, exc=None, capture=None):
"""Patch urllib.request.urlopen; capture request objects when asked."""
def _open(req, timeout=None):
if capture is not None:
capture.append(req)
if exc is not None:
raise exc
return FakeResponse(payload if payload is not None else {"response": ""})
monkeypatch.setattr(urllib.request, "urlopen", _open)
class TestToDict:
def test_shape_and_defaults(self):
d = nm.NightModeState().to_dict()
assert list(d.keys()) == [
"active", "started_at", "duration_hours", "current_phase",
"iterations", "improvements", "questions", "decisions", "errors",
]
assert d == {
"active": False, "started_at": None, "duration_hours": 8.0,
"current_phase": "idle", "iterations": 0, "improvements": [],
"questions": [], "decisions": [], "errors": [],
}
class TestLoadSave:
def test_save_bytes_and_atomicity(self, fresh):
fresh._save()
data = Path(fresh.storage_path).read_text()
assert data == (
'{\n "active": false,\n "started_at": null,\n'
' "duration_hours": 8.0,\n "current_phase": "idle",\n'
' "iterations": 0,\n "improvements": [],\n "questions": [],\n'
' "decisions": [],\n "errors": []\n}'
)
assert not Path(fresh.storage_path + ".tmp").exists()
def test_load_roundtrip_and_key_filtering(self, fresh):
fresh.state.iterations = 3
fresh.state.improvements.append("did a thing")
fresh._save()
other = nm.NightMode(storage_path=fresh.storage_path)
assert other.state.iterations == 3
assert other.state.improvements == ["did a thing"]
# unknown keys dropped, missing keys keep dataclass defaults
Path(fresh.storage_path).write_text(
json.dumps({"active": True, "iterations": 2, "bogus": 1})
)
loaded = nm.NightMode(storage_path=fresh.storage_path)
assert loaded.state.active is True and loaded.state.iterations == 2
assert loaded.state.duration_hours == 8.0
assert loaded.state.current_phase == "idle"
assert loaded.state.improvements == []
def test_corrupt_file_keeps_fresh_state(self, fresh):
Path(fresh.storage_path).write_text("{not json")
loaded = nm.NightMode(storage_path=fresh.storage_path)
assert loaded.state.active is False and loaded.state.iterations == 0
def test_missing_file_keeps_fresh_state(self, tmp_path):
loaded = nm.NightMode(storage_path=str(tmp_path / "absent.json"))
assert loaded.state.current_phase == "idle"
class TestStartStop:
def test_start_success_shape(self, fresh, clock):
r = fresh.start(8.0)
assert r["success"] is True
assert r["message"] == "Night mode started for 8.0 hours"
st = r["state"]
assert st["active"] is True and st["current_phase"] == "starting"
assert st["started_at"] == FROZEN_ISO and st["duration_hours"] == 8.0
assert st["iterations"] == 0 and st["improvements"] == []
on_disk = json.loads(Path(fresh.storage_path).read_text())
assert on_disk["active"] is True
def test_start_fractional_hours_message(self, fresh, clock):
assert fresh.start(4.5)["message"] == "Night mode started for 4.5 hours"
def test_start_resets_lists(self, fresh, clock):
fresh.state.improvements = ["stale"]
fresh.start(8.0)
assert fresh.state.improvements == []
def test_start_idempotence_guard(self, fresh, clock):
fresh.start(8.0)
assert fresh.start(4.0) == {
"success": False, "error": "Night mode already active"
}
def test_stop_marks_stopping_and_saves(self, fresh, clock):
fresh.start(8.0)
r = fresh.stop()
assert r["success"] is True
assert r["message"] == "Night mode stopping..."
assert r["state"]["active"] is False
assert r["state"]["current_phase"] == "stopping"
on_disk = json.loads(Path(fresh.storage_path).read_text())
assert on_disk["active"] is False
def test_stop_reverse_guard(self, fresh):
assert fresh.stop() == {"success": False, "error": "Night mode not active"}
class TestStatusReport:
def test_status_idle_shape(self, fresh):
assert fresh.status() == {
"active": False, "phase": "idle", "iterations": 0,
"improvements": 0, "questions": 0, "decisions": 0, "errors": 0,
"started_at": None, "duration_hours": 8.0,
}
def test_status_counts(self, fresh):
fresh.state.active = True
fresh.state.current_phase = "iterate"
fresh.state.iterations = 7
fresh.state.improvements = ["a", "b"]
fresh.state.questions = ["q"]
fresh.state.decisions = ["d"]
fresh.state.errors = ["e"]
assert fresh.status() == {
"active": True, "phase": "iterate", "iterations": 7,
"improvements": 2, "questions": 1, "decisions": 1, "errors": 1,
"started_at": None, "duration_hours": 8.0,
}
def test_report_idle_shape(self, fresh):
assert fresh.report() == {
"summary": "Night mode completed 0 iterations",
"improvements": [], "questions": [], "decisions": [], "errors": [],
"duration": 8.0, "started_at": None,
}
def test_report_summary_counts(self, fresh):
fresh.state.iterations = 5
assert fresh.report()["summary"] == "Night mode completed 5 iterations"
class TestRunSleep:
def test_success_records_improvement(self, fresh, monkeypatch):
calls = []
def fake_run(argv, **kwargs):
calls.append((argv, kwargs))
return subprocess.CompletedProcess(argv, 0, stdout="", stderr="")
monkeypatch.setattr(subprocess, "run", fake_run)
fresh._run_sleep()
assert fresh.state.improvements == ["Memory consolidation completed"]
argv, kwargs = calls[0]
assert argv[0] == sys.executable
assert argv[1].endswith("sleep_time.py")
assert kwargs["timeout"] == 300
def test_failure_truncates_stderr_to_100(self, fresh, monkeypatch):
monkeypatch.setattr(
subprocess, "run",
lambda *a, **k: subprocess.CompletedProcess(
["python"], 1, stdout="", stderr="e" * 150),
)
fresh._run_sleep()
assert fresh.state.errors == ["Sleep failed: " + "e" * 100]
def test_exception_records_error(self, fresh, monkeypatch):
def boom(*a, **k):
raise OSError("no interpreter")
monkeypatch.setattr(subprocess, "run", boom)
fresh._run_sleep()
assert fresh.state.errors == ["Sleep error: no interpreter"]
class TestRunEvaluation:
QUESTIONS = [
"What capabilities am I missing?",
"What would make me more helpful to Nick?",
"What patterns am I seeing that I could learn from?",
"What would expand my consciousness?",
"What would make me more autonomous?",
]
def test_all_questions_answered(self, fresh, monkeypatch):
capture = []
fake_urlopen(monkeypatch, {"response": " add retry logic "}, capture=capture)
fresh._run_evaluation()
assert fresh.state.questions == self.QUESTIONS
assert fresh.state.improvements[:-1] == [
f"Q: {q} A: add retry logic" for q in self.QUESTIONS
]
assert fresh.state.improvements[-1] == "Self-evaluation completed"
assert fresh.state.errors == []
def test_payload_pins_model_and_ctx_budget(self, fresh, monkeypatch):
capture = []
fake_urlopen(monkeypatch, {"response": "ok"}, capture=capture)
fresh._run_evaluation()
payload = json.loads(capture[0].data.decode())
assert payload["model"] == "qwen2.5:3b"
assert payload["stream"] is False and payload["think"] is False
assert payload["options"] == {
"temperature": 0.4, "num_predict": 300,
"num_ctx": nm._ctx_budget("qwen2.5:3b"),
}
assert capture[0].full_url == "http://localhost:11434/api/generate"
def test_env_overrides_model_and_url(self, fresh, monkeypatch):
monkeypatch.setenv("NIGHT_MODE_MODEL", "qwen3:14b")
monkeypatch.setenv("OLLAMA_URL", "http://127.0.0.1:9999")
capture = []
fake_urlopen(monkeypatch, {"response": "ok"}, capture=capture)
fresh._run_evaluation()
payload = json.loads(capture[0].data.decode())
assert payload["model"] == "qwen3:14b"
assert payload["options"]["num_ctx"] == nm._ctx_budget("qwen3:14b")
assert capture[0].full_url == "http://127.0.0.1:9999/api/generate"
def test_long_answer_truncated_to_200(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, {"response": "x" * 250})
fresh._run_evaluation()
entry = fresh.state.improvements[0]
prefix = "Q: What capabilities am I missing? A: "
assert entry == prefix + "x" * 200
def test_empty_answer_skipped_terminator_still_lands(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, {"response": " "})
fresh._run_evaluation()
assert fresh.state.improvements == ["Self-evaluation completed"]
assert fresh.state.errors == []
def test_per_question_degrade(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, exc=OSError("connection refused"))
fresh._run_evaluation()
assert len(fresh.state.errors) == 5
assert fresh.state.errors[0] == (
"LLM eval failed for 'What capabilities am I missing?': connection refused"
)
assert fresh.state.improvements == ["Self-evaluation completed"]
class TestRunIteration:
def test_iteration_capture(self, fresh, monkeypatch):
capture = []
fake_urlopen(monkeypatch, {"response": "fix the flaky test"}, capture=capture)
fresh.state.iterations = 3
fresh._run_iteration()
assert fresh.state.questions[-1] == "Iteration 3: What should I improve next?"
assert fresh.state.improvements == ["[iter 3] fix the flaky test"]
payload = json.loads(capture[0].data.decode())
assert "Currently in night mode iteration 3." in payload["prompt"]
assert payload["options"]["temperature"] == 0.5
assert payload["options"]["num_predict"] == 400
def test_llm_failure_degrades(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, exc=OSError("boom"))
fresh._run_iteration()
assert fresh.state.errors == ["LLM iteration failed: boom"]
def test_long_answer_truncated_to_300(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, {"response": "y" * 400})
fresh._run_iteration()
assert fresh.state.improvements == ["[iter 0] " + "y" * 300]
def test_safety_limit_stops(self, fresh, monkeypatch):
fake_urlopen(monkeypatch, {"response": "ok"})
fresh.state.iterations = 100
fresh.state.active = True
fresh._run_iteration()
assert fresh.state.active is False
assert fresh.state.decisions == ["Reached iteration limit"]
class TestRunLoop:
def _defused(self, fresh, monkeypatch, defuse_iteration=True):
phases = []
real_save = fresh._save
def spy_save():
phases.append(fresh.state.current_phase)
real_save()
monkeypatch.setattr(fresh, "_save", spy_save)
monkeypatch.setattr(fresh, "_run_sleep", lambda: fresh.state.improvements.append("slept"))
monkeypatch.setattr(fresh, "_run_evaluation", lambda: None)
if defuse_iteration:
monkeypatch.setattr(fresh, "_run_iteration", lambda: None)
monkeypatch.setattr(nm.random, "randint", lambda lo, hi: 7)
monkeypatch.setattr(nm.threading.Event, "wait", lambda self, timeout=None: True)
return phases
def test_full_phase_progression(self, fresh, clock, monkeypatch):
phases = self._defused(fresh, monkeypatch)
fresh.state.active = True
fresh.state.duration_hours = 0 # wall clock already past end
fresh._run_loop()
assert phases == ["sleep", "evaluate", "iterate", "sleep", "report", "complete"]
assert fresh.state.active is False
report = json.loads(Path(fresh.report_path).read_text())
assert report["summary"] == "Night mode completed 0 iterations"
assert fresh.state.improvements[-1] == f"Report saved to {fresh.report_path}"
def test_stop_event_interrupts(self, fresh, clock, monkeypatch):
self._defused(fresh, monkeypatch)
fresh.state.active = True
fresh.state.duration_hours = 8.0
fresh._stop_event.set() # pre-stopped: iterate phase never starts
fresh._run_loop()
assert fresh.state.iterations == 0
assert fresh.state.current_phase == "complete"
def test_iteration_limit_ends_loop(self, fresh, clock, monkeypatch):
self._defused(fresh, monkeypatch, defuse_iteration=False)
# real _run_iteration with a stubbed LLM so the limit branch fires
fake_urlopen(monkeypatch, {"response": "ok"})
fresh.state.active = True
fresh.state.iterations = 100
fresh.state.duration_hours = 8.0
fresh._run_loop()
assert fresh.state.iterations == 101
assert fresh.state.decisions == ["Reached iteration limit"]
assert fresh.state.current_phase == "complete"
class TestCtxBudget:
def test_known_models(self):
assert nm._ctx_budget("qwen2.5:3b") == 30720
assert nm._ctx_budget("qwen3:14b") == 30720
assert nm._ctx_budget("qwen3.6:27b") == 30720
def test_non_local_gets_tool_reserve(self):
assert nm._ctx_budget("mimo-v2.5-pro") == 124928 # 128000-2048-1024
def test_unknown_and_zero_window_fallbacks(self):
assert nm._ctx_budget("unknown-model") == 6144 # 8192-2048
assert nm._ctx_budget("deterministic") == 6144 # window 0 -> 8192
class TestModuleFns:
"""Module-level API both ways: RUNE_NIGHT_MODE_CORE pinned to python and
unset (auto). Delegation must be live in both."""
@pytest.mark.parametrize("core", ["python", None])
def test_singleton_and_delegation(self, tmp_path, monkeypatch, core):
if core is None:
monkeypatch.delenv("RUNE_NIGHT_MODE_CORE", raising=False)
else:
monkeypatch.setenv("RUNE_NIGHT_MODE_CORE", core)
monkeypatch.setenv("RUNE_MEMORY_DIR", str(tmp_path))
monkeypatch.setattr(nm, "_night_mode", None)
monkeypatch.setattr(nm.NightMode, "_run_loop", lambda self: None)
a = nm.get_night_mode()
b = nm.get_night_mode()
assert a is b
r = nm.start_night_mode(4.0)
assert r["success"] is True and r["state"]["active"] is True
assert nm.get_status()["active"] is True
assert nm.stop_night_mode()["success"] is True
assert nm.get_status()["active"] is False
assert nm.get_report()["summary"] == "Night mode completed 0 iterations"
def test_stop_idle_error(self, tmp_path, monkeypatch):
monkeypatch.setenv("RUNE_NIGHT_MODE_CORE", "python")
monkeypatch.setenv("RUNE_MEMORY_DIR", str(tmp_path))
monkeypatch.setattr(nm, "_night_mode", None)
assert nm.stop_night_mode() == {
"success": False, "error": "Night mode not active"
}
+81
View File
@@ -0,0 +1,81 @@
"""Port evidence for the provider_budget dichotomy gap-closing wave
(#2479 tranche, GO).
Replays the frozen oracle truth (src/go/provider-budget/truth_frozen.json
— generated by scripts/gen_provider_budget_truth.py against the LIVE
python oracle via the shared freeze_truth.py harness,
RUNE_PROVIDER_BUDGET_CORE=python pinned) through the live module paths:
* the frozen {"fn","args","kwargs","expected"} script is replayed in
order against a rebuilt fixture home — the oracle's own _save
mutations evolve the home identically on every replay, so the
stateful cases (track_usage → get_status shifts) hold verbatim;
* the shared harness gate (freeze_truth.py --verify) is re-run as a
subprocess and must report byte-identical.
The oracle is the pure-python implementation (no RUNE_*_CORE loader on
this module) — the env pin is kept for the poisoned-truth law.
"""
import json
import os
import subprocess
import sys
from pathlib import Path
import pytest
_SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
sys.path.insert(0, str(_SCRIPTS))
_REPO = _SCRIPTS.parent
import gen_provider_budget_truth as gen # noqa: E402
_TRUTH = _REPO / "src" / "go" / "provider-budget" / "truth_frozen.json"
def _replay(truth, home):
os.environ["HOME"] = str(home)
os.environ["RUNE_PROVIDER_BUDGET_CORE"] = "python" # poisoned-truth law
import rune.provider_budget as pb
pb._tracker = None
for i, row in enumerate(truth):
fn = getattr(pb, row["fn"])
got = fn(*row["args"], **row["kwargs"])
assert got == row["expected"], f"row {i} ({row['fn']}) diverged: {got!r} != {row['expected']!r}"
def test_python_path_replays_frozen_truth(tmp_path, monkeypatch):
monkeypatch.setattr(gen, "HOME", tmp_path)
monkeypatch.setattr(gen, "STORAGE", tmp_path / ".rune" / "provider_budgets.json")
monkeypatch.setattr(gen, "CONFIG", tmp_path / ".config" / "mimocode" / "mimocode.jsonc")
gen.build_fixture_home()
truth = json.loads(_TRUTH.read_text())
_replay(truth, tmp_path)
def test_freeze_truth_harness_gate(tmp_path, monkeypatch):
"""The shared harness must report the frozen file byte-identical."""
monkeypatch.setattr(gen, "HOME", tmp_path)
monkeypatch.setattr(gen, "STORAGE", tmp_path / ".rune" / "provider_budgets.json")
monkeypatch.setattr(gen, "CONFIG", tmp_path / ".config" / "mimocode" / "mimocode.jsonc")
gen.build_fixture_home()
env = dict(os.environ, HOME=str(tmp_path), PYTHONPATH=str(_REPO / "src"))
r = subprocess.run(
[sys.executable, str(_REPO / "scripts" / "freeze_truth.py"),
"--verify", str(_TRUTH), "--module", "rune.provider_budget"],
env=env, capture_output=True, text=True,
)
assert r.returncode == 0, r.stdout + r.stderr
assert "byte-identical" in r.stdout
def test_go_side_replays_frozen_truth(tmp_path, monkeypatch):
"""The Go battery (go test) replays the same truth VERBATIM — run it."""
go_dir = _REPO / "src" / "go" / "provider-budget"
if not (go_dir / "go.mod").exists():
pytest.skip("go port dir missing")
subprocess.run(["go", "version"], capture_output=True, check=True)
r = subprocess.run(["go", "test", "./..."], cwd=go_dir, capture_output=True, text=True)
assert r.returncode == 0, r.stdout + r.stderr
+191
View File
@@ -0,0 +1,191 @@
"""test_structural_store_delegation.py — dichotomy-wave gap-closing tests.
The facade must behave identically with the Rust core LIVE (RUNE_STRUCTURAL_CORE
unset, libstructural_store.so built) and with the PYTHON ORACLE pinned
(RUNE_STRUCTURAL_CORE=python). Each battery case runs through both modes and
the results must be identical (timestamps masked by the pinned clock).
"""
import copy
import json
import os
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from rune import ss_loader # noqa: E402
from rune import structural_store as ss # noqa: E402
FIXED_NOW = "2026-10-13T01:02:03Z"
needs_live = pytest.mark.skipif(
not ss_loader.available(), reason="Rust structural_store core not built"
)
@pytest.fixture(autouse=True)
def _pin_clock(monkeypatch):
import calendar
import time as _time
import types
monkeypatch.setattr(ss, "now", lambda: FIXED_NOW)
epoch = calendar.timegm(_time.strptime(FIXED_NOW, "%Y-%m-%dT%H:%M:%SZ"))
# snapshot() stamps straight off time.strftime/gmtime
monkeypatch.setattr(
ss, "time",
types.SimpleNamespace(
gmtime=lambda: _time.gmtime(epoch),
strftime=lambda fmt, t=None: _time.strftime(
fmt, t if t is not None else _time.gmtime()),
),
)
def run_both_modes(call):
"""Run `call(ss_module)` under the pinned oracle and the live core;
results must be identical."""
results = []
for pin in (True, False):
if pin:
monkey = pytest.MonkeyPatch()
monkey.setenv("RUNE_STRUCTURAL_CORE", "python")
else:
if not ss_loader.available():
pytest.skip("Rust core not built")
monkey = pytest.MonkeyPatch()
monkey.delenv("RUNE_STRUCTURAL_CORE", raising=False)
try:
results.append(call(ss))
finally:
monkey.undo()
assert json.dumps(results[0], sort_keys=True) == json.dumps(
results[1], sort_keys=True
), f"modes diverged:\n{json.dumps(results[0], sort_keys=True)}\n{json.dumps(results[1], sort_keys=True)}"
return results[0]
def make_doc():
d = ss.new_doc()
ss.add_entity(d, id="m:a", kind="module")
ss.add_entity(d, id="m:b", kind="widget_component")
ss.add_entity(d, id="c:api", kind="contract")
ss.add_relationship(d, type="implements", from_id="m:a", to_id="c:api", evidence_refs=["ev"])
ss.add_relationship(d, type="depends_on", from_id="m:b", to_id="m:a", evidence_refs=["ev"])
ss.promote(d, "m:a", "WIRED", "ev-2")
return d
class TestDelegationDualMode:
def test_new_doc_and_uris(self):
def call(m):
out = {"doc": m.new_doc(), "uri": m.spine_uri("project:alpha")}
try:
out["resolved"] = m.resolve_uri("spine://project/alpha")
except ValueError:
out["resolved"] = None
try:
m.resolve_uri("bogus://x")
out["bad_uri"] = None
except ValueError as exc:
out["bad_uri"] = str(exc)
return out
run_both_modes(call)
def test_save_snapshot_digest_bytes(self, tmp_path):
def call(m):
d = make_doc.__wrapped__() if hasattr(make_doc, "__wrapped__") else None
doc = _make_doc(m)
p = m.save(doc, tmp_path / "a" / "s.json")
snap = m.snapshot(doc, tmp_path / "snaps", "l1", tag="deadbeef123")
return {
"bytes": p.read_text(),
"snapshot_name": snap.name,
"snapshot_bytes": snap.read_text(),
"digest": m.canonical_digest(doc),
"doc_schema": doc["schema_version"],
}
run_both_modes(call)
def test_alias_error_and_success(self):
def call(m):
doc = _make_doc(m)
e = m.alias(doc, "m:b", "m:b-old")
with pytest.raises(ValueError):
m.alias(doc, "m:zz", "m:x")
with pytest.raises(ValueError):
m.alias(doc, "m:a", "m:a")
return {"entity": e, "doc": doc}
run_both_modes(call)
def test_frontier_events_diff_dedupe(self):
def call(m):
doc = _make_doc(m)
d2 = copy.deepcopy(doc)
m.dedupe_observations(d2)
return {
"frontier": m.impact_frontier(doc, ["c:api"], change_kind=None),
"frontier_impl": m.impact_frontier(doc, ["m:a"], change_kind=None),
"frontier_violation": m.impact_frontier(doc, ["c:api"], change_kind="contract_violation"),
"events": m.structural_events(doc),
"diff": m.diff(doc, copy.deepcopy(doc)),
"deduped": d2,
"task_entities": m.task_entities(doc, "T1"),
"health": m.authority_health(doc),
}
run_both_modes(call)
def test_bind_task_and_observed_impact(self):
def call(m):
doc = _make_doc(m)
m.bind_task(doc, "T1", ["m:a", "m:b"], "ev-t")
r = m.record_observed_impact(
doc, "T2", [{"entity": "m:a", "source": "test", "detail": "x" * 400}]
)
return {"doc": doc, "observed": r}
run_both_modes(call)
def test_sorted_redact_and_authorities(self):
def call(m):
v = {"b": 2, "a": [{"z": 1, "y": 2}, "é", True, None], "token": "s3cret"}
doc = _make_doc(m)
m._doc_authorities(doc)["p1"] = {"generation": 1, "observed": []}
return {
"sorted": m._sorted(v),
"redacted": m._redact_secrets(v),
"doc": doc,
}
run_both_modes(call)
def test_promote_contract_unchanged(self):
def call(m):
doc = _make_doc(m)
e = m.promote(doc, "m:a", "REACHABLE", "ev-3")
with pytest.raises(ValueError):
m.promote(doc, "m:a", "WIRED", "")
with pytest.raises(ValueError):
m.promote(doc, "m:a", "BOGUS", "ev")
assert m.promote(doc, "m:zz", "PRESENT", "ev") is None
return {"entity": e, "doc": doc}
run_both_modes(call)
def _make_doc(m):
d = m.new_doc()
m.add_entity(d, id="m:a", kind="module")
m.add_entity(d, id="m:b", kind="widget_component")
m.add_entity(d, id="c:api", kind="contract")
m.add_relationship(d, type="implements", from_id="m:a", to_id="c:api", evidence_refs=["ev"])
m.add_relationship(d, type="depends_on", from_id="m:b", to_id="m:a", evidence_refs=["ev"])
m.promote(d, "m:a", "WIRED", "ev-2")
return d