diff --git a/persistent-memory.md b/persistent-memory.md index 3ff37ab..d18d070 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -1,6 +1,6 @@ # Persistent memory — ratatoskr -_Last updated: 2026-06-19_ +_Last updated: 2026-06-20_ This file captures durable intent and supporting evidence (goals, decisions, foot-gun warnings, in-flight state) across context resets. Read it at session @@ -39,25 +39,26 @@ upstream API key stays server-side (INV-003). ## Current state / in-flight -_As of 2026-06-19:_ +_As of 2026-06-20:_ -**#18 CLOSED end-to-end — the composite ships (`v0.18.0`).** Both deliverables landed. -**D2** (PAD read-endpoint, `v0.17.14`) renders live PAD/valence in the web pane from our -`:8390` store. **D1** (composite endpoint, `v0.17.16` `7f4ceaa`) — `build_combined_provider_app` -(`provider/combined.py`) on `:8392` wraps bifrost's public `build_combined_app` over BOTH -stores + mounts the SHARED affect read route (`add_affect_read_route`); one bound Worldtree -session drives memory.* AND affect.* through ONE endpoint. Op-feed derives plane per request -path (`plane='combined'`). Published as **`v0.18.0`** (`359dbb1`). Suite **503 green**. +**#17 and #18 BOTH CLOSED — the composite both-plane binding is fully proven.** #18 shipped +`v0.18.0` (`359dbb1`): D2 (PAD read-endpoint, `v0.17.14`) renders live PAD in the web pane from our +`:8390` store; D1 (composite endpoint, `v0.17.16` `7f4ceaa`) — `build_combined_provider_app` +(`provider/combined.py`) on `:8392` wraps bifrost's public `build_combined_app` over BOTH stores + +the shared affect read route; one bound session drives memory.* AND affect.* through ONE endpoint, +op-feed deriving plane per path. Suite **503 green**. **#17 closed in the tracker 2026-06-20** +(shipped `v0.17.8`–`.13` + the `v0.17.17` op-feed field fix). -**LIVE-SMOKE PROVEN at wire+dispatch** (real stores + bifrost 0.10.0 on a running `:8392`): -handshake grants BOTH caps by store presence; the PAD read route serves real sindra PAD; a -memory `search` + an affect `emit` both dispatch through the one endpoint at a single bound -`session_id` with the op-feed deriving plane per path. **The only un-run leg is a -Worldtree-DRIVEN turn — GATED on infra-ops adding `http://10.100.10.50:8392` to WT's -`BIFROST_CLIENT_ALLOWED_HOSTS`** (`:8390/:8391` allowlisted, `:8392` not → bind 422s; requested -via infra-ops `01KVHWJGTT…`). FR-1 already code-verified the WT side (one BifrostClient, both -stores attach off one endpoint iff caps granted), so this is empirical confirmation of -known-good behavior, not open risk. +**#18's final leg — the Worldtree-DRIVEN composite turn — RAN and is PROVEN end-to-end + persisted +(2026-06-20).** infra-ops added `10.100.10.50:8392` to the personal WT's (`:8081`) +`BIFROST_CLIENT_ALLOWED_HOSTS` (thread `01KVHWJGTT…`), unblocking the smoke. A real WT turn through +`:8392` (session `b83a66b6`, agent `ratatoskr:sindra`, fresh end_user `resmoke-choco-1`) drove the +FULL both-plane lifecycle on ONE endpoint, caps-routed by path: `handshake` +(`caps_granted=[memory, affect]`) → `affect.fetch` + `memory.search` (reads) → `affect.emit` +(`stored:true`, PAD row in `affect_snapshots`) → `memory.upsert_many` (`upserted:1`, chunk +`2df1b79de761b948` in `memory_chunks`). Both writes verified directly in our SQLite. The +model-backend outage that blocked the first attempt (both agents' models `model_unavailable`) was +operator-fixed mid-session, then the resmoke completed clean. **No open legs remain on the composite.** **bifrost repinned 0.8.0 → 0.10.0** (floor, `provider` extra). 0.10.0 made `affect.fetch` MANDATORY (strong-or-absent: `_supports_affect_plane` requires `affect_supported`+`emit`+`fetch`, @@ -65,15 +66,14 @@ gating EVERY affect op incl. emit) — so the repin FORCED `affect.fetch` (`v0.1 to bifrost's reference `InMemoryAffectStore.fetch` → `{found, snapshot?}`) or our shipped affect plane would 400. The composite's affect cap depends on it. -**OPERATOR SESSION STATE — running shells are PRE-#18 code (foot-gun).** web `:8765` + affect -`:8390` + memory `:8391` are the prior session's background shells running OLD code. A -throwaway **`:8392` composite smoke instance is RUNNING** (background, NEW code, shared -`affect.db`/`memory.db` — the two-process topology, proven). To see the full stack on new code, -RESTART `:8390`/`:8765` from current code (D2 web needs `RATATOSKR_AFFECT_READ_URL`); the `:8392` -smoke instance is ready for the WT-turn once `:8392` is allowlisted. Consumer/owner key = -`wt_live_d81b…` (`~/.config/ratatoskr/provider.env`, mode 600, rotate via infra-ops); providers -SQLite + sqlite-vec, `memory.db`/`affect.db` at repo root (affect.db: live sindra PAD vuong -pleasure 0.146, familiarity 0.589, 8 interactions). +**OPERATOR SESSION STATE — `:8390`/`:8391`/`:8765` shells are PRE-#18 code (foot-gun).** web `:8765` ++ affect `:8390` + memory `:8391` are prior-session background shells on OLD code. The **`:8392` +composite provider is RUNNING on NEW code** (`ratatoskr-combined-provider`, pid started Jun19, +`RATATOSKR_OPFEED_PATH=/tmp/ratatoskr-combined-opfeed.jsonl`, shared `affect.db`/`memory.db`) — now +`:8392`-allowlisted and WT-turn-proven. To see the full web stack on new code, RESTART `:8390`/`:8765` +from current code (D2 web needs `RATATOSKR_AFFECT_READ_URL`). Consumer/owner key = `wt_live_d81b…` +(`~/.config/ratatoskr/provider.env`, mode 600, rotate via infra-ops); providers SQLite + sqlite-vec, +`memory.db`/`affect.db` at repo root (live sindra PAD: vuong + the `resmoke-choco-1` smoke fixture). **Tier-3 memory PROVEN end-to-end** (earlier this session): `ratatoskr:terse-probe` cold-recalled a seeded user fact (scope_any → 1 hit @ cosine 0.6994), and the verbose @@ -88,13 +88,15 @@ linguistic layer → Worldtree #305). `:8081` runs v0.36.0. **Standing:** Worldtree spec pin v0.35.16 (`f1b59f8`); **bifrost 0.10.0 / wire v0.6** (`scope_all`+`scope_any`). Heimdall key env-only at `~/.config/ratatoskr/provider.env` (mode -600); rotate via infra-ops. `graphify-out/` runs dirty (auto-regen, not chased). Open issues: -#10 (subject migration), #11 (AdminEvents pane — the next-reachable Worldtree-I/O coverage gap, -unblockable via an `admin.events.read` scope request) — deferred; **#18 CLOSED** (D1+D2 shipped, -`v0.18.0`). Codex-first pilot dormant. +600); rotate via infra-ops. `graphify-out/` runs dirty (auto-regen, not chased). **Open issues: +#11** (AdminEvents pane — the next-reachable Worldtree-I/O coverage gap, blocked on an +`admin.events.read` scope request) and **#10** (subject-migration watch on Worldtree #196) — both +deferred. **#17 + #18 CLOSED.** Codex-first pilot dormant. No in-flight implementation work — repo +is at a converged checkpoint; v1 advances when Worldtree does (v1 = full Worldtree I/O coverage). -Branch: `main` (== `359dbb1`, tag `v0.18.0`) — **4 commits AHEAD of `origin/main` (`39eebd1`), -not yet pushed** (push is the operator's call). Remote: `origin → git@gitea.phasefinal.com:vh/ratatoskr.git`. +Branch: `main` (tag `v0.18.0`, `359dbb1`) — **in sync with `origin/main`** (the full #17+#18 arc is +pushed). This `/snapshot` commit will sit one ahead of origin until pushed (push is the operator's +call). Remote: `origin → git@gitea.phasefinal.com:vh/ratatoskr.git`. ## Recent decisions @@ -134,6 +136,8 @@ decision. Captures rationale that won't be obvious from code alone. - `[2026-06-19]` **op-feed handshake field-name fix (#17, `v0.17.17` `d60b77d`): `capabilities_requested`→`capabilities`.** The summary read a field that never exists on the wire (bifrost reads `capabilities`, `_protocol.py:181`) → caps_requested was always null. Surfaced by the heid panel (Regin) during the D1 review — a latent #17 bug, not D1 drift. - `[2026-06-19]` **Ratatoskr is a REFERENCE implementation of the Worldtree/Bifrost standard (operator).** Adopt the dep's canonical way (even if ours works); INFORM of drift/gaps; ADVISE a different approach only when ours is genuinely better (dep owner decides), never unilaterally fork. [auto-memory `feedback-ratatoskr-is-a-reference-impl-adopt-canonical`] - `[2026-06-19]` **Ratatoskr v1 is DERIVED from Worldtree I/O coverage (operator) — no self-defined feature ROADMAP.** v1 = consume all of Worldtree's I/O points, reached when Worldtree hits 1.0; the convergence target is a coverage map, not a 3–7 capability list. [auto-memory `project-ratatoskr-v1-derived-from-worldtree-io-coverage`] +- `[2026-06-20]` **#18's final leg PROVEN — composite `:8392` WT-driven smoke ran end-to-end + persisted.** infra-ops allowlisted `10.100.10.50:8392` on the personal WT (`01KVHWJGTT…`); a real WT turn (session `b83a66b6`, `ratatoskr:sindra`, fresh end_user `resmoke-choco-1`) dispatched the full both-plane lifecycle through ONE endpoint — handshake (both caps) → `affect.fetch` + `memory.search` → `affect.emit` (`stored:true`) → `memory.upsert_many` (`upserted:1`) — both writes verified in our SQLite (`affect_snapshots` PAD row + `memory_chunks` chunk `2df1b79…`). First attempt blocked by a `model_unavailable` outage on the personal WT (both agents' models down), operator-fixed mid-session, then clean. The composite has no open legs. +- `[2026-06-20]` **#17 CLOSED in the tracker.** Shipped end-to-end (`v0.17.8`–`.13` + op-feed field fix `v0.17.17`); the 2026-06-20 composite smoke re-exercised its op-feed live. Closing comment captures the full both-plane proof. Open issues now just #11 (scope-blocked) + #10 (watch). _41 older entries (2026-05-* — the original debug-TUI/web build era) archived to archival-memory.md._ @@ -168,4 +172,6 @@ defense against re-attempting the same cul-de-sac. - `[2026-06-19]` **Full WT-driven `:8392` live-smoke is infra-gated — `:8392` not in WT's `BIFROST_CLIENT_ALLOWED_HOSTS` (bind 422s).** New provider ports are NOT auto-allowlisted (only `:8390/:8391` are). Self-driven dispatch (minted consumer-key JWTs → `:8392`) is the wire-proof; the WT-turn needs infra-ops to add `:8392` (requested `01KVHWJGTT…`). - `[2026-06-19]` **heid-code-review pulled MORE weight than its own "marginal" self-assessment.** The panel returned zero drift, but its single test-fidelity finding CASCADED into 2 real latent-bug fixes when applied (the memory `check_same_thread` bug + Regin's op-feed field-name bug). **Lesson: a contract-fidelity nudge can transitively expose bugs the test never reached — don't dismiss a "marginal" finding by its count.** +- `[2026-06-20]` **The post-turn-async timing trap bit AGAIN — even a 35s post-`[done]` read missed the promotion `upsert_many` by ~2s** (it landed `19:48:58`; the read was ~`19:48:56`). A 15s-interval background poll caught it on the first tick. Same family as the affect.emit / async-promotion traps already logged — re-confirmed that "wait once then read" is fragile for post-turn writes; **poll a window, don't snapshot once.** (The affect.emit write, by contrast, DID land inside the 35s window — promotion is the slower of the two post-turn writes.) + _18 older entries (2026-05-* — the original debug-TUI/web build era) archived to archival-memory.md._