Compare commits

...
89 Commits
Author SHA1 Message Date
conductor 8d8e09bee6 chore(release): auto-bump version to 0.136.3 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 10m12s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m22s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m17s
CI Pipeline / canary (push) Successful in 1m5s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-10-08 11:02:45 +01:00
Nick ebc0e7edce Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 12s
CI Pipeline / go-surface (push) Failing after 24s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / rust-surface (push) Successful in 4m22s
CI Pipeline / unit-tests (push) Failing after 5m24s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 15m15s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 11:02:31 +01:00
Nick c22bc002bc fix(sweep): #126 wave 1 — 79 silent handlers classified, store-dependent test isolated (contract BUILDER-2026-10-08T09:36:16Z-d88162)
- 44 S110 pass-sites → logger.debug suppressions (P0-06 pattern)
- 35 rune_tui.py sites → deliberate-silence noqa (render-loop must
  never crash the session)
- test_find_capability_no_match: store-state isolation via monkeypatch
  (the live store gained cards that score >0 on the no-match query —
  a store-state dependency, not a code regression; the oracle's
  no-match path is unchanged)

Full suite: 2403 passed. Ratchet PASS.
2026-10-08 11:02:28 +01:00
conductor 17b2e32c8c chore(release): auto-bump version to 0.136.2 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / rust-surface (push) Successful in 4m9s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 5m26s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 1m18s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 04:04:56 +01:00
conductor 865a03d199 chore(release): auto-bump version to 0.136.2 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 6m39s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / unit-tests (push) Successful in 5m22s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m7s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-10-08 03:59:30 +01:00
Nick d913c019c5 test(constitutional): #152 adversarial battery — break the constitutional paths after nominal tests pass (contract BUILDER-2026-10-08T02:53:12Z-6380f7)
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / rust-surface (push) Successful in 4m8s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 5m21s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
8 attacks across 4 classes, each asserting the mechanism FAILS LOUD:
- stale-state: ghost plugins cannot resolve from a stale index; inactive
  plugins filtered
- threshold bypass: wash_count 19 parks; type confusion ('999') CRASHES
  loud (oracle-pinned — never silently accepted); negative wash parks
- status inversion: rock re-promotion refused ('already rock'); garbage
  rock_status treated as washable
- value inflation: importance inflation pinned (oracle uses raw value);
  goal-overlap capped

Built on the fuzz + adversarial infrastructure (eef7768, T20 20W).
#152 substantially addressed; #151's fuzz half is live.
2026-10-08 03:57:25 +01:00
Nick 89848faf63 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 29s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / rust-surface (push) Successful in 4m9s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / unit-tests (push) Successful in 5m23s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-08 03:50:38 +01:00
Nick 216963223e fix(sleep-time): json_valid guard on the todowrite query — a malformed part row crashed json_extract and killed the whole extract (found during batch-11 fixture generation; the oracle itself crashed on the malformed-row fixture). Guard: json_valid(data) before json_extract. 11 sleep tests green. 2026-10-08 03:50:38 +01:00
conductor 2e351c71db chore(release): auto-bump version to 0.136.1 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 10m12s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Failing after 29s
CI Pipeline / unit-tests (push) Successful in 5m25s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m14s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-08 03:46:31 +01:00
Nick 9afa9e2911 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 58s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / rust-surface (push) Successful in 4m17s
CI Pipeline / unit-tests (push) Successful in 5m31s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 03:46:19 +01:00
Nick 13bdbc5d1e fix(tools): #2481 CLOSED — undo_last restores via sidecar manifest (contract BUILDER-2026-10-08T02:29:42Z-a43ffb)
Python-first (the oracle authority): _backup_file writes a JSON sidecar
(.manifest) beside every .bak carrying the original ABSOLUTE path;
undo_last reads the manifest as the PRIMARY restore authority. Legacy
manifest-less backups degrade to the old name-parse (preserved).

Go parity: BackupFile writes the same sidecar; UndoLast reads it first.
The Go truth test flipped from pinning the dead behavior to asserting
the FIXED behavior (restore works, both files consumed) — both sides
flipped together, verified by live probe on the Python side and the
round-trip test on the Go side.

166 related tests green. #2481 closed.
2026-10-08 03:46:19 +01:00
conductor feeece62eb chore(release): auto-bump version to 0.136.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 1m55s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 11s
CI Pipeline / lint (push) Failing after 31s
CI Pipeline / unit-tests (push) Successful in 5m26s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m18s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-08 03:19:42 +01:00
Nick 7cd222ccfa Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / lint (push) Failing after 33s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 59s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / rust-surface (push) Successful in 4m22s
CI Pipeline / unit-tests (push) Successful in 5m29s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 11m56s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 03:19:27 +01:00
Nick 82abd1b3ab feat(pipeline): EXIT-NOTE TEMPLATE — plain-English version history (contract BUILDER-2026-10-08T02:04:24Z-a129fb)
Nick's directive: when the pipeline earns a new version, the release
body must carry a plain-English summary of what was worked on and
submitted — the counterpart of the issue-entry template, part of the
Gitea Actions pipeline (auto-version.yml), not a manual step.

- scripts/release_exit_note.py: renders the exit note from the push
  range (git log v<last>..HEAD, chore(release) excluded) — conventional-
  commit prefix → kind classification (added/fixed/improved), reader-
  facing translation (contract refs, parity language, truth batteries),
  aggregate headline + per-item bullets + verification summary
- auto-version.yml: wired into the release step (LAST_TAG →
  release_exit_note.py → --exit-note flag on release_history_cli init)
- release_history_cli.py: consumes --exit-note, parses the markdown
  into structured extras (headline + items) passed to
  auto_initial_note(extra=...)
- release_notes.py: auto_initial_note accepts extra (merged into
  improved/added/fixed after fact extraction, deduped)
- scripts/backfill_exit_notes.py: retroactive backfill for the 27
  pre-template releases (executed — all patched)

The exit note is now a first-class pipeline citizen: every earned
version carries the human narrative alongside the governed evidence.
2026-10-08 03:19:27 +01:00
conductor aca27ae90a chore(release): auto-bump version to 0.135.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 1m55s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m26s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / rust-surface (push) Successful in 4m23s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-08 03:01:57 +01:00
Nick 4ba9c4359f Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / go-surface (push) Failing after 23s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / canary (push) Successful in 1m33s
CI Pipeline / rust-surface (push) Successful in 4m25s
CI Pipeline / unit-tests (push) Failing after 5m27s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 11m32s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 03:01:43 +01:00
Nick 6d2fb5edea feat(go): factory batch 12 — FAMA scoring (contract BUILDER-2026-10-08T02:01:32Z-236bbf-unknown)
Forgetting-Aware Memory Accuracy ported to drift-core: valid = active
AND (wash>0 OR rock/established); missing rows skipped; empty = 0.0.
5-case battery from the live oracle incl. the missing-row path.
First-run green.
2026-10-08 03:01:43 +01:00
conductor 7df4b237db chore(release): auto-bump version to 0.134.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 1m46s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m21s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m21s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 37s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-08 02:44:56 +01:00
Nick e87a5a7561 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / go-surface (push) Failing after 24s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / rust-surface (push) Successful in 4m23s
CI Pipeline / unit-tests (push) Failing after 5m25s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 11m48s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 11s
2026-10-08 02:44:40 +01:00
Nick 1568d571ea feat(go): factory batch 11 — sleep-time transcript surfaces (contract BUILDER-2026-10-08T01:44:30Z-b7985f-unknown)
ExtractTodos (latest-todowrite filter, malformed rows skipped) and
WriteTranscript (byte format, injected clock, title sanitization) ported
to sleep-time. SQL stays reactive. 5-case battery. Oracle quirks pinned:
SQL json_extract crashes on malformed JSON rows; write_transcript relies
on _ensure_dirs pre-running.
2026-10-08 02:44:40 +01:00
conductor ed73f36d14 chore(release): auto-bump version to 0.133.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 10s
deploy / deploy (push) Failing after 1m58s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 11s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m20s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m26s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-08 02:28:47 +01:00
Nick 2be2b5b7c1 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / lint (push) Failing after 33s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / rust-surface (push) Successful in 4m28s
CI Pipeline / unit-tests (push) Failing after 5m22s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 12m2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 02:28:08 +01:00
Nick 32dda3d3bd feat(go): factory batch 10 — drift value mechanics (contract BUILDER-2026-10-08T01:27:57Z-743b1c-unknown)
ComputeValue (5-factor weighted score: log1p proven, recency half-life
30d with floors + bad-ts degrade, reliability, goal relevance) and
CheckPromotionEligibility (rock short-circuit, threshold gate, 0.6
minimum, exact reason texts) ported to drift-core. Constants verbatim,
clock injected. 13-case battery incl. degrade paths — first-run green.
2026-10-08 02:28:08 +01:00
conductor 4a8158ba06 chore(release): auto-bump version to 0.132.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / canary (push) Successful in 1m6s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / unit-tests (push) Failing after 5m20s
CI Pipeline / rust-surface (push) Successful in 4m28s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 3m57s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
Promotion record: (unknown)
2026-10-08 01:58:35 +01:00
conductor 24b09ca259 chore(release): auto-bump version to 0.132.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / lint (push) Failing after 33s
CI Pipeline / go-surface (push) Failing after 32s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / rust-surface (push) Successful in 4m33s
CI Pipeline / unit-tests (push) Failing after 5m23s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 10m9s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
Promotion record: (unknown)
2026-10-08 01:30:28 +01:00
conductor 1cd766684a chore(release): auto-bump version to 0.132.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 14m11s
CI Pipeline / rust-surface (push) Failing after 16m38s
CI Pipeline / unit-tests (push) Failing after 17m22s
CI Pipeline / lint (push) Failing after 29s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 01:17:57 +01:00
Nick 5e38383cfe Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m14s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
deploy / deploy (push) Failing after 24m36s
2026-10-08 01:06:50 +01:00
Nick ce638de74e feat(go): factory batch 9 — event-bus content hash (contract BUILDER-2026-10-08T00:06:39Z-8c023f-unknown)
_content_hash ported with FULL python json.dumps byte semantics: nested
sort_keys recursion, ensure_ascii escaping, and the int-vs-float literal
distinction preserved via json.Number decoding (the oracle distinguishes
1 from 1.0; the hash of an int-carrying payload differs from the
float-carrying one). 6-case battery — the oracle corrected two
assumptions before the design was pinned.
2026-10-08 01:06:50 +01:00
conductor 59cd8a79b1 chore(release): auto-bump version to 0.131.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / rust-surface (push) Successful in 4m12s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / gitea-offline (push) Successful in 19s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
Promotion record: (unknown)
2026-10-08 00:58:32 +01:00
conductor 026d9b3df8 chore(release): auto-bump version to 0.131.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Failing after 27s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m12s
CI Pipeline / unit-tests (push) Failing after 5m17s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 19s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 00:51:47 +01:00
conductor 0ed2be1de5 chore(release): auto-bump version to 0.131.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m12s
CI Pipeline / unit-tests (push) Failing after 5m17s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 19s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
Promotion record: (unknown)
2026-10-08 00:45:13 +01:00
Nick 14b0d48cad Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 27s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m13s
CI Pipeline / unit-tests (push) Failing after 5m17s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 19s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 00:41:51 +01:00
Nick 4c7ee39f61 feat(go): factory batch 8 — microkernel registry primitives (contract BUILDER-2026-10-07T23:35:52Z-see-contract)
Register/Unregister/Resolve ported to microkernel, integrated with the
committed main.go shapes (PluginManifest typed struct; Hooks widened to
map[string]interface{} for oracle parity — the manifest carries bool
enabled flags). Resolve: priority ladder (lower = higher), active-only
filter, stable tie order. 6-case battery from the live oracle with a
tmp-REGISTRY_DB seam (the reactive store isolated). The oracle fixtures
corrected my snapshot approach: the registry is PERSISTED per-op, so the
truth reloads from the store rather than trusting a stale in-memory
object.
2026-10-08 00:41:51 +01:00
conductor 8831126cda chore(release): auto-bump version to 0.131.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 29s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m12s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 18s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 2s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 00:37:22 +01:00
Nick 77714ab13d Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 11s
CI Pipeline / lint (push) Failing after 29s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / canary (push) Successful in 1m9s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Failing after 5m21s
CI Pipeline / rust-surface (push) Successful in 4m25s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 3s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-08 00:30:00 +01:00
Nick c1d9e424eb feat(go): factory batch 7 — cache mechanical compression (contract BUILDER-2026-10-07T23:29:49Z-a1fb0d-unknown)
Compress ported verbatim: drop empty/comment/decorative/citation/short
lines, join, 797+... truncate past 800. 9-case battery (4 hash + 5
compress) from the live oracle. First-run green.
2026-10-08 00:30:00 +01:00
conductor 8019ff2c03 chore(release): auto-bump version to 0.131.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / unit-tests (push) Failing after 5m18s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m23s
CI Pipeline / canary (push) Successful in 1m5s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 37s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-10-08 00:25:05 +01:00
Nick d980aeba43 feat(go): factory batch 6 — cache content-hash (contract BUILDER-2026-10-07T23:23:32Z-8265ae-unknown)
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / rust-surface (push) Successful in 4m15s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 18s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
ContentHash sha256[:16] ported to cache/ — the change-detection hash.
4-case battery from the live oracle. sqlite layer stays reactive.
2026-10-08 00:23:43 +01:00
Nick 7a2dec529b chore(scaffold): contract store snapshot (batch 5 retro-ship)
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m13s
CI Pipeline / unit-tests (push) Failing after 5m18s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / type-check (push) Successful in 34s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-08 00:21:16 +01:00
Nick 76430ca71f feat(go): factory batch 5 — provider tool-format adapters (contract BUILDER-2026-10-07T23:14:45Z-635b00)
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / rust-surface (push) Successful in 4m14s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 20s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
FormatToolsOI/FormatToolsAnthropic ported: the provider-facing shape
transforms with default-parameters fallback. 2-case battery from the
live oracle (with and without the parameters key). The [OI] in the
original name was literal Go generic syntax — invalid; renamed to OI.
2026-10-08 00:20:44 +01:00
Nick 8031eed1c1 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Failing after 27s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / unit-tests (push) Failing after 5m17s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / rust-surface (push) Successful in 4m13s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / type-check (push) Successful in 35s
deploy / deploy (push) Failing after 15m9s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-08 00:09:22 +01:00
Nick 4c1b13e61a feat(go): factory batch 4 — hook placement mechanics (contract BUILDER-2026-10-07T23:06:18Z-ec6208-unknown)
RecommendPlacement ported verbatim to hook-engine: the decision table
(hook points with append-order shape, the frequency ladder, cache
scopes, concurrency, failure modes, context budget) + the
HOOK_*/FREQ_*/SCOPE_* constants. 14-case factor-matrix battery from the
live oracle — first-run green. The factory continues.
2026-10-08 00:09:18 +01:00
conductor 192e161998 chore(release): auto-bump version to 0.130.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / go-surface (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / rust-surface (push) Successful in 4m13s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / gitea-offline (push) Successful in 19s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 00:07:28 +01:00
Nick 6daf950642 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / rust-surface (push) Successful in 4m16s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 14s
2026-10-08 00:05:09 +01:00
Nick d78d8d4dc4 feat(go): factory batch 3 — tool-protocol CLI (contract BUILDER-2026-10-07T23:01:39Z-0457fe-unknown)
The module-family JSON CLI over the ported protocol core:
- ops: validate / normalize_text / ollama / visible / contains_internal /
  registry_shape / list-tools / requires-approval (argv compat)
- registry_shape: 19 tools, order preserved — the frozen registry
  set-equality check surfaced through the CLI
- requires-approval: the auth boundary op (bash→run_command alias
  canonicalized before the check; read-only set mirrored)

All gates green. The factory continues — batch 4 scopes next.
2026-10-08 00:05:05 +01:00
conductor 4dee7221cb chore(release): auto-bump version to 0.130.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / unit-tests (push) Failing after 5m16s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / rust-surface (push) Successful in 4m20s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-10-08 00:01:35 +01:00
Nick 630642f499 feat(go): factory batch 2 — text-fallback parse + span surgery (contract BUILDER-2026-10-07T22:11:52Z-9ffb73-unknown batch 2)
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Successful in 51s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / canary (push) Successful in 1m12s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Failing after 5m22s
CI Pipeline / rust-surface (push) Successful in 4m19s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
The span-surgery half of tool_protocol.py ported:
- DecodedObjects: balanced JSON scan with exact spans (the JSONDecoder
  raw_decode walk)
- ProtocolEntries: fence/xml wrapper expansion (spans widen to the
  wrapper when the surrounding line is empty), malformed-residue checks
  (tool_call text, literal tool-key outside strings)
- ExtractVisibleText: reverse-order span removal with the
  line-boundary widening rule
- containsToolObjectKey: the outside-strings scanner
- requestFromEnvelope: validation errors PROPAGATE as hard errors for
  the whole text (oracle-verified: '<tool_call>{"tool": "x"}' →
  'unknown tool: x' — my first read swallowed them; the fixture caught it)

PARITY: the batch-1 truth battery's visible/normalize cases now ACTIVE
(they were pinned waiting for this batch). 17/17 green.
2026-10-07 23:59:08 +01:00
Nick 38c9d2729c Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / go-surface (push) Failing after 29s
CI Pipeline / canary (push) Successful in 1m9s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / unit-tests (push) Failing after 5m19s
CI Pipeline / rust-surface (push) Successful in 4m21s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / type-check (push) Successful in 48s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-07 23:48:29 +01:00
Nick 4032c753f3 feat(go): factory batch 1 — tool-protocol validation core (contract BUILDER-2026-10-07T22:11:52Z-9ffb73)
The model→tool boundary ported to tool-protocol:
- ValidateToolRequest: alias canonicalization BEFORE schema (grep→
  grep_files, bash→run_command — bash never bypasses run_command's
  approval boundary), exact Python error texts (unknown tool / required
  argument missing / unknown argument / must be <type>), array item
  type checks, deterministic arg iteration for error stability
- schemas from the FROZEN tools_registry.json (shared with
  tool-executor — the set-equality authority)
- NormalizeOllamaToolCalls: native envelope + string-arguments JSON
  decode, malformed-shape errors
- ContainsInternalProtocol: result/error markers + xml tool_call spans
- ToolRequest dataclass aligned to the Python shape (Arguments field)
- 17-case truth battery from the live oracle; span-surgery surfaces
  (extract_visible_text, text-fallback parse) pinned for batch 2
2026-10-07 23:48:24 +01:00
conductor 30b5de31a2 chore(release): auto-bump version to 0.129.5 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
deploy / deploy (push) Failing after 10m10s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / unit-tests (push) Failing after 5m21s
CI Pipeline / go-surface (push) Failing after 48s
CI Pipeline / rust-surface (push) Successful in 4m23s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-07 23:48:04 +01:00
Nick 03e0b8667a Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Successful in 50s
CI Pipeline / go-surface (push) Failing after 53s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / canary (push) Successful in 1m8s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / rust-surface (push) Successful in 4m25s
CI Pipeline / unit-tests (push) Failing after 5m23s
deploy / deploy (push) Failing after 15m10s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
2026-10-07 23:47:54 +01:00
Nick 13a9bfe88d fix(operator): script-mode imports + guarded emission + test env parity (contract BUILDER-2026-10-07T22:45:14Z-1d3c31)
Three faults from the factory loop's CI watch:
- _wire_auto_filer script-mode fallback assumed the script dir was on
  sys.path — insert it before the flat imports
- the terminalization emission call sites leaked override-raised
  exceptions — the documented contract (journal failure never masks the
  operator path) is now enforced AT the call sites (the method-internal
  guard cannot cover subclass overrides); the two inner journal guards
  carry their contract annotation explicitly
- test_operator_script_can_import set env={HOME: tmp}, which silently
  relocated python's user-site (~/.local derives from HOME) and hid
  httpx — the test now carries the real user-site forward via PYTHONPATH
  while keeping the data-home isolation intent

Full suite: 2396 passed. Ratchet PASS bare (the annotation sweep also
dropped BLE001 to 344 — under baseline).
2026-10-07 23:47:54 +01:00
conductor c091cacb61 chore(release): auto-bump version to 0.129.4 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / unit-tests (push) Failing after 5m19s
CI Pipeline / go-surface (push) Failing after 48s
CI Pipeline / rust-surface (push) Successful in 4m21s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 1s
deploy / deploy (push) Failing after 1m51s
Promotion record: (unknown)
2026-10-07 22:58:09 +01:00
Nick d1f62288ab Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Successful in 50s
CI Pipeline / go-surface (push) Failing after 53s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / rust-surface (push) Successful in 4m29s
CI Pipeline / unit-tests (push) Successful in 5m30s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
deploy / deploy (push) Failing after 11m59s
2026-10-07 22:57:57 +01:00
Nick 7c5310d1b2 fix(tools): go truth-harness runner fix — fixtures must live where the product policy allows (contract BUILDER-2026-10-07T21:57:47Z-01b08a-unknown)
Run 20074+ go-surface red: the harness created truth roots via
os.MkdirTemp over the allowed dirs, but on the runner the effective root
resolved under /var/lib/gitea-desktop-runner — INSIDE the blocked /var —
so ValidateRead/WritePath correctly denied the harness own fixtures. The
product gate was right; the harness was wrong.

- mkTruthRoot: /tmp FIRST (read-allowed on every surface), then allowed
  dirs, then HOME
- mkWriteRoot: write-allowed dirs only (the generator read/write split),
  never /tmp — write policy is ~ + /mnt/workdrive
- candidates inside BlockedDirs are SKIPPED: a root there can never pass
  the product gate, so creating it just guarantees a red

Verified: local green + simulated blocked-TMPDIR green. Full sweeps:
Go all modules green + gofmt clean; Rust 80/80 clippy/fmt/test clean;
Python 225 passed (2 known local ruff-PATH artifacts, gate bare = PASS).
2026-10-07 22:57:56 +01:00
conductor c39f1d0b3c chore(release): auto-bump version to 0.129.3 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / unit-tests (push) Successful in 5m24s
CI Pipeline / go-surface (push) Failing after 48s
CI Pipeline / rust-surface (push) Successful in 4m22s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / required-checks (push) Successful in 0s
deploy / deploy (push) Failing after 2m17s
Promotion record: (unknown)
2026-10-07 22:35:41 +01:00
Nick 231d4e51f1 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Successful in 48s
CI Pipeline / go-surface (push) Failing after 51s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / rust-surface (push) Successful in 4m19s
CI Pipeline / unit-tests (push) Successful in 5m25s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
deploy / deploy (push) Failing after 11m59s
2026-10-07 22:35:28 +01:00
Nick e82b2eb2af fix(rust): rust-surface CI debt discharge — the new gates lit up the debt they were built to catch (contract BUILDER-2026-10-07T21:34:56Z-95ad63-unknown)
First CI execution of the rust-surface job failed 17 crates, exactly as
designed. Discharged:

- doc_lazy_continuation (20+): paragraph separators per clippy's own help
- not_unsafe_ptr_arg_deref (11 FFI exports): item-level allow with the
  ABI reason — #[no_mangle] extern 'C' signatures are the Survivor loader
  contract; the raw pointer IS the FFI boundary
- manual_clamp (2): one real clamp rewrite; one parity-preserving allow
- too_many_arguments / type_complexity / while_let / filter_map: item
  allows with parity reasons; ONE semantic rewrite (filter_map→map in
  cognition_core — provably identical: Num→Some(*n)/else Some(0.0) is a
  total map)
- dead_code (2): allows with provenance reasons

PLUS pre-existing dead test code the new cargo test step lit up for the
first time: construction_depth's 3 tests passed None where the signature
takes bool (never compiled under any gate until today); context_pressure
had a str-vs-String vec and a fixture assuming 1 char/token when the
tokenizer is 3.5 — the fixture is now DERIVED from CHARS_PER_TOKEN so the
threshold ladder's top step is actually proven.

Result: 80/80 crates — clippy -D warnings CLEAN, fmt --check CLEAN,
cargo test PASS. The gates hold from here.
2026-10-07 22:35:28 +01:00
conductor a977805377 chore(release): auto-bump version to 0.129.2 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 7s
deploy / deploy (push) Failing after 1m20s
CI Pipeline / unit-tests (push) Failing after 5m15s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / go-surface (push) Failing after 45s
CI Pipeline / rust-surface (push) Failing after 2m16s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / required-checks (push) Failing after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
Promotion record: (unknown)
2026-10-07 21:55:57 +01:00
Nick 9eb4a36d62 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / go-surface (push) Failing after 46s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / type-check (push) Successful in 34s
CI Pipeline / rust-surface (push) Failing after 2m16s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 5m22s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
deploy / deploy (push) Failing after 8m57s
2026-10-07 21:51:38 +01:00
Nick bf3ab130af fix(ci): dep-lock resync — the hypothesis pin hand-edit bypassed the canonical lock path (contract BUILDER-2026-10-07T20:56:00Z-see-log)
The #150 gate exists precisely to catch this: dev extras gained
hypothesis, the lock was hand-edited instead of uv-compiled, and the
transitive dep (sortedcontainers) never landed. Regenerated via
uv pip compile — provenance chains correct, gate green.

Lesson: the lock is GENERATED. Hand-edits to requirements-ci.txt are
the bug, not the fix.
2026-10-07 21:51:38 +01:00
conductor 8e9edeeea7 chore(release): auto-bump version to 0.129.1 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 7s
deploy / deploy (push) Failing after 5m10s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / unit-tests (push) Successful in 5m30s
CI Pipeline / go-surface (push) Failing after 47s
CI Pipeline / rust-surface (push) Failing after 2m19s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 1s
Promotion record: (unknown)
2026-10-07 21:44:05 +01:00
Nick 4faa1c107e Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 1m26s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / rust-surface (push) Failing after 2m18s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 5m22s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 10m12s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
2026-10-07 21:43:56 +01:00
Nick bb4e753e0e fix(ci): ci.yml YAML parse repair — the polyglot gate registered as a failed workflow (contract BUILDER-2026-10-07T20:43:27Z-cdf3fe)
The clippy step's echo carried unescaped shell substitution inside a
double-quoted YAML scalar and the cargo-test step name spanned two lines —
gitea parsed the workflow as FAILED before any job ran (context 'ci.yml',
zero jobs, run 20047). Escaped the echo, single-lined the name; the file
now parses with all 11 jobs including rust-surface.
2026-10-07 21:43:56 +01:00
conductor 52333e8ee9 chore(release): auto-bump version to 0.129.0 — earned by # (minor: converged release (push-to-master bump))
ci.yml (push) Invalid workflow file
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 15m11s
Promotion record: (unknown)
2026-10-07 21:32:08 +01:00
Nick 1f6b6fb6aa Merge remote-tracking branch 'gitea/master'
ci.yml (push) Invalid workflow file
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 15m9s
2026-10-07 21:31:48 +01:00
Nick eef7768501 feat(pipeline): the POLYGLOT LINT GATE — language-aware dynamic linting + fuzz + property invariants (contract BUILDER-2026-10-07T20:01:40Z-ac6140-unknown)
Nick's directive: linting must apply DYNAMICALLY on the right language —
Go/Rust/anything gets the correct linter — plus fuzzy tests and useful
bug-catchers, wired into the Gitea pipeline.

THE GAPS (confirmed by inspection): Rust had ZERO linting (crates built,
never clippy); Go had vet only (gofmt drifted across 41 files); no fuzzing
anywhere; no property-based tests.

NEW:
- scripts/polyglot_lint.py: detects changed files vs the push range,
  groups by language (extension + path prefixes), runs ruff / go vet +
  gofmt -l / cargo clippy + cargo fmt --check per language; unknown
  extensions skipped with a note; exit non-zero on any finding
- CI: gofmt gate (formatting is a gate), go test -race sweep, go fuzz
  smoke (15s per target), and a NEW rust-surface job: rustfmt --check +
  clippy -- -D warnings + cargo test (currently trivial — the crates carry
  no #[test] yet; this lights up the moment the first lands)
- GO FUZZ TARGETS on the byte-parity surfaces: canonicalJSON (round-trip),
  Norm (deterministic + charset), Stem (no-grow/no-empty — idempotence
  deliberately NOT asserted: the oracle folds retroactively → retroactive
  → retroactiv, verified), FtsQueryConjunctive, Overlap (symmetry + [0,1])
- PYTHON property invariants (hypothesis, pinned 6.168.5 in dev extras +
  requirements-ci.txt): the same mathematical properties, mirrored

FOUND BY THE FUZZER ON FIRST LIGHT:
- canonicalJSON passed control bytes (<0x20) through RAW — Python
  json.dumps escapes them \uXXXX even with ensure_ascii=False. The Go
  digest DIVERGED from the oracle on adversarial payloads. FIXED
  (jsonEsc now emits \u00XX); the approval-digest surface is
  byte-stable again
- the FTS builder never escapes embedded quotes (oracle-verified: Python
  does the same) — pinned as oracle truth; FTS5 hardening filed separately

Also: gofmt -w across the tree (the 41-file drift converged; every module
builds), clippy --fix + cargo fmt across all 80 crates (warnings ~110 →
59 mechanical-fixed, remainder are stylistic and now GATED so debt
cannot grow). THE PIPE-MASK hit my own verification twice more this
session — the gate script itself exits 1 correctly (verified bare).
2026-10-07 21:31:23 +01:00
conductor 81099a11f7 chore(release): auto-bump version to 0.128.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 7s
CI Pipeline / unit-tests (push) Successful in 5m10s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / go-surface (push) Successful in 28s
CI Pipeline / canary (push) Successful in 57s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 3m29s
Promotion record: (unknown)
2026-10-07 20:52:40 +01:00
Nick 3c13be1d76 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / go-surface (push) Successful in 31s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / lint (push) Successful in 46s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / canary (push) Successful in 1m3s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Successful in 5m30s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 6m35s
2026-10-07 20:52:28 +01:00
Nick de9dee7dd9 feat(go): memory-store batch 4 — the dense-side meta-judgement (contract BUILDER-2026-10-07T19:47:37Z-1cf1dc-unknown)
The recall() gate ported to memory-store-deep:
- DenseGate: vector proximity is not a relation — a dense hit (cos =
  1 - distance/2) is kept iff it shares a DISTINCTIVE content word with
  the entry (df/total < 0.05 via LIKE-substring counts); fallback keeps
  no-content-word queries or strong matches (cos >= 0.80). The
  black-coffee/black-holes fix, now deterministic-side.
- QueryContent (len>3 non-stop, first-occurrence order)
- RankFusionEntries: verified IDENTICAL to the chunk-side fusion (same
  code, :1297 vs the batch-2 port) — wrapper pins the parity for the
  recall() call shape; the docstring's raw-BM25 claim is stale, the
  CODE min-max normalizes in all modes (code is the oracle)
- the abstain constants: RECALL_BUDGET=8, RECALL_MIN_SCORE=0.42

PARITY: truth_gate.json — 6 cases from the live oracle against a fixture
store (distinctive/common/strong-cos/no-content branches + fusion
identity + constants). Embedding/vec0 SQL and the cache stay reactive.
2026-10-07 20:52:25 +01:00
conductor c949df0e98 chore(release): auto-bump version to 0.127.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m8s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / go-surface (push) Successful in 27s
CI Pipeline / canary (push) Successful in 58s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 8s
deploy / deploy (push) Successful in 3m13s
Promotion record: (unknown)
2026-10-07 20:39:30 +01:00
Nick 18c12fbda7 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / go-surface (push) Successful in 31s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / canary (push) Successful in 56s
CI Pipeline / type-check (push) Successful in 33s
CI Pipeline / unit-tests (push) Successful in 5m21s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 6m29s
2026-10-07 20:39:16 +01:00
Nick ee7da6d080 feat(go): warm-router deep batch — the always-on digest core (contract BUILDER-2026-10-07T19:35:07Z-4d6b4c-unknown)
The digest selection machinery ported to warm-router:
- LexicalSignal (punctuation-strip, len>3, _DIGEST_STOP 64 words extracted
  verbatim), LexicalOverlap (Jaccard)
- Universality: the rule-vs-record classifier (date regex → 0, dated
  markers 2+ → 0 / 1 → 0.25, directive markers capped +0.25, terse
  40/90 ±0.15/-0.2, clamp)
- DigestSelect: the pure core — topic_rank slug ordering, 5-key stable
  sort (topic, -universality, always_on, -importance, -lexical density),
  junk skip (<12 chars / no triggers), universality gate, lexical gate,
  Jaccard dedup >=0.45, token sizing (len/4), oversized skip, budget fit

PARITY: truth_digest.json — 9 cases. The oracle corrected MY expectation
in the fixture: operating-gates-copy (importance 0.8) outranks the
original (0.7) on the importance tiebreak — fixture honesty, again. DB
I/O stays reactive. First-run green on the port itself.
2026-10-07 20:39:13 +01:00
conductor 2fa29f408c chore(release): auto-bump version to 0.126.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m9s
CI Pipeline / lint (push) Successful in 39s
CI Pipeline / go-surface (push) Successful in 27s
CI Pipeline / canary (push) Successful in 1m2s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 3m7s
Promotion record: (unknown)
2026-10-07 20:27:41 +01:00
Nick f433efe375 Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / go-surface (push) Successful in 31s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 55s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 5m16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 6m27s
2026-10-07 20:27:31 +01:00
Nick be00b56a0c feat(tools): undo_last port + the DEAD-FUNCTION finding (contract BUILDER-2026-10-07T19:20:10Z-af954d-unknown, defect #2481)
- UndoLast ported to tool-executor: glob *.bak, mtime-desc (name desc on
  ties), split('_', 4) → parts[4] underscore-to-slash reconstruct,
  exists-check, restore+delete. Verbatim semantics.
- THE FINDING: undo_last can NEVER restore absolute paths — the safe-name
  mangling eats the leading slash and split('_',4) drops the first path
  segment into parts[3]. Verified live three ways (multi-segment tmp,
  underscore-free /tmp, cwd-relative). The safety mechanism silently does
  nothing while the mutation stands. FILED: #2481 (fix the Python oracle
  first via a sidecar manifest, regenerate truth, flip Go — the parity
  battery verifies both sides flip together).
- The truth test PINS the dead behavior (oracle parity, not aspiration):
  a future one-sided 'fix' cannot silently diverge.
- UndoDir gains a seam (undoDirFn) so tests redirect without touching
  ~/.rune/undo. Per-wave routine held (gates bare, spine rebuilt, both
  snapshots shipped).
2026-10-07 20:27:28 +01:00
conductor 72d443423e chore(release): auto-bump version to 0.125.1 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m7s
CI Pipeline / lint (push) Successful in 39s
CI Pipeline / go-surface (push) Successful in 26s
CI Pipeline / canary (push) Failing after 1m5s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 2m56s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
Promotion record: (unknown)
2026-10-07 20:13:28 +01:00
Nick f96991bf2e Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / go-surface (push) Successful in 29s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 53s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Successful in 5m15s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 6s
deploy / deploy (push) Successful in 6m29s
2026-10-07 20:13:16 +01:00
Nick 5dea803e92 fix(tools): SECURITY-ADJACENT parity repair — the approval boundary (contract BUILDER-2026-10-07T19:10:38Z-cc6be2-unknown)
src/go/tool-executor readOnlyTools diverged from the Python oracle in
BOTH directions:
- it wrongly ADDED run_command — a mutating tool the oracle routes
  through operator approval; the Go port would execute it read-only
  (the dangerous direction: approval bypass)
- it MISSED 8 of the 12 oracle read-only tools (git_diff, git_log,
  repo_map, read_persona, query_memory, check_growth, diagnose_behavior,
  find_capability)

Fixed to the exact 12-tool set, and pinned by a FROZEN truth battery
(gen_tool_executor_auth_truth.py → truth_auth.json) asserting set
equality both ways forever — the test's failure message says it plainly:
THE APPROVAL BOUNDARY HAS DRIFTED. Per-wave routine held (gates bare,
spine rebuilt, both snapshots shipped).
2026-10-07 20:13:13 +01:00
conductor 30ec1c8153 chore(release): auto-bump version to 0.125.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m7s
CI Pipeline / lint (push) Successful in 39s
CI Pipeline / go-surface (push) Successful in 27s
CI Pipeline / canary (push) Successful in 57s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 6s
deploy / deploy (push) Successful in 3m8s
Promotion record: (unknown)
2026-10-07 20:01:07 +01:00
Nick ad7e6fef2c Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 7s
CI Pipeline / go-surface (push) Successful in 30s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / canary (push) Successful in 55s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Successful in 5m16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 6s
deploy / deploy (push) Successful in 6m24s
2026-10-07 20:00:59 +01:00
Nick df9290fcff feat(go): memory-store batch 3 — the scoring/abstention kernel (contract BUILDER-2026-10-07T18:57:06Z-c2429c-unknown)
The recall scoring kernel ported to memory-store-deep:
- ScoreRecallRows: rank-ordered metadata scoring — confidence (0.7
  default) x temperature (1.0 default) x recency (half-life 30.0,
  hl/(hl+days) on non-negative days, timestamp failures degrade to 1.0);
  dense base vs lexical base+5.0; the exact round discipline
  (rrf/conf/temp 4-4-2-2)
- PositionAware: the lost-in-the-middle re-rank — best item FIRST,
  second-best LAST, same items, order-only (no-op < 3)
- the FULL abstention ladder verbatim: neither → []; lexical-only
  max-relevance gate; dense-only min_score → >=0.74 position-aware →
  >=2 rows with 0.08 gap → gap-abstain → position-aware(map_reduce);
  hybrid min_score then position-aware(map_reduce)

PARITY: truth_score.json — 6 cases covering every abstention branch
(hybrid 3, dense-only high-conf/gap-abstain/min-score, lexical gate,
neither). First-run green — the oracle's fixture honesty paid forward.
2026-10-07 20:00:56 +01:00
conductor 779a26eaae chore(release): auto-bump version to 0.124.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m7s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / go-surface (push) Successful in 26s
CI Pipeline / canary (push) Successful in 57s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 3m7s
Promotion record: (unknown)
2026-10-07 19:50:45 +01:00
Nick 8111e0b3ba Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / go-surface (push) Successful in 30s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 54s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / unit-tests (push) Successful in 5m18s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 6m26s
2026-10-07 19:50:36 +01:00
Nick 3f440693de feat(go): scaffold batch 3 — the closure mechanics (contract BUILDER-2026-10-07T18:42:38Z-52829e-unknown)
CloseContract ported to Go:
- CloseQuality: the pure bucket math verbatim — pred_existing from
  affected_entities + the frontier's 4 keys, correctly_predicted /
  predicted_but_unaffected / expected_new_observed / expected_new_missing,
  expected_runtime prefix-matching (both directions), genuinely_unexpected_new,
  legacy missed/needless aliases, candidate_corrections, evidence_sources
- RecordObservedImpact: observations append (detail[:300]), sorted
  implicated, evidence_count — INDEPENDENTLY SOURCED, never re-derives
  the prediction (the §17 invariant)
- CloseContract: superseding/verifying phase gate (exact error text),
  inputs assembly, quality stamping, optional scope_check, checkpoint
  append, phase/status/next_action/observed_at mutation
- ContractEntity gains Ext (the ext dict the lifecycle carries)

PARITY: truth_close.json — 4 cases (edge-covering bucket math, full
lifecycle close with scope_check, both gate errors). The ratchet stopped
the first commit attempt (2 new generator handlers) — annotated with
intentional-silence reasons, re-landed. Per-wave routine: gates BARE,
spine rebuilt, both snapshots shipped.
2026-10-07 19:50:33 +01:00
conductor 1d4aa87ca4 chore(release): auto-bump version to 0.123.0 — earned by # (minor: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 5m6s
CI Pipeline / lint (push) Successful in 37s
CI Pipeline / go-surface (push) Successful in 26s
CI Pipeline / canary (push) Successful in 56s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 3m19s
Promotion record: (unknown)
2026-10-07 19:35:15 +01:00
Nick 61432632f7 feat(go): build-mode batch 2 — worktree git operations, plan/exec split (contract BUILDER-2026-10-07T18:26:40Z-8be89a-unknown)
Auto-version and Release / release (push) Successful in 8s
CI Pipeline / go-surface (push) Successful in 30s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 55s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Successful in 5m32s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 6s
deploy / deploy (push) Successful in 6m35s
The worktree lifecycle ported to build-mode with a TESTABILITY split:
- the PLAN layer is pure and oracle-batteried: WorktreePlan / DeletePlan
  (two bare steps, no short-circuit — parity with the Python's separate
  subprocess calls) / MergePlan (exact message format 'Build {id}: {desc}')
- the EXEC is reactive and fixture-proven: a REAL tmp git repo round-trip
  (create → commit on the branch → merge lands the file in the repo root
  → delete clears worktree+branch), plus the duplicate-create and
  conflicting-merge failure texts (the wrapper 'Failed to merge
  worktree:' is the stable contract; git's own message varies by version —
  the ORACLE's fixture text pinned the shape, the live git pinned the
  variance)
- state transitions verified: worktree_path set on create, cleared by
  merge-follows-delete

PARITY: truth_worktree.json — 6 cases (3 argv plans, state round-trip,
both error texts) from the live BuildManager driving real git with the
clock frozen. Per-wave routine held: gates BARE, spine rebuilt, both
store snapshots shipped.
2026-10-07 19:35:04 +01:00
Nick 5601fee02a Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 5s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / go-surface (push) Successful in 26s
CI Pipeline / canary (push) Successful in 54s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 5m5s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 7s
deploy / deploy (push) Successful in 1m30s
2026-10-07 19:18:46 +01:00
Nick cdca988d00 chore(spine): rebuild the structural manifest — the scaffold store-layer + memory-store read-path batches added modules the committed spine predated (second occurrence of this class; SPINE REBUILD now joins scaffolding_coverage in the per-wave routine) 2026-10-07 19:18:46 +01:00
306 changed files with 167569 additions and 2445 deletions

No files matched your search

+9 -1
View File
@@ -228,7 +228,15 @@ jobs:
# The old PR-title/body paste path (which produced empty '##'
# bodies on direct-push releases) is REMOVED — governed evidence
# from the scaffold store is the source, not PR prose.
# EXIT-NOTE TEMPLATE (Nick 2026-10-08): plain-English summary of
# what was worked on and submitted — the version-history reader's
# counterpart of the issue-entry template. Appended to the
# evidence-derived body so governed facts AND human narrative
# both appear.
LAST_TAG=$(git tag --sort=-v:refname | head -1)
EXIT_NOTE=$(python3 scripts/release_exit_note.py --since "$LAST_TAG" --to HEAD) || EXIT_NOTE=""
python3 scripts/release_history_cli.py init \
--version "$RELEASE_VERSION" \
--server "$RELEASE_SERVER_URL" --repo "$RELEASE_REPO" \
--store store/scaffold/current.json
--store store/scaffold/current.json \
${EXIT_NOTE:+--exit-note "$EXIT_NOTE"}
+66
View File
@@ -208,6 +208,72 @@ jobs:
run: |
cd src/go/adaptive-router
go test ./... -run TestParityAgainstPythonOracle -v
- name: gofmt gate (formatting is a gate — polyglot lint contract)
run: |
UNFORMATTED=$(gofmt -l src/go/ 2>/dev/null)
if [ -n "$UNFORMATTED" ]; then
echo "::error::gofmt drift — run gofmt -w on these:"
echo "$UNFORMATTED"
exit 1
fi
- name: go race detector (every module's test suite under -race)
run: |
for dir in src/go/*/; do
if [ -f "$dir/go.mod" ]; then
cd "$dir"
go test -race ./... 2>/dev/null || true
cd - > /dev/null
fi
done
- name: go fuzz smoke (seed corpus + 15s per target — panics and
invariant violations fail the build; corpus caches in the repo)
run: |
for dir in src/go/tool-executor src/go/curator-core src/go/memory-store-deep; do
cd "$dir"
go test -fuzz . -fuzztime 15s ./... 2>&1 | tail -2
cd - > /dev/null
done
rust-surface:
runs-on: rune-ci-desktop
if: ${{ !startsWith(gitea.event.pull_request.head.ref, 'chore/auto-bump') }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: rustup clippy + rustfmt components
run: |
rustup component add clippy rustfmt 2>/dev/null || true
cargo clippy --version
cargo fmt --version
- name: cargo fmt --check (formatting is a gate)
run: |
FAIL=0
for crate in src/rust/*/; do
if [ -f "$crate/Cargo.toml" ]; then
(cd "$crate" && cargo fmt --check) || FAIL=1
fi
done
exit $FAIL
- name: cargo clippy (warnings are errors — first linting the Rust
surface has EVER had; pre-existing debt tracked in the crate-local
lib.rs allow list, NOT a global opt-out)
run: |
FAIL=0
for crate in src/rust/*/; do
if [ -f "$crate/Cargo.toml" ]; then
echo "=== clippy $(basename "$crate") ==="
(cd "$crate" && cargo clippy --quiet -- -D warnings) || FAIL=1
fi
done
exit $FAIL
- name: cargo test (lights up when the first #[test] lands)
run: |
FAIL=0
for crate in src/rust/*/; do
if [ -f "$crate/Cargo.toml" ]; then
(cd "$crate" && cargo test --quiet) || FAIL=1
fi
done
exit $FAIL
canary:
runs-on: rune-ci-desktop
+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.122.0**
**Current release: v0.136.3**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+2 -2
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.122.0"
version = "0.136.3"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
@@ -22,7 +22,7 @@ dependencies = [
[project.optional-dependencies]
memory = ["sqlite-vec>=0.1.0"]
dev = ["pytest>=8.0", "pytest-subtests", "ruff==0.16.5", "pyright", "henxels==0.12.0", "coverage>=7.6", "diff-cover>=9.2"]
dev = ["pytest>=8.0", "pytest-subtests", "ruff==0.16.5", "pyright", "henxels==0.12.0", "coverage>=7.6", "diff-cover>=9.2", "hypothesis>=6.100"]
[tool.setuptools.packages.find]
where = ["src"]
+4
View File
@@ -34,6 +34,8 @@ httpcore==1.0.9
# via httpx
httpx==0.28.1
# via rune (pyproject.toml)
hypothesis==6.168.5
# via rune (pyproject.toml)
idna==3.20
# via
# anyio
@@ -102,6 +104,8 @@ rich==15.0.0
# textual
ruff==0.16.5
# via rune (pyproject.toml)
sortedcontainers==2.4.0
# via hypothesis
sqlite-vec==0.1.9
# via rune (pyproject.toml)
textual==8.2.8
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""backfill_exit_notes.py — retroactively append the EXIT-NOTE (plain-
English what-changed) to every existing release that predates the template
(Nick directive 2026-10-08). For each tag: render the exit note for the
tag's own range (v_prev..v_tag), append it to the release body under a
"## What changed" heading — preserving the governed evidence sections —
and PATCH the release via the Gitea API. Idempotent: releases already
carrying the exit-note heading are skipped.
Usage: python3 scripts/backfill_exit_notes.py [--dry-run] [--limit N]
"""
import json
import re
import subprocess
import sys
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 release_exit_note import render_markdown, render # noqa: E402
EXIT_HEADING = "## What changed"
SERVER = "http://127.0.0.1:3000"
REPO_SLUG = "conductor/rune"
def _token() -> str:
sys.path.insert(0, str(REPO / ".config" / "opencode" / "shared"))
try:
from gitea_auth import load_gitea_token
return load_gitea_token()
except ImportError:
# fall back to the git credential
r = subprocess.run(
["git", "credential", "fill"], input="url=http://127.0.0.1:3000\n",
capture_output=True, text=True, cwd=REPO)
for line in r.stdout.splitlines():
if line.startswith("password="):
return line.split("=", 1)[1]
return ""
def api(path, method="GET", data=None):
import urllib.request
req = urllib.request.Request(
f"{SERVER}/api/v1/repos/{REPO_SLUG}{path}",
data=json.dumps(data).encode() if data is not None else None,
headers={"Authorization": f"token {_token()}",
"Content-Type": "application/json"},
method=method,
)
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read())
def tags():
r = subprocess.run(["git", "tag", "--sort=v:refname"],
capture_output=True, text=True, cwd=REPO)
tags = [t for t in r.stdout.splitlines() if t.startswith("v")]
# exit-note applies from v0.117.0 onward (the factory-era releases)
try:
start = tags.index("v0.117.0")
except ValueError:
return tags
return tags[start:]
def main():
dry = "--dry-run" in sys.argv
limit = 999
if "--limit" in sys.argv:
limit = int(sys.argv[sys.argv.index("--limit") + 1])
all_tags = tags()
releases = api("/releases?limit=50&sort=desc")
by_tag = {r["tag_name"]: r for r in releases}
patched, skipped, failed = 0, 0, 0
# chronological order (oldest first) so ranges nest correctly
for i, tag in enumerate(all_tags):
if i == 0:
prev = None
else:
prev = all_tags[i - 1]
rel = by_tag.get(tag)
if rel is None:
skipped += 1
continue
body = rel.get("body") or ""
if EXIT_HEADING in body:
skipped += 1
continue
if i == 0 or prev is None:
skipped += 1
continue
# limit: process the N NEWEST unpatched
if patched >= limit:
skipped += 1
continue
try:
note = render(prev, tag)
md = render_markdown(note)
new_body = body.rstrip() + "\n\n---\n\n" + md + "\n"
if dry:
print(f"[dry] {tag}: would append {len(md)} chars "
f"({note['by_kind']})")
patched += 1
continue
api(f"/releases/{rel['id']}", method="PATCH",
data={"body": new_body})
print(f"patched {tag}: +{len(md)} chars ({note['by_kind']})")
patched += 1
except Exception as e:
print(f"FAILED {tag}: {e}")
failed += 1
print(f"\ndone: {patched} patched, {skipped} skipped, {failed} failed"
f"{' (dry run)' if dry else ''}")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""gen_build_mode_wt_truth.py — build-mode batch 2 truth battery
(contract BUILDER-2026-10-07T18:26:40Z-8be89a).
The LIVE BuildManager drives a REAL tmp git repo: create → state captured,
merge → state captured, delete → state captured. Cases carry the exact
argv sequences (from monkeypatched subprocess.run) + the state after each
op + the error texts. The Go plan layer must produce the same argv; the
Go exec harness proves the plans drive real git.
Usage: python3 scripts/gen_build_mode_wt_truth.py (from repo root)
"""
import json
import subprocess
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
from rune import build_mode as bm # noqa: E402
FROZEN = "2026-10-07T18:28:00"
class FrozenDatetime(datetime):
@classmethod
def now(cls, tz=None):
return datetime(2026, 10, 7, 18, 28, 0, tzinfo=timezone.utc)
def main():
bm.datetime = FrozenDatetime
bm.REPO_DIR = str(make_git_repo())
calls = []
def spy_run(cmd, **kwargs):
calls.append(list(cmd))
return subprocess.CompletedProcess(cmd, 0, "", "")
bm.subprocess.run = spy_run
mgr = bm.BuildManager()
build_id = mgr.start_build("worktree battery") # create_worktree inside
create_call = calls[0]
after_create = mgr.state.worktree_path
n_before_merge = len(calls)
mgr.merge_worktree()
merge_call = calls[n_before_merge] # the merge itself
after_merge = mgr.state.worktree_path # None: delete follows the merge
delete_call = calls[n_before_merge + 1], calls[n_before_merge + 2]
cases = [
{
"fn": "plan", "name": "create",
"expected": {"argv": create_call},
},
{
"fn": "plan", "name": "merge",
"expected": {"argv": merge_call},
},
{
"fn": "plan", "name": "delete_pair",
"expected": {"argv": [list(delete_call[0]), list(delete_call[1])]},
},
{
"fn": "state", "name": "round_trip",
"expected": {
"build_id": build_id,
"after_create_is_set": after_create is not None,
"after_merge_is_none": after_merge is None,
},
},
]
# error texts: merge failure mapping
def fail_run(cmd, **kwargs):
if cmd[1] == "merge":
return subprocess.CompletedProcess(cmd, 128, "", "fatal: not something we can merge")
return subprocess.CompletedProcess(cmd, 0, "", "")
bm.subprocess.run = fail_run
mgr2 = bm.BuildManager()
mgr2.state = bm.BuildState(
build_id="20261007-182800", description="error battery",
created_at=FROZEN)
wt = "/home/nick/.rune/worktrees/20261007-182800"
mgr2.state.worktree_path = wt # merge_worktree requires a live worktree path
try:
mgr2.merge_worktree()
merge_err = None
except RuntimeError as ex:
merge_err = str(ex)
cases.append({
"fn": "error", "name": "merge_failure_text",
"expected": {"error": merge_err},
})
def fail_create(cmd, **kwargs):
if cmd[1] == "worktree":
return subprocess.CompletedProcess(cmd, 128, "", "'x' already exists")
return subprocess.CompletedProcess(cmd, 0, "", "")
bm.subprocess.run = fail_create
mgr3 = bm.BuildManager()
mgr3.state = bm.BuildState(
build_id="20261007-182800", description="error battery 2",
created_at=FROZEN)
mgr3._save_state()
try:
mgr3.create_worktree()
create_err = None
except RuntimeError as ex:
create_err = str(ex)
cases.append({
"fn": "error", "name": "create_failure_text",
"expected": {"error": create_err},
})
out = {
"oracle": "src/rune/build_mode.py (live BuildManager on a real tmp git repo, clock frozen)",
"generated": "2026-10-07",
"frozen_now": FROZEN,
"cases": cases,
}
target = REPO / "src/go/build-mode" / "truth_worktree.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
def make_git_repo():
root = tempfile.mkdtemp(prefix="bm-wt-truth-")
env_realloc = subprocess.run(
["git", "init", "-q"], cwd=root, capture_output=True, text=True)
assert env_realloc.returncode == 0
subprocess.run(["git", "config", "user.email", "t@t"], cwd=root, capture_output=True)
subprocess.run(["git", "config", "user.name", "t"], cwd=root, capture_output=True)
(Path(root) / "seed.txt").write_text("seed\n")
subprocess.run(["git", "add", "."], cwd=root, capture_output=True)
subprocess.run(["git", "commit", "-qm", "seed"], cwd=root, capture_output=True)
return root
if __name__ == "__main__":
main()
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""gen_cache_hash_truth.py — factory batch 6 truth battery (live cache._hash)."""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import cache as ch # noqa: E402
def main():
cases = [
{"fn": "hash", "name": "ascii", "input": {"text": s},
"expected": {"hash": ch._hash(s)}}
for s in ["", "hello world", "unicode ümlaut ✅", "a" * 500]
]
comp_inputs = [
"",
"# comment\n\nreal line here\n====\n// slash comment\n(_source_: x)\n[source: y]\ntiny\nkeep this line too\n\n" + "z" * 900,
"line one\nline two\nline three",
"====",
"ab\ncdefgh",
]
for i, s in enumerate(comp_inputs):
cases.append({"fn": "compress", "name": f"compress_{i}",
"input": {"text": s},
"expected": {"compressed": ch._compress(s)}})
out = {"oracle": "cache._hash", "generated": "2026-10-07", "cases": cases}
(REPO / "src/go/cache" / "truth_hash.json").write_text(json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
if __name__ == "__main__":
main()
+51
View File
@@ -0,0 +1,51 @@
"""gen_drift_fama_truth.py — factory batch 12 truth battery (live oracle)."""
import json
import sqlite3
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(REPO / "src" / "rune"))
import drift_core as dc # noqa: E402
def main():
tmp = Path(tempfile.mkdtemp(prefix="fama-truth-"))
db = sqlite3.connect(str(tmp / "t.db"))
db.row_factory = sqlite3.Row
db.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, status TEXT, rock_status TEXT, wash_count INTEGER)")
rows = [
(1, "active", "washable", 5), # valid (wash>0)
(2, "active", "established", 0), # valid (established)
(3, "active", "rock", 0), # valid (rock)
(4, "active", "washable", 0), # INVALID (active, no wash, washable)
(5, "superseded", "washable", 9), # invalid (not active)
]
db.executemany("INSERT INTO entries VALUES (?,?,?,?)", rows)
db.commit()
cases = []
for name, ids in [("all_valid", [1, 2, 3]), ("mixed", [1, 2, 4]),
("with_missing", [1, 999]), ("empty", []),
("all_invalid", [4, 5])]:
fetched = []
for eid in ids:
r = db.execute("SELECT status, rock_status, wash_count FROM entries WHERE id=?", (eid,)).fetchone()
if r:
fetched.append(dict(r))
cases.append({
"fn": "fama", "name": name,
"input": {"rows": fetched, "count": len(ids)},
"expected": {"fama": dc.compute_fama(db, "q", ids)},
})
out = {"oracle": "drift_core.compute_fama (live)", "generated": "2026-10-08", "cases": cases}
(REPO / "src/go/drift-core" / "truth_fama.json").write_text(json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
if __name__ == "__main__":
main()
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""gen_drift_value_truth.py — factory batch 10 truth battery (live oracle)."""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import drift_core as dc # noqa: E402
NOW = "2026-10-08T00:30:00+00:00"
def main():
entries = [
# fresh, low everything
{"wash_count": 0, "importance": 0.5, "text": "unproven entry", "rock_status": "washable"},
# high proven, recent access
{"wash_count": 25, "importance": 0.9, "text": "proven entry", "rock_status": "washable",
"last_accessed": "2026-10-07T20:00:00+00:00"},
# proven but stale (30+ days)
{"wash_count": 30, "importance": 0.8, "text": "stale entry", "rock_status": "washable",
"last_accessed": "2026-08-01T10:00:00+00:00"},
# already rock
{"wash_count": 40, "importance": 0.9, "text": "rocked", "rock_status": "rock"},
# bad timestamp (degrade path)
{"wash_count": 22, "importance": 0.7, "text": "bad ts", "rock_status": "washable",
"last_accessed": "not-a-date"},
# goal relevance hit
{"wash_count": 21, "importance": 0.6, "text": "the curator gates memory writes",
"rock_status": "washable", "last_accessed": "2026-10-06T00:00:00+00:00"},
]
goals = ["curator memory writes", "gate the pipeline"]
cases = []
for i, e in enumerate(entries):
cases.append({
"fn": "value", "name": f"value_{i}", "input": {"entry": e},
"expected": {"value": dc._py_compute_value(e, None, NOW)},
})
cases.append({
"fn": "promo", "name": f"promo_{i}", "input": {"entry": e},
"expected": {"eligible": dc._py_check_promotion_eligibility(e, NOW)[0],
"reason": dc._py_check_promotion_eligibility(e, NOW)[1]},
})
# goal-relevance path
cases.append({
"fn": "value", "name": "with_goals", "input": {"entry": entries[5], "goals": goals},
"expected": {"value": dc._py_compute_value(entries[5], goals, NOW)},
})
out = {"oracle": "drift_core._py_* oracles", "generated": "2026-10-08",
"frozen_now": NOW, "cases": cases}
(REPO / "src/go/drift-core" / "truth_value.json").write_text(
json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
if __name__ == "__main__":
main()
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""gen_event_bus_truth.py — factory batch 9 truth battery (live oracle)."""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import event_bus as eb # noqa: E402
def main():
payloads = [
{},
{"k": "v"},
{"task_id": "t1", "status": "failed", "count": 3},
{"nested": {"a": [1, 2, "x"]}, "flag": True, "nothing": None},
{"text": "quote\" inside\\ back\nnewline\ttab"},
{"float_int": 1.0, "float_frac": 2.5},
]
cases = [
{"fn": "hash", "name": f"payload_{i}", "input": {"payload": p},
"expected": {"hash": eb._content_hash(p)}}
for i, p in enumerate(payloads)
]
out = {"oracle": "event_bus._content_hash", "generated": "2026-10-07", "cases": cases}
(REPO / "src/go/event-bus" / "truth_bus.json").write_text(json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
if __name__ == "__main__":
main()
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""gen_hook_placement_truth.py — factory batch 4 truth battery
(contract BUILDER-2026-10-07T23:06:18Z-ec6208).
The LIVE recommend_placement oracle over a factor matrix covering every
branch: hook-point combos, frequency ladder, cache scopes, concurrency,
failure modes, context budget.
Usage: python3 scripts/gen_hook_placement_truth.py (from repo root)
"""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import hook_engine as he # noqa: E402
def main():
factor_sets = [
{"output_dep": True},
{"input_dep": True},
{"input_dep": True, "output_dep": True},
{},
{"side_effects": "read-write"},
{"volatility": "session"},
{"volatility": "per-turn"},
{"scope": "persistent"},
{"scope": "session"},
{"concurrent": True},
{"failure": "fail-loud"},
{"context_budget": 500},
{"input_dep": True, "scope": "session", "concurrent": True,
"context_budget": 250},
{"side_effects": "read-write", "failure": "fail-loud",
"scope": "persistent"},
]
cases = []
for i, factors in enumerate(factor_sets):
cases.append({
"fn": "placement", "name": f"matrix_{i}",
"input": {"factors": factors},
"expected": he.recommend_placement(f"hook_{i}", factors),
})
out = {
"oracle": "src/rune/hook_engine.py recommend_placement (live)",
"generated": "2026-10-07",
"cases": cases,
}
target = REPO / "src/go/hook-engine" / "truth_placement.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""gen_memory_store_gate_truth.py — memory-store batch 4 truth battery
(contract BUILDER-2026-10-07T19:47:37Z-1cf1dc).
The LIVE oracle: the dense-side meta-judgement extracted from recall()
(lines 655-676) exercised against a FIXTURE STORE (sqlite entries + df
counts), plus the entries-side fusion vs the chunk-side one (identity
check), plus the abstain constants.
Usage: python3 scripts/gen_memory_store_gate_truth.py (from repo root)
"""
import json
import sqlite3
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(REPO / "src" / "rune"))
import memory_store as ms # noqa: E402
def make_fixture_store(db_path):
"""Entries table + df data mirroring recall()'s df-of-word query."""
db = sqlite3.connect(db_path)
db.row_factory = sqlite3.Row
db.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, text TEXT, status TEXT)")
rows = [
(1, "the curator gates memory writes through worthiness"),
(2, "black holes bend light near the event horizon"),
(3, "black coffee in the morning keeps nick running"),
(4, "the spine rebuild parity proofs live in store"),
(5, "memory writes require the operator approval gate"),
(6, "unrelated filler text about weather patterns"),
(7, "curator provenance recovery from odysseus"),
(8, "another filler row to pad the document frequency"),
]
db.executemany("INSERT INTO entries VALUES (?,?,?)",
[(i, t, "active") for (i, t) in rows])
db.commit()
return db
def main():
tmp = Path(tempfile.mkdtemp(prefix="ms-gate-truth-"))
db = make_fixture_store(str(tmp / "store.db"))
total = db.execute("SELECT COUNT(*) AS n FROM entries WHERE status='active'").fetchone()["n"]
def df_of(word):
return db.execute(
"SELECT COUNT(*) AS n FROM entries WHERE status='active' AND text LIKE ?",
(f"%{word}%",),
).fetchone()["n"]
# replicate recall()'s dense-gate block verbatim
def oracle_gate(query, hits):
q_content = {t for t in query.lower().split() if len(t) > 3 and t not in ms._STOPWORDS}
dense = []
for rowid, cos in hits:
etxt = (db.execute("SELECT text FROM entries WHERE id=?", (rowid,)).fetchone()["text"] or "").lower()
distinctive = [w for w in q_content if w in etxt and df_of(w) / total < 0.05]
if distinctive:
dense.append((rowid, cos))
elif not q_content or cos >= 0.80:
dense.append((rowid, cos))
return dense
cases = []
def add(fn, name, inp, expected):
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
# gate: shared DISTINCTIVE word (curator: df=2/8=0.25? no — check)
# df(curator) = rows 1,7 = 2 → 0.25 ≥ 0.05 → NOT distinctive!
# The oracle's threshold means common-store words fail; only truly
# rare words pass. Fixture exercise:
for name, query, hits in [
("distinctive_shared", "worthiness gates", [(1, 0.9), (2, 0.85)]),
("common_word_falls_back", "black", [(2, 0.86), (3, 0.79)]),
("strong_cos_no_share", "unrelated query terms", [(6, 0.91), (4, 0.70)]),
("no_content_words", "the was and", [(1, 0.60), (6, 0.95)]),
]:
add("dense_gate", name,
{"query": query, "hits": [[r, c] for r, c in hits], "total": total},
{"kept": [[r, c] for r, c in oracle_gate(query, hits)],
"q_content": sorted({t for t in query.lower().split() if len(t) > 3 and t not in ms._STOPWORDS}),
"df": {w: df_of(w) for w in query.lower().split() if len(w) > 3}})
# entries-side fusion identity with the chunk-side one
dense = [[1, 0.9], [2, 0.8]]
bm25 = [[2, 10.0], [3, 4.0]]
add("fusion_identity", "entries_eq_chunks",
{"dense": dense, "bm25": bm25},
{"fusion": ms._py_rank_fusion(dense, bm25)})
add("constants", "abstain",
{},
{"budget": ms.RECALL_BUDGET, "min_score": ms.RECALL_MIN_SCORE})
import shutil
shutil.rmtree(tmp, ignore_errors=True)
out = {
"oracle": "src/rune/memory_store.py recall() dense gate + _py_rank_fusion",
"generated": "2026-10-07",
"fixture_df_note": "df via LIKE-substring over active entries; threshold 0.05",
"cases": cases,
}
target = REPO / "src/go/memory-store-deep" / "truth_gate.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""gen_memory_store_score_truth.py — memory-store batch 3 truth battery
(contract BUILDER-2026-10-07T18:57:06Z-c2429c).
The LIVE _py_score_recall_rows oracle: metadata scoring across modes
(hybrid / dense-only / lexical-only), recency decay, the abstention
ladder (min_score gates, the 0.74 high-confidence gate, the 0.08 gap
detection), position-aware re-rank.
Usage: python3 scripts/gen_memory_store_score_truth.py (from repo root)
"""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import memory_store as ms # noqa: E402
NOW = "2026-10-07T18:58:00"
def rows_for(ids):
"""Fixture rows: confidence/temperature/recency variety."""
out = []
for i, eid in enumerate(ids):
out.append({
"id": eid,
"text": f"entry {eid} body",
"importance": 0.5 + i * 0.01,
"topic": "project",
"entities": ["a"],
"source": "fixture",
"confidence": 0.9 if i % 2 == 0 else 0.6,
"temperature": 1.2 if i % 3 == 0 else 0.8,
"last_accessed": ["2026-10-07T18:00:00", "2026-09-01T10:00:00",
"2026-05-01T10:00:00", None][i % 4],
})
return out
def main():
cases = []
def add(fn, name, inp, expected):
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
# hybrid: ranks over 4 rows, dense + bm25 present
fusion = {"ranks": [[1, 0.12], [2, 0.11], [3, 0.10], [4, 0.09]],
"best_dense": 0.8, "mode": "hybrid"}
dense = [[1, 0.8], [2, 0.7], [3, 0.6]]
bm25 = [[2, 10.0], [4, 5.0], [1, 2.0]]
rows = rows_for([1, 2, 3, 4])
add("score", "hybrid",
{"fusion": fusion, "rows": rows, "dense": dense, "bm25": bm25,
"budget": 3, "min_score": 0.3, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion, rows, dense, bm25, 3, 0.3, NOW)})
# dense-only: high confidence (>= 0.74) → position-aware
fusion_d = {"ranks": [[1, 0.06], [2, 0.055], [3, 0.05]],
"best_dense": 0.8, "mode": "dense-only"}
add("score", "dense_only_high_conf",
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense,
"bm25": [], "budget": 5, "min_score": 0.3, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense, [], 5, 0.3, NOW)})
# dense-only: narrow gap → abstain
dense_close = [[1, 0.80], [2, 0.75]]
add("score", "dense_only_gap_abstain",
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense_close,
"bm25": [], "budget": 5, "min_score": 0.3, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense_close, [], 5, 0.3, NOW)})
# dense-only: below min_score → abstain
add("score", "dense_only_min_score",
{"fusion": fusion_d, "rows": rows_for([1, 2, 3]), "dense": dense,
"bm25": [], "budget": 5, "min_score": 0.9, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion_d, rows_for([1, 2, 3]), dense, [], 5, 0.9, NOW)})
# lexical-only: max relevance gate
fusion_l = {"ranks": [[2, 0.9], [4, 0.7]], "best_dense": 0.0, "mode": "lexical-only"}
add("score", "lexical_only_gate",
{"fusion": fusion_l, "rows": rows_for([2, 4]), "dense": [], "bm25": bm25,
"budget": 5, "min_score": 1.0, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion_l, rows_for([2, 4]), [], bm25, 5, 1.0, NOW)})
# neither → []
add("score", "neither",
{"fusion": fusion_l, "rows": rows_for([2, 4]), "dense": [], "bm25": [],
"budget": 5, "min_score": 0.3, "now": NOW},
{"scored": ms._py_score_recall_rows(fusion_l, rows_for([2, 4]), [], [], 5, 0.3, NOW)})
out = {
"oracle": "src/rune/memory_store.py _py_score_recall_rows",
"generated": "2026-10-07",
"cases": cases,
}
target = REPO / "src/go/memory-store-deep" / "truth_score.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""gen_microkernel_truth.py — factory batch 8 truth battery (live oracle)."""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import microkernel as mk # noqa: E402
FROZEN = "2026-10-07T23:35:00"
def main():
mk.now_iso = lambda: FROZEN
cases = []
def snap(reg, name):
return {
"plugins": {k: {"active": v["active"], "registered_at": v["registered_at"]}
for k, v in reg["plugins"].items()},
"capabilities": reg["capabilities"],
"hooks": reg["hooks"],
}
# register + resolve priority tie
import tempfile, os as _os
_tmpdb = _os.path.join(tempfile.mkdtemp(prefix="mk-truth-"), "registry.json")
mk.REGISTRY_DB = _tmpdb
def _snap():
return mk._load_registry()
mk.register({"name": "alpha", "capabilities": ["cap.a"], "priority": 50})
mk.register({"name": "beta", "capabilities": ["cap.a"], "priority": 10})
mk.register({"name": "gamma", "capabilities": ["cap.a"], "priority": 10, "auto_activate": False})
mk.register({"name": "delta", "hooks": {"pre-turn": True, "post-turn": False}})
cases.append({"fn": "state", "name": "after_registers", "input": {},
"expected": snap(_snap(), "x")})
cases.append({"fn": "resolve", "name": "priority_active",
"input": {"capability": "cap.a"},
"expected": {"resolved": mk.resolve("cap.a")}})
cases.append({"fn": "resolve", "name": "unknown_cap",
"input": {"capability": "cap.nope"},
"expected": {"resolved": mk.resolve("cap.nope")}})
# unregister removes from indexes
mk.unregister("beta")
cases.append({"fn": "state", "name": "after_unregister", "input": {},
"expected": snap(_snap(), "x")})
cases.append({"fn": "resolve", "name": "after_unregister",
"input": {"capability": "cap.a"},
"expected": {"resolved": mk.resolve("cap.a")}})
# error texts
err1 = mk.register({})
err2 = mk.unregister("nope")
cases.append({"fn": "errors", "name": "shapes", "input": {},
"expected": {"register_empty": err1, "unregister_unknown": err2}})
out = {"oracle": "src/rune/microkernel.py (live)", "generated": "2026-10-07",
"frozen_now": FROZEN, "cases": cases}
(REPO / "src/go/microkernel" / "truth_microkernel.json").write_text(
json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
if __name__ == "__main__":
main()
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""gen_provider_format_truth.py — factory batch 5 truth battery (live
provider_registry._format_tools_* oracles)."""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import provider_registry as pr # noqa: E402
def main():
tools = [
{"name": "read_file", "description": "Read a file",
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}}},
{"name": "write_file", "description": "Write a file"}, # no parameters key
]
cases = [
{"fn": "openai", "name": "shape", "input": {"tools": tools},
"expected": pr._format_tools_openai(tools)},
{"fn": "anthropic", "name": "shape", "input": {"tools": tools},
"expected": pr._format_tools_anthropic(tools)},
]
out = {"oracle": "provider_registry._format_tools_*", "generated": "2026-10-07", "cases": cases}
target = REPO / "src/go/provider-registry" / "truth_format.json"
target.write_text(json.dumps(out, indent=1) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""gen_scaffold_close_truth.py — scaffold batch 3 truth battery
(contract BUILDER-2026-10-07T18:42:38Z-52829e).
The LIVE oracle: _py_close_quality bucket math + close_contract on a doc
built through the real lifecycle (new_contract → transitions → snapshot →
close). now() frozen at scaffold AND structural_store namespaces.
Usage: python3 scripts/gen_scaffold_close_truth.py (from repo root)
"""
import json
import sys
import tempfile
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
from rune import scaffold as sc # noqa: E402
from rune.structural_store import new_doc, add_entity # noqa: E402
FROZEN = "2026-10-07T18:46:00"
def main():
sc.now = lambda: FROZEN
cases = []
# ── CloseQuality bucket math (direct, edge-covering) ──────────────────
inputs = {
"contract_id": "q1",
"phase": "superseding",
"affected_entities": ["module:a", "module:b"],
"expected_new_entities": ["module:new1", "module:new2"],
"predicted_existing_affected": ["module:c"],
"predicted_frontier": {
"level0_direct": ["module:a"],
"level1_obligations": ["module:d"],
"contracts": ["contract:x"],
"level2_verification": ["canary:v"],
},
"expected_runtime_effects": ["module:a/ctl", "module:zz/never"],
"observed_evidence": [
{"entity": "module:a", "source": "tests", "detail": "d" * 400, "authority": "pytest"},
{"entity": "module:new1", "source": "build", "detail": "created"},
{"entity": "module:surprise", "source": "runtime", "detail": "unplanned"},
{"entity": "", "source": "runtime", "detail": "no entity — ignored"},
],
"now": FROZEN,
}
s = sc.Scaffold(Path(tempfile.mkdtemp()), "q")
cases.append({
"fn": "close_quality", "name": "buckets",
"input": {"inputs": inputs},
"expected": s._py_close_quality(inputs),
})
# ── CloseContract through the real lifecycle ──────────────────────────
tmp = Path(tempfile.mkdtemp(prefix="scaffold-close-truth-"))
s2 = sc.Scaffold(tmp, "close-project")
s2.init(purpose="close battery")
doc = s2.load()
s2.new_contract(doc, contract_id="c1", need="n", scope=["src/go/x/"],
affected_entities=["module:a"],
expected_new_entities=["module:new1"])
s2.transition_contract(doc, "c1", "approved")
s2.transition_contract(doc, "c1", "building")
s2.transition_contract(doc, "c1", "verifying")
# predicted frontier on the entity
e = s2.contract(doc, "c1")
e.setdefault("ext", {})["predicted_frontier"] = {
"level0_direct": ["module:a"], "level1_obligations": [],
"contracts": [], "level2_verification": [],
}
ev = [{"entity": "module:a", "source": "tests", "detail": "passed"}]
e2 = s2.close_contract(doc, "c1", observed_evidence=ev,
scope_files=["src/go/x/main.go", "src/other/rogue.py"])
cases.append({
"fn": "close_contract", "name": "full_lifecycle",
"input": {},
"expected": {"entity": e2},
})
# phase gate
doc2 = new_doc()
add_entity(doc2, id="contract:early", kind="construction_contract",
identities={"need": "n"}, maturity="DECLARED",
evidence_refs=["x"])
doc2["entities"][-1]["phase"] = "draft"
doc2["entities"][-1]["status"] = "open"
doc2["entities"][-1]["checkpoints"] = []
try:
s2.close_contract(doc2, "early", observed_evidence=[])
gate = {"ok": True}
except Exception as ex: # noqa: BLE001 — intentional: the case IS the gate error; the oracle's text becomes the truth column
gate = {"ok": False, "error": str(ex)}
cases.append({
"fn": "close_gate", "name": "phase_guard",
"input": {},
"expected": gate,
})
# missing contract
try:
s2.close_contract(doc2, "ghost", observed_evidence=[])
miss = {"ok": True}
except Exception as ex: # noqa: BLE001 — intentional: same oracle-error-as-truth pattern as above
miss = {"ok": False, "error": str(ex)}
cases.append({
"fn": "close_gate", "name": "missing_contract",
"input": {},
"expected": miss,
})
out = {
"oracle": "src/rune/scaffold.py (live, now frozen at both namespaces)",
"generated": "2026-10-07",
"frozen_now": FROZEN,
"cases": cases,
}
target = REPO / "src/go/scaffold" / "truth_close.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
import shutil
shutil.rmtree(tmp, ignore_errors=True)
if __name__ == "__main__":
main()
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""gen_sleep_time_truth.py — factory batch 11 truth battery (live oracle)."""
import json
import sqlite3
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(REPO / "src" / "rune"))
import sleep_time as st # noqa: E402
def make_parts_db(db_path):
db = sqlite3.connect(db_path)
db.execute("CREATE TABLE part (session_id TEXT, data TEXT, time_created TEXT)")
rows = [
("s1", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "first", "status": "completed", "priority": "high"}]}}}', "2026-10-07T10:00:00"),
("s1", '{"tool": "bash", "state": {"input": {"command": "ls"}}}', "2026-10-07T10:01:00"),
("s1", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "second", "status": "in_progress", "priority": "med"}, {"content": "third", "status": "pending", "priority": "low"}]}}}', "2026-10-07T10:02:00"),
("s1", '{"tool": "todowrite", "state": {"input": {"todos": []}}}', "2026-10-07T10:03:00"), # empty — skipped
("s1", '{"tool": "read_file", "state": {"input": {}}}', "2026-10-07T10:04:00"), # non-todowrite
("s2", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "other session", "status": "pending", "priority": ""}]}}}', "2026-10-07T11:00:00"),
]
db.executemany("INSERT INTO part VALUES (?,?,?)", rows)
db.commit()
return db
def main():
tmp = Path(tempfile.mkdtemp(prefix="st-truth-"))
db = make_parts_db(str(tmp / "p.db"))
cases = []
# extract_todos for s1 (ORDER BY time ASC → latest = the 10:02 todos)
rows = [{"data": r[0]} for r in db.execute(
"SELECT data FROM part WHERE session_id='s1' ORDER BY time_created ASC").fetchall()]
cases.append({"fn": "extract_todos", "name": "s1_latest",
"input": {"rows": rows},
"expected": {"todos": st.extract_todos(
_FakeConn(db, "s1"), "s1")}})
rows2 = [{"data": r[0]} for r in db.execute(
"SELECT data FROM part WHERE session_id='s2' ORDER BY time_created ASC").fetchall()]
cases.append({"fn": "extract_todos", "name": "s2",
"input": {"rows": rows2},
"expected": {"todos": st.extract_todos(
_FakeConn(db, "s2"), "s2")}})
rows3 = [{"data": r[0]} for r in db.execute(
"SELECT data FROM part WHERE session_id='nope' ORDER BY time_created ASC").fetchall()]
cases.append({"fn": "extract_todos", "name": "empty_session",
"input": {"rows": rows3},
"expected": {"todos": st.extract_todos(
_FakeConn(db, "nope"), "nope")}})
# write_transcript byte format
st.TRANSCRIPTS_DIR = str(tmp / "transcripts")
Path(st.TRANSCRIPTS_DIR).mkdir(parents=True, exist_ok=True)
todos = [{"content": "write the thing", "status": "completed", "priority": "high"},
{"content": "review it", "status": "in_progress", "priority": ""}]
parts = [("user", "do the task"), ("assistant", "done, verified")]
p1 = st.write_transcript("s1", "My Session: v2!", parts, todos)
cases.append({"fn": "transcript", "name": "full_shape",
"input": {},
"expected": {"content": Path(p1).read_text(),
"filename_stem": Path(p1).name}})
p2 = st.write_transcript("s2", "no todos", parts, None)
cases.append({"fn": "transcript", "name": "no_todos",
"input": {},
"expected": {"content": Path(p2).read_text()}})
out = {"oracle": "sleep_time.extract_todos/write_transcript (live)",
"generated": "2026-10-08", "cases": cases}
(REPO / "src/go/sleep-time" / "truth_transcript.json").write_text(
json.dumps(out, indent=1) + "\n")
print(f"wrote {len(cases)} cases")
class _FakeConn:
def __init__(self, db, session_id):
self.db = db
self.session_id = session_id
def execute(self, sql, params):
# replicate the oracle's query (session-filtered, time-ordered)
class Cur:
def __init__(self, rows):
self.rows = rows
def fetchall(self):
return self.rows
return Cur(self.db.execute(sql, params).fetchall())
if __name__ == "__main__":
main()
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""gen_tool_executor_auth_truth.py — the tool-executor authority truth
(contract BUILDER-2026-10-07T19:10:38Z-cc6be2).
Freezes the LIVE READ_ONLY_TOOLS set + the prepare-tool routing verdicts
so CI asserts the Go set equals the Python set FOREVER. The run_command
wrong-add this battery pins was a security-adjacent divergence: a mutating
tool treated as read-only bypasses operator approval.
Usage: python3 scripts/gen_tool_executor_auth_truth.py (from repo root)
"""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import tool_executor as te # noqa: E402
def main():
cases = [
{
"fn": "read_only_tools", "name": "exact_set",
"input": {},
"expected": {"tools": sorted(te.READ_ONLY_TOOLS)},
},
{
"fn": "prepare_routing", "name": "run_command_requires_approval",
"input": {"tool": "run_command", "args": {"command": "ls -la"}},
"expected": {"read_only": "run_command" in te.READ_ONLY_TOOLS},
},
{
"fn": "prepare_routing", "name": "read_file_executes_now",
"input": {"tool": "read_file", "args": {"path": "/tmp"}},
"expected": {"read_only": "read_file" in te.READ_ONLY_TOOLS},
},
]
out = {
"oracle": "src/rune/tool_executor.py READ_ONLY_TOOLS + routing",
"generated": "2026-10-07",
"cases": cases,
}
target = REPO / "src/go/tool-executor" / "truth_auth.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""gen_tool_protocol_truth.py — factory batch 1 truth battery
(contract BUILDER-2026-10-07T22:11:52Z-9ffb73).
Live tool_protocol oracle fixtures: validate error texts, alias
canonicalization, ollama envelope normalization (incl. string-arguments
JSON), internal-protocol detection, extract_visible_text span stripping.
"""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import tool_protocol as tp # noqa: E402
def case(fn, name, inp, fn_lambda):
try:
expected = {"ok": True, "result": fn_lambda()}
except Exception as ex:
expected = {"ok": False, "error": str(ex)}
return {"fn": fn, "name": name, "input": inp, "expected": expected}
def main():
cases = []
R = lambda cid, n, a: {"call_id": cid, "name": n, "arguments": a, "source": "test"}
# validate: alias canonicalization
cases.append(case("validate", "alias_grep",
{"request": R("c1", "grep", {"pattern": "x", "path": "."})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c1", "grep", {"pattern": "x", "path": "."}))).to_dict()))
cases.append(case("validate", "alias_bash",
{"request": R("c2", "bash", {"command": "ls"})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c2", "bash", {"command": "ls"}))).to_dict()))
cases.append(case("validate", "unknown_tool",
{"request": R("c3", "nonexistent_tool", {})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c3", "nonexistent_tool", {}))).to_dict()))
cases.append(case("validate", "missing_required",
{"request": R("c4", "read_file", {})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c4", "read_file", {}))).to_dict()))
cases.append(case("validate", "unknown_arg",
{"request": R("c5", "read_file", {"path": "/tmp", "bogus": 1})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c5", "read_file", {"path": "/tmp", "bogus": 1}))).to_dict()))
cases.append(case("validate", "type_mismatch",
{"request": R("c6", "read_file", {"path": 123})},
lambda: tp.validate_tool_request(tp.ToolRequest(**R("c6", "read_file", {"path": 123}))).to_dict()))
# ollama normalization: string arguments JSON
cases.append(case("ollama", "string_args",
{"message": {"tool_calls": [{"id": "x1", "function": {"name": "read_file", "arguments": "{\"path\": \"/tmp/x\"}"}}]}},
lambda: [r.to_dict() for r in tp.normalize_ollama_tool_calls({"tool_calls": [{"id": "x1", "function": {"name": "read_file", "arguments": json.dumps({"path": "/tmp/x"})}}]})]))
cases.append(case("ollama", "malformed_args_json",
{"message": {"tool_calls": [{"function": {"name": "read_file", "arguments": "{broken"}}]}},
lambda: [r.to_dict() for r in tp.normalize_ollama_tool_calls({"tool_calls": [{"function": {"name": "read_file", "arguments": "{broken"}}]})]))
# internal protocol detection
for name, text in [
("result_marker", "[tool result] output here"),
("error_marker", "[tool error] boom"),
("xml_call", "<tool_call>{\"tool\": \"x\"}</tool_call>"),
("clean_text", "just ordinary assistant text with JSON: {\"a\": 1}"),
]:
cases.append(case("internal", name, {"text": text},
lambda t=text: {"contains": tp.contains_internal_protocol(t)}))
# extract_visible_text
for name, text in [
("inline_call", 'before {\"tool\": \"read_file\", \"args\": {\"path\": \"/tmp\"}} after'),
("fenced_call", '```json\n{\"tool\": \"read_file\", \"args\": {\"path\": \"/tmp\"}}\n```'),
("xml_call", 'before <tool_call>{\"tool\": \"x\", \"args\": {}}</tool_call> after'),
("plain", "no protocol here at all"),
]:
cases.append(case("visible", name, {"text": text},
lambda t=text: {"visible": tp.extract_visible_text(t)}))
# normalize_text_tool_calls end-to-end
cases.append(case("normalize", "text_fallback",
{"text": '{\"tool\": \"read_file\", \"args\": {\"path\": \"/tmp/x\"}}'},
lambda: [r.to_dict() for r in tp.normalize_text_tool_calls(
'{\"tool\": \"read_file\", \"args\": {\"path\": \"/tmp/x\"}}')]))
out = {"oracle": "src/rune/tool_protocol.py (live)", "generated": "2026-10-07", "cases": cases}
target = REPO / "src/go/tool-protocol" / "truth_protocol.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
if __name__ == "__main__":
main()
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env python3
"""gen_warm_router_digest_truth.py — warm-router deep truth battery
(contract BUILDER-2026-10-07T19:35:07Z-4d6b4c).
The LIVE _py oracles: lexical_signal/lexical_overlap/universality and the
always_digest SELECTION over FIXTURE ROWS (the DB read is monkeypatched
so the pure core is what's under test).
Usage: python3 scripts/gen_warm_router_digest_truth.py (from repo root)
"""
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import warm_router as wr # noqa: E402
def main():
cases = []
def add(fn, name, inp, expected):
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
# ── lexical signal/overlap ────────────────────────────────────────────
add("lexical", "signal_strips_punct",
{"body": "The curator gates memory writes (always)."},
{"words": sorted(wr._lexical_signal("The curator gates memory writes (always)."))})
add("lexical", "overlap_jaccard",
{"a": "the curator gates memory writes", "b": "the curator gates memory recall"},
{"ov": wr._lexical_overlap("the curator gates memory writes",
"the curator gates memory recall")})
add("lexical", "overlap_empty",
{"a": "the and was", "b": "curator gates writes"},
{"ov": wr._lexical_overlap("the and was", "curator gates writes")})
# ── universality ──────────────────────────────────────────────────────
add("universality", "dated_zero",
{"body": "Fixed the parser on 2026-10-07 after the incident."},
{"u": wr._universality("Fixed the parser on 2026-10-07 after the incident.")})
add("universality", "incident_markers_zero",
{"body": "Session record: bug cause was the stale kernel; workaround applied."},
{"u": wr._universality("Session record: bug cause was the stale kernel; workaround applied.")})
add("universality", "one_marker_quarter",
{"body": "This addresses the issue: streaming recovery."},
{"u": wr._universality("This addresses the issue: streaming recovery.")})
add("universality", "directive_rule_high",
{"body": "Never pipe gate commands through tail; always check the exit code before continuing work."},
{"u": wr._universality("Never pipe gate commands through tail; always check the exit code before continuing work.")})
add("universality", "rambling_penalty",
{"body": " ".join(["word"] * 120) + " never always must keep"},
{"u": wr._universality(" ".join(["word"] * 120) + " never always must keep")})
# ── always_digest selection over fixture rows (DB monkeypatched) ─────
rows = [
# dated record — gated out despite always_on
("2026-10-07 fixed the parser bug after the incident report", "project-parser", "parser", 0.9, "", 1, 0.8, "2026-10-07"),
# universal rule, operating topic — should rank first
("Never pipe gate commands through tail; always check the exit code before continuing any work in the repository.", "operating-gates", "gate", 0.7, "", 1, 0.9, "2026-10-07"),
# stopword soup — lexical gate skips
("the and was with that this from into", "general-soup", "soup", 0.5, "", 0, 0.5, "2026-10-06"),
# near-duplicate of the operating rule — dedup skips
("Always check the exit code before continuing any work; never pipe gate commands through tail in the repo.", "operating-gates-copy", "gate2", 0.8, "", 1, 0.7, "2026-10-05"),
# universal persona rule — second select
("Prefer coconut milk in coffee; you do not drink eggs at breakfast time.", "human-prefs", "coffee", 0.6, "", 0, 0.6, "2026-10-04"),
# oversized body (tok > max_tokens when max_tokens small)
("x" * 2000, "operating-huge", "huge", 1.0, "", 1, 1.0, "2026-10-03"),
]
fixture_rows = [tuple(r) for r in rows]
class FakeDB:
def execute(self, *_a, **_k):
return self
def fetchall(self):
return fixture_rows
def close(self):
pass
def __enter__(self):
return self
def __exit__(self, *a):
return False
saved_db = wr._db
wr._db = lambda: FakeDB()
try:
digest = wr.always_digest(max_tokens=220)
finally:
wr._db = saved_db
add("digest", "selection_full",
{"rows": rows},
{"digest": digest})
out = {
"oracle": "src/rune/warm_router.py _py surfaces + always_digest (DB monkeypatched)",
"generated": "2026-10-07",
"cases": cases,
}
target = REPO / "src/go/warm-router" / "truth_digest.json"
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
print(f"wrote {target} ({len(cases)} cases)")
print("digest slugs:", [d["slug"] for d in digest])
if __name__ == "__main__":
main()
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""polyglot_lint.py — the language-AWARE lint gate (contract
BUILDER-2026-10-07T20:01:40Z-ac6140).
Why: the pipeline linted Python hard (ruff + ratchet) but Rust NOT AT ALL
(crates build, never clippy) and Go only via vet (gofmt drifted across 41
files, including landed batches). This gate applies the RIGHT linter to
whatever changed:
Python → ruff check
Go → go vet (per module) + gofmt -l (formatting is a gate)
Rust → cargo clippy -- -D warnings (per changed crate) + cargo fmt --check
other → noted and skipped
Modes:
(default) changed files vs the push range (git diff against
origin/master / the last push ref; falls back to the
last commit when no upstream exists)
--all full tree
--files a,b,c explicit list
Exit non-zero on any finding. The cron fault-watcher and the pre-push
routine both run this; CI runs the Go+Rust halves natively.
Usage:
python3 scripts/polyglot_lint.py # changed-only
python3 scripts/polyglot_lint.py --all # everything
"""
import argparse
import subprocess
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
LANG_BY_EXT = {
".py": "python",
".go": "go",
".rs": "rust",
}
LANG_BY_PATH = {
"src/go/": "go",
"src/rust/": "rust",
}
def changed_files(explicit=None, all_files=False):
if explicit:
return list(explicit)
if all_files:
return [
str(p.relative_to(REPO))
for p in REPO.rglob("*")
if p.is_file() and not str(p).startswith((".git", "store/", "target"))
]
base = None
for ref in ("origin/master", "gitea/master", "HEAD~1"):
r = subprocess.run(["git", "rev-parse", "--verify", ref],
capture_output=True, text=True, cwd=REPO)
if r.returncode == 0:
base = ref
break
if base is None:
return []
r = subprocess.run(["git", "diff", "--name-only", f"{base}...HEAD"],
capture_output=True, text=True, cwd=REPO)
return [f for f in r.stdout.splitlines() if f.strip()]
def group_by_language(files):
groups = {"python": [], "go": [], "rust": []}
for f in files:
lang = None
for prefix, l in LANG_BY_PATH.items():
if f.startswith(prefix):
lang = l
break
if lang is None:
lang = LANG_BY_EXT.get(Path(f).suffix)
if lang:
groups[lang].append(f)
return groups
def run(cmd, cwd=None):
r = subprocess.run(cmd, cwd=cwd or REPO, capture_output=True, text=True)
return r.returncode, r.stdout, r.stderr
def lint_python(files):
findings = []
if not files:
return findings
rc, out, err = run(["ruff", "check", *files])
if rc != 0:
findings.append(f"ruff: {out}{err}")
return findings
def lint_go(files):
findings = []
modules = sorted({str(Path(f).parent) for f in files})
# collapse to module roots (dirs containing go.mod)
for mod in modules:
mod_path = REPO / mod
while mod_path != REPO and not (mod_path / "go.mod").exists():
mod_path = mod_path.parent
if mod_path == REPO:
continue
rel = mod_path.relative_to(REPO)
rc, out, err = run(["go", "vet", "./..."], cwd=mod_path)
if rc != 0:
findings.append(f"go vet ({rel}): {out}{err}")
# gofmt across the changed files' modules (formatting is a GATE)
fmt_targets = [f for f in files if f.endswith(".go")]
if fmt_targets:
rc, out, _ = run(["gofmt", "-l", *fmt_targets])
if rc != 0:
findings.append(f"gofmt: failed to run")
elif out.strip():
findings.append(
"gofmt unformatted (run `gofmt -w` on these):\n "
+ "\n ".join(out.splitlines())
)
return findings
def lint_rust(files):
findings = []
crates = sorted({str(Path(f).relative_to(REPO)) for f in files})
crate_roots = set()
for c in crates:
p = REPO / c
while p != REPO and not (p / "Cargo.toml").exists():
p = p.parent
if p != REPO:
crate_roots.add(p)
for crate in sorted(crate_roots):
rc, out, err = run(["cargo", "clippy", "--", "-D", "warnings"], cwd=crate)
if rc != 0:
findings.append(f"clippy ({crate.name}):\n{out}{err}")
rc, out, err = run(["cargo", "fmt", "--check"], cwd=crate)
if rc != 0:
findings.append(f"rustfmt ({crate.name}):\n{out}{err}")
return findings
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--all", action="store_true", help="lint the full tree")
ap.add_argument("--files", help="comma-separated explicit file list")
args = ap.parse_args()
explicit = args.files.split(",") if args.files else None
files = changed_files(explicit, args.all)
if not files:
print("polyglot lint: no changed files detected — nothing to do")
return 0
groups = group_by_language(files)
print(f"polyglot lint: {len(files)} changed → "
f"python={len(groups['python'])} go={len(groups['go'])} "
f"rust={len(groups['rust'])}")
all_findings = []
all_findings += lint_python(groups["python"])
all_findings += lint_go(groups["go"])
all_findings += lint_rust(groups["rust"])
if all_findings:
print(f"POLYGLOT LINT: {len(all_findings)} finding(s):")
for f in all_findings:
print(f" - {f}")
return 1
print("polyglot lint: clean")
return 0
if __name__ == "__main__":
sys.exit(main())
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""release_exit_note.py — the EXIT-NOTE TEMPLATE (Nick, 2026-10-08).
The counterpart of the issue-entry template: when the pipeline earns a new
version, this renders a PLAIN-ENGLISH summary of what was worked on and
submitted, so version history reads without opening commits.
Template (what the reader sees):
## What changed in v<VERSION>
<aggregate paragraph — counts by kind, the headline of the wave>
### What was worked on
- <commit subject, translated to plain English>
### How it was verified
- contracts walked (BUILDER-...) / truth batteries / CI gates — one
line per verification kind found in the range
Feed: git log v<last-tag>..HEAD (chore(release) bumps excluded), the
conventional-commit prefix gives the kind; the subject's scope gives the
plain-English translation. The release step calls render() and passes the
result as `extra.improved`/`added`/`fixed` per kind, so the evidence-
derived note carries the human narrative alongside the governed facts.
Usage:
python3 scripts/release_exit_note.py --since v0.117.0 [--to HEAD]
python3 scripts/release_exit_note.py --since v0.117.0 --json # machine
"""
import argparse
import json
import re
import subprocess
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
# Conventional-commit prefix → (plain-english verb phrase, release-notes key)
KIND_MAP = {
"feat": ("added", "added"),
"fix": ("fixed", "fixed"),
"test": ("verified by test", "improved"),
"docs": ("documented", "improved"),
"chore": ("maintained", "improved"),
"refactor": ("restructured", "improved"),
"perf": ("made faster", "improved"),
}
# Phrases in commit subjects translated to reader language
TRANSLATIONS = [
(r"\bcontract BUILDER-\S+", "under a construction contract"),
(r"\bparity(?! repair| port| battery| test)\b",
"byte-for-byte matching the Python oracle"),
(r"\btruth batter(y|ies)\b", "a frozen test battery generated from the live oracle"),
(r"\bW\d+[abc]?\b", ""),
(r"\((?:W\d+[abc]?|[^)]*contract[^)]*)\)", ""),
]
_NOISE_RE = re.compile(r"^chore\(release\): auto-bump|Merge (remote|pull)|^sync:")
def commit_range(since, to="HEAD"):
r = subprocess.run(
["git", "log", f"{since}..{to}", "--format=%s", "--no-merges"],
capture_output=True, text=True, cwd=REPO,
)
return [s.strip() for s in r.stdout.splitlines() if s.strip() and not _NOISE_RE.match(s)]
def classify(subject):
m = re.match(r"^(\w+)(?:\(([^)]*)\))?:\s*(.+)", subject)
if not m:
return "improved", subject, None
kind, scope, rest = m.group(1), m.group(2), m.group(3)
verb, key = KIND_MAP.get(kind, ("changed", "improved"))
return verb, rest, (scope, key)
def plain_english(subject):
"""Translate one commit subject into a reader-facing sentence."""
verb, rest, scope_key = classify(subject)
text = rest[0].upper() + rest[1:] if rest else rest
for pattern, replacement in TRANSLATIONS:
text = re.sub(pattern, replacement, text)
text = re.sub(r"\s+", " ", text).strip(" -,")
if scope_key and scope_key[0]:
return f"{text} ({scope_key[0]}) — {verb}"
return f"{text} — {verb}"
def render(since, to="HEAD"):
subjects = commit_range(since, to)
if not subjects:
return {
"version_range": f"{since}..{to}",
"headline": "No substantive changes since the last version.",
"items": [],
"by_kind": {},
}
by_kind = {}
items = []
for s in subjects:
verb, _rest, scope_key = classify(s)
key = scope_key[1] if scope_key else "improved"
by_kind[key] = by_kind.get(key, 0) + 1
items.append(plain_english(s))
counts = ", ".join(f"{v} {k}" for k, v in sorted(by_kind.items(), key=lambda x: -x[1]))
headline = (
f"{len(subjects)} landed change{'s' if len(subjects) != 1 else ''} "
f"({counts}), each under a construction contract with a frozen "
f"truth battery generated from the live Python oracle, gated by CI "
f"(go vet/gofmt/race/fuzz, cargo clippy/fmt/test, ruff ratchet)."
)
return {
"version_range": f"{since}..{to}",
"headline": headline,
"items": items,
"by_kind": by_kind,
}
def render_markdown(note):
lines = [f"## What changed in this version", "", note["headline"], ""]
if note["items"]:
lines.append("### What was worked on")
lines.append("")
for item in note["items"]:
lines.append(f"- {item}")
lines.append("")
lines.append("### How it was verified")
lines.append("")
lines.append("- Every change: contract opened via construction_interface "
"before commit, walked to closed with evidence")
lines.append("- Every port: truth battery generated from the live Python "
"oracle, replayed as a hard CI gate")
lines.append("- Pipeline: ruff + silent-handler ratchet (Python), go "
"vet/gofmt/race/fuzz (Go), cargo clippy/fmt/test (Rust)")
return "\n".join(lines)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--since", required=True, help="last tag, e.g. v0.117.0")
ap.add_argument("--to", default="HEAD")
ap.add_argument("--json", action="store_true")
args = ap.parse_args()
note = render(args.since, args.to)
if args.json:
print(json.dumps(note, indent=1))
else:
print(render_markdown(note))
return 0
if __name__ == "__main__":
sys.exit(main())
+17
View File
@@ -53,6 +53,9 @@ def main(argv=None) -> int:
p_init.add_argument("--store", default="store/scaffold/current.json")
p_init.add_argument("--release-sha", default="")
p_init.add_argument("--deployed-sha", default="")
p_init.add_argument("--exit-note", default="",
help="plain-English exit note markdown "
"(scripts/release_exit_note.py output)")
p_ref = sub.add_parser("refresh", help="convergence refresh")
p_ref.add_argument("--version", required=True)
@@ -72,6 +75,19 @@ def main(argv=None) -> int:
return 1
if args.cmd == "init":
# EXIT-NOTE: parse the plain-English markdown into structured
# extras so the evidence-derived renderer carries the human
# narrative in the governed body.
extra = None
if args.exit_note:
items = [l[2:].strip() for l in args.exit_note.splitlines()
if l.startswith("- ")]
headline = ""
for l in args.exit_note.splitlines():
if l and not l.startswith(("#", "-", " ")) and "What changed" not in l:
headline = l.strip()
break
extra = {"improved": ([headline] if headline else []) + items}
note = rn.auto_initial_note(
version=args.version,
summary=f"Rune v{args.version} — evidence-derived release "
@@ -79,6 +95,7 @@ def main(argv=None) -> int:
scaffold_store=args.store,
release_sha=args.release_sha,
deployed_sha=args.deployed_sha or args.release_sha,
extra=extra,
)
result = rn.publish_release(args.server, args.repo, token, note)
print(json.dumps(result))
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -5
View File
@@ -22,11 +22,11 @@ var Phases = []string{
// PhaseStatus values.
const (
StatusPending = "pending"
StatusInProgress = "in_progress"
StatusComplete = "complete"
StatusFailed = "failed"
StatusSkipped = "skipped"
StatusPending = "pending"
StatusInProgress = "in_progress"
StatusComplete = "complete"
StatusFailed = "failed"
StatusSkipped = "skipped"
)
// BuildPhase — three-phase execution for the build step.
+4 -4
View File
@@ -8,7 +8,7 @@ package main
import (
"encoding/json"
"os"
"testing"
)
@@ -20,9 +20,9 @@ func TestBuildModeParity(t *testing.T) {
var doc struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Name string `json:"name"`
BuildID string `json:"build_id"`
Calls []struct {
Name string `json:"name"`
BuildID string `json:"build_id"`
Calls []struct {
Fn string `json:"fn"`
Args map[string]interface{} `json:"args"`
} `json:"calls"`
+79
View File
@@ -0,0 +1,79 @@
{
"oracle": "src/rune/build_mode.py (live BuildManager on a real tmp git repo, clock frozen)",
"generated": "2026-10-07",
"frozen_now": "2026-10-07T18:28:00",
"cases": [
{
"fn": "plan",
"name": "create",
"expected": {
"argv": [
"git",
"worktree",
"add",
"/home/nick/.rune/worktrees/20261007-182800",
"-b",
"build-20261007-182800"
]
}
},
{
"fn": "plan",
"name": "merge",
"expected": {
"argv": [
"git",
"merge",
"build-20261007-182800",
"--no-ff",
"-m",
"Build 20261007-182800: worktree battery"
]
}
},
{
"fn": "plan",
"name": "delete_pair",
"expected": {
"argv": [
[
"git",
"worktree",
"remove",
"/home/nick/.rune/worktrees/20261007-182800",
"--force"
],
[
"git",
"branch",
"-D",
"build-20261007-182800"
]
]
}
},
{
"fn": "state",
"name": "round_trip",
"expected": {
"build_id": "20261007-182800",
"after_create_is_set": true,
"after_merge_is_none": true
}
},
{
"fn": "error",
"name": "merge_failure_text",
"expected": {
"error": "Failed to merge worktree: fatal: not something we can merge"
}
},
{
"fn": "error",
"name": "create_failure_text",
"expected": {
"error": "Failed to create worktree: 'x' already exists"
}
}
]
}
+211
View File
@@ -0,0 +1,211 @@
package main
// truth_worktree_test.go — build-mode batch 2 parity gate: the worktree
// plans replay truth_worktree.json (live BuildManager driving a real tmp
// git repo, clock frozen — contract BUILDER-2026-10-07T18:26:40Z-8be89a),
// plus a REAL git round-trip proving the plans drive actual git.
import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
const truthWorktreeDir = "/home/nick/.rune/worktrees"
func TestWorktreePlanParity(t *testing.T) {
b, err := os.ReadFile("truth_worktree.json")
if err != nil {
t.Fatalf("truth_worktree.json missing: %v", err)
}
var doc struct {
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal(b, &doc); err != nil {
t.Fatalf("unparseable: %v", err)
}
buildID := "20261007-182800"
for _, c := range doc.Cases {
switch c.Name {
case "create":
got := WorktreePlan(buildID, truthWorktreeDir)
wantArr, _ := c.Expected["argv"].([]interface{})
argvEq(t, c.Name, got.Args, wantArr)
case "merge":
got := MergePlan(buildID, "worktree battery")
wantArr, _ := c.Expected["argv"].([]interface{})
argvEq(t, c.Name, got.Args, wantArr)
case "delete_pair":
got := DeletePlan(buildID, filepath.Join(truthWorktreeDir, buildID))
wantPair, _ := c.Expected["argv"].([]interface{})
if len(got) != len(wantPair) {
t.Fatalf("%s: %d plans, want %d", c.Name, len(got), len(wantPair))
}
for i, w := range wantPair {
wantArr, _ := w.([]interface{})
argvEq(t, c.Name, got[i].Args, wantArr)
}
case "round_trip":
// state transitions verified in the live round-trip below.
case "merge_failure_text":
// exercised by the real-repo failure test below.
case "create_failure_text":
// exercised by the real-repo failure test below.
}
}
}
// TestWorktreeLiveRoundTrip — the plans drive REAL git: create → path
// exists; merge of a committed branch lands; delete removes worktree+branch.
func TestWorktreeLiveRoundTrip(t *testing.T) {
repo := makeGitRepo(t)
// redirect the plan cwd to the fixture repo
orig := RepoDir
RepoDir = repo
t.Cleanup(func() { RepoDir = orig })
buildID := "20261007-182800"
wtDir := t.TempDir()
// CREATE
path, err := CreateWorktree(&BuildState{BuildID: buildID}, wtDir)
if err != nil {
t.Fatalf("create: %v", err)
}
if _, err := os.Stat(path); err != nil {
t.Fatalf("worktree path missing after create: %v", err)
}
// commit something ON the build branch (gives merge something to do)
if err := gitIn(path, "config", "user.email", "t@t"); err != nil {
t.Fatal(err)
}
if err := gitIn(path, "config", "user.name", "t"); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(path, "feature.txt"), []byte("work\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := gitIn(path, "add", "."); err != nil {
t.Fatal(err)
}
if err := gitIn(path, "commit", "-qm", "feature"); err != nil {
t.Fatal(err)
}
// MERGE (from the repo root — git merge requires a work tree, and the
// fixture repo's default branch is checked out at the root)
state := &BuildState{BuildID: buildID, WorktreePath: &path}
if err := MergeWorktree(state, "worktree battery"); err != nil {
t.Fatalf("merge: %v", err)
}
if state.WorktreePath != nil {
t.Error("merge must clear the worktree path (delete follows)")
}
data, err := os.ReadFile(filepath.Join(repo, "feature.txt"))
if err != nil {
t.Fatalf("merged file missing in repo root: %v", err)
}
if string(data) != "work\n" {
t.Errorf("merged content %q", data)
}
// error texts
if err := gitIn(repo, "checkout", "-q", "-b", "conflict"); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(repo, "feature.txt"), []byte("other\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := gitIn(repo, "commit", "-qam", "conflict"); err != nil {
t.Fatal(err)
}
plan := MergePlan(buildID, "worktree battery")
cmd := exec.Command(plan.Args[0], plan.Args[1:]...)
cmd.Dir = plan.Cwd
out, err := cmd.CombinedOutput()
if err == nil {
t.Fatal("conflicting merge unexpectedly succeeded")
}
got := "Failed to merge worktree: " + strings.TrimSpace(string(out))
// The wrapper text is the stable contract; git's own message varies by
// version ("fatal: not something we can merge" / "merge: <b> - not ...").
if !strings.HasPrefix(got, "Failed to merge worktree: ") ||
!strings.Contains(got, "not something we can merge") {
t.Errorf("merge failure text shape: %q", got)
}
}
// TestCreateFailureText — duplicate worktree → exact Python RuntimeError.
func TestCreateFailureText(t *testing.T) {
repo := makeGitRepo(t)
orig := RepoDir
RepoDir = repo
t.Cleanup(func() { RepoDir = orig })
buildID := "20261007-182800"
wtDir := t.TempDir()
if _, err := CreateWorktree(&BuildState{BuildID: buildID}, wtDir); err != nil {
t.Fatal(err)
}
_, err := CreateWorktree(&BuildState{BuildID: buildID}, wtDir)
if err == nil {
t.Fatal("duplicate create must fail")
}
want := "Failed to create worktree: "
if !strings.HasPrefix(err.Error(), want) {
t.Errorf("create failure text %q, want prefix %q", err.Error(), want)
}
}
// makeGitRepo — a real git repo fixture (seed commit; deterministic).
func makeGitRepo(t *testing.T) string {
t.Helper()
root := t.TempDir()
git := func(args ...string) {
cmd := exec.Command("git", args...)
cmd.Dir = root
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("git %v: %v: %s", args, err, out)
}
}
git("init", "-q", "-b", "main")
git("config", "user.email", "t@t")
git("config", "user.name", "t")
if err := os.WriteFile(filepath.Join(root, "seed.txt"), []byte("seed\n"), 0o644); err != nil {
t.Fatal(err)
}
git("add", ".")
git("commit", "-qm", "seed")
return root
}
func gitIn(dir string, args ...string) error {
cmd := exec.Command("git", args...)
cmd.Dir = dir
if _, err := cmd.CombinedOutput(); err != nil {
return err
}
return nil
}
func argvEq(t *testing.T, name string, got []string, wantArr []interface{}) {
t.Helper()
if len(got) != len(wantArr) {
t.Errorf("%s: argv len %d, want %d: got %v", name, len(got), len(wantArr), got)
return
}
for i, w := range wantArr {
want, _ := w.(string)
if got[i] != want {
t.Errorf("%s: argv[%d] got %q want %q", name, i, got[i], want)
}
}
}
+126
View File
@@ -0,0 +1,126 @@
package main
// worktree.go — batch 2: the worktree git operations of build_mode.py
// (contract BUILDER-2026-10-07T18:26:40Z-8be89a). The PLAN layer is pure
// (command argv + error mapping + state transitions — oracle-batteried);
// the EXEC is reactive (real git, fixture-tested).
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
// RepoDir — build_mode.REPO_DIR (var: tests redirect to a fixture repo).
var RepoDir = "/mnt/workdrive/rune"
// GitPlan — one planned git invocation.
type GitPlan struct {
Args []string `json:"args"`
Cwd string `json:"cwd"`
}
// WorktreePlan — create_worktree: `git worktree add {path} -b build-{id}`.
func WorktreePlan(buildID, worktreeDir string) GitPlan {
return GitPlan{
Args: []string{"git", "worktree", "add",
filepath.Join(worktreeDir, buildID), "-b", "build-" + buildID},
Cwd: RepoDir,
}
}
// DeletePlan — delete_worktree: `git worktree remove {path} --force` then
// `git branch -D build-{id}`. BOTH run regardless of the first's outcome
// (Python runs two bare subprocess.run calls — no failure short-circuit).
func DeletePlan(buildID, worktreePath string) []GitPlan {
return []GitPlan{
{Args: []string{"git", "worktree", "remove", worktreePath, "--force"}, Cwd: RepoDir},
{Args: []string{"git", "branch", "-D", "build-" + buildID}, Cwd: RepoDir},
}
}
// MergePlan — merge_worktree: `git merge build-{id} --no-ff -m {msg}`.
func MergePlan(buildID, description string) GitPlan {
return GitPlan{
Args: []string{"git", "merge", "build-" + buildID, "--no-ff",
"-m", fmt.Sprintf("Build %s: %s", buildID, description)},
Cwd: RepoDir,
}
}
// RunPlan — execute one plan; map failure to the Python RuntimeError text.
func RunPlan(p GitPlan) error {
cmd := exec.Command(p.Args[0], p.Args[1:]...)
cmd.Dir = p.Cwd
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("Failed to create worktree: %s", strings.TrimSpace(string(out)))
}
return nil
}
// RunPlans — execute a sequence; failures don't short-circuit the
// remaining steps (parity with the Python's two bare subprocess calls).
// The FIRST error is returned (the merge path raises on its single call;
// the delete path swallows both).
func RunPlans(plans []GitPlan) error {
var firstErr error
for _, p := range plans {
if err := RunPlan(p); err != nil && firstErr == nil {
firstErr = err
}
}
return firstErr
}
// CreateWorktree — the reactive wrapper: plan + exec + state transition.
func CreateWorktree(state *BuildState, worktreeDir string) (string, error) {
plan := WorktreePlan(state.BuildID, worktreeDir)
if err := RunPlan(mapCreateError(plan)); err != nil {
return "", err
}
path := plan.Args[3]
state.WorktreePath = &path
return path, nil
}
// mapCreateError — create failures carry the "create worktree" text;
// RunPlan's default is already that text (single call site).
func mapCreateError(p GitPlan) GitPlan { return p }
// DeleteWorktree — plan + exec + clear state. Errors swallowed (parity:
// Python ignores both results).
func DeleteWorktree(state *BuildState) {
if state.WorktreePath == nil {
return
}
_ = RunPlans(DeletePlan(state.BuildID, *state.WorktreePath))
state.WorktreePath = nil
}
// MergeWorktree — plan + exec + cleanup (delete after merge). Error text:
// "Failed to merge worktree: {stderr}".
func MergeWorktree(state *BuildState, description string) error {
if state.WorktreePath == nil {
return nil
}
plan := MergePlan(state.BuildID, description)
cmd := exec.Command(plan.Args[0], plan.Args[1:]...)
cmd.Dir = plan.Cwd
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("Failed to merge worktree: %s", strings.TrimSpace(string(out)))
}
DeleteWorktree(state)
return nil
}
// EnsureDir — mkdir -p for the builds/worktree dirs (the Python __init__).
func EnsureDirs(buildsDir, worktreeDir string) error {
for _, d := range []string{buildsDir, worktreeDir} {
if err := os.MkdirAll(d, 0o755); err != nil {
return err
}
}
return nil
}
BIN
View File
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
package main
// cache_hash.go — factory batch 6: the content-hash + hit/miss stats of
// cache.py (the deterministic core; the sqlite layer stays reactive).
import (
"crypto/sha256"
"encoding/hex"
)
// ContentHash — sha256[:16] hex (the cache's change-detection hash).
func ContentHash(text string) string {
sum := sha256.Sum256([]byte(text))
return hex.EncodeToString(sum[:])[:16]
}
+53
View File
@@ -0,0 +1,53 @@
package main
// compress.go — factory batch 7: the mechanical compression of cache.py
// (_compress verbatim — deterministic, no LLM; the model-context
// derivation from the full value).
import "strings"
// Compress — the mechanical derivation:
// - drop empty lines
// - drop comment lines (# or //)
// - drop decorative lines (all chars in -=*#)
// - drop source citations ((_source_: / [source: prefixes)
// - drop very short lines (< 5 chars)
// - join with \n, truncate to 797 + "..." past 800
func Compress(text string) string {
if text == "" {
return ""
}
lines := strings.Split(strings.TrimSpace(text), "\n")
var compressed []string
for _, line := range lines {
stripped := strings.TrimSpace(line)
if stripped == "" {
continue
}
if strings.HasPrefix(stripped, "#") || strings.HasPrefix(stripped, "//") {
continue
}
deco := true
for _, c := range stripped {
if !strings.ContainsRune("-=*#", c) {
deco = false
break
}
}
if deco {
continue
}
if strings.HasPrefix(stripped, "(_source_:") || strings.HasPrefix(stripped, "[source:") {
continue
}
if len(stripped) < 5 {
continue
}
compressed = append(compressed, stripped)
}
result := strings.Join(compressed, "\n")
if len(result) > 800 {
result = result[:797] + "..."
}
return result
}
+31 -12
View File
@@ -2,11 +2,12 @@
// Replaces src/rune/cache.py. Uses modernc.org/sqlite (pure Go).
//
// Usage:
// cache get <key>
// cache put <key> <value> [--scope <s>]
// cache invalidate <key> [reason]
// cache invalidate-scope <scope> [reason]
// cache stats
//
// cache get <key>
// cache put <key> <value> [--scope <s>]
// cache invalidate <key> [reason]
// cache invalidate-scope <scope> [reason]
// cache stats
package main
import (
@@ -40,7 +41,9 @@ func connect() (*sql.DB, error) {
p := dbPath()
os.MkdirAll(filepath.Dir(p), 0755)
db, err := sql.Open("sqlite", p)
if err != nil { return nil, err }
if err != nil {
return nil, err
}
db.Exec("PRAGMA journal_mode=WAL")
db.Exec("PRAGMA synchronous=NORMAL")
db.Exec(`CREATE TABLE IF NOT EXISTS cache (
@@ -78,7 +81,10 @@ func main() {
switch cmd {
case "get":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache get <key>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: cache get <key>")
os.Exit(1)
}
var compressed, full, contentHash, scope, createdAt sql.NullString
var hitCount int
err := db.QueryRow(
@@ -107,12 +113,17 @@ func main() {
fmt.Println(string(out))
case "put":
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: cache put <key> <value> [--scope <s>]"); os.Exit(1) }
if len(args) < 2 {
fmt.Fprintln(os.Stderr, "usage: cache put <key> <value> [--scope <s>]")
os.Exit(1)
}
key := args[0]
value := args[1]
scope := "general"
for i := 2; i < len(args); i++ {
if args[i] == "--scope" && i+1 < len(args) { scope = args[i+1] }
if args[i] == "--scope" && i+1 < len(args) {
scope = args[i+1]
}
}
contentHash := hashText(value)
db.Exec(`INSERT INTO cache (key, scope, content_hash, full_value, compressed_value, source_hash, created_at, invalidated_at, hit_count, miss_count)
@@ -124,13 +135,19 @@ func main() {
fmt.Println(string(out))
case "invalidate":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache invalidate <key>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: cache invalidate <key>")
os.Exit(1)
}
db.Exec("UPDATE cache SET invalidated_at=? WHERE key=? AND invalidated_at IS NULL", nowISO(), args[0])
out, _ := json.Marshal(Result{Success: true, Data: map[string]interface{}{"invalidated": args[0]}})
fmt.Println(string(out))
case "invalidate-scope":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: cache invalidate-scope <scope>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: cache invalidate-scope <scope>")
os.Exit(1)
}
db.Exec("UPDATE cache SET invalidated_at=? WHERE scope=? AND invalidated_at IS NULL", nowISO(), args[0])
out, _ := json.Marshal(Result{Success: true, Data: map[string]interface{}{"invalidated_scope": args[0]}})
fmt.Println(string(out))
@@ -149,6 +166,8 @@ func main() {
}
func min(a, b int) int {
if a < b { return a }
if a < b {
return a
}
return b
}
+96
View File
@@ -0,0 +1,96 @@
{
"oracle": "cache._hash",
"generated": "2026-10-07",
"cases": [
{
"fn": "hash",
"name": "ascii",
"input": {
"text": ""
},
"expected": {
"hash": "e3b0c44298fc1c14"
}
},
{
"fn": "hash",
"name": "ascii",
"input": {
"text": "hello world"
},
"expected": {
"hash": "b94d27b9934d3e08"
}
},
{
"fn": "hash",
"name": "ascii",
"input": {
"text": "unicode \u00fcmlaut \u2705"
},
"expected": {
"hash": "2b2d658af990224c"
}
},
{
"fn": "hash",
"name": "ascii",
"input": {
"text": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"expected": {
"hash": "69206a472a1f3842"
}
},
{
"fn": "compress",
"name": "compress_0",
"input": {
"text": ""
},
"expected": {
"compressed": ""
}
},
{
"fn": "compress",
"name": "compress_1",
"input": {
"text": "# comment\n\nreal line here\n====\n// slash comment\n(_source_: x)\n[source: y]\ntiny\nkeep this line too\n\nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
},
"expected": {
"compressed": "real line here\nkeep this line too\nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..."
}
},
{
"fn": "compress",
"name": "compress_2",
"input": {
"text": "line one\nline two\nline three"
},
"expected": {
"compressed": "line one\nline two\nline three"
}
},
{
"fn": "compress",
"name": "compress_3",
"input": {
"text": "===="
},
"expected": {
"compressed": ""
}
},
{
"fn": "compress",
"name": "compress_4",
"input": {
"text": "ab\ncdefgh"
},
"expected": {
"compressed": "cdefgh"
}
}
]
}
+40
View File
@@ -0,0 +1,40 @@
package main
// truth_hash_test.go — factory batch 6 parity gate.
import (
"encoding/json"
"os"
"testing"
)
func TestHashParity(t *testing.T) {
b, err := os.ReadFile("truth_hash.json")
if err != nil {
t.Fatalf("truth_hash.json missing: %v", err)
}
var doc struct {
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Input struct {
Text string `json:"text"`
} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
json.Unmarshal(b, &doc)
for _, c := range doc.Cases {
switch c.Fn {
case "hash":
if got := ContentHash(c.Input.Text); got != c.Expected["hash"] {
t.Errorf("%s: hash got %q want %v", c.Name, got, c.Expected["hash"])
}
case "compress":
want, _ := c.Expected["compressed"].(string)
if got := Compress(c.Input.Text); got != want {
t.Errorf("%s: compress\n got %q\nwant %q", c.Name, got, want)
}
}
}
}
+7 -4
View File
@@ -21,9 +21,12 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "cs_evaluate_fit": result = C.cs_evaluate_fit(cArg)
case "cs_score_card": result = C.cs_score_card(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "cs_evaluate_fit":
result = C.cs_evaluate_fit(cArg)
case "cs_score_card":
result = C.cs_score_card(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.cs_free_string(result)
var out map[string]interface{}
@@ -34,4 +37,4 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
}
func EvaluateFit(arg string) (map[string]interface{}, error) { return call("cs_evaluate_fit", arg) }
func ScoreCard(arg string) (map[string]interface{}, error) { return call("cs_score_card", arg) }
func ScoreCard(arg string) (map[string]interface{}, error) { return call("cs_score_card", arg) }
+27 -9
View File
@@ -92,7 +92,9 @@ func TierGet(entry map[string]interface{}, now string, hotDays, warmDays float64
"entry": entry, "now": now, "hot": hotDays, "warm": warmDays,
})
result, err := call("cc_tier_get", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -105,7 +107,9 @@ func ConsolidationMemory(text string, score float64, washCount int, entryID *int
"entry_id": entryID, "now": now,
})
result, err := call("cc_consolidation_memory", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -119,7 +123,9 @@ func ConsolidationNeuron(slug, body string, importance float64, triggers []strin
"entry_id": entryID, "now": now,
})
result, err := call("cc_consolidation_neuron", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -131,7 +137,9 @@ func WitnessExtractTopic(text string, stopwords []string, cap int) ([]string, er
"text": text, "stopwords": stopwords, "cap": cap,
})
result, err := call("cc_witness_extract_topic", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out []string
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -145,7 +153,9 @@ func WitnessSignals(message string, tables map[string]interface{}, toolError, ta
"recent_topics": recentTopics,
})
result, err := call("cc_witness_signals", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -155,7 +165,9 @@ func WitnessSignals(message string, tables map[string]interface{}, toolError, ta
func SafetyGetParams(rows []map[string]interface{}) (map[string]interface{}, error) {
arg, _ := json.Marshal(rows)
result, err := call("cc_safety_get_params", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -167,7 +179,9 @@ func DriftCheck(text string, patterns []map[string]interface{}) ([]string, error
"text": text, "patterns": patterns,
})
result, err := call("cc_drift_check", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out []string
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -179,7 +193,9 @@ func PinsRecall(pins []map[string]interface{}, term string, limit int) ([]map[st
"pins": pins, "term": term, "limit": limit,
})
result, err := call("cc_pins_recall", string(arg))
if err != nil { return nil, err }
if err != nil {
return nil, err
}
var out []map[string]interface{}
json.Unmarshal([]byte(result), &out)
return out, nil
@@ -189,7 +205,9 @@ func PinsRecall(pins []map[string]interface{}, term string, limit int) ([]map[st
func GrowthNearDup(a, b string) (bool, error) {
arg, _ := json.Marshal(map[string]interface{}{"a": a, "b": b})
result, err := call("cc_growth_near_dup", string(arg))
if err != nil { return false, err }
if err != nil {
return false, err
}
var out map[string]interface{}
json.Unmarshal([]byte(result), &out)
isDup, _ := out["value"].(bool)
+2 -2
View File
@@ -7,8 +7,8 @@ import (
func TestTierGet(t *testing.T) {
entry := map[string]interface{}{
"wash_count": 25,
"last_accessed": "2026-10-06T12:00:00Z",
"wash_count": 25,
"last_accessed": "2026-10-06T12:00:00Z",
}
result, err := TierGet(entry, "2026-10-06T20:00:00Z", 7.0, 30.0)
if err != nil {
+28 -15
View File
@@ -27,15 +27,24 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "ep_append_entry": result = C.ep_append_entry(cArg)
case "ep_bl_accept_limitation": result = C.ep_bl_accept_limitation(cArg)
case "ep_bl_define": result = C.ep_bl_define(cArg)
case "ep_bl_get": result = C.ep_bl_get(cArg)
case "ep_bl_invalidate": result = C.ep_bl_invalidate(cArg)
case "ep_bl_outstanding": result = C.ep_bl_outstanding(cArg)
case "ep_bl_record_auto": result = C.ep_bl_record_auto(cArg)
case "ep_bl_record_real_world": result = C.ep_bl_record_real_world(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "ep_append_entry":
result = C.ep_append_entry(cArg)
case "ep_bl_accept_limitation":
result = C.ep_bl_accept_limitation(cArg)
case "ep_bl_define":
result = C.ep_bl_define(cArg)
case "ep_bl_get":
result = C.ep_bl_get(cArg)
case "ep_bl_invalidate":
result = C.ep_bl_invalidate(cArg)
case "ep_bl_outstanding":
result = C.ep_bl_outstanding(cArg)
case "ep_bl_record_auto":
result = C.ep_bl_record_auto(cArg)
case "ep_bl_record_real_world":
result = C.ep_bl_record_real_world(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.ep_free_string(result)
var out map[string]interface{}
@@ -46,10 +55,14 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
}
func AppendEntry(arg string) (map[string]interface{}, error) { return call("ep_append_entry", arg) }
func BLAcceptLimitation(arg string) (map[string]interface{}, error) { return call("ep_bl_accept_limitation", arg) }
func BLDefine(arg string) (map[string]interface{}, error) { return call("ep_bl_define", arg) }
func BLGet(arg string) (map[string]interface{}, error) { return call("ep_bl_get", arg) }
func BLInvalidate(arg string) (map[string]interface{}, error) { return call("ep_bl_invalidate", arg) }
func BLAcceptLimitation(arg string) (map[string]interface{}, error) {
return call("ep_bl_accept_limitation", arg)
}
func BLDefine(arg string) (map[string]interface{}, error) { return call("ep_bl_define", arg) }
func BLGet(arg string) (map[string]interface{}, error) { return call("ep_bl_get", arg) }
func BLInvalidate(arg string) (map[string]interface{}, error) { return call("ep_bl_invalidate", arg) }
func BLOutstanding(arg string) (map[string]interface{}, error) { return call("ep_bl_outstanding", arg) }
func BLRecordAuto(arg string) (map[string]interface{}, error) { return call("ep_bl_record_auto", arg) }
func BLRecordRealWorld(arg string) (map[string]interface{}, error) { return call("ep_bl_record_real_world", arg) }
func BLRecordAuto(arg string) (map[string]interface{}, error) { return call("ep_bl_record_auto", arg) }
func BLRecordRealWorld(arg string) (map[string]interface{}, error) {
return call("ep_bl_record_real_world", arg)
}
+19 -12
View File
@@ -26,13 +26,20 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "qm_adaptive_rate": result = C.qm_adaptive_rate(cArg)
case "qm_classify": result = C.qm_classify(cArg)
case "qm_dead_weight": result = C.qm_dead_weight(cArg)
case "qm_health": result = C.qm_health(cArg)
case "qm_new": result = C.qm_new(cArg)
case "qm_record": result = C.qm_record(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "qm_adaptive_rate":
result = C.qm_adaptive_rate(cArg)
case "qm_classify":
result = C.qm_classify(cArg)
case "qm_dead_weight":
result = C.qm_dead_weight(cArg)
case "qm_health":
result = C.qm_health(cArg)
case "qm_new":
result = C.qm_new(cArg)
case "qm_record":
result = C.qm_record(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.qm_string_free(result)
var out map[string]interface{}
@@ -43,8 +50,8 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
}
func AdaptiveRate(arg string) (map[string]interface{}, error) { return call("qm_adaptive_rate", arg) }
func Classify(arg string) (map[string]interface{}, error) { return call("qm_classify", arg) }
func DeadWeight(arg string) (map[string]interface{}, error) { return call("qm_dead_weight", arg) }
func Health(arg string) (map[string]interface{}, error) { return call("qm_health", arg) }
func New(arg string) (map[string]interface{}, error) { return call("qm_new", arg) }
func Record(arg string) (map[string]interface{}, error) { return call("qm_record", arg) }
func Classify(arg string) (map[string]interface{}, error) { return call("qm_classify", arg) }
func DeadWeight(arg string) (map[string]interface{}, error) { return call("qm_dead_weight", arg) }
func Health(arg string) (map[string]interface{}, error) { return call("qm_health", arg) }
func New(arg string) (map[string]interface{}, error) { return call("qm_new", arg) }
func Record(arg string) (map[string]interface{}, error) { return call("qm_record", arg) }
+29 -13
View File
@@ -26,14 +26,22 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "ms_base_level_from_uses": result = C.ms_base_level_from_uses(cArg)
case "ms_check_promotion_eligibility": result = C.ms_check_promotion_eligibility(cArg)
case "ms_compress_entry": result = C.ms_compress_entry(cArg)
case "ms_compress_text": result = C.ms_compress_text(cArg)
case "ms_compute_priority": result = C.ms_compute_priority(cArg)
case "ms_compute_value": result = C.ms_compute_value(cArg)
case "ms_get_compression_ratio": result = C.ms_get_compression_ratio(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "ms_base_level_from_uses":
result = C.ms_base_level_from_uses(cArg)
case "ms_check_promotion_eligibility":
result = C.ms_check_promotion_eligibility(cArg)
case "ms_compress_entry":
result = C.ms_compress_entry(cArg)
case "ms_compress_text":
result = C.ms_compress_text(cArg)
case "ms_compute_priority":
result = C.ms_compute_priority(cArg)
case "ms_compute_value":
result = C.ms_compute_value(cArg)
case "ms_get_compression_ratio":
result = C.ms_get_compression_ratio(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.ms_free_string(result)
var out map[string]interface{}
@@ -43,10 +51,18 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
return out, nil
}
func BaseLevelFromUses(arg string) (map[string]interface{}, error) { return call("ms_base_level_from_uses", arg) }
func CheckPromotionEligibility(arg string) (map[string]interface{}, error) { return call("ms_check_promotion_eligibility", arg) }
func BaseLevelFromUses(arg string) (map[string]interface{}, error) {
return call("ms_base_level_from_uses", arg)
}
func CheckPromotionEligibility(arg string) (map[string]interface{}, error) {
return call("ms_check_promotion_eligibility", arg)
}
func CompressEntry(arg string) (map[string]interface{}, error) { return call("ms_compress_entry", arg) }
func CompressText(arg string) (map[string]interface{}, error) { return call("ms_compress_text", arg) }
func ComputePriority(arg string) (map[string]interface{}, error) { return call("ms_compute_priority", arg) }
func CompressText(arg string) (map[string]interface{}, error) { return call("ms_compress_text", arg) }
func ComputePriority(arg string) (map[string]interface{}, error) {
return call("ms_compute_priority", arg)
}
func ComputeValue(arg string) (map[string]interface{}, error) { return call("ms_compute_value", arg) }
func GetCompressionRatio(arg string) (map[string]interface{}, error) { return call("ms_get_compression_ratio", arg) }
func GetCompressionRatio(arg string) (map[string]interface{}, error) {
return call("ms_get_compression_ratio", arg)
}
+13 -8
View File
@@ -23,11 +23,16 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "sp_drift": result = C.sp_drift(cArg)
case "sp_export": result = C.sp_export(cArg)
case "sp_project": result = C.sp_project(cArg)
case "sp_query": result = C.sp_query(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "sp_drift":
result = C.sp_drift(cArg)
case "sp_export":
result = C.sp_export(cArg)
case "sp_project":
result = C.sp_project(cArg)
case "sp_query":
result = C.sp_query(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.sp_free_string(result)
var out map[string]interface{}
@@ -37,7 +42,7 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
return out, nil
}
func Drift(arg string) (map[string]interface{}, error) { return call("sp_drift", arg) }
func Export(arg string) (map[string]interface{}, error) { return call("sp_export", arg) }
func Drift(arg string) (map[string]interface{}, error) { return call("sp_drift", arg) }
func Export(arg string) (map[string]interface{}, error) { return call("sp_export", arg) }
func Project(arg string) (map[string]interface{}, error) { return call("sp_project", arg) }
func Query(arg string) (map[string]interface{}, error) { return call("sp_query", arg) }
func Query(arg string) (map[string]interface{}, error) { return call("sp_query", arg) }
+12 -5
View File
@@ -21,9 +21,12 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
defer C.free(unsafe.Pointer(cArg))
var result *C.char
switch symbol {
case "tc_compress_context": result = C.tc_compress_context(cArg)
case "tc_estimate_tokens": result = C.tc_estimate_tokens(cArg)
default: return nil, fmt.Errorf("unknown symbol: %s", symbol)
case "tc_compress_context":
result = C.tc_compress_context(cArg)
case "tc_estimate_tokens":
result = C.tc_estimate_tokens(cArg)
default:
return nil, fmt.Errorf("unknown symbol: %s", symbol)
}
defer C.tc_free_string(result)
var out map[string]interface{}
@@ -33,5 +36,9 @@ func call(symbol string, arg string) (map[string]interface{}, error) {
return out, nil
}
func CompressContext(arg string) (map[string]interface{}, error) { return call("tc_compress_context", arg) }
func EstimateTokens(arg string) (map[string]interface{}, error) { return call("tc_estimate_tokens", arg) }
func CompressContext(arg string) (map[string]interface{}, error) {
return call("tc_compress_context", arg)
}
func EstimateTokens(arg string) (map[string]interface{}, error) {
return call("tc_estimate_tokens", arg)
}
Binary file not shown.
+2 -2
View File
@@ -68,9 +68,9 @@ func (p *ConnectionPool) Status() map[string]interface{} {
dbs := make([]string, len(p.order))
copy(dbs, p.order)
return map[string]interface{}{
"connections": len(p.conns),
"connections": len(p.conns),
"max_connections": p.maxConns,
"databases": dbs,
"databases": dbs,
}
}
Binary file not shown.
Binary file not shown.
+5 -4
View File
@@ -2,7 +2,8 @@
// Replaces src/rune/core_server.py. Go net/http, goroutine-safe.
//
// Usage:
// core-server [--port <port>]
//
// core-server [--port <port>]
package main
import (
@@ -26,7 +27,7 @@ type HealthResponse struct {
}
type ChatRequest struct {
Model string `json:"model"`
Model string `json:"model"`
Messages []map[string]string `json:"messages"`
}
@@ -53,8 +54,8 @@ func (s *Server) chatHandler(w http.ResponseWriter, r *http.Request) {
}
// Proxy to the Ollama provider
out, _ := json.Marshal(map[string]interface{}{
"status": "received",
"model": req.Model,
"status": "received",
"model": req.Model,
"messages_count": len(req.Messages),
})
w.Header().Set("Content-Type", "application/json")
Binary file not shown.
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
package main
// fuzz_test.go — native Go fuzz targets on the curator-core byte surfaces
// (polyglot gate contract: fuzzing wired into the pipeline). Invariants:
// panic-free + structural properties that must hold for ARBITRARY input.
import (
"strings"
"testing"
)
// FuzzNorm — Norm never panics, emits no markdown/punctuation, and is
// deterministic (same input → same output).
func FuzzNorm(f *testing.F) {
for _, s := range []string{"", "- **bold** entry", "### Header text", " spaced out ",
"punctuation, gone!", "> quoted line", "***___```", "\t\ntabs\nand\nnewlines", "üñí©ödé ✅"} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
a := Norm(s)
b := Norm(s)
if a != b {
t.Fatalf("Norm not deterministic: %q → %q vs %q", s, a, b)
}
for _, ch := range a {
if strings.ContainsRune("*_`#,.!?;:()", ch) {
t.Fatalf("Norm kept punctuation %q for input %q → %q", ch, s, a)
}
}
if strings.ToLower(a) != a {
t.Fatalf("Norm not lowercased: %q → %q", s, a)
}
})
}
// FuzzStem — the stemmer never panics, never returns an empty stem for
// non-empty input of >=4 chars, and is idempotent (stem(stem(w))==stem(w)).
func FuzzStem(f *testing.F) {
for _, s := range []string{"migration", "migrated", "honesty", "retroactively",
"capacity", "abilities", "nations", "ations", "e", "s", "y", ""} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
one := Stem(s)
if s != "" && len([]rune(s)) >= 4 && one == "" {
t.Fatalf("Stem emptied a >=4-char word: %q", s)
}
if len(one) > len(s) {
t.Fatalf("Stem grew the word: %q (%d) → %q (%d)", s, len(s), one, len(one))
}
})
}
// FuzzOverlap — Jaccard stays in [0,1] and is symmetric for arbitrary text.
func FuzzOverlap(f *testing.F) {
f.Add("alpha beta", "beta gamma")
f.Add("", "anything")
f.Add("!!??", "''``")
f.Add("Mixed CASE text", "mixed case TEXT")
f.Fuzz(func(t *testing.T, a, b string) {
x, y := Overlap(a, b), Overlap(b, a)
if x != y {
t.Fatalf("Overlap not symmetric: %q vs %q → %f vs %f", a, b, x, y)
}
if x < 0.0 || x > 1.0 {
t.Fatalf("Overlap out of [0,1]: %f (inputs %q %q)", x, a, b)
}
})
}
+1 -1
View File
@@ -121,7 +121,7 @@ func DistinctiveTerms(fact string, corpusTexts []string) map[string]bool {
docTerms[s]++
}
}
thresh := float64(total)*lexDistinctiveDF
thresh := float64(total) * lexDistinctiveDF
if thresh < 1.5 {
thresh = 1.5
}
Binary file not shown.
+11 -6
View File
@@ -4,10 +4,11 @@
// contradiction detection, identity checks, entry dedup.
//
// Usage:
// curator promote-eligible <proposal> <existing> <strength> [min-strength] [wash-count]
// curator contradicts-identity <fact>
// curator is-topic-fact <fact>
// curator entry-key <text>
//
// curator promote-eligible <proposal> <existing> <strength> [min-strength] [wash-count]
// curator contradicts-identity <fact>
// curator is-topic-fact <fact>
// curator entry-key <text>
package main
import (
@@ -183,8 +184,12 @@ func main() {
fmt.Sscanf(args[2], "%d", &strength)
minStrength := 3
washCount := 0
if len(args) > 3 { fmt.Sscanf(args[3], "%d", &minStrength) }
if len(args) > 4 { fmt.Sscanf(args[4], "%d", &washCount) }
if len(args) > 3 {
fmt.Sscanf(args[3], "%d", &minStrength)
}
if len(args) > 4 {
fmt.Sscanf(args[4], "%d", &washCount)
}
result := promoteEligible(proposal, existing, strength, minStrength, nil, washCount)
out, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(out))
+32
View File
@@ -0,0 +1,32 @@
package main
// fama.go — factory batch 12: FAMA (Forgetting-Aware Memory Accuracy)
// from drift_core.py. The entry-row classification is the deterministic
// core; the SQL stays reactive (callers pass fetched rows).
// EntryRow — the fetched (status, rock_status, wash_count) triple.
type EntryRow struct {
Status string
RockStatus string
WashCount int
}
// ComputeFAMA — the fraction of retrieved ids that are "valid":
// status=active AND (wash_count>0 OR rock in {established, rock}).
// Missing rows are skipped (parity: `continue`); an empty id list = 0.0.
func ComputeFAMA(rows []EntryRow, retrievedCount int) float64 {
if retrievedCount == 0 {
return 0.0
}
valid := 0
for _, r := range rows {
if r.Status == "active" {
if r.WashCount > 0 {
valid++
} else if r.RockStatus == "established" || r.RockStatus == "rock" {
valid++
}
}
}
return float64(valid) / float64(retrievedCount)
}
+3
View File
@@ -0,0 +1,3 @@
module rune/drift-core
go 1.21
+110
View File
@@ -0,0 +1,110 @@
{
"oracle": "drift_core.compute_fama (live)",
"generated": "2026-10-08",
"cases": [
{
"fn": "fama",
"name": "all_valid",
"input": {
"rows": [
{
"status": "active",
"rock_status": "washable",
"wash_count": 5
},
{
"status": "active",
"rock_status": "established",
"wash_count": 0
},
{
"status": "active",
"rock_status": "rock",
"wash_count": 0
}
],
"count": 3
},
"expected": {
"fama": 1.0
}
},
{
"fn": "fama",
"name": "mixed",
"input": {
"rows": [
{
"status": "active",
"rock_status": "washable",
"wash_count": 5
},
{
"status": "active",
"rock_status": "established",
"wash_count": 0
},
{
"status": "active",
"rock_status": "washable",
"wash_count": 0
}
],
"count": 3
},
"expected": {
"fama": 0.6666666666666666
}
},
{
"fn": "fama",
"name": "with_missing",
"input": {
"rows": [
{
"status": "active",
"rock_status": "washable",
"wash_count": 5
}
],
"count": 2
},
"expected": {
"fama": 0.5
}
},
{
"fn": "fama",
"name": "empty",
"input": {
"rows": [],
"count": 0
},
"expected": {
"fama": 0.0
}
},
{
"fn": "fama",
"name": "all_invalid",
"input": {
"rows": [
{
"status": "active",
"rock_status": "washable",
"wash_count": 0
},
{
"status": "superseded",
"rock_status": "washable",
"wash_count": 9
}
],
"count": 2
},
"expected": {
"fama": 0.0
}
}
]
}
+42
View File
@@ -0,0 +1,42 @@
package main
// truth_fama_test.go — factory batch 12 parity gate.
import (
"encoding/json"
"os"
"testing"
)
func TestFAMAParity(t *testing.T) {
b, err := os.ReadFile("truth_fama.json")
if err != nil {
t.Fatalf("truth_fama.json missing: %v", err)
}
var doc struct {
Cases []struct {
Name string `json:"name"`
Input map[string]interface{} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
json.Unmarshal(b, &doc)
for _, c := range doc.Cases {
rowsAny, _ := c.Input["rows"].([]interface{})
var rows []EntryRow
for _, r := range rowsAny {
m, _ := r.(map[string]interface{})
status, _ := m["status"].(string)
rock, _ := m["rock_status"].(string)
wash, _ := m["wash_count"].(float64)
rows = append(rows, EntryRow{Status: status, RockStatus: rock, WashCount: int(wash)})
}
count := int(c.Input["count"].(float64))
want, _ := c.Expected["fama"].(float64)
got := ComputeFAMA(rows, count)
diff := got - want
if diff > 1e-9 || diff < -1e-9 {
t.Errorf("%s: fama got %f want %f", c.Name, got, want)
}
}
}
+221
View File
@@ -0,0 +1,221 @@
{
"oracle": "drift_core._py_* oracles",
"generated": "2026-10-08",
"frozen_now": "2026-10-08T00:30:00+00:00",
"cases": [
{
"fn": "value",
"name": "value_0",
"input": {
"entry": {
"wash_count": 0,
"importance": 0.5,
"text": "unproven entry",
"rock_status": "washable"
}
},
"expected": {
"value": 0.375
}
},
{
"fn": "promo",
"name": "promo_0",
"input": {
"entry": {
"wash_count": 0,
"importance": 0.5,
"text": "unproven entry",
"rock_status": "washable"
}
},
"expected": {
"eligible": false,
"reason": "proven_uses 0 < threshold 20"
}
},
{
"fn": "value",
"name": "value_1",
"input": {
"entry": {
"wash_count": 25,
"importance": 0.9,
"text": "proven entry",
"rock_status": "washable",
"last_accessed": "2026-10-07T20:00:00+00:00"
}
},
"expected": {
"value": 0.8488
}
},
{
"fn": "promo",
"name": "promo_1",
"input": {
"entry": {
"wash_count": 25,
"importance": 0.9,
"text": "proven entry",
"rock_status": "washable",
"last_accessed": "2026-10-07T20:00:00+00:00"
}
},
"expected": {
"eligible": true,
"reason": "wash_count=25, value=0.849"
}
},
{
"fn": "value",
"name": "value_2",
"input": {
"entry": {
"wash_count": 30,
"importance": 0.8,
"text": "stale entry",
"rock_status": "washable",
"last_accessed": "2026-08-01T10:00:00+00:00"
}
},
"expected": {
"value": 0.7015
}
},
{
"fn": "promo",
"name": "promo_2",
"input": {
"entry": {
"wash_count": 30,
"importance": 0.8,
"text": "stale entry",
"rock_status": "washable",
"last_accessed": "2026-08-01T10:00:00+00:00"
}
},
"expected": {
"eligible": true,
"reason": "wash_count=30, value=0.702"
}
},
{
"fn": "value",
"name": "value_3",
"input": {
"entry": {
"wash_count": 40,
"importance": 0.9,
"text": "rocked",
"rock_status": "rock"
}
},
"expected": {
"value": 0.895
}
},
{
"fn": "promo",
"name": "promo_3",
"input": {
"entry": {
"wash_count": 40,
"importance": 0.9,
"text": "rocked",
"rock_status": "rock"
}
},
"expected": {
"eligible": false,
"reason": "already rock"
}
},
{
"fn": "value",
"name": "value_4",
"input": {
"entry": {
"wash_count": 22,
"importance": 0.7,
"text": "bad ts",
"rock_status": "washable",
"last_accessed": "not-a-date"
}
},
"expected": {
"value": 0.691
}
},
{
"fn": "promo",
"name": "promo_4",
"input": {
"entry": {
"wash_count": 22,
"importance": 0.7,
"text": "bad ts",
"rock_status": "washable",
"last_accessed": "not-a-date"
}
},
"expected": {
"eligible": true,
"reason": "wash_count=22, value=0.691"
}
},
{
"fn": "value",
"name": "value_5",
"input": {
"entry": {
"wash_count": 21,
"importance": 0.6,
"text": "the curator gates memory writes",
"rock_status": "washable",
"last_accessed": "2026-10-06T00:00:00+00:00"
}
},
"expected": {
"value": 0.7504
}
},
{
"fn": "promo",
"name": "promo_5",
"input": {
"entry": {
"wash_count": 21,
"importance": 0.6,
"text": "the curator gates memory writes",
"rock_status": "washable",
"last_accessed": "2026-10-06T00:00:00+00:00"
}
},
"expected": {
"eligible": true,
"reason": "wash_count=21, value=0.750"
}
},
{
"fn": "value",
"name": "with_goals",
"input": {
"entry": {
"wash_count": 21,
"importance": 0.6,
"text": "the curator gates memory writes",
"rock_status": "washable",
"last_accessed": "2026-10-06T00:00:00+00:00"
},
"goals": [
"curator memory writes",
"gate the pipeline"
]
},
"expected": {
"value": 0.8004
}
}
]
}
+55
View File
@@ -0,0 +1,55 @@
package main
// truth_value_test.go — factory batch 10 parity gate.
import (
"encoding/json"
"os"
"testing"
)
func TestValueParity(t *testing.T) {
b, err := os.ReadFile("truth_value.json")
if err != nil {
t.Fatalf("truth_value.json missing: %v", err)
}
var doc struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Input map[string]interface{} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
json.Unmarshal(b, &doc)
for _, c := range doc.Cases {
entryAny, _ := c.Input["entry"].(map[string]interface{})
switch c.Fn {
case "value":
var goals []string
if g, has := c.Input["goals"].([]interface{}); has {
for _, x := range g {
s, _ := x.(string)
goals = append(goals, s)
}
}
got := ComputeValue(entryAny, goals, doc.FrozenNow)
want, _ := c.Expected["value"].(float64)
diff := got - want
if diff > 1e-9 || diff < -1e-9 {
t.Errorf("%s: value got %f want %f", c.Name, got, want)
}
case "promo":
gotElig, gotReason := CheckPromotionEligibility(entryAny, doc.FrozenNow)
wantElig, _ := c.Expected["eligible"].(bool)
wantReason, _ := c.Expected["reason"].(string)
if gotElig != wantElig {
t.Errorf("%s: eligible got %v want %v (reason %q)", c.Name, gotElig, wantElig, gotReason)
}
if gotReason != wantReason {
t.Errorf("%s: reason\n got %q\nwant %q", c.Name, gotReason, wantReason)
}
}
}
}
+153
View File
@@ -0,0 +1,153 @@
package main
// value.go — factory batch 10: the multi-factor value score + promotion
// eligibility of drift_core.py (_py_compute_value / _py_check_promotion_
// eligibility verbatim; the Rust-core delegate path is the production
// seam — the Python fallback IS the oracle we port).
import (
"fmt"
"math"
"strings"
"time"
)
const (
ProvenUsesThreshold = 20
RecencyHalfLifeDays = 30.0
ReliabilityWindow = 50
WeightProvenUses = 0.30
WeightImportance = 0.25
WeightRecency = 0.20
WeightReliability = 0.15
WeightGoalRelevance = 0.10
)
func entryFloat(entry map[string]interface{}, key string, def float64) float64 {
if v, has := entry[key].(float64); has && v != 0 {
return v
}
return def
}
// ComputeValue — the weighted 5-factor score, rounded to 4 decimals.
// nowISO is INJECTED (no-clock law); it must carry a timezone offset or
// Z (datetime.fromisoformat semantics).
func ComputeValue(entry map[string]interface{}, currentGoals []string, nowISO string) float64 {
proven := entryFloat(entry, "wash_count", 0)
imp := entryFloat(entry, "importance", 0.5)
provenFactor := math.Min(1.0, math.Log1p(proven)/math.Log1p(ProvenUsesThreshold))
recency := 1.0
lastAccessed := ""
if v, has := entry["last_accessed"].(string); has && v != "" {
lastAccessed = v
} else if v, has := entry["last_washed"].(string); has && v != "" {
lastAccessed = v
}
if lastAccessed != "" {
if last, err := parseISODrift(lastAccessed); err == nil {
nowDT, err2 := parseISODrift(nowISO)
if err2 != nil {
nowDT = time.Now().UTC()
}
hoursSince := nowDT.Sub(last).Hours()
if hoursSince < 0.1 {
hoursSince = 0.1
}
recency = 1.0 / (1.0 + hoursSince/(RecencyHalfLifeDays*24))
if recency < 0.1 {
recency = 0.1
}
} else {
recency = 0.5
}
}
den := float64(ReliabilityWindow)
if den < 1 {
den = 1
}
reliability := math.Min(1.0, proven/den)
goalRelevance := 0.5
if len(currentGoals) > 0 {
text := strings.ToLower(textOf(entry, "text"))
goalWords := map[string]bool{}
for _, g := range currentGoals {
for _, w := range strings.Fields(strings.ToLower(g)) {
goalWords[w] = true
}
}
textWords := map[string]bool{}
for _, w := range strings.Fields(text) {
textWords[w] = true
}
overlap := 0
for w := range goalWords {
if textWords[w] {
overlap++
}
}
denom := float64(len(goalWords)) * 0.3
if denom < 1 {
denom = 1
}
goalRelevance = math.Min(1.0, float64(overlap)/denom)
}
value := WeightProvenUses*provenFactor +
WeightImportance*imp +
WeightRecency*recency +
WeightReliability*reliability +
WeightGoalRelevance*goalRelevance
return round4D(value)
}
func textOf(entry map[string]interface{}, key string) string {
v, _ := entry[key].(string)
return v
}
func round4D(f float64) float64 {
return float64(int64(f*10000+0.5)) / 10000
}
// parseISODrift — fromisoformat with the Z→+00:00 swap.
func parseISODrift(s string) (time.Time, error) {
s = strings.Replace(s, "Z", "+00:00", 1)
layouts := []string{
"2006-01-02T15:04:05.999999-07:00",
"2006-01-02T15:04:05-07:00",
"2006-01-02T15:04:05.999999",
"2006-01-02T15:04:05",
}
for _, l := range layouts {
if t, err := time.Parse(l, s); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("bad iso: %s", s)
}
// CheckPromotionEligibility — (eligible, reason) with exact text shapes.
func CheckPromotionEligibility(entry map[string]interface{}, nowISO string) (bool, string) {
wash := int(entryFloat(entry, "wash_count", 0))
status := "washable"
if v, has := entry["rock_status"].(string); has && v != "" {
status = v
}
if status == "rock" {
return false, "already rock"
}
if wash < ProvenUsesThreshold {
return false, fmt.Sprintf("proven_uses %d < threshold %d", wash, ProvenUsesThreshold)
}
value := ComputeValue(entry, nil, nowISO)
if value < 0.6 {
return false, fmt.Sprintf("value %.3f < 0.6 minimum", value)
}
return true, fmt.Sprintf("wash_count=%d, value=%.3f", wash, value)
}
Binary file not shown.
+19 -12
View File
@@ -3,8 +3,9 @@
// calculate_budget. Classifies how much cognition an event deserves.
//
// Usage:
// elastic-cognition classify <text> [--channel <ch>]
// elastic-cognition budget <salience-json> [--channel <ch>]
//
// elastic-cognition classify <text> [--channel <ch>]
// elastic-cognition budget <salience-json> [--channel <ch>]
package main
import (
@@ -16,17 +17,17 @@ import (
)
type SalienceDecision struct {
Score float64 `json:"score"`
Flags []string `json:"flags"`
MinimumTier string `json:"minimum_tier"`
WitnessNeeded bool `json:"witness_needed"`
Score float64 `json:"score"`
Flags []string `json:"flags"`
MinimumTier string `json:"minimum_tier"`
WitnessNeeded bool `json:"witness_needed"`
RationaleCodes []string `json:"rationale_codes"`
}
type CognitiveBudget struct {
Route string `json:"route"`
MinTier string `json:"min_tier"`
MaxTokens int `json:"max_tokens"`
Route string `json:"route"`
MinTier string `json:"min_tier"`
MaxTokens int `json:"max_tokens"`
TempOverride *float64 `json:"temp_override,omitempty"`
}
@@ -163,10 +164,14 @@ func classifySalience(text, channel string) SalienceDecision {
// CHANNEL PRIORS
if channel == "work" {
if score < 0.5 { score = 0.5 }
if score < 0.5 {
score = 0.5
}
rationale = append(rationale, "work_channel")
} else if channel == "chat" {
if score > 0.3 { score = 0.3 }
if score > 0.3 {
score = 0.3
}
rationale = append(rationale, "chat_channel")
}
@@ -192,7 +197,9 @@ func classifySalience(text, channel string) SalienceDecision {
func containsFlag(flags []string, flag string) bool {
for _, f := range flags {
if f == flag { return true }
if f == flag {
return true
}
}
return false
}
+165
View File
@@ -0,0 +1,165 @@
package main
// bus.go — factory batch 9: the event-bus content-hash + envelope shape
// (event_bus.py _content_hash — the orchestration sha256: convention).
// The journal store I/O stays reactive.
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"sort"
"strings"
)
// ContentHashEvent — "sha256:" + sha256(json.dumps(payload, sort_keys=True))
// — Python default separators (", " / ": "), ensure_ascii escaping.
func ContentHashEvent(payload map[string]interface{}) string {
keys := make([]string, 0, len(payload))
for k := range payload {
keys = append(keys, k)
}
sort.Strings(keys)
var sb strings.Builder
sb.WriteString("{")
for i, k := range keys {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(pyQuoteEvent(k))
sb.WriteString(": ")
writeEventJSON(&sb, payload[k])
}
sb.WriteString("}")
sum := sha256.Sum256([]byte(sb.String()))
return "sha256:" + hex.EncodeToString(sum[:])
}
func writeEventJSON(sb *strings.Builder, v interface{}) {
switch x := v.(type) {
case json.Number:
// PARITY: the oracle distinguishes int (1) from float (1.0) at
// the literal level; json.Number preserves it through decode.
sb.WriteString(x.String())
case nil:
sb.WriteString("null")
case bool:
if x {
sb.WriteString("true")
} else {
sb.WriteString("false")
}
case string:
sb.WriteString(pyQuoteEvent(x))
case float64:
// PARITY: Python json.dumps renders 1.0 as "1.0" (floats keep
// .0; ints stay ints). The oracle fixture pinned this.
if x == float64(int64(x)) && x < 1e16 && x > -1e16 {
sb.WriteString(itoaE(int64(x)))
sb.WriteString(".0")
} else {
sb.WriteString(jsonNumber(x))
}
case []interface{}:
sb.WriteString("[")
for i, e := range x {
if i > 0 {
sb.WriteString(", ")
}
writeEventJSON(sb, e)
}
sb.WriteString("]")
case map[string]interface{}:
keys := make([]string, 0, len(x))
for k := range x {
keys = append(keys, k)
}
sort.Strings(keys) // sort_keys=True — NESTED maps too
sb.WriteString("{")
for i, k := range keys {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(pyQuoteEvent(k))
sb.WriteString(": ")
writeEventJSON(sb, x[k])
}
sb.WriteString("}")
default:
b, _ := json.Marshal(x)
sb.Write(b)
}
}
func trimFloatE(f float64) string {
s := fmtFloatE(f)
return s
}
func fmtFloatE(f float64) string {
// Python repr semantics: integral → no decimal point
if f == float64(int64(f)) && f < 1e16 && f > -1e16 {
return itoaE(int64(f))
}
return strconvFormatE(f)
}
func itoaE(n int64) string {
if n == 0 {
return "0"
}
neg := n < 0
if neg {
n = -n
}
var b []byte
for n > 0 {
b = append([]byte{byte('0' + n%10)}, b...)
n /= 10
}
if neg {
return "-" + string(b)
}
return string(b)
}
func strconvFormatE(f float64) string {
return strings.TrimSpace(strings.Replace(jsonNumber(f), "e+", "e+", 1))
}
func jsonNumber(f float64) string {
b, _ := json.Marshal(f)
return string(b)
}
func pyQuoteEvent(s string) string {
var sb strings.Builder
sb.WriteByte('"')
for _, r := range s {
switch r {
case '"':
sb.WriteString("\\\"")
case '\\':
sb.WriteString("\\\\")
case '\n':
sb.WriteString("\\n")
case '\r':
sb.WriteString("\\r")
case '\t':
sb.WriteString("\\t")
default:
if r < 0x20 {
sb.WriteString("\\u")
const hexdig = "0123456789abcdef"
sb.WriteByte('0')
sb.WriteByte('0')
sb.WriteByte(hexdig[(r>>4)&0xf])
sb.WriteByte(hexdig[r&0xf])
} else {
sb.WriteRune(r)
}
}
}
sb.WriteByte('"')
return sb.String()
}
Binary file not shown.
+39 -28
View File
@@ -4,9 +4,10 @@
// append safety; os.WriteFile for the durable journal.
//
// Usage:
// event-bus emit <event_type> [--source <s>] [--payload <json>]
// event-bus log [--limit N] [--type <t>]
// event-bus stats
//
// event-bus emit <event_type> [--source <s>] [--payload <json>]
// event-bus log [--limit N] [--type <t>]
// event-bus stats
package main
import (
@@ -24,15 +25,15 @@ import (
// EventEnvelope — the canonical record (matches rune/orchestration/records.py).
type EventEnvelope struct {
EventID string `json:"event_id"`
EventType string `json:"event_type"`
PartitionKey string `json:"partition_key"`
ParentID string `json:"parent_id,omitempty"`
ActorID string `json:"actor_id,omitempty"`
DeviceID string `json:"device_id,omitempty"`
EventID string `json:"event_id"`
EventType string `json:"event_type"`
PartitionKey string `json:"partition_key"`
ParentID string `json:"parent_id,omitempty"`
ActorID string `json:"actor_id,omitempty"`
DeviceID string `json:"device_id,omitempty"`
Authorization string `json:"authorization,omitempty"`
PayloadHash string `json:"payload_hash,omitempty"`
Timestamp string `json:"timestamp"`
PayloadHash string `json:"payload_hash,omitempty"`
Timestamp string `json:"timestamp"`
}
func newID(prefix string) string {
@@ -200,7 +201,6 @@ func main() {
}, "", " ")
fmt.Println(string(out))
case "create-envelope":
args := os.Args[2:]
source, channel, text := "", "", ""
@@ -208,13 +208,25 @@ func main() {
for i := 0; i < len(args); i++ {
switch args[i] {
case "--source":
if i+1 < len(args) { source = args[i+1]; i++ }
if i+1 < len(args) {
source = args[i+1]
i++
}
case "--channel":
if i+1 < len(args) { channel = args[i+1]; i++ }
if i+1 < len(args) {
channel = args[i+1]
i++
}
case "--text":
if i+1 < len(args) { text = args[i+1]; i++ }
if i+1 < len(args) {
text = args[i+1]
i++
}
case "--payload":
if i+1 < len(args) { json.Unmarshal([]byte(args[i+1]), &payload); i++ }
if i+1 < len(args) {
json.Unmarshal([]byte(args[i+1]), &payload)
i++
}
}
}
out, _ := json.MarshalIndent(createEnvelope(source, channel, text, payload), "", " ")
@@ -229,10 +241,10 @@ func main() {
// ── event envelope operations (W4: event_envelope port) ──────────────────
type EnvelopeRequest struct {
Source string `json:"source"`
Channel string `json:"channel"`
Payload map[string]interface{} `json:"payload"`
Text string `json:"text"`
Source string `json:"source"`
Channel string `json:"channel"`
Payload map[string]interface{} `json:"payload"`
Text string `json:"text"`
}
func classifyAuthority(text, channel string) string {
@@ -315,14 +327,13 @@ func createEnvelope(source, channel, text string, payload map[string]interface{}
env.PayloadHash = contentHash(payload)
}
return map[string]interface{}{
"event_id": env.EventID,
"timestamp": env.Timestamp,
"source": source,
"channel": channel,
"event_id": env.EventID,
"timestamp": env.Timestamp,
"source": source,
"channel": channel,
"authority_class": authority,
"urgency": urgency,
"payload_hash": env.PayloadHash,
"payload": payload,
"urgency": urgency,
"payload_hash": env.PayloadHash,
"payload": payload,
}
}
+87
View File
@@ -0,0 +1,87 @@
{
"oracle": "event_bus._content_hash",
"generated": "2026-10-07",
"cases": [
{
"fn": "hash",
"name": "payload_0",
"input": {
"payload": {}
},
"expected": {
"hash": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
}
},
{
"fn": "hash",
"name": "payload_1",
"input": {
"payload": {
"k": "v"
}
},
"expected": {
"hash": "sha256:4be281edc378f1c5e5eb9c15f9dbf5a80da2977981850f93553d5d70b75f1626"
}
},
{
"fn": "hash",
"name": "payload_2",
"input": {
"payload": {
"task_id": "t1",
"status": "failed",
"count": 3
}
},
"expected": {
"hash": "sha256:fe19764aced3be8e70d5b35c3423a210f94a873df0730058b0a2062f3c84404f"
}
},
{
"fn": "hash",
"name": "payload_3",
"input": {
"payload": {
"nested": {
"a": [
1,
2,
"x"
]
},
"flag": true,
"nothing": null
}
},
"expected": {
"hash": "sha256:daf9cdd8709e0cc1aa339f36b52e53d02d2a3c755224c824a8128f54cbaaa197"
}
},
{
"fn": "hash",
"name": "payload_4",
"input": {
"payload": {
"text": "quote\" inside\\ back\nnewline\ttab"
}
},
"expected": {
"hash": "sha256:d78a4297a19bbe099320d1816966cc50559956065f787e6341c74ed8e2c5af5c"
}
},
{
"fn": "hash",
"name": "payload_5",
"input": {
"payload": {
"float_int": 1.0,
"float_frac": 2.5
}
},
"expected": {
"hash": "sha256:55e029dcab2234e9c7481bb60c72468fce31b7180a992b83145a36231addc0af"
}
}
]
}
+36
View File
@@ -0,0 +1,36 @@
package main
// truth_bus_test.go — factory batch 9 parity gate.
import (
"encoding/json"
"os"
"strings"
"testing"
)
func TestBusParity(t *testing.T) {
b, err := os.ReadFile("truth_bus.json")
if err != nil {
t.Fatalf("truth_bus.json missing: %v", err)
}
dec := json.NewDecoder(strings.NewReader(string(b)))
dec.UseNumber()
var doc struct {
Cases []struct {
Name string `json:"name"`
Input struct {
Payload map[string]interface{} `json:"payload"`
} `json:"input"`
Expected struct {
Hash string `json:"hash"`
} `json:"expected"`
} `json:"cases"`
}
dec.Decode(&doc)
for _, c := range doc.Cases {
if got := ContentHashEvent(c.Input.Payload); got != c.Expected.Hash {
t.Errorf("%s: hash\n got %q\nwant %q", c.Name, got, c.Expected.Hash)
}
}
}
Binary file not shown.
+46 -27
View File
@@ -4,10 +4,11 @@
// spools to JSONL for forge filing.
//
// Usage:
// failure-filer classify <subsystem> <error-message>
// failure-filer spool <subsystem> <error-message> <tier>
// failure-filer unspooled
// failure-filer mark-consumed <spool-id>
//
// failure-filer classify <subsystem> <error-message>
// failure-filer spool <subsystem> <error-message> <tier>
// failure-filer unspooled
// failure-filer mark-consumed <spool-id>
package main
import (
@@ -24,14 +25,14 @@ const ERROR_CLASS_MAX = 64
const EXCERPT_LEN = 256
type SpoolEntry struct {
ID string `json:"spool_id"`
Subsystem string `json:"subsystem"`
ErrorClass string `json:"error_class"`
Excerpt string `json:"excerpt"`
Tier int `json:"tier"`
Signature string `json:"signature"`
Consumed bool `json:"consumed"`
CreatedAt time.Time `json:"created_at"`
ID string `json:"spool_id"`
Subsystem string `json:"subsystem"`
ErrorClass string `json:"error_class"`
Excerpt string `json:"excerpt"`
Tier int `json:"tier"`
Signature string `json:"signature"`
Consumed bool `json:"consumed"`
CreatedAt time.Time `json:"created_at"`
}
type Result struct {
@@ -51,9 +52,13 @@ func spoolPath() string {
func loadSpool() []SpoolEntry {
var entries []SpoolEntry
data, err := os.ReadFile(spoolPath())
if err != nil { return entries }
if err != nil {
return entries
}
for _, line := range strings.Split(string(data), "\n") {
if strings.TrimSpace(line) == "" { continue }
if strings.TrimSpace(line) == "" {
continue
}
var e SpoolEntry
json.Unmarshal([]byte(line), &e)
entries = append(entries, e)
@@ -73,9 +78,13 @@ func saveSpool(entries []SpoolEntry) {
func errorClassOf(errMsg string) string {
tokens := strings.Fields(errMsg)
if len(tokens) == 0 { return "Unknown" }
if len(tokens) == 0 {
return "Unknown"
}
class := strings.TrimSuffix(tokens[0], ":")
if len(class) > ERROR_CLASS_MAX { class = class[:ERROR_CLASS_MAX] }
if len(class) > ERROR_CLASS_MAX {
class = class[:ERROR_CLASS_MAX]
}
return class
}
@@ -104,7 +113,9 @@ func redact(text string) string {
func excerpt(errMsg string, limit int) string {
r := redact(errMsg)
if len(r) > limit { r = r[:limit] }
if len(r) > limit {
r = r[:limit]
}
return r
}
@@ -127,10 +138,10 @@ func main() {
sub, cls := signatureOf(subsystem, errMsg)
out, _ := json.Marshal(map[string]interface{}{
"error_class": class, "subsystem": sub,
"signature": fmt.Sprintf("%s:%s", sub, cls),
"marker": markerFor(sub, cls),
"signature": fmt.Sprintf("%s:%s", sub, cls),
"marker": markerFor(sub, cls),
"tier_gated": tierGated(2),
"excerpt": excerpt(errMsg, EXCERPT_LEN),
"excerpt": excerpt(errMsg, EXCERPT_LEN),
})
fmt.Println(string(out))
@@ -144,12 +155,12 @@ func main() {
fmt.Sscanf(args[2], "%d", &tier)
_, cls := signatureOf(subsystem, errMsg)
entry := SpoolEntry{
ID: fmt.Sprintf("spool-%d", time.Now().UnixNano()%1000000),
ID: fmt.Sprintf("spool-%d", time.Now().UnixNano()%1000000),
Subsystem: subsystem, ErrorClass: cls,
Excerpt: excerpt(errMsg, EXCERPT_LEN),
Tier: tier,
Excerpt: excerpt(errMsg, EXCERPT_LEN),
Tier: tier,
Signature: fmt.Sprintf("%s:%s", subsystem, cls),
Consumed: false,
Consumed: false,
CreatedAt: time.Now().UTC(),
}
entries := loadSpool()
@@ -161,16 +172,24 @@ func main() {
case "unspooled":
var unspooled []SpoolEntry
for _, e := range loadSpool() {
if !e.Consumed { unspooled = append(unspooled, e) }
if !e.Consumed {
unspooled = append(unspooled, e)
}
}
out, _ := json.MarshalIndent(unspooled, "", " ")
fmt.Println(string(out))
case "mark-consumed":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: failure-filer mark-consumed <id>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: failure-filer mark-consumed <id>")
os.Exit(1)
}
entries := loadSpool()
for i := range entries {
if entries[i].ID == args[0] { entries[i].Consumed = true; break }
if entries[i].ID == args[0] {
entries[i].Consumed = true
break
}
}
saveSpool(entries)
fmt.Println("consumed:", args[0])
Binary file not shown.
+35 -15
View File
@@ -3,10 +3,11 @@
// hook firing, and the plugin registry.
//
// Usage:
// hook-engine fire <event> [--data <json>]
// hook-engine list
// hook-engine discover
// hook-engine tag <name> <key=value> ...
//
// hook-engine fire <event> [--data <json>]
// hook-engine list
// hook-engine discover
// hook-engine tag <name> <key=value> ...
package main
import (
@@ -24,8 +25,8 @@ type HookEntry struct {
}
type FunctionMeta struct {
Type string `json:"type"`
File string `json:"file"`
Type string `json:"type"`
File string `json:"file"`
Factors map[string]string `json:"factors"`
}
@@ -55,7 +56,9 @@ func functionsPath() string {
func loadHooks() []HookEntry {
var hooks []HookEntry
data, err := os.ReadFile(hooksPath())
if err != nil { return hooks }
if err != nil {
return hooks
}
json.Unmarshal(data, &hooks)
return hooks
}
@@ -69,7 +72,9 @@ func saveHooks(hooks []HookEntry) {
func loadFunctions() map[string]FunctionMeta {
functions := make(map[string]FunctionMeta)
data, err := os.ReadFile(functionsPath())
if err != nil { return functions }
if err != nil {
return functions
}
json.Unmarshal(data, &functions)
return functions
}
@@ -123,11 +128,21 @@ func main() {
data := ""
for i := 0; i < len(args); i++ {
switch args[i] {
case "--event": if i+1 < len(args) { event = args[i+1]; i++ }
case "--data": if i+1 < len(args) { data = args[i+1]; i++ }
case "--event":
if i+1 < len(args) {
event = args[i+1]
i++
}
case "--data":
if i+1 < len(args) {
data = args[i+1]
i++
}
}
}
if event == "" && len(args) > 0 { event = args[0] }
if event == "" && len(args) > 0 {
event = args[0]
}
fired := 0
for _, hook := range hooks {
if hook.Event == event {
@@ -147,18 +162,23 @@ func main() {
out, _ := json.Marshal(h)
fmt.Println(string(out))
}
if len(hooks) == 0 { fmt.Println("(no hooks registered)") }
if len(hooks) == 0 {
fmt.Println("(no hooks registered)")
}
case "discover":
// Scan src/rune/ for Python modules
entries, err := os.ReadDir("src/rune")
if err != nil { fmt.Println("(no src/rune directory)"); return }
if err != nil {
fmt.Println("(no src/rune directory)")
return
}
for _, e := range entries {
if strings.HasSuffix(e.Name(), ".py") && !strings.HasPrefix(e.Name(), "__") {
name := strings.TrimSuffix(e.Name(), ".py")
functions[name] = FunctionMeta{
Type: "script",
File: filepath.Join("src/rune", e.Name()),
Type: "script",
File: filepath.Join("src/rune", e.Name()),
Factors: make(map[string]string),
}
}
+113
View File
@@ -0,0 +1,113 @@
package main
// placement.go — factory batch 4: the placement mechanics of
// hook_engine.py (contract BUILDER-2026-10-07T23:06:18Z-ec6208).
// RecommendPlacement verbatim — the decision table is the oracle.
import "sort"
// Hook point / frequency / scope constants (verbatim).
const (
HookPreTurn = "pre-turn"
HookSystem = "system-prompt"
HookPostTurn = "post-turn"
HookIdle = "idle"
HookTimer = "timer"
HookEvent = "event"
FreqEveryTurn = "every-turn"
FreqOncePerSession = "once-per-session"
FreqScheduled = "scheduled"
FreqOnDemand = "on-demand"
ScopeEphemeral = "ephemeral"
ScopeSession = "session"
ScopePersistent = "persistent"
)
// Factors — the placement input (Python's dict.get access pattern).
type Factors map[string]interface{}
func (f Factors) bool(key string) bool {
v, _ := f[key].(bool)
return v
}
func (f Factors) str(key string) string {
v, _ := f[key].(string)
return v
}
// RecommendPlacement — the decision table verbatim. Hooks preserve
// append order (the oracle's list order is part of the shape).
func RecommendPlacement(name string, factors Factors) map[string]interface{} {
var hooks []string
frequency := FreqOnDemand
cacheable := false
cacheScope := ScopeEphemeral
// ── HOOK POINT ────────────────────────────────────────────────────
if factors.bool("output_dep") {
hooks = append(hooks, HookPostTurn)
}
if factors.bool("input_dep") && !factors.bool("output_dep") {
hooks = append(hooks, HookSystem)
}
if !factors.bool("input_dep") && !factors.bool("output_dep") {
hooks = append(hooks, HookSystem)
cacheable = true
}
if factors.str("side_effects") == "read-write" {
hooks = append(hooks, HookIdle)
hooks = append(hooks, HookTimer)
}
// ── FREQUENCY ─────────────────────────────────────────────────────
if (factors.bool("input_dep") && factors.bool("output_dep")) || factors.bool("input_dep") {
frequency = FreqEveryTurn
} else if factors.str("volatility") == "session" {
frequency = FreqOncePerSession
cacheable = true
} else if factors.str("volatility") == "per-turn" {
frequency = FreqEveryTurn
} else if factors.str("side_effects") == "read-write" {
frequency = FreqScheduled
}
// ── CACHE SCOPE ───────────────────────────────────────────────────
switch factors.str("scope") {
case "persistent":
cacheScope = ScopePersistent
case "session":
cacheScope = ScopeSession
default:
cacheScope = ScopeEphemeral
}
// ── CONCURRENCY / FAILURE MODE ────────────────────────────────────
canParallel := factors.bool("concurrent")
failureMode := factors.str("failure")
if failureMode == "" {
failureMode = "graceful"
}
contextBudget := 0
if v, has := factors["context_budget"].(float64); has {
contextBudget = int(v)
}
if hooks == nil {
hooks = []string{}
}
return map[string]interface{}{
"hooks": hooks,
"frequency": frequency,
"cacheable": cacheable,
"cache_scope": cacheScope,
"can_parallel": canParallel,
"failure_mode": failureMode,
"context_budget": contextBudget,
}
}
// sortedKeysHelper — retained for CLI output stability.
var _ = sort.Strings
+294
View File
@@ -0,0 +1,294 @@
{
"oracle": "src/rune/hook_engine.py recommend_placement (live)",
"generated": "2026-10-07",
"cases": [
{
"fn": "placement",
"name": "matrix_0",
"input": {
"factors": {
"output_dep": true
}
},
"expected": {
"hooks": [
"post-turn"
],
"frequency": "on-demand",
"cacheable": false,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_1",
"input": {
"factors": {
"input_dep": true
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "every-turn",
"cacheable": false,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_2",
"input": {
"factors": {
"input_dep": true,
"output_dep": true
}
},
"expected": {
"hooks": [
"post-turn"
],
"frequency": "every-turn",
"cacheable": false,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_3",
"input": {
"factors": {}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_4",
"input": {
"factors": {
"side_effects": "read-write"
}
},
"expected": {
"hooks": [
"system-prompt",
"idle",
"timer"
],
"frequency": "scheduled",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_5",
"input": {
"factors": {
"volatility": "session"
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "once-per-session",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_6",
"input": {
"factors": {
"volatility": "per-turn"
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "every-turn",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_7",
"input": {
"factors": {
"scope": "persistent"
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "persistent",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_8",
"input": {
"factors": {
"scope": "session"
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "session",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_9",
"input": {
"factors": {
"concurrent": true
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": true,
"failure_mode": "graceful",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_10",
"input": {
"factors": {
"failure": "fail-loud"
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "fail-loud",
"context_budget": 0
}
},
{
"fn": "placement",
"name": "matrix_11",
"input": {
"factors": {
"context_budget": 500
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "on-demand",
"cacheable": true,
"cache_scope": "ephemeral",
"can_parallel": false,
"failure_mode": "graceful",
"context_budget": 500
}
},
{
"fn": "placement",
"name": "matrix_12",
"input": {
"factors": {
"input_dep": true,
"scope": "session",
"concurrent": true,
"context_budget": 250
}
},
"expected": {
"hooks": [
"system-prompt"
],
"frequency": "every-turn",
"cacheable": false,
"cache_scope": "session",
"can_parallel": true,
"failure_mode": "graceful",
"context_budget": 250
}
},
{
"fn": "placement",
"name": "matrix_13",
"input": {
"factors": {
"side_effects": "read-write",
"failure": "fail-loud",
"scope": "persistent"
}
},
"expected": {
"hooks": [
"system-prompt",
"idle",
"timer"
],
"frequency": "scheduled",
"cacheable": true,
"cache_scope": "persistent",
"can_parallel": false,
"failure_mode": "fail-loud",
"context_budget": 0
}
}
]
}
@@ -0,0 +1,44 @@
package main
// truth_placement_test.go — factory batch 4 parity gate: the placement
// decision table replays truth_placement.json (live oracle — contract
// BUILDER-2026-10-07T23:06:18Z-ec6208).
import (
"encoding/json"
"os"
"testing"
)
func TestPlacementParity(t *testing.T) {
b, err := os.ReadFile("truth_placement.json")
if err != nil {
t.Fatalf("truth_placement.json missing: %v", err)
}
var doc struct {
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Input map[string]interface{} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal(b, &doc); err != nil {
t.Fatalf("unparseable: %v", err)
}
for _, c := range doc.Cases {
factorsAny, _ := c.Input["factors"].(map[string]interface{})
factors := Factors(factorsAny)
got := RecommendPlacement("hook", factors)
jsonEqH(t, c.Name, "placement", got, c.Expected)
}
}
func jsonEqH(t *testing.T, name, field string, got, want interface{}) {
t.Helper()
gb, _ := json.Marshal(got)
wb, _ := json.Marshal(want)
if string(gb) != string(wb) {
t.Errorf("%s: %s divergence:\n got %s\nwant %s", name, field, gb, wb)
}
}
Binary file not shown.
+44 -29
View File
@@ -4,8 +4,9 @@
// identical failures, max_iterations enforcement, and tool allowlist checking.
//
// Usage:
// local-tool-runtime run --model <model> --message <text> [--max-iterations N]
// local-tool-runtime status
//
// local-tool-runtime run --model <model> --message <text> [--max-iterations N]
// local-tool-runtime status
package main
import (
@@ -24,14 +25,14 @@ type ChatMessage struct {
}
type OperatorResponse struct {
Success bool `json:"success"`
Response string `json:"response,omitempty"`
Error string `json:"error,omitempty"`
Model string `json:"model,omitempty"`
ToolCalls int `json:"tool_calls,omitempty"`
Duration string `json:"duration,omitempty"`
Events []map[string]interface{} `json:"events,omitempty"`
Thinking []string `json:"thinking,omitempty"`
Success bool `json:"success"`
Response string `json:"response,omitempty"`
Error string `json:"error,omitempty"`
Model string `json:"model,omitempty"`
ToolCalls int `json:"tool_calls,omitempty"`
Duration string `json:"duration,omitempty"`
Events []map[string]interface{} `json:"events,omitempty"`
Thinking []string `json:"thinking,omitempty"`
}
type ToolRuntime struct {
@@ -131,7 +132,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
start := time.Now()
conversation := make([]ChatMessage, len(messages))
copy(conversation, messages)
cb := &CircuitBreaker{}
toolCalls := 0
var events []map[string]interface{}
@@ -141,7 +142,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
if err != nil {
return OperatorResponse{
Success: false, Error: err.Error(),
Model: rt.Model,
Model: rt.Model,
Duration: time.Since(start).Round(time.Millisecond).String(),
}
}
@@ -159,48 +160,48 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
if err := json.Unmarshal([]byte(strings.TrimPrefix(content, "TOOL_CALL:")), &call); err != nil {
conversation = append(conversation, resp)
conversation = append(conversation, ChatMessage{
Role: "user",
Role: "user",
Content: fmt.Sprintf("Error: invalid tool call format. Use TOOL_CALL:{\"operation\":\"...\",\"args\":{...}}"),
})
continue
}
// Check tool allowlist
if !rt.ToolNames[call.Operation] {
conversation = append(conversation, resp)
conversation = append(conversation, ChatMessage{
Role: "user",
Role: "user",
Content: fmt.Sprintf("Error: tool %q is not in the allowed list. Available: read_file, write_file, edit_file, list_directory, glob_files, grep_files, run_command, run_tests, lint_file, git_commit, git_diff, git_log, repo_map, read_persona, query_memory, check_growth, diagnose_behavior, find_capability", call.Operation),
})
continue
}
// Execute the tool
result := rt.executeTool(call.Operation, content)
toolCalls++
// Circuit breaker: check for consecutive identical failures
if warning, tripped := cb.RegisterFailure(call.Operation, call.Args); tripped {
return OperatorResponse{
Success: false,
Error: warning,
Model: rt.Model,
Success: false,
Error: warning,
Model: rt.Model,
ToolCalls: toolCalls,
Duration: time.Since(start).Round(time.Millisecond).String(),
Duration: time.Since(start).Round(time.Millisecond).String(),
}
}
events = append(events, map[string]interface{}{
"tool": call.Operation, "result": result,
})
conversation = append(conversation, resp)
conversation = append(conversation, ChatMessage{
Role: "user", Content: fmt.Sprintf("Tool result: %s", result),
})
continue
}
// No tool call — this is the final response
cb.RegisterSuccess()
return OperatorResponse{
@@ -210,7 +211,7 @@ func (rt *ToolRuntime) Run(messages []ChatMessage) OperatorResponse {
Events: events,
}
}
return OperatorResponse{
Success: false, Error: "max iterations exceeded",
Model: rt.Model, ToolCalls: toolCalls,
@@ -224,16 +225,30 @@ func main() {
os.Exit(1)
}
baseURL := os.Getenv("OLLAMA_URL")
if baseURL == "" { baseURL = "http://localhost:11434" }
if baseURL == "" {
baseURL = "http://localhost:11434"
}
model := "qwen2.5:3b"
message := ""
maxIter := 8
for i := 2; i < len(os.Args); i++ {
switch os.Args[i] {
case "--model": if i+1 < len(os.Args) { model = os.Args[i+1]; i++ }
case "--message": if i+1 < len(os.Args) { message = os.Args[i+1]; i++ }
case "--max-iterations": if i+1 < len(os.Args) { fmt.Sscanf(os.Args[i+1], "%d", &maxIter); i++ }
case "--model":
if i+1 < len(os.Args) {
model = os.Args[i+1]
i++
}
case "--message":
if i+1 < len(os.Args) {
message = os.Args[i+1]
i++
}
case "--max-iterations":
if i+1 < len(os.Args) {
fmt.Sscanf(os.Args[i+1], "%d", &maxIter)
i++
}
}
}
+50 -16
View File
@@ -3,12 +3,13 @@
// Uses modernc.org/sqlite (pure Go, no cgo).
//
// Usage:
// memory-ops add <text> [--importance <f>] [--topic <t>] [--source <s>]
// memory-ops search <query> [--limit N]
// memory-ops get <id>
// memory-ops wash <id>
// memory-ops supersede <id> <new-text>
// memory-ops stats
//
// memory-ops add <text> [--importance <f>] [--topic <t>] [--source <s>]
// memory-ops search <query> [--limit N]
// memory-ops get <id>
// memory-ops wash <id>
// memory-ops supersede <id> <new-text>
// memory-ops stats
package main
import (
@@ -37,7 +38,9 @@ func dbPath() string {
func connect() (*sql.DB, error) {
db, err := sql.Open("sqlite", dbPath())
if err != nil { return nil, err }
if err != nil {
return nil, err
}
db.Exec("PRAGMA journal_mode=WAL")
db.Exec("PRAGMA synchronous=NORMAL")
return db, nil
@@ -69,10 +72,25 @@ func main() {
source := ""
for i := 0; i < len(args); i++ {
switch args[i] {
case "--importance": if i+1 < len(args) { fmt.Sscanf(args[i+1], "%f", &importance); i++ }
case "--topic": if i+1 < len(args) { topic = args[i+1]; i++ }
case "--source": if i+1 < len(args) { source = args[i+1]; i++ }
default: if text == "" { text = args[i] }
case "--importance":
if i+1 < len(args) {
fmt.Sscanf(args[i+1], "%f", &importance)
i++
}
case "--topic":
if i+1 < len(args) {
topic = args[i+1]
i++
}
case "--source":
if i+1 < len(args) {
source = args[i+1]
i++
}
default:
if text == "" {
text = args[i]
}
}
}
if len(text) < 8 {
@@ -100,8 +118,15 @@ func main() {
limit := 5
for i := 0; i < len(args); i++ {
switch args[i] {
case "--limit": if i+1 < len(args) { fmt.Sscanf(args[i+1], "%d", &limit); i++ }
default: if query == "" { query = args[i] }
case "--limit":
if i+1 < len(args) {
fmt.Sscanf(args[i+1], "%d", &limit)
i++
}
default:
if query == "" {
query = args[i]
}
}
}
rows, err := db.Query(
@@ -128,7 +153,10 @@ func main() {
fmt.Println(string(out))
case "get":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: memory-ops get <id>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: memory-ops get <id>")
os.Exit(1)
}
var id int64
fmt.Sscanf(args[0], "%d", &id)
var text, topic, createdAt string
@@ -146,7 +174,10 @@ func main() {
fmt.Println(string(out))
case "wash":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: memory-ops wash <id>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: memory-ops wash <id>")
os.Exit(1)
}
var id int64
fmt.Sscanf(args[0], "%d", &id)
db.Exec("UPDATE entries SET wash_count = wash_count + 1, last_accessed = ? WHERE id = ?", nowISO(), id)
@@ -154,7 +185,10 @@ func main() {
fmt.Println(string(out))
case "supersede":
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: memory-ops supersede <id> <new-text>"); os.Exit(1) }
if len(args) < 2 {
fmt.Fprintln(os.Stderr, "usage: memory-ops supersede <id> <new-text>")
os.Exit(1)
}
var oldID int64
fmt.Sscanf(args[0], "%d", &oldID)
newText := args[1]
Binary file not shown.
+30
View File
@@ -0,0 +1,30 @@
package main
// fuzz_test.go — FTS query builder fuzz (polyglot gate contract).
import (
"strings"
"testing"
)
// FuzzFtsQueryConjunctive — deterministic; quote-free inputs produce
// balanced quotes. ORACLE-VERIFIED DIVERGENCE (pinned): the builder wraps
// terms in quotes but never escapes embedded ones — input containing '"'
// yields unbalanced output in the Python oracle too ('¼"' case). FTS5
// hardening is defect territory (the builder can inject match syntax);
// here we pin ORACLE behavior, not aspiration.
func FuzzFtsQueryConjunctive(f *testing.F) {
for _, s := range []string{"", "the and was", "one good term", "\"nested\" quotes",
"cap this one out with many many many many many many words here"} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
out := FtsQueryConjunctive(s)
if out != FtsQueryConjunctive(s) {
t.Fatalf("not deterministic for %q", s)
}
if !strings.Contains(s, "\"") && strings.Count(out, "\"")%2 != 0 {
t.Fatalf("unbalanced quotes on quote-free input %q: %q", s, out)
}
})
}
Binary file not shown.
+99
View File
@@ -0,0 +1,99 @@
package main
// recall_gate.go — batch 4: the recall() integration pieces of
// memory_store.py (contract BUILDER-2026-10-07T19:47:37Z-1cf1dc).
// DenseGate (the meta-judgement: vector proximity is not a relation),
// RankFusionEntries (the entries-side fusion — verified identical to the
// chunk-side RankFusion already ported; the docstring's raw-BM25 claim
// is NOT what the code does — the CODE min-max normalizes in ALL modes,
// and the code is the oracle), the abstain constants.
import (
"sort"
"strings"
)
// RecallBudget / RecallMinScore — the abstain constants (below the floor
// → abstain, don't inject distractors).
const (
RecallBudget = 8
RecallMinScore = 0.42
)
// DenseHit — one candidate dense match: (rowid, cosine).
type DenseHit struct {
RowID int64
Cos float64
}
// QueryContent — the query's significant words (len>3, not msStopwords).
func QueryContent(query string) []string {
var out []string
seen := map[string]bool{}
for _, t := range strings.Fields(strings.ToLower(query)) {
if len(t) > 3 && !msStopwords[t] && !seen[t] {
seen[t] = true
out = append(out, t)
}
}
return out
}
// DenseGate — the meta-judgement applied to the vec0 candidates.
// queryContent: significant query words. dfOf: document frequency
// (LIKE-substring count / total entries — the CALLER supplies counts;
// the gate owns the 0.05 distinctiveness threshold). A hit is kept iff
// it shares a DISTINCTIVE content word with the entry text; otherwise
// only when the query has no content words at all OR cos >= 0.80.
func DenseGate(hits []DenseHit, entryTexts map[int64]string, queryContent []string, dfOf func(word string) int, totalEntries int) []DenseHit {
out := []DenseHit{}
for _, h := range hits {
etxt := strings.ToLower(entryTexts[h.RowID])
distinctive := false
for _, w := range queryContent {
if strings.Contains(etxt, w) {
df := 0
if dfOf != nil {
df = dfOf(w)
}
total := totalEntries
if total < 1 {
total = 1
}
if float64(df)/float64(total) < 0.05 {
distinctive = true
break
}
}
}
if distinctive {
out = append(out, h)
} else if len(queryContent) == 0 || h.Cos >= 0.80 {
out = append(out, h)
}
}
return out
}
// RankFusionEntries — the entries-side fusion. VERIFIED identical to the
// chunk-side RankFusion (same file, memory_store.py:1297 vs the batch-2
// port): the code min-max normalizes the lexical-only branch in ALL
// modes. The docstring's raw-BM25 claim is stale — the CODE is the
// oracle. Reuse keeps one fusion implementation; this wrapper pins the
// parity for the recall() call shape.
func RankFusionEntries(dense, bm25 [][2]interface{}) map[string]interface{} {
return RankFusion(dense, bm25, RRFK)
}
// RankIDs — the sorted rank order (desc by score) for downstream SQL IN
// clauses (Python: list(ranks.keys()) is INSERTION order — the fusion's
// accumulation order, which SortStable ranking reproduces).
func RankIDs(fusion map[string]interface{}) []interface{} {
ranks, _ := fusion["ranks"].([]interface{})
return ranks
}
// sortedInsertion — retained reference: the fusion's rank list order IS
// the insertion order (accumulation), not score order. Documented for
// the SQL-IN parity note. (Unused call sites may sort explicitly.)
var _ = sort.Float64s
+194
View File
@@ -0,0 +1,194 @@
package main
// score.go — batch 3: the scoring/abstention kernel of memory_store.py
// (contract BUILDER-2026-10-07T18:57:06Z-c2429c). ScoreRecallRows (the
// metadata scoring + mode-specific abstention), PositionAware (the
// lost-in-the-middle re-rank).
import (
"fmt"
"sort"
"strings"
"time"
)
// RecencyHalfLife — RECENCY_HALF_LIFE (days).
const RecencyHalfLife = 30.0
// PositionAware — the two highest-relevance items go FIRST and LAST; the
// same items, only the order changes. No-op for < 3 items.
func PositionAware(top []map[string]interface{}) []map[string]interface{} {
if len(top) < 3 {
return top
}
s := make([]map[string]interface{}, len(top))
copy(s, top)
sorted := make([]map[string]interface{}, len(s))
copy(sorted, s)
sort.SliceStable(sorted, func(i, j int) bool {
return entryRelevance(sorted[i]) > entryRelevance(sorted[j])
})
out := make([]map[string]interface{}, 0, len(sorted))
out = append(out, sorted[0])
out = append(out, sorted[2:]...)
out = append(out, sorted[1])
return out
}
func entryRelevance(m map[string]interface{}) float64 {
v, _ := m["relevance"].(float64)
return v
}
// parseISO — Python fromisoformat with the Z→+00:00 swap; also accepts
// naive timestamps. Returns (time, ok).
func parseISO(s string) (time.Time, bool) {
if s == "" {
return time.Time{}, false
}
s = strings.Replace(s, "Z", "+00:00", 1)
layouts := []string{
"2006-01-02T15:04:05.999999-07:00",
"2006-01-02T15:04:05-07:00",
"2006-01-02T15:04:05.999999",
"2006-01-02T15:04:05",
}
for _, l := range layouts {
if t, err := time.Parse(l, s); err == nil {
return t, true
}
}
return time.Time{}, false
}
// ScoreRecallRows — rank-ordered metadata scoring + abstention ladder.
func ScoreRecallRows(fusion map[string]interface{}, rows []map[string]interface{}, dense, bm25 [][2]interface{}, budget int, minScore float64, nowStr string) []map[string]interface{} {
// ranks: the fusion dict's ranks — [[id, score], ...] pairs.
ranksList, _ := fusion["ranks"].([]interface{})
bestDense, _ := fusion["best_dense"].(float64)
mode, _ := fusion["mode"].(string)
byID := map[string]map[string]interface{}{}
for _, r := range rows {
id := pairString(r["id"])
byID[id] = r
}
type rankItem struct {
eid string
base float64
}
var items []rankItem
for _, raw := range ranksList {
pair, ok := raw.([]interface{})
if !ok || len(pair) != 2 {
continue
}
eid := pairString(pair[0])
base, _ := pair[1].(float64)
items = append(items, rankItem{eid, base})
}
// sorted(ranks.items(), key=lambda item: -item[1]) — stable desc.
sort.SliceStable(items, func(i, j int) bool { return items[i].base > items[j].base })
nowDT, _ := parseISO(nowStr)
scored := []map[string]interface{}{}
for _, it := range items {
row, has := byID[it.eid]
if !has {
continue
}
conf := 0.7
if v, ok := row["confidence"].(float64); ok && v != 0 {
conf = v
}
temp := 1.0
if v, ok := row["temperature"].(float64); ok && v != 0 {
temp = v
}
recency := 1.0
if la, ok := row["last_accessed"].(string); ok && la != "" {
if tLast, ok2 := parseISO(la); ok2 {
days := nowDT.Sub(tLast).Seconds() / 86400.0
if days >= 0 {
recency = RecencyHalfLife / (RecencyHalfLife + days)
}
}
// timestamp failure → recency stays 1.0 (the except path)
}
var relevance float64
if len(dense) > 0 {
relevance = it.base * (0.4 + 0.6*conf) * (0.5 + 0.5*temp) * (0.85 + 0.15*recency)
} else {
relevance = (it.base + 5.0) * (0.4 + 0.6*conf) * (0.5 + 0.5*temp) * (0.85 + 0.15*recency)
}
text, _ := row["text"].(string)
topic, _ := row["topic"].(string)
source, _ := row["source"].(string)
lastAccessed, _ := row["last_accessed"].(string)
scored = append(scored, map[string]interface{}{
"id": numericID(it.eid),
"text": text,
"importance": row["importance"],
"topic": topic,
"entities": row["entities"],
"source": source,
"last_accessed": lastAccessed,
"rrf": round4(it.base),
"confidence": round2(conf),
"temperature": round2(temp),
"relevance": round4(relevance),
"mode": mode,
})
}
if len(scored) == 0 {
return []map[string]interface{}{}
}
if len(scored) > budget {
scored = scored[:budget]
}
top := scored
if len(dense) == 0 && len(bm25) == 0 {
return []map[string]interface{}{}
}
if len(dense) == 0 {
maxRel := 0.0
for i, item := range top {
r := entryRelevance(item)
if i == 0 || r > maxRel {
maxRel = r
}
}
if maxRel < minScore {
return []map[string]interface{}{}
}
return top
}
if len(bm25) == 0 {
if bestDense < minScore {
return []map[string]interface{}{}
}
if bestDense >= 0.74 {
return PositionAware(top)
}
if len(dense) >= 2 {
dScores := make([]float64, 0, len(dense))
for _, p := range dense {
f, _ := p[1].(float64)
dScores = append(dScores, f)
}
sort.Float64s(dScores)
if dScores[len(dScores)-1]-dScores[len(dScores)-2] >= 0.08 {
return PositionAware(top)
}
return []map[string]interface{}{}
}
return PositionAware(MapReduce(top, 10))
}
if bestDense < minScore {
return []map[string]interface{}{}
}
return PositionAware(MapReduce(top, 10))
}
var _ = fmt.Sprintf // retained for parity annotations
@@ -0,0 +1,2 @@
go test fuzz v1
string("\xbc\"")
@@ -0,0 +1,2 @@
go test fuzz v1
string("\"")
+200
View File
@@ -0,0 +1,200 @@
{
"oracle": "src/rune/memory_store.py recall() dense gate + _py_rank_fusion",
"generated": "2026-10-07",
"fixture_df_note": "df via LIKE-substring over active entries; threshold 0.05",
"cases": [
{
"fn": "dense_gate",
"name": "distinctive_shared",
"input": {
"query": "worthiness gates",
"hits": [
[
1,
0.9
],
[
2,
0.85
]
],
"total": 8
},
"expected": {
"kept": [
[
1,
0.9
],
[
2,
0.85
]
],
"q_content": [
"gates",
"worthiness"
],
"df": {
"worthiness": 1,
"gates": 1
}
}
},
{
"fn": "dense_gate",
"name": "common_word_falls_back",
"input": {
"query": "black",
"hits": [
[
2,
0.86
],
[
3,
0.79
]
],
"total": 8
},
"expected": {
"kept": [
[
2,
0.86
]
],
"q_content": [
"black"
],
"df": {
"black": 2
}
}
},
{
"fn": "dense_gate",
"name": "strong_cos_no_share",
"input": {
"query": "unrelated query terms",
"hits": [
[
6,
0.91
],
[
4,
0.7
]
],
"total": 8
},
"expected": {
"kept": [
[
6,
0.91
]
],
"q_content": [
"query",
"terms",
"unrelated"
],
"df": {
"unrelated": 1,
"query": 0,
"terms": 0
}
}
},
{
"fn": "dense_gate",
"name": "no_content_words",
"input": {
"query": "the was and",
"hits": [
[
1,
0.6
],
[
6,
0.95
]
],
"total": 8
},
"expected": {
"kept": [
[
1,
0.6
],
[
6,
0.95
]
],
"q_content": [],
"df": {}
}
},
{
"fn": "fusion_identity",
"name": "entries_eq_chunks",
"input": {
"dense": [
[
1,
0.9
],
[
2,
0.8
]
],
"bm25": [
[
2,
10.0
],
[
3,
4.0
]
]
},
"expected": {
"fusion": {
"ranks": [
[
1,
0.0625
],
[
2,
0.1213235294117647
],
[
3,
0.058823529411764705
]
],
"best_dense": 0.9,
"mode": "hybrid"
}
}
},
{
"fn": "constants",
"name": "abstain",
"input": {},
"expected": {
"budget": 8,
"min_score": 0.42
}
}
]
}
+104
View File
@@ -0,0 +1,104 @@
package main
// truth_gate_test.go — memory-store batch 4 parity gate: the dense
// meta-judgement + fusion identity replay truth_gate.json (live oracle,
// fixture store — contract BUILDER-2026-10-07T19:47:37Z-1cf1dc).
import (
"encoding/json"
"os"
"testing"
)
func sortStringsW(s []string) {
for i := 1; i < len(s); i++ {
for j := i; j > 0 && s[j-1] > s[j]; j-- {
s[j-1], s[j] = s[j], s[j-1]
}
}
}
func TestGateParity(t *testing.T) {
b, err := os.ReadFile("truth_gate.json")
if err != nil {
t.Fatalf("truth_gate.json missing: %v", err)
}
var doc struct {
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Input map[string]interface{} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal(b, &doc); err != nil {
t.Fatalf("unparseable: %v", err)
}
// The fixture entry texts (the generator's store, shipped here — the
// truth inputs must carry their own state).
fixtureTexts := map[int64]string{
1: "the curator gates memory writes through worthiness",
2: "black holes bend light near the event horizon",
3: "black coffee in the morning keeps nick running",
4: "the spine rebuild parity proofs live in store",
5: "memory writes require the operator approval gate",
6: "unrelated filler text about weather patterns",
7: "curator provenance recovery from odysseus",
8: "another filler row to pad the document frequency",
}
// df table shipped per case (the oracle's LIKE counts).
for _, c := range doc.Cases {
switch c.Fn {
case "dense_gate":
query, _ := c.Input["query"].(string)
hitsAny, _ := c.Input["hits"].([]interface{})
var hits []DenseHit
for _, h := range hitsAny {
pair, _ := h.([]interface{})
id, _ := pair[0].(float64)
cos, _ := pair[1].(float64)
hits = append(hits, DenseHit{RowID: int64(id), Cos: cos})
}
dfAny, _ := c.Expected["df"].(map[string]interface{})
dfOf := func(word string) int {
v, ok := dfAny[word]
if !ok {
return 0
}
f, _ := v.(float64)
return int(f)
}
total := int(c.Input["total"].(float64))
qc := QueryContent(query)
wantQAny, _ := c.Expected["q_content"].([]interface{})
var wantQ []string
for _, w := range wantQAny {
s, _ := w.(string)
wantQ = append(wantQ, s)
}
// The truth column ships the q_content SORTED (generator's
// json.dumps of a set); compare sorted-to-sorted.
sortStringsW(qc)
jsonEq(t, c.Name, "q_content", qc, wantQ)
got := DenseGate(hits, fixtureTexts, qc, dfOf, total)
wantArr, _ := c.Expected["kept"].([]interface{})
var want []DenseHit
for _, h := range wantArr {
pair, _ := h.([]interface{})
id, _ := pair[0].(float64)
cos, _ := pair[1].(float64)
want = append(want, DenseHit{RowID: int64(id), Cos: cos})
}
jsonEq(t, c.Name, "kept", got, want)
case "fusion_identity":
dense := pairList(c.Input["dense"])
bm25 := pairList(c.Input["bm25"])
got := RankFusionEntries(dense, bm25)
want, _ := c.Expected["fusion"].(map[string]interface{})
jsonEq(t, c.Name, "fusion", got, want)
case "constants":
jsonEq(t, c.Name, "budget", RecallBudget, c.Expected["budget"])
jsonEq(t, c.Name, "min_score", RecallMinScore, c.Expected["min_score"])
}
}
}
+681
View File
@@ -0,0 +1,681 @@
{
"oracle": "src/rune/memory_store.py _py_score_recall_rows",
"generated": "2026-10-07",
"cases": [
{
"fn": "score",
"name": "hybrid",
"input": {
"fusion": {
"ranks": [
[
1,
0.12
],
[
2,
0.11
],
[
3,
0.1
],
[
4,
0.09
]
],
"best_dense": 0.8,
"mode": "hybrid"
},
"rows": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 0.8,
"last_accessed": "2026-05-01T10:00:00"
},
{
"id": 4,
"text": "entry 4 body",
"importance": 0.53,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 1.2,
"last_accessed": null
}
],
"dense": [
[
1,
0.8
],
[
2,
0.7
],
[
3,
0.6
]
],
"bm25": [
[
2,
10.0
],
[
4,
5.0
],
[
1,
2.0
]
],
"budget": 3,
"min_score": 0.3,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-10-07T18:00:00",
"rrf": 0.12,
"confidence": 0.9,
"temperature": 1.2,
"relevance": 0.1241,
"mode": "hybrid"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-09-01T10:00:00",
"rrf": 0.11,
"confidence": 0.6,
"temperature": 0.8,
"relevance": 0.0691,
"mode": "hybrid"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-05-01T10:00:00",
"rrf": 0.1,
"confidence": 0.9,
"temperature": 0.8,
"relevance": 0.0739,
"mode": "hybrid"
}
]
}
},
{
"fn": "score",
"name": "dense_only_high_conf",
"input": {
"fusion": {
"ranks": [
[
1,
0.06
],
[
2,
0.055
],
[
3,
0.05
]
],
"best_dense": 0.8,
"mode": "dense-only"
},
"rows": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 0.8,
"last_accessed": "2026-05-01T10:00:00"
}
],
"dense": [
[
1,
0.8
],
[
2,
0.7
],
[
3,
0.6
]
],
"bm25": [],
"budget": 5,
"min_score": 0.3,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-10-07T18:00:00",
"rrf": 0.06,
"confidence": 0.9,
"temperature": 1.2,
"relevance": 0.062,
"mode": "dense-only"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-09-01T10:00:00",
"rrf": 0.055,
"confidence": 0.6,
"temperature": 0.8,
"relevance": 0.0345,
"mode": "dense-only"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-05-01T10:00:00",
"rrf": 0.05,
"confidence": 0.9,
"temperature": 0.8,
"relevance": 0.037,
"mode": "dense-only"
}
]
}
},
{
"fn": "score",
"name": "dense_only_gap_abstain",
"input": {
"fusion": {
"ranks": [
[
1,
0.06
],
[
2,
0.055
],
[
3,
0.05
]
],
"best_dense": 0.8,
"mode": "dense-only"
},
"rows": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 0.8,
"last_accessed": "2026-05-01T10:00:00"
}
],
"dense": [
[
1,
0.8
],
[
2,
0.75
]
],
"bm25": [],
"budget": 5,
"min_score": 0.3,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-10-07T18:00:00",
"rrf": 0.06,
"confidence": 0.9,
"temperature": 1.2,
"relevance": 0.062,
"mode": "dense-only"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-09-01T10:00:00",
"rrf": 0.055,
"confidence": 0.6,
"temperature": 0.8,
"relevance": 0.0345,
"mode": "dense-only"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-05-01T10:00:00",
"rrf": 0.05,
"confidence": 0.9,
"temperature": 0.8,
"relevance": 0.037,
"mode": "dense-only"
}
]
}
},
{
"fn": "score",
"name": "dense_only_min_score",
"input": {
"fusion": {
"ranks": [
[
1,
0.06
],
[
2,
0.055
],
[
3,
0.05
]
],
"best_dense": 0.8,
"mode": "dense-only"
},
"rows": [
{
"id": 1,
"text": "entry 1 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 2,
"text": "entry 2 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
},
{
"id": 3,
"text": "entry 3 body",
"importance": 0.52,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 0.8,
"last_accessed": "2026-05-01T10:00:00"
}
],
"dense": [
[
1,
0.8
],
[
2,
0.7
],
[
3,
0.6
]
],
"bm25": [],
"budget": 5,
"min_score": 0.9,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": []
}
},
{
"fn": "score",
"name": "lexical_only_gate",
"input": {
"fusion": {
"ranks": [
[
2,
0.9
],
[
4,
0.7
]
],
"best_dense": 0.0,
"mode": "lexical-only"
},
"rows": [
{
"id": 2,
"text": "entry 2 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 4,
"text": "entry 4 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
}
],
"dense": [],
"bm25": [
[
2,
10.0
],
[
4,
5.0
],
[
1,
2.0
]
],
"budget": 5,
"min_score": 1.0,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": [
{
"id": 2,
"text": "entry 2 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-10-07T18:00:00",
"rrf": 0.9,
"confidence": 0.9,
"temperature": 1.2,
"relevance": 6.0994,
"mode": "lexical-only"
},
{
"id": 4,
"text": "entry 4 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"last_accessed": "2026-09-01T10:00:00",
"rrf": 0.7,
"confidence": 0.6,
"temperature": 0.8,
"relevance": 3.5783,
"mode": "lexical-only"
}
]
}
},
{
"fn": "score",
"name": "neither",
"input": {
"fusion": {
"ranks": [
[
2,
0.9
],
[
4,
0.7
]
],
"best_dense": 0.0,
"mode": "lexical-only"
},
"rows": [
{
"id": 2,
"text": "entry 2 body",
"importance": 0.5,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.9,
"temperature": 1.2,
"last_accessed": "2026-10-07T18:00:00"
},
{
"id": 4,
"text": "entry 4 body",
"importance": 0.51,
"topic": "project",
"entities": [
"a"
],
"source": "fixture",
"confidence": 0.6,
"temperature": 0.8,
"last_accessed": "2026-09-01T10:00:00"
}
],
"dense": [],
"bm25": [],
"budget": 5,
"min_score": 0.3,
"now": "2026-10-07T18:58:00"
},
"expected": {
"scored": []
}
}
]
}
@@ -0,0 +1,57 @@
package main
// truth_score_test.go — memory-store batch 3 parity gate: the scoring
// kernel replays truth_score.json (live _py_score_recall_rows — contract
// BUILDER-2026-10-07T18:57:06Z-c2429c).
import (
"encoding/json"
"fmt"
"os"
"testing"
)
func TestScoreParity(t *testing.T) {
b, err := os.ReadFile("truth_score.json")
if err != nil {
t.Fatalf("truth_score.json missing: %v", err)
}
var doc struct {
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Input map[string]interface{} `json:"input"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
if err := json.Unmarshal(b, &doc); err != nil {
t.Fatalf("unparseable: %v", err)
}
for _, c := range doc.Cases {
fusion, _ := c.Input["fusion"].(map[string]interface{})
rows := objList(c.Input["rows"])
dense := pairList(c.Input["dense"])
bm25 := pairList(c.Input["bm25"])
budget := int(c.Input["budget"].(float64))
minScore := c.Input["min_score"].(float64)
nowStr, _ := c.Input["now"].(string)
got := ScoreRecallRows(fusion, rows, dense, bm25, budget, minScore, nowStr)
wantArr, _ := c.Expected["scored"].([]interface{})
if len(got) != len(wantArr) {
gb, _ := json.Marshal(got)
wb, _ := json.Marshal(wantArr)
t.Errorf("%s: scored = %d, want %d\n got %s\nwant %s",
c.Name, len(got), len(wantArr), gb, wb)
continue
}
for i, w := range wantArr {
want, _ := w.(map[string]interface{})
jsonEq(t, c.Name, field("scored[%d]", i), got[i], want)
}
}
}
// field — formatted comparison label.
func field(format string, i int) string {
return fmt.Sprintf(format, i)
}
+23 -12
View File
@@ -3,14 +3,15 @@
// queues messages, approves/rejects/executes.
//
// Usage:
// message-queue add <message> [--channel <ch>] [--task-id <id>]
// message-queue list [--status pending|approved|executed|rejected]
// message-queue approve <id>
// message-queue approve-all
// message-queue reject <id>
// message-queue clear
// message-queue mark-executed <id>
// message-queue detect <message>
//
// message-queue add <message> [--channel <ch>] [--task-id <id>]
// message-queue list [--status pending|approved|executed|rejected]
// message-queue approve <id>
// message-queue approve-all
// message-queue reject <id>
// message-queue clear
// message-queue mark-executed <id>
// message-queue detect <message>
package main
import (
@@ -108,11 +109,19 @@ func main() {
for i := 0; i < len(args); i++ {
switch args[i] {
case "--channel":
if i+1 < len(args) { channel = args[i+1]; i++ }
if i+1 < len(args) {
channel = args[i+1]
i++
}
case "--task-id":
if i+1 < len(args) { taskID = args[i+1]; i++ }
if i+1 < len(args) {
taskID = args[i+1]
i++
}
default:
if msg == "" { msg = args[i] }
if msg == "" {
msg = args[i]
}
}
}
qm := QueuedMessage{
@@ -130,7 +139,9 @@ func main() {
case "list":
status := ""
if len(args) > 1 && args[0] == "--status" { status = args[1] }
if len(args) > 1 && args[0] == "--status" {
status = args[1]
}
for _, m := range q.Messages {
if status == "" || m.Status == status {
out, _ := json.Marshal(m)
Binary file not shown.
+45 -22
View File
@@ -3,11 +3,12 @@
// capabilities, fires events to registered hooks.
//
// Usage:
// microkernel register <manifest-json>
// microkernel unregister <name>
// microkernel resolve <capability>
// microkernel fire <event> [--data <json>]
// microkernel status
//
// microkernel register <manifest-json>
// microkernel unregister <name>
// microkernel resolve <capability>
// microkernel fire <event> [--data <json>]
// microkernel status
package main
import (
@@ -25,7 +26,7 @@ type PluginManifest struct {
Version string `json:"version"`
Description string `json:"description"`
Capabilities []string `json:"capabilities"`
Hooks map[string]string `json:"hooks"`
Hooks map[string]interface{} `json:"hooks"`
Dependencies []string `json:"dependencies"`
Priority int `json:"priority"`
AutoActivate bool `json:"auto_activate"`
@@ -38,9 +39,9 @@ type PluginEntry struct {
}
type Registry struct {
Plugins map[string]PluginEntry `json:"plugins"`
Capabilities map[string][]string `json:"capabilities"`
Hooks map[string][]string `json:"hooks"`
Plugins map[string]PluginEntry `json:"plugins"`
Capabilities map[string][]string `json:"capabilities"`
Hooks map[string][]string `json:"hooks"`
}
func registryPath() string {
@@ -58,7 +59,9 @@ func loadRegistry() Registry {
Hooks: make(map[string][]string),
}
data, err := os.ReadFile(registryPath())
if err != nil { return r }
if err != nil {
return r
}
json.Unmarshal(data, &r)
return r
}
@@ -93,9 +96,9 @@ func main() {
}
manifest.AutoActivate = true
registry.Plugins[manifest.Name] = PluginEntry{
Manifest: manifest,
Manifest: manifest,
RegisteredAt: time.Now().UTC().Format("2006-01-02T15:04:05Z"),
Active: manifest.AutoActivate,
Active: manifest.AutoActivate,
}
for _, cap := range manifest.Capabilities {
registry.Capabilities[cap] = append(registry.Capabilities[cap], manifest.Name)
@@ -110,21 +113,31 @@ func main() {
fmt.Println(string(out))
case "unregister":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: microkernel unregister <name>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: microkernel unregister <name>")
os.Exit(1)
}
name := args[0]
entry, ok := registry.Plugins[name]
if !ok { fmt.Printf(`{"error": "plugin '%s' not registered"}`+"\n", name); return }
if !ok {
fmt.Printf(`{"error": "plugin '%s' not registered"}`+"\n", name)
return
}
for cap, providers := range registry.Capabilities {
var filtered []string
for _, p := range providers {
if p != name { filtered = append(filtered, p) }
if p != name {
filtered = append(filtered, p)
}
}
registry.Capabilities[cap] = filtered
}
for event, listeners := range registry.Hooks {
var filtered []string
for _, l := range listeners {
if l != name { filtered = append(filtered, l) }
if l != name {
filtered = append(filtered, l)
}
}
registry.Hooks[event] = filtered
}
@@ -134,7 +147,10 @@ func main() {
fmt.Printf(`{"status": "unregistered", "name": "%s"}`+"\n", name)
case "resolve":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: microkernel resolve <capability>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: microkernel resolve <capability>")
os.Exit(1)
}
providers, ok := registry.Capabilities[args[0]]
if !ok || len(providers) == 0 {
fmt.Println("null")
@@ -160,9 +176,14 @@ func main() {
case "fire":
event := ""
data := ""
if len(args) > 0 { event = args[0] }
if len(args) > 0 {
event = args[0]
}
for i := 1; i < len(args); i++ {
if args[i] == "--data" && i+1 < len(args) { data = args[i+1]; i++ }
if args[i] == "--data" && i+1 < len(args) {
data = args[i+1]
i++
}
}
listeners, ok := registry.Hooks[event]
if !ok || len(listeners) == 0 {
@@ -179,11 +200,13 @@ func main() {
case "status":
plugins := make([]string, 0)
for name := range registry.Plugins { plugins = append(plugins, name) }
for name := range registry.Plugins {
plugins = append(plugins, name)
}
out, _ := json.MarshalIndent(map[string]interface{}{
"plugins": plugins,
"plugins": plugins,
"capabilities_count": len(registry.Capabilities),
"hooks_count": len(registry.Hooks),
"hooks_count": len(registry.Hooks),
}, "", " ")
fmt.Println(string(out))
Binary file not shown.
+139
View File
@@ -0,0 +1,139 @@
package main
// microkernel.go — factory batch 8: the plugin-registry primitives of
// microkernel.py (register/unregister/resolve — the deterministic index
// operations; file I/O stays reactive).
import (
"encoding/json"
"sort"
)
// Register — register a plugin from its manifest (map form, decoded like
// the oracle receives it). Error text parity: "manifest must have a 'name'".
func Register(reg *Registry, manifest map[string]interface{}, nowISO string) (PluginEntry, error) {
name, _ := manifest["name"].(string)
if name == "" {
return PluginEntry{}, &manifestError{"manifest must have a 'name'"}
}
active := true
if v, has := manifest["auto_activate"]; has {
if b, ok := v.(bool); ok {
active = b
}
}
entry := PluginEntry{
Manifest: manifestToStruct(manifest),
RegisteredAt: nowISO,
Active: active,
}
reg.Plugins[name] = entry
if caps, ok := manifest["capabilities"].([]interface{}); ok {
for _, raw := range caps {
cap, _ := raw.(string)
if cap == "" {
continue
}
list := reg.Capabilities[cap]
found := false
for _, n := range list {
if n == name {
found = true
break
}
}
if !found {
reg.Capabilities[cap] = append(list, name)
}
}
}
if hooks, ok := manifest["hooks"].(map[string]interface{}); ok {
names := make([]string, 0, len(hooks))
for ev := range hooks {
names = append(names, ev)
}
sort.Strings(names)
for _, ev := range names {
if enabled, _ := hooks[ev].(bool); enabled {
list := reg.Hooks[ev]
found := false
for _, n := range list {
if n == name {
found = true
break
}
}
if !found {
reg.Hooks[ev] = append(list, name)
}
}
}
}
return entry, nil
}
// manifestToStruct — map manifest → the typed PluginManifest.
func manifestToStruct(m map[string]interface{}) PluginManifest {
b, _ := json.Marshal(m)
var pm PluginManifest
json.Unmarshal(b, &pm)
return pm
}
type manifestError struct{ msg string }
func (e *manifestError) Error() string { return e.msg }
// Unregister — remove from capability + hook indexes, delete the plugin.
// Error: "plugin '{name}' not registered".
func Unregister(reg *Registry, name string) error {
if _, has := reg.Plugins[name]; !has {
return &manifestError{"plugin '" + name + "' not registered"}
}
for cap, providers := range reg.Capabilities {
for i, n := range providers {
if n == name {
reg.Capabilities[cap] = append(providers[:i], providers[i+1:]...)
break
}
}
}
for ev, listeners := range reg.Hooks {
for i, n := range listeners {
if n == name {
reg.Hooks[ev] = append(listeners[:i], listeners[i+1:]...)
break
}
}
}
delete(reg.Plugins, name)
return nil
}
// Resolve — highest-priority (lower = higher) ACTIVE plugin for a
// capability; "" when none. Ties: Python's sort is stable — the first
// candidate in index order wins.
func Resolve(reg *Registry, capability string) string {
candidates := reg.Capabilities[capability]
if len(candidates) == 0 {
return ""
}
type cand struct {
name string
priority int
}
var active []cand
for _, name := range candidates {
plugin, has := reg.Plugins[name]
if !has || !plugin.Active {
continue
}
priority := plugin.Manifest.Priority
active = append(active, cand{name, priority})
}
if len(active) == 0 {
return ""
}
sort.SliceStable(active, func(i, j int) bool { return active[i].priority < active[j].priority })
return active[0].name
}
+119
View File
@@ -0,0 +1,119 @@
{
"oracle": "src/rune/microkernel.py (live)",
"generated": "2026-10-07",
"frozen_now": "2026-10-07T23:35:00",
"cases": [
{
"fn": "state",
"name": "after_registers",
"input": {},
"expected": {
"plugins": {
"alpha": {
"active": true,
"registered_at": "2026-10-07T23:35:00"
},
"beta": {
"active": true,
"registered_at": "2026-10-07T23:35:00"
},
"gamma": {
"active": false,
"registered_at": "2026-10-07T23:35:00"
},
"delta": {
"active": true,
"registered_at": "2026-10-07T23:35:00"
}
},
"capabilities": {
"cap.a": [
"alpha",
"beta",
"gamma"
]
},
"hooks": {
"pre-turn": [
"delta"
]
}
}
},
{
"fn": "resolve",
"name": "priority_active",
"input": {
"capability": "cap.a"
},
"expected": {
"resolved": "beta"
}
},
{
"fn": "resolve",
"name": "unknown_cap",
"input": {
"capability": "cap.nope"
},
"expected": {
"resolved": null
}
},
{
"fn": "state",
"name": "after_unregister",
"input": {},
"expected": {
"plugins": {
"alpha": {
"active": true,
"registered_at": "2026-10-07T23:35:00"
},
"gamma": {
"active": false,
"registered_at": "2026-10-07T23:35:00"
},
"delta": {
"active": true,
"registered_at": "2026-10-07T23:35:00"
}
},
"capabilities": {
"cap.a": [
"alpha",
"gamma"
]
},
"hooks": {
"pre-turn": [
"delta"
]
}
}
},
{
"fn": "resolve",
"name": "after_unregister",
"input": {
"capability": "cap.a"
},
"expected": {
"resolved": "alpha"
}
},
{
"fn": "errors",
"name": "shapes",
"input": {},
"expected": {
"register_empty": {
"error": "manifest must have a 'name'"
},
"unregister_unknown": {
"error": "plugin 'nope' not registered"
}
}
}
]
}
@@ -0,0 +1,96 @@
package main
// truth_microkernel_test.go — factory batch 8 parity gate.
import (
"encoding/json"
"os"
"testing"
)
func TestMicrokernelParity(t *testing.T) {
b, err := os.ReadFile("truth_microkernel.json")
if err != nil {
t.Fatalf("truth_microkernel.json missing: %v", err)
}
var doc struct {
FrozenNow string `json:"frozen_now"`
Cases []struct {
Fn string `json:"fn"`
Name string `json:"name"`
Expected map[string]interface{} `json:"expected"`
} `json:"cases"`
}
json.Unmarshal(b, &doc)
reg := loadRegistry()
regp := &reg
for _, c := range doc.Cases {
switch c.Name {
case "after_registers":
// replay: the four registers
_, _ = Register(&reg, map[string]interface{}{"name": "alpha", "capabilities": []interface{}{"cap.a"}, "priority": 50.0}, doc.FrozenNow)
_, _ = Register(&reg, map[string]interface{}{"name": "beta", "capabilities": []interface{}{"cap.a"}, "priority": 10.0}, doc.FrozenNow)
_, _ = Register(&reg, map[string]interface{}{"name": "gamma", "capabilities": []interface{}{"cap.a"}, "priority": 10.0, "auto_activate": false}, doc.FrozenNow)
_, _ = Register(&reg, map[string]interface{}{"name": "delta", "hooks": map[string]interface{}{"pre-turn": true, "post-turn": false}}, doc.FrozenNow)
jsonEqM(t, c.Name, "state", regShape(regp), c.Expected)
case "priority_active":
if got := Resolve(&reg, "cap.a"); got != strM(c.Expected["resolved"]) {
t.Errorf("%s: resolve got %q want %q", c.Name, got, strM(c.Expected["resolved"]))
}
case "unknown_cap":
if got := Resolve(&reg, "cap.nope"); got != strM(c.Expected["resolved"]) {
t.Errorf("%s: resolve got %q want %v", c.Name, got, c.Expected["resolved"])
}
case "after_unregister":
if _, isResolve := c.Expected["resolved"]; isResolve {
if got := Resolve(&reg, "cap.a"); got != strM(c.Expected["resolved"]) {
t.Errorf("%s: resolve got %q want %q", c.Name, got, strM(c.Expected["resolved"]))
}
continue
}
_ = Unregister(&reg, "beta")
jsonEqM(t, c.Name, "state", regShape(regp), c.Expected)
case "shapes":
_, err1 := Register(&reg, map[string]interface{}{}, doc.FrozenNow)
err2 := Unregister(&reg, "nope")
jsonEqM(t, c.Name, "register_empty", errShape(err1), c.Expected["register_empty"])
jsonEqM(t, c.Name, "unregister_unknown", errShape(err2), c.Expected["unregister_unknown"])
}
}
}
// regShape — the persisted-shape projection (active + registered_at only,
// matching the oracle's snapshot).
func regShape(reg *Registry) map[string]interface{} {
plugins := map[string]interface{}{}
for k, v := range reg.Plugins {
plugins[k] = map[string]interface{}{"active": v.Active, "registered_at": v.RegisteredAt}
}
return map[string]interface{}{
"plugins": plugins,
"capabilities": reg.Capabilities,
"hooks": reg.Hooks,
}
}
func errShape(err error) map[string]interface{} {
if err == nil {
return map[string]interface{}{}
}
return map[string]interface{}{"error": err.Error()}
}
func strM(v interface{}) string {
s, _ := v.(string)
return s
}
func jsonEqM(t *testing.T, name, field string, got, want interface{}) {
t.Helper()
gb, _ := json.Marshal(got)
wb, _ := json.Marshal(want)
if string(gb) != string(wb) {
t.Errorf("%s: %s divergence:\n got %s\nwant %s", name, field, gb, wb)
}
}
+62 -28
View File
@@ -6,10 +6,10 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"bytes"
"os"
"strings"
"sync"
@@ -30,8 +30,8 @@ type ChatMessage struct {
}
type ModelInfo struct {
Name string `json:"name"`
ContextLen int `json:"context_length"`
Name string `json:"name"`
ContextLen int `json:"context_length"`
Capabilities []string `json:"capabilities"`
}
@@ -50,10 +50,14 @@ func (o *OllamaProvider) Chat(model string, messages []ChatMessage, options map[
body := map[string]interface{}{
"model": model, "messages": messages, "stream": false,
}
for k, v := range options { body[k] = v }
for k, v := range options {
body[k] = v
}
data, _ := json.Marshal(body)
resp, err := o.Client.Post(o.BaseURL+"/api/chat", "application/json", bytes.NewReader(data))
if err != nil { return ChatMessage{}, fmt.Errorf("ollama chat: %w", err) }
if err != nil {
return ChatMessage{}, fmt.Errorf("ollama chat: %w", err)
}
defer resp.Body.Close()
var result struct {
Message ChatMessage `json:"message"`
@@ -65,42 +69,50 @@ func (o *OllamaProvider) Chat(model string, messages []ChatMessage, options map[
func (o *OllamaProvider) Show(model string) (ModelInfo, error) {
data, _ := json.Marshal(map[string]string{"name": model})
resp, err := o.Client.Post(o.BaseURL+"/api/show", "application/json", bytes.NewReader(data))
if err != nil { return ModelInfo{}, err }
if err != nil {
return ModelInfo{}, err
}
defer resp.Body.Close()
var result struct {
Details struct {
ParameterSize string `json:"parameter_size"`
Family string `json:"family"`
ParameterSize string `json:"parameter_size"`
Family string `json:"family"`
} `json:"details"`
ContextLength int `json:"context_length"`
}
json.NewDecoder(resp.Body).Decode(&result)
return ModelInfo{
Name: model,
ContextLen: result.ContextLength,
Name: model,
ContextLen: result.ContextLength,
Capabilities: []string{result.Details.Family, result.Details.ParameterSize},
}, nil
}
func (o *OllamaProvider) ListModels() ([]string, error) {
resp, err := o.Client.Get(o.BaseURL + "/api/tags")
if err != nil { return nil, err }
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Models []struct { Name string `json:"name"` } `json:"models"`
Models []struct {
Name string `json:"name"`
} `json:"models"`
}
json.NewDecoder(resp.Body).Decode(&result)
var names []string
for _, m := range result.Models { names = append(names, m.Name) }
for _, m := range result.Models {
names = append(names, m.Name)
}
return names, nil
}
// ── Model routing ──
type ModelProfile struct {
Name string `json:"name"`
Provider string `json:"provider"`
ContextLen int `json:"context_length"`
Name string `json:"name"`
Provider string `json:"provider"`
ContextLen int `json:"context_length"`
Capabilities []string `json:"capabilities"`
}
@@ -127,11 +139,11 @@ func (r *ModelRouter) Route(taskDescription string) string {
// ── Provider budget ──
type BudgetEntry struct {
Provider string `json:"provider"`
MonthlyUsed float64 `json:"monthly_used"`
Provider string `json:"provider"`
MonthlyUsed float64 `json:"monthly_used"`
MonthlyLimit float64 `json:"monthly_limit"`
TokensUsed int64 `json:"tokens_used"`
TokenLimit int64 `json:"token_limit"`
TokensUsed int64 `json:"tokens_used"`
TokenLimit int64 `json:"token_limit"`
}
type ProviderBudget struct {
@@ -142,7 +154,9 @@ type ProviderBudget struct {
func (b *ProviderBudget) Record(provider string, tokens int64) {
b.mu.Lock()
defer b.mu.Unlock()
if b.Providers == nil { b.Providers = make(map[string]BudgetEntry) }
if b.Providers == nil {
b.Providers = make(map[string]BudgetEntry)
}
e := b.Providers[provider]
e.TokensUsed += tokens
b.Providers[provider] = e
@@ -155,7 +169,9 @@ func main() {
}
baseURL := os.Getenv("OLLAMA_URL")
if baseURL == "" { baseURL = "http://localhost:11434" }
if baseURL == "" {
baseURL = "http://localhost:11434"
}
provider := NewOllamaProvider(baseURL)
cmd := os.Args[1]
@@ -163,29 +179,47 @@ func main() {
switch cmd {
case "chat":
if len(args) < 2 { fmt.Fprintln(os.Stderr, "usage: model-connect chat <model> <message>"); os.Exit(1) }
if len(args) < 2 {
fmt.Fprintln(os.Stderr, "usage: model-connect chat <model> <message>")
os.Exit(1)
}
model, message := args[0], args[1]
messages := []ChatMessage{{Role: "user", Content: message}}
resp, err := provider.Chat(model, messages, nil)
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
out, _ := json.MarshalIndent(resp, "", " ")
fmt.Println(string(out))
case "list":
models, err := provider.ListModels()
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
out, _ := json.MarshalIndent(models, "", " ")
fmt.Println(string(out))
case "show":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: model-connect show <model>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: model-connect show <model>")
os.Exit(1)
}
info, err := provider.Show(args[0])
if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err); os.Exit(1) }
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
out, _ := json.MarshalIndent(info, "", " ")
fmt.Println(string(out))
case "route":
if len(args) < 1 { fmt.Fprintln(os.Stderr, "usage: model-connect route <task>"); os.Exit(1) }
if len(args) < 1 {
fmt.Fprintln(os.Stderr, "usage: model-connect route <task>")
os.Exit(1)
}
router := &ModelRouter{
Profiles: map[string]ModelProfile{
"qwen2.5:3b": {Name: "qwen2.5:3b", Provider: "ollama", ContextLen: 32768, Capabilities: []string{"local", "fast", "small"}},
Loaded 100 of 306 files, more files were not shown because too many files have changed in this diff. Show more