memory: snapshot — #17 SHIPPED end-to-end (slices 1-3c, v0.17.8-.13, suite 470 green, live-smoke PROVEN: bound CLI->sindra->op-feed captured 2 recall searches @ exact bound session_id 2c0c7482 with #297/#298 union scopes; dispatch JWT carries session_id=sub, open-q resolved). Operator session UP: web :8765 bind-configured + plane selector, providers :8390/:8391 with op-feed, althing monitor armed. Persona-pane PAD gap diagnosed (affect persists to :8390 stored:true but pane reads Tier-3-404 persona_state) -> #18 filed (composite endpoint + PAD read-endpoint, operator approved 'A', contract-first next).

This commit is contained in:
vh
2026-06-18 01:17:55 -07:00
parent 179a8dff6e
commit f15c8c6153
+27 -8
View File
@@ -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