From f15c8c61535f7811bf501f077c925079943c29e0 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Thu, 18 Jun 2026 01:17:55 -0700 Subject: [PATCH] =?UTF-8?q?memory:=20snapshot=20=E2=80=94=20#17=20SHIPPED?= =?UTF-8?q?=20end-to-end=20(slices=201-3c,=20v0.17.8-.13,=20suite=20470=20?= =?UTF-8?q?green,=20live-smoke=20PROVEN:=20bound=20CLI->sindra->op-feed=20?= =?UTF-8?q?captured=202=20recall=20searches=20@=20exact=20bound=20session?= =?UTF-8?q?=5Fid=202c0c7482=20with=20#297/#298=20union=20scopes;=20dispatc?= =?UTF-8?q?h=20JWT=20carries=20session=5Fid=3Dsub,=20open-q=20resolved).?= =?UTF-8?q?=20Operator=20session=20UP:=20web=20:8765=20bind-configured=20+?= =?UTF-8?q?=20plane=20selector,=20providers=20:8390/:8391=20with=20op-feed?= =?UTF-8?q?,=20althing=20monitor=20armed.=20Persona-pane=20PAD=20gap=20dia?= =?UTF-8?q?gnosed=20(affect=20persists=20to=20:8390=20stored:true=20but=20?= =?UTF-8?q?pane=20reads=20Tier-3-404=20persona=5Fstate)=20->=20#18=20filed?= =?UTF-8?q?=20(composite=20endpoint=20+=20PAD=20read-endpoint,=20operator?= =?UTF-8?q?=20approved=20'A',=20contract-first=20next).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- persistent-memory.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/persistent-memory.md b/persistent-memory.md index e5fb8ba..291bf11 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -1,6 +1,6 @@ # Persistent memory — ratatoskr -_Last updated: 2026-06-16_ +_Last updated: 2026-06-18_ This file captures durable intent and supporting evidence (goals, decisions, foot-gun warnings, in-flight state) across context resets. Read it at session @@ -77,13 +77,27 @@ the Tier-3 persona_state roadmap (thread `01KVCR6P…`). De-uglied our web perso to render a clear Tier-3 message instead of a bare "HTTP 404". **CAVEAT still stands: the web client does NOT bind to `:8391`/`:8390` (#17 unbuilt) → web chat = persona + debug only; no memory persistence, no affect telemetry.** -**NEXT (fresh context): #17 — bifrost-binding the chat client.** The single unblock for BOTH (a) memory persistence -in the web/TUI/CLI chat (Sindra remembering in a real session, not just scripts) AND (b) feeding the persona pane -from OUR `:8390` affect store — `affect.emit` PAD/valence, ours to render per ADR-0009 (NOT a WT persona_state to -wait for; see the reframe in Recent decisions). Contract `docs/contracts/issues/17.contract.md` is WRITTEN + -Heid-reviewed + drift-clean; **TDD is the next step** — slice 1 = the `create_session` bifrost-binding primitive -(consumer-key per-request bearer + missing-key precondition + 502→`BifrostHandshakeFailed`, respx-mocked), then -`endpoint_for_plane` → dispatch-layer op-feed → CLI/TUI/web triggers → live smoke. althing monitor armed. +**#17 SHIPPED END-TO-END (2026-06-18 PM) + LIVE-SMOKE PROVEN; #18 FILED.** Bifrost-binding the chat client is +DONE across all surfaces — 6 commits `v0.17.8`→`v0.17.13`, full suite 470 green, NOT pushed (operator's call). +Slices: (1) `create_session` bind primitive `BifrostBinding`+consumer-key-override+`BifrostConsumerKeyMissing`/ +`BifrostHandshakeFailed`+`endpoint_for_plane` (`7be162e`); (2) dispatch-layer op-feed `ratatoskr.provider.opfeed` +(`OpEvent`/`OpSink`/`JsonlOpSink`/`instrument_provider_app` ASGI middleware, opt-in serve wiring via +`RATATOSKR_OPFEED_PATH`) (`8ebe227`); (3a) CLI `--bifrost-plane`/`--bifrost-url` (`0bebad7`); (3b) TUI pre-alt-screen +(`016defc`); (3c) web server-side bind + UI plane selector (`2806aba`+`179a8df`). **LIVE SMOKE:** bound CLI → +sindra session vs personal `:8081` → handshake 200 → op-feed captured 2 recall searches with the EXACT bound +session_id (`2c0c7482`) carrying `scope_any=[{end_user},{agent_self:ratatoskr:sindra}]` @ top_k=128 (the +#297/#298 union recall, observed provider-side). Contract open-q RESOLVED: the dispatch JWT DOES carry +session_id (`= sub`). Affect bind also proven (op-feed `emit stored:true`, session `7f65a975`). + +**OPERATOR SESSION STATE (background shells still UP):** web `:8765` RESTARTED with bind config (consumer key + +`RATATOSKR_PROVIDER_VISIBLE_HOST=10.100.10.50`, sindra-capable, plane selector live); memory provider `:8391` ++ affect provider `:8390` running WITH op-feed (`/tmp/opfeed-{memory,affect}.jsonl`); althing light-monitor armed +(not signed off). Consumer/owner key = `wt_live_d81b…`. + +**PERSONA-PANE PAD GAP (→ #18):** binding affect persists PAD to `:8390` (proven), but the web persona pane still +reads Worldtree `persona_state` (`loadPersona` index.html:707) which 404s for Tier-3 (ADR-0009 Tier-1-only) → shows +"telemetry isn't exposed". The pane was never wired to render PAD from OUR store — the unbuilt #17 affect payoff. +**Filed #18** (composite endpoint + PAD read-endpoint) — see Recent decisions. **(2026-06-16 PM) — BIFROST REPINNED 0.7.0→0.8.0 (wire v0.5→v0.6).** The memory `search` scope filter was split into `scope_all` (AND/intersection) + @@ -268,6 +282,11 @@ decision. Captures rationale that won't be obvious from code alone. - `[2026-06-18]` **Tier-3 persona_state is a Worldtree limitation (not ours); sindra → thoughtful-character.** The web Persona-pane 404 ("persona not available") = `persona_state` hard-404s ALL Tier-3 (colon-id) agents by design (`api.py:1220`); a persona block in the define doesn't help (endpoint short-circuits before the row). Pinged worldtree-dev on the Tier-3 persona_state roadmap (thread `01KVCR6P…`) + de-uglied our web pane (`index.html loadPersona`) to render a clear message (v0.17.7). Separately switched `ratatoskr:sindra` to the `thoughtful-character` role (→ `mistral-small-4-reasoning`) via DELETE+redefine (kept her prompt; added an inert persona block). **REFRAME (worldtree-dev `01KVCRK9…`):** persona_state GET is **Tier-1-only by ADR-0009**, the colon-id 404 is correct-by-design (NOT a stub to wait for). Tier-3 affect is **CLIENT-persisted** — we ALREADY hold the PAD `{pleasure,arousal,dominance}` + valence at `:8390` from the `affect.emit` payload. So the Persona-pane fix is **OUR side**: #17 affect-binding → WT dispatches `affect.emit` → `:8390` → the web pane renders PAD/valence from our own store. WT #289 (`affect.fetch`/`affect:read`) = optional mediated-read (their intelligence over our raw store), NOT a prerequisite. WT #300 = their forthcoming v1 client-impl guide (who-owns-what), folding in this exact case. +- `[2026-06-18]` **#17 implemented end-to-end via direct in-session TDD** (6 patch bumps `v0.17.8`→`v0.17.13`, suite 470 green). Slice order: bind primitive → op-feed → CLI → TUI → web(server) → web(UI). Tests drive the REAL bifrost dispatch via minted JWTs (`bifrost.core.dispatch_jwt.mint_dispatch_jwt`) — the "test against the shipped lib" posture, not hand-mocked envelopes. Op-feed reads `session_id` off the dispatch JWT `sub` claim (the contract open-q, resolved YES at the ASGI layer where the JWT is always present — `bifrost.reference_server._dispatch_auth.DispatchContext.session_id = payload["sub"]`). bifrost wire facts captured in-code: memory envelope `{operation, args}`→`memory_result(**payload)`={success,...}; verbs bare (search/upsert_many/get/get_many/delete_many); affect `{operation:"affect.emit"}`→`{success,stored}`; error envelope `{code, message}`; scopes `memory:read|write`. +- `[2026-06-18]` **#17 live-smoke PROVEN — the whole thesis validated.** A self-driven bound CLI session showed, from the PROVIDER side, exactly which memory ops a turn produced (2 recall searches, exact bound session_id, real union-recall scopes). This is #17's reason to exist (ratatoskr owns both ends → sees the round-trip). Negative (canary→auth_rejected) NOT live-constructible (Tier-1 agents aren't memory-bindable; a wrong key for an owner-scoped agent fails at agent-auth before the handshake) — covered by the unit test + prior hand-proof. +- `[2026-06-18]` **Fixed a pre-existing test-isolation bug exposed by the #17 CLI tests** (`0bebad7`): `test_no_textual_import` did a live `importlib.reload(ratatoskr.cli)` that mutated the shared module in place, breaking class identity (`isinstance`/`pytest.raises`) for every test ordered after it. The real check is the static source-grep; the reload was vestigial → removed. Lesson: never `importlib.reload` a shared module in a test without restoring it. +- `[2026-06-18]` **Composite endpoint APPROVED (operator "A is correct") + persona-pane PAD-render — DEFERRED, tracked at Gitea #18.** Two pieces: (1) a composite Bifrost facade (new port e.g. `:8392`) fronting BOTH `:8390`+`:8391` advertising both caps at handshake → one session binds both planes (un-parks the #17 contract open-q; bifrost reference_server already mounts both planes in one app, so a thin combined builder; needs per-plane failure-status + the op-feed deriving plane PER-REQUEST from the path instead of its fixed `plane` param). (2) a non-bifrost PAD read-endpoint on the affect provider (recommended over web-reads-`affect.db`-directly) → web persona pane renders PAD/valence from OUR `:8390` store, fixing the Tier-3 "telemetry isn't exposed". `affect.fetch` over bifrost is RESERVED/blocked but irrelevant (we own the store, read it directly). Contract-first next session. + _For per-issue TDD implementation notes, Volva findings, and contract amendments, see the git log — every per-issue commit carries a structured message capturing the trail._ ## Tried and abandoned