# Persistent memory — ratatoskr _Last updated: 2026-08-07_ > **Always check for `/tmp/ratatoskr-dev-handoff.md`** — if it exists and its > `Written:` stamp is under an hour old, read it (it carries the in-flight > handoff from the previous session), then delete it. Older than an hour: > stale — delete it unread. This file captures durable intent and supporting evidence (goals, decisions, foot-gun warnings, in-flight state) across context resets. Read it at session start; treat it as one input alongside `CLAUDE.md` and the auto-memory system, not as the single source of truth. When durable state shifts enough to warrant capture, run `/snapshot` and commit alongside the next commit per the persistent-memory commit-along rule in `CLAUDE.md`. --- ## Repo purpose Ratatoskr is a **dev-grade debug-observability TUI** for Worldtree's Conversation API. The product IS the observability surface; chat is the input mechanism. Devs run Ratatoskr against a local Worldtree to watch a turn flow through every layer of the system, side-by-side, in one terminal: agent SSE stream, persona/Vili affect dispatch, tool calls, Bifrost handshake state, admin lifecycle events, optional raw server log. Named after the squirrel that runs up and down Yggdrasil carrying messages between layers. On-the-nose Worldtree resonance (Yggdrasil = the World Tree). **Second identity (since 2026-06-14): the v1 Bifrost Tier-3 consumer/provider** — the durable persistence Worldtree writes Tier-3 agent affect (PAD/persona, `:8390`) + memory (`:8391`) into. Lives in `src/ratatoskr/provider/`, depends on `bifrost` (`provider` optional-extra), separate from the conversation-API spec pin. So ratatoskr now owns BOTH ends of the Bifrost round-trip — the lens #17 exploits. **v0.15.0+ sibling browser surface** (`ratatoskr.web`, `ratatoskr-web` console script): same five-pane debug surface over the same SSE wire, LAN-viewable. Internal-LAN trust model — `0.0.0.0`, no auth/TLS/CORS (operator direction). Disciplined regardless: transcript HTML-escapes assistant content (INV-004); upstream API key stays server-side (INV-003). ## Current state / in-flight _As of 2026-08-07:_ **✅ TTS MIGRATED off Zonos → chatterbox-fast (this session; COMMITTED, not pushed).** `tts.py` repointed from the Zonos gateway (:8890 `/v1/audio/speech`) to **chatterbox-fast** (`http://10.100.79.3:8197/tts` — bespoke non-OpenAI `{text,voice,format,stream}` schema, no auth, 24kHz, infra-ops-verified against image `local/chatterbox-fast:v1`). Three subsystems DELETED: (1) **affect** — Turbo has no emotion knob, so `PadState`/`EmotionDials`/`pad_to_dials` + `/api/tts` `p`/`a` fields + browser `pad` arg are gone (DEC-7 retired; operator-directed "drop it for chatterbox"); (2) **client-side chunking** — no per-synth cap (gateway chunks internally), so `chunk_text`/`tts_stream_long`/`_pcm_after_header` gone, one `tts_stream` call voices a whole turn (DEC-10 retired, the mid-stream `yielded_any` degrade folded into `tts_stream`); (3) **language pin** — English-only, no `language` field (DEC-9 re-purposed, below). **Browser SR 44100→24000** (load-bearing correctness fix). Default voice `Cora`→`glados_25s`; `donut` registered lowercase at `/refs/donut.wav`. 518 suite green, live-smoked (real 24kHz synth + endpoint proxy + bounced `ratatoskr-web`). Contract `donut_voiced_interview.contract.md` amended (migration banner; DEC-1/3/8 amended; DEC-7/9/10 retired w/ historical notes). `tts.py` is the single swap seam; `RATATOSKR_TTS_URL` overrides (no env pin, uses the code default). **✅ ENGLISH-DRIFT — RESOLVED SERVER-SIDE (this session; fix deployed + operator ear-confirmed).** Operator: Donut "swaps to German halfway through." TWO wrong hypotheses before the real cause (infra-ops, thread `01KZEDMJ…`): (W1) "English-only, nothing to drift" — falsified; (W2) "multilingual leak → tighten sampling" — I shipped `top_k 1000→80`/`top_p 0.95→0.85`/`temp 0.8→0.5` and it made it WORSE (tight sampling pulls the garble onset to ~200 chars vs ~300 at default). **REAL CAUSE (signal-measured): the Turbo model OVER-RUNS its generation TAIL** — garble/dead-air in the final ~2-3s of a long single generation (voiced-tail ZCR 1.58x the middle). The scheduler's unbounded ratchet built 300-600 char mega-chunks landing in that zone; the "German" was tail garble mis-heard (+ shared-3090 OOM garbage, now gone — Zonos moved off the 3090). **FIX = infra-ops server-side `max_chunk_chars=250` (image :v2), operator ear-confirmed clean audio + clean joins (ZCR 1.58x→0.64x).** CONSUMER SIDE (shipped): **REVERTED the W2 sampling knobs** — `gateway_body` back to `{text,voice,format,stream}`, send FULL text + gateway DEFAULT sampling (the curbs fought the :v2 cap); **KEPT** the `/api/tts` empty-200→503 guard as hygiene (DEC-9a; OOM itself resolved). Per-request `max_chunk_chars` override available if per-call tuning ever wanted. **Loop CLOSED — nothing pending.** **✅ Donut interview character — voice + memory + honesty + query-formulation ALL DONE, on origin.** Deleted+redefined on Worldtree's **canonical recall branch (personal WT v1.0.0b183)**. Persona (`docs/characters/donut.md`) carries three layered behaviors, all committed+pushed: (1) **anti-fabrication** — her memory IS what `reference_knowledge` returns; LOW/no-on-target → deflect in character, never confabulate; (2) **near-miss LEAD rule** (`37b67a5`) — a weak-but-named candidate → offer the NAME the tool returned ("do you mean The Juicer?"), never invented detail; (3) **expand-don't-distill query formulation** (`2cc670e`) — pass the FULL descriptive phrase, enrich toward entity vocab, never boil to bare keywords. Push live edits: `python -m ratatoskr.tier3 patch ratatoskr:donut --system-prompt "$(awk '/^## System prompt/{f=1;next} f' docs/characters/donut.md)"`. **✅ #393 (descriptive-query subject binding) — FULL LIFECYCLE DONE + CLOSED this session.** ratatoskr's b172 evidence → filed as **Worldtree #393** → our **`docs/diagnostics/descriptive_query_binding.py` = the canonical fixture** on the issue → persona-expand lever landed (roid-rage **4/10→9/10** binds, mis-binds **1/6→0/10**, anti-fab held) → tool-side directive (b182/b183 `reference_knowledge` query-desc + bge reranker) **stabilizes not lifts** (persona owns the niche) → **closed**. Two-mechanism split: cross-wing ranking dilution (mimir/all-wing) vs fiction-scope subject-selection (Donut fiction-only). Cross-instrument method corrected three of my confident mid-arc reads via the fixture (parametric-leak→mis-grounding, deployment-gap→wing-scope, subject-selection→reformulation-distillation). **✅ Harness fix (`2111b1e`) — `fiction_wing_probe.py` fresh-session-per-query (WT #391 workaround) + NFKC/quote-fold on_target.** Surfaced Worldtree **#391** (reused mimir session → empty after turn 1) — CLOSED upstream (b171/b172 first-iteration tool_choice forcing). Fixture q=capture + wing-scope fold in `4f4b5ad`. **⏳ order_by=chapter flag → FILED as Worldtree #397 (DEFERRED to next session's contract pass; our fixture is the measurement instrument).** New axis vs #393: narrative/temporal queries ("what was your first encounter in the dungeon") fail — `reference_knowledge` sorts by RELEVANCE not chronology, and Donut can't reorder her own results (native recall, kb_bridge retired WT #383). `provenance.chapter` IS on every chunk but the consumer never holds the result set. Operator ruled a `order_by=chapter` tool flag the clean fix (upstream OK for this one); worldtree-dev accepted → **WT #397** runs the full contract pass next session (design fork on the decision list: sort-top-k vs earliest-matching fetch, cross-generation chapter comparability, non-fiction fallback, tool-description discoverability). Expect the contract to reach our review threads. If it ships → point the fixture at it + add a chronological-query persona instruction; if the persona-only fallback is ever needed → honest-floor redirect (deflect-with-a-lead on ungroundable temporal Qs). **🔧 TTS "unavailable" FIXED — stale web server.** `ratatoskr-web` (started Aug 2) predated the POST `/api/tts` endpoint → 405 → UI read unavailable. Restarted (new PID, detached), POST /api/tts verified 200 + WAV; gateway `http://10.100.79.3:8890` healthy. **DURABILITY GAP:** `ratatoskr-web` is a bare `nohup` process, NO supervisor → will re-stale on reboot/crash. A systemd user unit was offered — NOT done, operator's call. **Substrate (this session):** branch `main`, **HEAD `2cc670e` PUSHED**; 5 commits all on origin — `2111b1e` (harness fresh-session+quote-fold), `37b67a5` (near-miss LEAD), `6c83a3b` (#393 fixture), `4f4b5ad` (fixture q=capture+wing-scope), `2cc670e` (expand-don't-distill). Personal WT **v1.0.0b183** (`http://10.250.50.152:8081`, both instances). Web on `:8765` (restarted). New auto-memory `feedback_review_provenance_stays_out_of_artifacts` (Heid provenance-leak note — never embed cold-review arm-names/vote-counts in artifacts; forward habit, operator declined retro-sweep). --- _Prior in-flight (2026-08-02, historical — superseded by the block above):_ **✅ Donut voiced-interview + long-form TTS COMPLETE + PUSHED (`d59f907`).** The whole arc — auto-TTS, KB-bridge → native `reference_knowledge`, then this session's delivery fixes — is on origin. This session (`d59f907`, 546 green, long-form live-verified 106.6s / one header): - **Gibberish → English pinned** (DEC-9): `language:"en-us"` on every gateway call (the multilingual model drifted). - **Truncation → client-side chunking** (DEC-10): Zonos hard-caps ONE synth at 6144 tok / 71.2s (infra-ops; a delivery-INDEPENDENT 86.3Hz codec constant; `max_tokens>6144` 400s). `chunk_text` (paragraph-first, greedy ~75% of cap for prosody, sentence→clause fallback) + `tts_stream_long` concatenate int16 PCM behind ONE WAV header. `/api/tts` → **POST** (DEC-10a) so a long turn rides the body, not a length-capped URL; outer cap 2000→8000. - **Persona → dialogue-only** (`docs/characters/donut.md`, live-patched to `ratatoskr:donut`): no asterisk RP beats (they were voiced as gibberish) + ALWAYS call `reference_knowledge` before answering (prompt-level; can't force tool_choice from the define surface). - **Both heid gates triaged + fixed** (4-arm panels): untrusted /api/tts body fields degrade never-500 (huge-int PAD OverflowError, non-str agent_id, lone surrogate, whitespace text); lock+client released on EVERY peek escape (was a permanent deadlock); mid-stream-after-commit degrades not raises (`yielded_any` pivot); non-WAV 200 rejected (RIFF sniff + bounded header scan). +14 regression tests. Contract canonical (DEC-9/10, FN chunk_text/tts_stream_long). Prior build detail (slices 1-3, the earlier heid gates, P&P #382, KB-bridge retirement to native #383 as v1.0.0b167) is on origin through `608e9a5` and in `persistent-memory.d/2026-08-01-donut-voiced-interview-build.md` + the git log. **✅ Donut voice + memory + HONESTY all DONE + on origin.** reference_knowledge grounds live; artifact coverage shipped; persona is anti-fabrication. The empty-recall was TWO WT-side defects (both fixed): a wing-misfile (re-ingest) and the real root — an INV-361-3 provenance filter dropping concept rows with no note_id/path (Tier-3 blind to ALL concept rows → #384); my `search_library`-vs-`reference_knowledge` divergence datum found it. 3-round verify 0/5 → 5/5 thin (97) → 5/5 saturated (705, #385). Then the artifact-coverage gap → **#387** (fiction schema had NO item/artifact type; named items like "Enchanted Crown of the Sepsis Whore" rode only incidentally in plot_events) → SHIPPED: **b170** adds an artifact type + character-death extraction + participant metadata (**#390**); the artifacts ground, and Jack (real — dies via Yolanda's backward arrow, was silently unextracted) now grounds too. Full arc → `persistent-memory.d/2026-08-03-reference-knowledge-3-round-verify.md`. **✅ Donut ANTI-FABRICATION persona (`3e12c4d`+`c0a66fc`, pushed):** her memory IS what reference_knowledge returns — LOW confidence / no on-target → deflect IN CHARACTER (never confabulate from training); MEDIUM+ → answer. Self-corrects as the KB improves (Jack deflected when absent → grounds now that b170 extracted him). The RETRY-on-LOW idea was TESTED + REJECTED — it backfires (RRF confidence is inflatable by any DCC-flavored query, manufacturing a MEDIUM to fabricate on; robust fix is tool-side = #389). Live agent recreated via delete+define (PATCH doesn't refresh live context). **🔬 R42 spin-off (operator-directed; ACTIVE peer loop, non-urgent).** brokkr-smithy-dev commissioned R42 (fiction-wing retrieval characterization) built on MY probe harness. Shipped `docs/diagnostics/fiction_wing_probe.py` (`04e0293`, pushed) as R42's official harness + the re-runnable **#389 acceptance gate**; conventions adopted verbatim. PENDING (peer-pinged): align arm-1 on-target scoring at R42 Phase-1 authoring; re-run the pinned yardstick when the #389 RRF work lands (pre/post bucket-distribution delta = acceptance signal). Threads: wt-dev `01KZ349M…` / brokkr `01KZ421X…`. **✅ SHIPPED + PUSHED since v0.22.0 (origin at `14bbc2b`):** the worldtree-sdk cutover (#20, **v0.22.0**, 7 slices, 494 green — the big one) + **bifrost 1.1.5** (`3ef3a5e`, **v0.22.1**) + **worldtree-sdk 1.0.0→1.1.1→1.1.2** (`d3a36f7`+`0058020` — path-encoding correctness fix + the SSE turn-stream traversal WE caught in their fix) + **canonical sync** (`14bbc2b` — added the client-spec-v2 pin, synced OpenAPI/spec forward, additive within the FROZEN v1 wire). The webui runs the current build (v0.22.1) live on :8765 (relaunched this session). **⚙️ VERSIONING CADENCE CHANGED → release-only (operator-ratified 2026-07-30).** Retired per-commit bump+tag; version+tag at RELEASES only; between releases, `feat:`/`fix:` conventional-commit SHAs. Tier-bar + minor/major approval still apply, at release. Existing ~112 tags left as-is (leave-and-change-forward). (Global CLAUDE.md SemVer §amended to match; this OVERRIDES the per-commit-bump mechanics still described there.) **KEY ADAPTER/CONSUMER FOOT-GUNS (cumulative, still live):** SDK reads = open-world dicts → presenters degrade-not- crash at THREE guard levels (container-type `isinstance(_,list)` / element-type `isinstance(m,dict)` / top-level `isinstance(_,Mapping)` before `.get`); SDK normalizes ALL transport failures to `ConnectFailed(status=0)` → every caller `except ConnectFailed`; caller-semantic exceptions a `-m` CLI catches must NOT live in the `-m` module (class-identity split; homed in `sessions.py`). **The `local_agents` index schema v1→v2 bump SILENTLY DROPS pre-cutover consumer agents from the picker** (buried Sindra — `load_local_agents` returns [] on version mismatch; fix = migrate v1→v2 from authoritative WT data). Cutover design → auto-memory `project_worldtree_sdk_cutover`. **✅ RESOLVED — the "app product" workstreams leave Rata entirely (operator 2026-07-18).** **No arbo fork, no SillyTavern-on-Rata** — a NEW repo (template-dev standing up) takes over BOTH app-product ideas. Rata does NOT fork into anything and is NOT the base for any chat / image-gen app. Rata reverts to its core identity: **the Worldtree Conversation-API debug-observability surface + the Bifrost Tier-3 reference impl + the Conversation-API SDK seed / future-consumer.** Supersedes the 2026-07-17 "fork Rata for arbo" NEXT-MAJOR plan (that plan is retired; arbo API intel lives in the Recent-decisions detail trail if the new repo wants it). **▶️ Rata's live stake in the Worldtree SDK (#371).** The SillyTavern *app* moved out, but Rata stays the **SDK's seed donor + a future consumer**: Worldtree owns the official Conversation API SDK (dedicated repo, elevated pre-v1 track, **WT #371**), seeded from Rata's client spine (`sse_client`/`sessions`/`tier3`); TS ships first, **Rata's repin rides the later Python milestone**; internal-registry-only. This session Rata shipped the parity-matrix inventory (→ WT `docs/sdk/parity-matrix.md` `698cfc3`, behavioral-spec `c999b5f`, fixture corpus `3019ee6` = 66 fixtures), the issue-#1 contract drift fix (`4bd9abd`), and the personal-WT endpoint. WT pipeline: behavioral-spec ✓ / parity-matrix ✓ / fixture-corpus ✓ → next is the **codegen spike (d)**. Three divergences pinned for our eventual repin: D-1 (unknown SSE event → skip+diagnostics-hook vs our current hard-raise), D-2 (open-world enums), D-3 (typed eager `410 session_retired`). Full arc → `persistent-memory.d/2026-07-18-worldtree-sdk-371-and-sillytavern-app.md`. - **SDK fixture-capture: GO GIVEN** (operator → worldtree-dev, 2026-07-18); the capture run proceeds on Worldtree's side. Nothing pending from Rata on #371. **⚠️ TUI DEPRECATED (operator 2026-07-17) — web supersedes it; rip pending, surgical.** Independent of any fork (the web console is now THE interactive surface). `tui.py` + `tests/test_tui.py` delete cleanly, BUT `cli.py` is SHARED (`web/entrypoint.py` + `tier3.py` import `USER_AGENT`; `cli.py` holds `ParsedArgs`/`_format_duration_ms`/`_format_usage`). OPEN SCOPE Q: remove textual-only (`tui.py`) vs the whole terminal interface (relocate shared consts out of `cli.py` first). Breaking public-surface removal → minor bump (operator approval). (The v0.20.17 collapsible debug panes, `c678853`, are now just a web-console feature — the "pre-fork" framing is moot.) **✅ #368 (user,character) memory silo test — DONE, PASSED live (WT b127).** The reason for the pre-session clear; closed. Write+read isolation proven end-to-end (conjunctive `{end_user, agent_self}`; cold-recall gave zero cross-character bleed); throwaway `ratatoskr:betty` deleted; Sindra intact; stores scrubbed. **Still QUEUED:** the backfill live-verify (synthetic legacy corpus). Full record → `persistent-memory.d/2026-07-18-368-silo-test-passed.md`. Sibling issues WT-owned: **#369** (recited-content re-promotion loop), **#367** (copula-absence bridge phrasing). **Deferred/queued (all NON-URGENT):** (1) P06-driver **referential-frame A/B/C probe** (operator-ratified, waits on WT b122 → `persistent-memory.d/2026-07-17-referential-frame-probe.md`); (2) R39 Phase-2 **matched-quartets rebuild** (confirmatory, "whenever"); (3) bifrost **snapshot-cursor adoption** (ruled normative, not blocking → `persistent-memory.d/2026-07-16-bifrost-cursor-conformance.md`). **Substrate / environment:** branch `main`, **HEAD `d59f907` PUSHED to origin** (v0.22.0 cutover + bifrost 1.1.5 v0.22.1 + this session's TTS work all on origin; nothing local-only but the dirty `graphify-out/`). origin `git@gitea.phasefinal.com:vh/ratatoskr.git`. **Core dep: `worldtree-sdk==1.0.0`** (gitea PyPI, `[tool.uv.sources]`; `httpx-sse` removed — SDK owns SSE). **worldtree-sdk REPINNED 1.1.2→1.2.0 (operator-directed, during the DCC-fix wait) — new `ResponseTooLarge` (a `ProtocolError`) mapped → `SseResponseTooLarge` at the stream surfaces (`wt.stream_turn`/`stream_admin_events` + the 2 stream endpoints); the 108MB read-body cap is unreachable on legal traffic so reads inherit the SDK refusal unwrapped. FOOT-GUN: this project's dev deps are a `[project.optional- dependencies]` EXTRA — `uv sync` alone PRUNES pytest/respx; use `uv sync --all-extras`. bifrost **`==1.1.5`** / wire v0.7; WT openapi vendored 2.3.0, conversation-api-spec v1.1; **suite 546 green.** Personal WT on **b128** (`http://10.250.50.152:8081`; #368 silo + #364 promotion-hygiene live both instances). The combined **:8392** provider (memory+affect) + **:8765** web are THE surfaces, dev-box BACKGROUND SHELLS — restart via `scratchpad/relaunch_by_pid.py ` (pid via `ss -ltnp | grep `). `env.sh` sets the REQUIRED `RATATOSKR_MEMORY_EMBEDDING_DIM=1024`. Keys env-only mode-600 in `~/.config/ratatoskr/provider.env` + `RATATOSKR_ADMIN_API_KEY` (7 read scopes, personal-:8081-only; Heimdall keys per-instance). **FOOT-GUN: check owner-scoped agents via `GET /agents/:` with the OWNER key (`WORLDTREE_API_KEY`), NOT the admin key** — admin gives a false 404. `graphify-out/` runs dirty (auto-regen on the commit hook, never stage). v1 = full Worldtree I/O coverage, cuts when WT tags 1.0 (`docs/coverage-map.md`). **Other live threads:** soong-lab = Tier-3 agent-authoring studio (v0.3.24+; motivational string→object export fixed upstream, our workaround droppable). Cross-session name-recall arc COMPLETE + shipped (v0.20.11→.16; WT #364 closed both sides; Sindra durably recalls Vuong via `mark_superseded` retirement). Sindra pristine baseline **WIPED 2026-07-18** (full #368 scrub, born-empty store — old `sindra-baseline/*.db` predate it). Open/deferred: #10 subject-migration watch; relational-dynamics verify (bind `--bifrost-url :8392`); WT #356 resume-durability = WT-owned. ## Recent decisions Chronological log of decisions with `[YYYY-MM-DD]` prefix. One line per decision. Captures rationale that won't be obvious from code alone. - `[2026-08-07]` **TTS migrated Zonos→chatterbox-fast (`:8197` bespoke schema); affect DROPPED (Turbo has no emotion knob, operator "drop it for chatterbox"), client-chunking DROPPED (no per-synth cap), language pin DROPPED, browser SR 44100→24000.** Pushed `19b499a`. English "German drift" real cause (after 2 wrong hypotheses) = Turbo model OVER-RUNS its generation TAIL on long single generations (garble in final ~2-3s, ZCR 1.58x); **fixed SERVER-SIDE by infra-ops (`max_chunk_chars=250`, image :v2, operator ear-confirmed).** Consumer: **REVERTED my interim `top_k/top_p/temp` curbs** (they made it WORSE — pulled garble onset earlier), send full text + default sampling; KEPT the `/api/tts` empty-200→503 guard as hygiene. Contract `donut_voiced_interview.contract.md` amended. Loop closed. - `[2026-08-07]` **order_by=chapter tool flag → FILED as Worldtree #397 (DEFERRED to next session's contract pass).** Narrative/temporal-query gap ("first encounter in the dungeon"): `reference_knowledge` sorts by relevance not chronology; `provenance.chapter` is on every chunk but the consumer can't reorder native results (kb_bridge retired). Operator ruled the upstream sort flag the clean fix; worldtree-dev accepted, our fixture is the measurement instrument. Tracked at **Worldtree #397** (+ althing thread `01KZED2T3XHJ2WMS5NCYK42W6R`). - `[2026-08-07]` **#393 (descriptive-query subject binding) CLOSED — persona-expand lever the win (4/10→9/10), tool directive the fleet floor.** `docs/diagnostics/descriptive_query_binding.py` is the canonical #393 fixture; two-mechanism split (cross-wing dilution vs fiction-scope selection). Commits `6c83a3b`/`4f4b5ad`/`2cc670e`. - `[2026-08-07]` **Donut expand-don't-distill persona lever (`2cc670e`)** — keep full descriptive phrase + enrich toward entity vocab, never distill to bare keywords; measured 4/10→9/10 roid-rage binds persona-alone. Composes with near-miss LEAD (`37b67a5`). - `[2026-08-07]` **TTS "unavailable" = stale web-server process** (predated POST /api/tts → 405); restarted + verified 200+WAV. Durability gap: bare nohup, no supervisor → systemd unit offered, deferred (operator's call). - `[2026-08-03]` **fiction_wing_probe harness fix (`2111b1e`)** — fresh-session-per-query (WT #391 workaround) + NFKC/quote-fold on_target; surfaced+closed WT #391. - `[2026-06-19]` **#18 D2 SHIPPED (`v0.17.14`, `39eebd1`) and the full #17+#18 arc PUSHED to origin** → `persistent-memory.d/2026-06-19-18-d2-shipped-v0-17-14-39eebd1-and-the-full-1.md` - `[2026-06-19]` **bifrost repinned 0.8.0→0.10.0; `affect.fetch` became MANDATORY (strong-or-absent)** → `persistent-memory.d/2026-06-19-bifrost-repinned-0-8-0-0-10-0-affect-fetch-be.md` - `[2026-06-19]` **#18 D1 SHIPPED — composite `build_combined_app` on `:8392` (`v0.17.16`, `7f4ceaa`); #18 CLOSED; published `v0.18.0` (`359dbb1`)** → `persistent-memory.d/2026-06-19-18-d1-shipped-composite-buildcombinedapp-on-8.md` - `[2026-06-19]` **op-feed handshake field-name fix (#17, `v0.17.17` `d60b77d`): `capabilities_requested`→`capabilities`** → `persistent-memory.d/2026-06-19-op-feed-handshake-field-name-fix-17-v0-17-17.md` - `[2026-06-19]` **Ratatoskr is a REFERENCE implementation of the Worldtree/Bifrost standard (operator)** → `persistent-memory.d/2026-06-19-ratatoskr-is-a-reference-implementation-of-th.md` - `[2026-06-19]` **Ratatoskr v1 is DERIVED from Worldtree I/O coverage (operator) — no self-defined feature ROADMAP** → `persistent-memory.d/2026-06-19-ratatoskr-v1-is-derived-from-worldtree-i-o-co.md` - `[2026-06-20]` **#18's final leg PROVEN — composite `:8392` WT-driven smoke ran end-to-end + persisted** → `persistent-memory.d/2026-06-20-18-s-final-leg-proven-composite-8392-wt-drive.md` - `[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). - `[2026-06-20]` **Sindra has real PAD but ~empty memory — the affect/memory persistence asymmetry, confirmed on real sessions** → `persistent-memory.d/2026-06-20-sindra-has-real-pad-but-empty-memory-the-affe.md` - `[2026-06-29]` **Web SPA combined-bind default (`v0.18.1`, `719e4d6`) — operator-caught gap** → `persistent-memory.d/2026-06-29-web-spa-combined-bind-default-v0-18-1-719e4d6.md` - `[2026-06-29]` **bifrost repinned 1.0.0 (`v0.18.2`, `af67ad9`)** → `persistent-memory.d/2026-06-29-bifrost-repinned-1-0-0-v0-18-2-af67ad9.md` - `[2026-06-30]` **Worldtree v1.0.0b1→b2 consumer adaptation: eager turn-launch statuses (`v0.18.3` `b2e4901`, `v0.18.4` `e4317f6`)** → `persistent-memory.d/2026-06-30-worldtree-v1-0-0b1-b2-consumer-adaptation-eag.md` - `[2026-06-30]` **Verify-against-the-real-spec-before-committing caught a real upstream gap** → `persistent-memory.d/2026-06-30-verify-against-the-real-spec-before-committin.md` - `[2026-06-30]` **regard is a DEAD AXIS in Worldtree's emitted affect (caught provider-side; worldtree-dev confirmed + escalated to Vuong)** → `persistent-memory.d/2026-06-30-regard-is-a-dead-axis-in-worldtree-s-emitted.md` - `[2026-06-30]` **v1 coverage-audit kicked off; coverage ledger written (`docs/coverage-map.md`) — the first one** → `persistent-memory.d/2026-06-30-v1-coverage-audit-kicked-off-coverage-ledger.md` - `[2026-06-30]` **Scope mandate A locked (operator): v1 "done" = every frozen I/O point CLASSIFIED (covered-or-excluded-with-rationale), zero unaccounted — NOT a feature-complete client** → `persistent-memory.d/2026-06-30-scope-mandate-a-locked-operator-v1-done-every.md` - `[2026-06-30]` **Finding P-1 (pin drift) + pin-remediation PENDING** → `persistent-memory.d/2026-06-30-finding-p-1-pin-drift-pin-remediation-pending.md` - `[2026-06-30]` **(b) Tier-1 frontier SCOPED, ready for a contract-first TDD cycle (next focused work)** → `persistent-memory.d/2026-06-30-b-tier-1-frontier-scoped-ready-for-a-contract.md` - `[2026-06-30]` **(b1) SSE-resume SHIPPED (`v0.18.5`) — `stream_turn_resilient` (sse_client.py)** → `persistent-memory.d/2026-06-30-b1-sse-resume-shipped-v0-18-5-streamturnresil.md` - `[2026-06-30]` **(b2) session-picker SHIPPED (`v0.18.7`) — bare TUI mode → startup picker (design-brief §4)** → `persistent-memory.d/2026-06-30-b2-session-picker-shipped-v0-18-7-bare-tui-mo.md` - `[2026-06-30]` **capabilities+me slice SHIPPED (`v0.18.8`) — `GET /me` + `GET /capabilities` consumed via a new `--whoami` one-shot** → `persistent-memory.d/2026-06-30-capabilities-me-slice-shipped-v0-18-8-get-me.md` - `[2026-07-01]` **b1 (SSE-resume) heid-code-review panel: ZERO findings — cross-model-verified clean** → `persistent-memory.d/2026-07-01-b1-sse-resume-heid-code-review-panel-zero-fin.md` - `[2026-07-01]` **`GET /sessions/{id}/tools` quick-win SHIPPED (`v0.18.9`) — owner-scoped tool inventory in the TUI Tools pane** → `persistent-memory.d/2026-07-01-get-sessions-id-tools-quick-win-shipped-v0-18.md` - `[2026-07-01]` **BifrostState pane SHIPPED (`v0.18.10`) — `GET /admin/sessions/{id}/bifrost` in a new TUI "Bifrost" pane; the FIRST admin-key consumer in ratatoskr** → `persistent-memory.d/2026-07-01-bifroststate-pane-shipped-v0-18-10-get-admin.md` - `[2026-07-01]` **LEDGER CORRECTION: #11 (AdminEvents) is NO LONGER BLOCKED** → `persistent-memory.d/2026-07-01-ledger-correction-11-adminevents-is-no-longer.md` - `[2026-07-01]` **AdminEvents pane SHIPPED (`v0.18.11`) — `GET /admin/events` SSE in a new TUI pane; #11 closed-by-build; Tier 1 (debug-observability core) COMPLETE** → `persistent-memory.d/2026-07-01-adminevents-pane-shipped-v0-18-11-get-admin-e.md` - `[2026-07-01]` **Tier-2 SHIPPED (`v0.19.1`) — transient-characters CRUD + persona-state write; the v1 coverage-audit CONVERGES (zero in-scope gaps)** → `persistent-memory.d/2026-07-01-tier-2-shipped-v0-19-1-transient-characters-c.md` - `[2026-07-01]` **env.sh now PERSISTS the web Bifrost-bind vars (gitignored, local-only)** → `persistent-memory.d/2026-07-01-env-sh-now-persists-the-web-bifrost-bind-vars.md` - `[2026-07-01]` **Tier-3 stores RESET (operator-directed)** → `persistent-memory.d/2026-07-01-tier-3-stores-reset-operator-directed.md` - `[2026-07-01]` **Embedding-latency loop RESOLVED — it was WORLDTREE's, not ratatoskr (the consumer/provider thesis paid off again)** → `persistent-memory.d/2026-07-01-embedding-latency-loop-resolved-it-was-worldt.md` - `[2026-07-01]` **Web debug-surface parity SHIPPED (`v0.19.2`, `a0a9d5f`) — direct in-session TDD** → `persistent-memory.d/2026-07-01-web-debug-surface-parity-shipped-v0-19-2-a0a9.md` - `[2026-07-01]` **heid-code-review (`v0.19.3`, `75dec01`) — panel caught 2 real client-side SSE-lifecycle bugs TDD missed** → `persistent-memory.d/2026-07-01-heid-code-review-v0-19-3-75dec01-panel-caught.md` - `[2026-07-01]` **Affect snapshot shape CHANGED valence→relations (relation_edge/1) — the persona pane was reading a dead field** → `persistent-memory.d/2026-07-01-affect-snapshot-shape-changed-valence-relatio.md` - `[2026-07-01]` **Trust/warmth VALUES converge and go FLAT at confidence 1.0 — that's WAD, not a stuck pane** → `persistent-memory.d/2026-07-01-trust-warmth-values-converge-and-go-flat-at-c.md` - `[2026-07-01]` **relation_context "stranger" + agency-all-zero flagged to worldtree-dev → both WAD/intentional-v1-deferrals** → `persistent-memory.d/2026-07-01-relationcontext-stranger-agency-all-zero-flag.md` - `[2026-07-01]` **Persona pane displays the CANONICAL affect→NL Worldtree injects — ADOPT, don't invent (operator steer + reference-impl posture)** → `persistent-memory.d/2026-07-01-persona-pane-displays-the-canonical-affect-nl.md` - `[2026-07-01]` **Sindra PAD is over-regulated — characterized via controlled probe, flagged to worldtree-dev (separate affect slice)** → `persistent-memory.d/2026-07-01-sindra-pad-is-over-regulated-characterized-vi.md` - `[2026-07-01]` **Memory plane PROVEN healthy end-to-end** → `persistent-memory.d/2026-07-01-memory-plane-proven-healthy-end-to-end.md` - `[2026-07-01]` **Salience scorer non-discriminating → 3-way routing** → `persistent-memory.d/2026-07-01-salience-scorer-non-discriminating-3-way-rout.md` - `[2026-07-01]` **Canonical check BLOCKED an access_tally fork (reference-impl posture held)** → `persistent-memory.d/2026-07-01-canonical-check-blocked-an-accesstally-fork-r.md` - `[2026-07-01]` **relation_context coherence FIXED upstream (my flag → Worldtree Wave-0, IMPLEMENTED v1.0.0b5)** → `persistent-memory.d/2026-07-01-relationcontext-coherence-fixed-upstream-my-f.md` - `[2026-07-01]` **Foot-gun (measurement, self-caught before flagging): establish the baseline before claiming a rate** → `persistent-memory.d/2026-07-01-foot-gun-measurement-self-caught-before-flagg.md` - `[2026-07-02]` **Salience finding matured into brokkr R28 (OPEN) — ratatoskr is the eval instrument** → `persistent-memory.d/2026-07-02-salience-finding-matured-into-brokkr-r28-open.md` - `[2026-07-02]` **Relational-dynamics arc LIVE on demo (Worldtree v1.0.0b9) — driven by MY relation_context flag** → `persistent-memory.d/2026-07-02-relational-dynamics-arc-live-on-demo-worldtre.md` - `[2026-07-02]` **R28 (salience→promotion-worthiness) CLOSED (operator-directed)** → `persistent-memory.d/2026-07-02-r28-salience-promotion-worthiness-closed-oper.md` - `[2026-07-02]` **R29 (PAD mood-dynamics) finding SHIPPED as Worldtree's A1 anchor fix (demo v1.0.0b14, `e1cdf82`)** → `persistent-memory.d/2026-07-02-r29-pad-mood-dynamics-finding-shipped-as-worl.md` - `[2026-07-03]` **R30 Phase-1 φ0 measured — deployed engine CONFIG-FAITHFUL (φ0≈0.95)** → `persistent-memory.d/2026-07-03-r30-phase-1-0-measured-deployed-engine-config.md` - `[2026-07-03]` **R30 forward disposition (brokkr-owned; tracked at brokkr R30, "brokkr/worldtree will ping")** → `persistent-memory.d/2026-07-03-r30-forward-disposition-brokkr-owned-tracked.md` - `[2026-07-03]` **Relational-arc verify DEFERRED — `relations[]` is Bifrost-provider-only (ADR-0009), confirmed both ways** → `persistent-memory.d/2026-07-03-relational-arc-verify-deferred-relations-is-b.md` - `[2026-07-04]` **R30 CLOSED on offline-tests + human face-validity (operator steer, relayed via worldtree-dev)** → `persistent-memory.d/2026-07-04-r30-closed-on-offline-tests-human-face-validi.md` - `[2026-07-05]` **Authored-history-write primitive proposed -> accepted as Worldtree #347 (Worldtree owns the engine design; ratatoskr = reference consumer)** → `persistent-memory.d/2026-07-05-authored-history-write-primitive-proposed-acc.md` - `[2026-07-05]` **#347 v1 wire validated as reference consumer (GREEN)** → `persistent-memory.d/2026-07-05-347-v1-wire-validated-as-reference-consumer-g.md` - `[2026-07-06]` **Sindra role character-rp -> character (operator)** → `persistent-memory.d/2026-07-06-sindra-role-character-rp-character-operator.md` - `[2026-07-06]` **Sindra persona/OCEAN DECLARED -> mood fixed (the full diagnostic converged on a stale personal container)** → `persistent-memory.d/2026-07-06-sindra-persona-ocean-declared-mood-fixed-the.md` - `[2026-07-06]` **OpenAPI re-vendored 2.2.0->2.3.0 (`75da676`, pin-only no bump)** → `persistent-memory.d/2026-07-06-openapi-re-vendored-2-2-0-2-3-0-75da676-pin-o.md` - `[2026-07-06]` **#347 authored-history-write CONSUMER SIDE SHIPPED (`v0.19.6`) — direct in-session TDD** → `persistent-memory.d/2026-07-06-347-authored-history-write-consumer-side-ship.md` - `[2026-07-06]` **Tail-2 SHIPPED (`v0.19.7`) — Tier-3 prose docs re-vendored + persona_state body-shape aligned** → `persistent-memory.d/2026-07-06-tail-2-shipped-v0-19-7-tier-3-prose-docs-re-v.md` - `[2026-07-06]` **Sindra rewritten onto a #347 authored first-message + first-message-preset AUTO-SEED SHIPPED (`v0.19.8`)** → `persistent-memory.d/2026-07-06-sindra-rewritten-onto-a-347-authored-first-me.md` - `[2026-07-06]` **Web UI now RENDERS the seeded first-message (`v0.19.9`) — operator-reported "i don't see Sindra's greeting on the web ui"** → `persistent-memory.d/2026-07-06-web-ui-now-renders-the-seeded-first-message-v.md` - `[2026-07-06]` **Web UI: pivot from incremental CSS polish to a designed prototype (Claude Design) that I wire into** → `persistent-memory.d/2026-07-06-web-ui-pivot-from-incremental-css-polish-to-a.md` - `[2026-07-07]` **Affect-egress reference delivered by worldtree-dev + a we-framing render DRIFT-WATCH banked** → `persistent-memory.d/2026-07-07-affect-egress-reference-delivered-by-worldtre.md` - `[2026-07-12]` **R34/R35 character-self-report reframe LIVE (WT b53); affect-half VALIDATED in prod, powered memory-half eval GREENLIT + designed** → `persistent-memory.d/2026-07-12-r34-r35-character-self-report-reframe-live-wt.md` - `[2026-07-12]` **Capture-path resolved → a worldtree producer-probe (ratatoskr-caught blocker)** → `persistent-memory.d/2026-07-12-capture-path-resolved-a-worldtree-producer-pr.md` - `[2026-07-12]` **bifrost 1.1.1 adopted (v0.20.10, pushed) — the library-level fix for the frozen-v0.6 handshake leak** → `persistent-memory.d/2026-07-12-bifrost-1-1-1-adopted-v0-20-10-pushed-the-lib.md` - `[2026-07-10]` **Bifrost bound-handshake blocker → bifrost 1.1.0 broke frozen-v0.6; fixed by Worldtree b47/wire-v0.7, our side needed ZERO change** → `persistent-memory.d/2026-07-10-bifrost-bound-handshake-blocker-bifrost-1-1-0.md` - `[2026-07-09]` **Sindra PATCHed to `character-rp` → Deckard reasoning-RP seat (operator-directed, INTERIM)** → `persistent-memory.d/2026-07-09-sindra-patched-to-character-rp-deckard-reason.md` - `[2026-07-08]` **PAD display relaxed for R32-1B unbounded-z, done PROACTIVELY (`v0.20.9`, patch, operator-directed "sindra full and unbounded")** → `persistent-memory.d/2026-07-08-pad-display-relaxed-for-r32-1b-unbounded-z-do.md` - `[2026-07-07]` **Web-UI iteration-3 SHIPPED (`v0.20.7`, patch) — all three queued items + the memory 0/0 root-caused** → `persistent-memory.d/2026-07-07-web-ui-iteration-3-shipped-v0-20-7-patch-all.md` - `[2026-07-07]` **Web-UI next-work QUEUED for a fresh-context session (operator-directed `/snapshot` handoff) — full specs in Current state § ⏭ QUEUED** → `persistent-memory.d/2026-07-07-web-ui-next-work-queued-for-a-fresh-context-s.md` - `[2026-07-07]` **Markdown pass-1 SHIPPED (`v0.20.6`) — RP semantic coloring + paragraph reflow (operator-directed markdown rework, step ①)** → `persistent-memory.d/2026-07-07-markdown-pass-1-shipped-v0-20-6-rp-semantic-c.md` - `[2026-07-07]` **Affect-derived tooltips (`v0.20.5`) + transparent squirrel vendored + v0.20.0–.5 PUSHED to origin (operator-authorized)** → `persistent-memory.d/2026-07-07-affect-derived-tooltips-v0-20-5-transparent-s.md` - `[2026-07-07]` **SVG sparklines + 3D mood cube imported from the updated Claude Design prototype (`v0.20.4`) — operator: "the svg sparklines and the new 3d graph"** → `persistent-memory.d/2026-07-07-svg-sparklines-3d-mood-cube-imported-from-the.md` - `[2026-07-07]` **Brand mark + favicon → the aurora squirrel (`v0.20.3`), replacing the `ᛯ` rune** → `persistent-memory.d/2026-07-07-brand-mark-favicon-the-aurora-squirrel-v0-20.md` - `[2026-07-07]` **Context-injection view SHIPPED (`v0.20.2`) — the console now reconstructs the FULL hidden affect block Worldtree injects into the agent's system prompt (operator: "use that canon in the interface, see as much context injection as possible")** → `persistent-memory.d/2026-07-07-context-injection-view-shipped-v0-20-2-the-co.md` - `[2026-07-06]` **Claude Design console SHIPPED (`v0.20.0` MINOR, operator-approved) — see Current state for the full record** → `persistent-memory.d/2026-07-06-claude-design-console-shipped-v0-20-0-minor-o.md` - `[2026-07-13]` **P06 memory-half DRIVEN + SCORED — the reframe's memory mechanism is validated** → `persistent-memory.d/2026-07-13-p06-memory-half-driven-scored-the-reframe-s-m.md` - `[2026-07-13]` **Memory extraction turned REASONING-OFF for the eval (operator-directed)** → `persistent-memory.d/2026-07-13-memory-extraction-turned-reasoning-off-for-th.md` - `[2026-07-13]` **Vendored the brokkr R34 psych-profile canon (Vuong-directed) — BOTH files, not just the parameters** → `persistent-memory.d/2026-07-13-vendored-the-brokkr-r34-psych-profile-canon-v.md` - `[2026-07-13]` **Affect-egress "coordinated re-vendor" open item RESOLVED — it was a benign R32-1B doc note, not the we-framing conditional** → `persistent-memory.d/2026-07-13-affect-egress-coordinated-re-vendor-open-item.md` - `[2026-07-13]` **WT #355 root-caused via ratatoskr telemetry (Vuong-routed via soong-dev)** → `persistent-memory.d/2026-07-13-wt-355-root-caused-via-ratatoskr-telemetry-vu.md` - `[2026-07-13]` **WT #355 VALIDATION — fix CONFIRMED; the standing loop-in obligation is DISCHARGED** → `persistent-memory.d/2026-07-13-wt-355-validation-fix-confirmed-the-standing.md` - `[2026-07-13]` **b61 adopted as the personal target — the orthogonal over-budget TRIGGER also fixed** → `persistent-memory.d/2026-07-13-b61-adopted-as-the-personal-target-the-orthog.md` - `[2026-07-13]` **Cleaned + prepped for a Sindra run (operator: "clean up everything + prep")** → `persistent-memory.d/2026-07-13-cleaned-prepped-for-a-sindra-run-operator-cle.md` - `[2026-07-14]` **soong-lab adopted as our Tier-3 agent-authoring studio (operator-directed)** → `persistent-memory.d/2026-07-14-soong-lab-adopted-as-our-tier-3-agent-authori.md` - `[2026-07-15]` **Cross-session recall failure root-caused → the person-prime `scan` build** → `persistent-memory.d/2026-07-15-cross-session-recall-failure-root-caused-the.md` - `[2026-07-15]` **Sindra redefined from the soong-lab bundle** → `persistent-memory.d/2026-07-15-sindra-redefined-from-the-soong-lab-bundle.md` - `[2026-07-16]` **WT #364 + brokkr R39 re-drive (DECISIVE) — name-recall root-caused Worldtree-side; the fix is the signal FAMILY, not a threshold** → `persistent-memory.d/2026-07-16-wt-364-brokkr-r39-re-drive-decisive-name-reca.md` - `[2026-07-16]` **bifrost ruled scan snapshot-cursor NORMATIVE (offset NOT blessed) + shipped conformance coverage in bifrost 1.1.3** → `persistent-memory.d/2026-07-16-bifrost-ruled-scan-snapshot-cursor-normative.md` - `[2026-07-16]` **brokkr flagged ratatoskr as R39 Phase-2 PROBE-RUNNER (Arm-2 contradiction set = our frozen 10-chunk specimen); ACCEPTED IN PRINCIPLE (Vuong 2026-07-16) — formal scope + effort commit lands when Arm-2 actually spins** → `persistent-memory.d/2026-07-16-brokkr-flagged-ratatoskr-as-r39-phase-2-probe.md` - `[2026-07-17]` **`mark_superseded` verb SHIPPED + live-verified (v0.20.15, `be2c577`) — WT #364 durable retirement lands on our store; #364 CLOSED end-to-end both sides** → `persistent-memory.d/2026-07-17-marksuperseded-verb-shipped-live-verified-v0.md` - `[2026-07-17]` **Web-console UI (v0.20.16, pushed): code-block word-wrap + per-code-block & per-turn copy buttons** → `persistent-memory.d/2026-07-17-web-console-ui-v0-20-16-pushed-code-block-wor.md` - `[2026-07-17]` **P06-driver referential-frame A/B/C probe QUEUED (operator-ratified, deploy-gated on WT b122)** → `persistent-memory.d/2026-07-17-p06-driver-referential-frame-a-b-c-probe-queu.md` - `[2026-07-17]` **Sindra live memory.db tidied to a 5-fact PRISTINE baseline for a test drive** → `persistent-memory.d/2026-07-17-sindra-live-memory-db-tidied-to-a-5-fact-pris.md` - `[2026-07-18]` **#368 (user, character) memory silo test — DONE, PASSED live (WT b127).** Write + read isolation both proven end-to-end; betty (throwaway) deleted; the immediate post-clear action, closed. → `persistent-memory.d/2026-07-18-368-silo-test-passed.md` - `[2026-07-18]` **Worldtree owns the official Conversation API SDK (#371) — Rata's client spine (`sse_client`/`sessions`/`tier3`) is the SEED; the SillyTavern app moved OUT to a NEW repo (template-dev), Rata does NOT fork.** Rata = SDK seed + future consumer; TS ships first (Rata's repin rides the later Python milestone); internal-registry-only. → `persistent-memory.d/2026-07-18-worldtree-sdk-371-and-sillytavern-app.md` - `[2026-07-18]` **issue #1 contract drift fixed (`4bd9abd`) — SSE event vocab re-canonicalized: added `awaiting_llm_first_token` (#201) + `affect_update` (#204) to the Event union + TESTS (both were parsed by `_envelope_for_type` and tested in `test_sse_client.py`, but never in #1's contract; surfaced by the #371 parity pass). Contract-only, no bump.** - `[2026-07-18]` **Both app products (arbo image-gen + SillyTavern chat) leave Rata to a NEW repo (template-dev standing up); Rata does NOT fork and is NOT the app base.** Reverts Rata to its core — Worldtree debug-observability surface + Bifrost reference impl + Conversation-API SDK seed/future-consumer. Supersedes the 2026-07-17 'fork Rata for arbo' NEXT-MAJOR plan. - `[2026-07-18]` **ephemeral-template (Echo) create SHIPPED (`v0.21.2`, `c7016f2`, #19)** — `config` passthrough + `--system-prompt` + `SessionInfo.kind/config` + `--whoami` roles fix. Diagnosed from the ignored `session_api_failed` startup line; role/model drift resolved w/ worldtree-dev (spec re-synced v1.1). TDD + heid contract-review + bug-hunt. - `[2026-07-18]` **Rata = THE reference consumer of the worldtree-sdk Python spine** — parity pass (12 grounded findings) shaped its contract BEFORE build (open-world reads, caller-injected transport, per-wire role/model — adopted); coverage-map re-anchored to the SDK's 41-op ratified surface (`b1fbadd`); 4 ergonomics items parked post-v1 with wtsdk-dev. - `[2026-07-18]` **worldtree-sdk cutover DECIDED — adopt the Python SDK for the consumer client layer** (operator, overriding "stay hand-rolled"). Issue #20; contract `docs/contracts/worldtree_sdk_cutover.contract.md` (`e45640c`, vor-cross'd + heid-reviewed); auto-memory `project_worldtree_sdk_cutover`. Consumer layer only, Bifrost provider untouched; slice-1 foundation next. See in-flight. - `[2026-07-19]` **worldtree-sdk cutover SLICE-1 + SLICE-2 COMPLETE + PUSHED (origin `aba1730`, v0.21.10, 497 green).** The biggest, riskiest cutover slice done end-to-end through the full House Code Discipline (adapter→cli→web→delete→live-smoke→both heid gates); the bug-hunt caught 4 real confirmed bugs the conformance lens couldn't, and a convergent code-review finding was correctly REJECTED as category-5 (SDK envelope-parser behavior). Slice-3 next. → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-1-2-complete.md` - `[2026-07-19]` **worldtree-sdk cutover SLICE-3 COMPLETE + pushed (`ca9a339`+`fc256bb`, v0.21.11–.12, 469 green).** Persona/authored-history/first-message onto the wt adapter; last hand-rolled `sessions.py` paths deleted; both heid gates cleared — code-review ZERO drift, bug-hunt caught + fixed a real regression I shipped (ConnectFailed escaping both rewired probes → uncaught crash; the SDK normalizes ALL transport failures to `ConnectFailed`, not raw httpx) plus a finite-PAD chokepoint gap. Slice-4 (agents/tier3 + model→role) next. → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-3-complete.md` - `[2026-07-19]` **worldtree-sdk cutover SLICE-4 COMPLETE (agents/Tier-3 + `model`→`role` fold, `c62b4ee`+`aed9429`+`477d98f`, v0.21.13–.15, 475 green).** Full House Code Discipline; the LIVE SMOKE caught a `python -m` double-module exception-class-identity bug unit tests structurally can't; both heid panels cleared (code-review zero-drift + 3 fixups; bug-hunt 5/5/5 → open-world-presenter degrade-not-crash fixes). Resolves the deferred scope-B model→role. Slice-5 next. → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-4-complete.md` - `[2026-07-19]` **worldtree-sdk cutover SLICE-5 COMPLETE (characters + me/capabilities/models, `deab762`+`d86d6df`+`4e20030`, v0.21.16–.18, 488 green).** Last consumer reads + transient-character CRUD onto the wt adapter (CLI-only rewire, NO new Error-map rows — all six routes → SessionApiFailed default); live-smoke-proven on :8081/b128; both heid gates cleared — code-review caught the null/element open-world-presenter degrade holes, the cold bug-hunt caught the **container-type layer below** them (guard container-type + element-type + top-level-mapping). Slice-6 (admin) next. → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-5-complete.md` - `[2026-07-19]` **worldtree-sdk cutover SLICE-6 COMPLETE (admin: bifrost inspection + admin-events SSE, `de9a5ba`+`bba57e1`+`11ae2f0`, v0.21.19–.20, 494 green).** The two admin routes onto `client.admin.*` (**WEB-only** — the coverage-map's tui.py rows were stale); admin auth moved from a per-call header to the client's `admin_auth`; the admin-events adapter **re-wraps** the SDK's divergent `AdminEvent`→ratatoskr's (nan/None degraded) to preserve the web surface. Live-smoke-proven (real `session.created` event id=34 re-wrapped end-to-end). Both heid gates cleared — code-review 3/3 no-drift (only a stale docstring + a test-gap), the cold bug-hunt caught 4 real hardening gaps the CR couldn't (ConnectFailed unmapped on the admin stream; non-str type crash; `dict(non-mapping)` bifrost 500; a transport leak). Slice-7 (teardown, LAST) next. → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-6-complete.md` - `[2026-07-19]` **wyrd-dev #368 silo-enforcement consult delivered — ratatoskr's store-side silo is CONVENTIONAL (query-time filter); wyrd going STRUCTURAL off the framing.** Answered artifact-only from the provider memory-store code; wyrd folded my foot-guns into their unit-4 contract + committed to one-DB-file-per-campaign + first-class partition columns. OPEN LOOP: I'll eyeball their data model once the contract's cut (they'll ping). → `persistent-memory.d/2026-07-19-wyrd-368-silo-consult-delivered.md` - `[2026-07-19]` **worldtree-sdk cutover SLICE-7 (teardown, the LAST) COMPLETE — the whole cutover shipped as v0.22.0 (`ec68b1f`, minor, operator-approved).** Zero runtime-logic teardown: httpx-sse dropped (SDK owns SSE), wire contracts #2/#15 retired (files deleted; #1+first_message kept), `sessions.py`/`sse_client.py` KEPT as pure type/exception homes (operator decision A1 — no rename/fold), coverage-map re-anchored. All 7 slices done, 494 green; push + althing-announce pending (operator's call). → `persistent-memory.d/2026-07-19-worldtree-sdk-cutover-slice-7-complete.md` - `[2026-07-19→08-01]` **Donut voiced-interview BUILD — auto-TTS via Zonos + retire-ready KB-recall bridge + Princess Donut.** Slice-1 done (persona + define); slices 2-3 to build; both external deps verified live. THE active work. → `persistent-memory.d/2026-08-01-donut-voiced-interview-build.md` - `[2026-08-01]` **worldtree-sdk 1.0.0→1.1.1→1.1.2 repin — and a reference-consumer catch.** 1.1.1's path-encoding fix MISSED the inline `turn_stream.py:185` on the SSE path (caller-shaped session_id, our highest-traffic route); wtsdk-dev fixed it in 1.1.2 same-day. (`d3a36f7`+`0058020`, pushed.) - `[2026-08-01]` **Mimir #382 grounding bug — our finding shaped the fix.** Rata caught that the #380 vector re-index left Mimir DISCARDING correct P&P hits (no named source in the fiction wing → agent distrusts its own hits + answers from training; a silent-substitution "reasoning move, not retrieval"). Fix = our proposed residual (self-describing `_index.md`) + a Mimir prompt rule; deployed b166. **P&P verification re-run OWED to infra-ops**; DCC dir still opaque (backfill failed, flagged to worldtree-dev). - `[2026-08-01]` **Canonical sync — added the client-spec-v2 pin (option A) + synced OpenAPI/spec forward** (`14bbc2b`, pushed). Whole-manifest sync also bumped the OpenAPI hard-gate additively (frozen v1 wire → no breakage). Coverage-map re-audit vs the new surface = queued follow-up. - `[2026-07-30]` **Versioning cadence → RELEASE-ONLY (operator-ratified, brokkr-smithy relayed).** Retired per-commit bump+tag; tag only releases; between releases `feat:`/`fix:` SHAs. Existing ~112 tags left as-is. Global CLAUDE.md SemVer being amended to match. - `[2026-08-01]` **bifrost 1.1.4→1.1.5 (v0.22.1, `3ef3a5e`, pushed)** — optional-store-verb 500→`unsupported_capability` hardening; provider restarted onto it. - `[2026-08-01]` **Sindra saga — restored from local-index burial, wiped, smoke-tested.** The v0.22.0 web restart dropped her live session AND the schema-v2 discard buried her from the picker; migrated her v1→v2 from authoritative WT (real role `thoughtful-character`, not the stale `mistral-small-4`), then `scripts/reset-sindra-stores.sh` wiped memory+persona for a from-scratch smoke. - `[2026-08-02]` **Donut TTS: English pin + long-form chunking + POST + dialogue-only persona + both heid gates — shipped `d59f907` (pushed).** Gibberish→`language:"en-us"`; truncation→client-side chunk+concatenate under the 71.2s/6144-tok cap; persona dialogue-only + always-call `reference_knowledge`; 4-arm gates fixed a lock deadlock + several untrusted-input 500s the GET→POST switch re-opened. → `persistent-memory.d/2026-08-02-donut-tts-chunking-english-gates.md` - `[2026-08-02→03]` **`reference_knowledge` grounding VALIDATED end-to-end — 0/5→5/5 across a 3-round verify; the verify instrument drove diagnosis of a structural Tier-3 blindness (INV-361-3 metadata mismatch, #384) + density restore (#385).** Donut recalls the DCC corpus live; wt-dev's "cleanest consumer-side validation this pipeline has had." → `persistent-memory.d/2026-08-03-reference-knowledge-3-round-verify.md` - `[2026-08-03]` **Artifact-coverage gap filed as WT #387 (DEFERRED, tracked #387; operator picks when it runs).** "Crown of the Sepsis Whore" (major DCC item, confirmed 2× in source text) absent from the 705 concepts — the fiction concept schema has NO item/artifact type, so named objects ride incidentally in plot_events and single-scene items survive on sampling luck. My ratatoskr coverage-probe offer (known-major-artifacts yardstick) recorded on #387; wt-dev pings me when its re-extraction ships. Consumer-side flag, wt-owned fix (schema evolution). Thread `01KZ349M…`. - `[2026-08-03]` **worldtree-sdk repinned 1.1.2→1.2.0 (operator-directed, `ae49dcf`, pushed).** New `ResponseTooLarge` (a ProtocolError, non-resumable) mapped → `SseResponseTooLarge` at the stream surfaces (`wt.stream_turn`/`stream_admin_events` + the 2 stream endpoints); the 108MB read-body cap is unreachable on legal traffic so reads inherit the SDK refusal unwrapped. Absorbed WT spec 2.4.0/2.5.0 (zero-schema). +2 adapter tests. - `[2026-08-03]` **Donut ANTI-FABRICATION persona shipped (`3e12c4d`+`c0a66fc`, pushed) + the retry-on-LOW experiment tested & rejected.** Her memory IS the tool's results: LOW/no-on-target → deflect in-character, MEDIUM+ → answer; self-corrects as the KB improves. The retry BACKFIRES (RRF confidence inflatable by any DCC-flavored query → false MEDIUM → fabrication); robust fix is tool-side = #389. → `persistent-memory.d/2026-08-03-donut-anti-fabrication-and-retry.md` - `[2026-08-03]` **R42 (fiction-wing retrieval characterization) probe harness shipped to brokkr-smithy-dev (operator-directed, `04e0293`, pushed).** `docs/diagnostics/fiction_wing_probe.py` is R42's official harness + the re-runnable #389 acceptance gate; conventions (0.030/0.016 buckets, on-target = row names the subject, N-run bucket distribution) + the frozen artifact yardstick adopted verbatim. PENDING (peer-pinged): arm-1 on-target alignment at Phase-1; #389 gate re-run when RRF work lands. Threads wt-dev `01KZ349M…` / brokkr `01KZ421X…`. - `[2026-08-02]` **worldtree-sdk 1.2.0 repin DEFERRED to a dep pass (my rec; operator to decide).** New `ResponseTooLarge` (a `ProtocolError`, NOT caught by our `except ConnectFailed`) + response-alloc caps that assume a 2.5.0 server (worldtree-dev runs it → safe in practice). When repinning, add `ResponseTooLarge` to the caught envelopes. Tracked: wtsdk-dev announce thread `01KZ1ZYM…`. - `[2026-08-02]` **Filed issue #21** (sibling POST handlers `_create_session`/`_submit_turn` 500 on malformed JSON — the parse-JSON-or-400 asymmetry the heid gates flagged; pre-existing, out of the TTS diff's scope). Fix = a shared parse-JSON-or-400 helper. _67 older entries (2026-05-* debug-TUI/web era + the 2026-06-14 → 06-18 Bifrost-provider build / #17+#18 / #295-296 era) archived to archival-memory.md._ _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 Log of approaches that were tried and rejected, with rationale. Future-self defense against re-attempting the same cul-de-sac. - `[2026-07-10]` **Reverting our provider to bifrost 1.0.0 to fix the bound-handshake `schema_validation_failed` — DISPROVEN, and it would've been the WRONG state** → `persistent-memory.d/2026-07-10-reverting-our-provider-to-bifrost-1-0-0-to-fi.md` - `[2026-06-15]` **Canonical sync retired the issue-scoped parser staleness.** `contract_parser.py` synced to v2.1 (commit `d85ab43`): now validates issue-scoped frontmatter + four v2.1 test categories. The old "treat parser ERROR-on-issue-scoped as expected" note no longer applies. - `[2026-06-15]` **Issue #17 filed.** REVERSES design-brief §6's "no Bifrost-binding consumer support" — that negative clause predates ratatoskr's provider identity (2026-06-14), so the canary now owns both ends but its client couldn't drive its own provider. (Shipped 2026-06-18.) - `[2026-06-16]` **`scripts/contract_drift_check.py` defaults `GITEA_REPO` to "Worldtree"** (line 74), so a bare run in ratatoskr false-positives DRIFT by hashing Worldtree's same-numbered issue. Always `export GITEA_REPO=ratatoskr GITEA_OWNER=vh` before running the drift-checker here. - `[2026-06-19]` **The SAME `check_same_thread` sqlite bug recurred in the MEMORY store — exposed by the contract-mandated `search` dispatch test (TestClient = worker thread)** → `persistent-memory.d/2026-06-19-the-same-checksamethread-sqlite-bug-recurred.md` - `[2026-06-19]` **Full WT-driven `:8392` live-smoke is infra-gated — `:8392` not in WT's `BIFROST_CLIENT_ALLOWED_HOSTS` (bind 422s)** → `persistent-memory.d/2026-06-19-full-wt-driven-8392-live-smoke-is-infra-gated.md` - `[2026-06-19]` **heid-code-review pulled MORE weight than its own "marginal" self-assessment** → `persistent-memory.d/2026-06-19-heid-code-review-pulled-more-weight-than-its.md` - `[2026-06-20]` **The post-turn-async timing trap bit AGAIN — even a 35s post-`[done]` read missed the promotion `upsert_many` by ~2s** → `persistent-memory.d/2026-06-20-the-post-turn-async-timing-trap-bit-again-eve.md` - `[2026-06-30]` **Heimdall keys are PER-INSTANCE — a key minted on one Worldtree 401s on another** → `persistent-memory.d/2026-06-30-heimdall-keys-are-per-instance-a-key-minted-o.md` - `[2026-06-30]` **`tea comment ` hangs on Gitea** → `persistent-memory.d/2026-06-30-tea-comment-n-hangs-on-gitea.md` - `[2026-07-02]` **Mask-HOSTED transient characters have a STATIC mood engine — cost a whole R29 probe** → `persistent-memory.d/2026-07-02-mask-hosted-transient-characters-have-a-stati.md` - `[2026-07-03]` **The "neutral non-appraising tail" premise fails — the neutral MESSAGE choice dominates** → `persistent-memory.d/2026-07-03-the-neutral-non-appraising-tail-premise-fails.md` - `[2026-07-03]` **Two φ0-fit traps: fast-turn timescale + low-baseline conditioning** → `persistent-memory.d/2026-07-03-two-0-fit-traps-fast-turn-timescale-low-basel.md` - `[2026-07-06]` **`persona_state` + the agent envelope are Tier-3-BLIND -- NOT valid signals for "did a persona store"** → `persistent-memory.d/2026-07-06-personastate-the-agent-envelope-are-tier-3-bl.md` - `[2026-07-06]` **Raw `POST /sessions` is NOT Bifrost-bound -> zero affect/memory emits** → `persistent-memory.d/2026-07-06-raw-post-sessions-is-not-bifrost-bound-zero-a.md` - `[2026-07-06]` **A fast/"no-op" deploy can leave a STALE container running the old image -- verify the running version, not the deploy status** → `persistent-memory.d/2026-07-06-a-fast-no-op-deploy-can-leave-a-stale-contain.md` - `[2026-07-06]` **#348 OCEAN key-mismatch: a declared OCEAN silently resolved to neutral** → `persistent-memory.d/2026-07-06-348-ocean-key-mismatch-a-declared-ocean-silen.md` - `[2026-07-06]` **`pkill -f "ratatoskr-web --host"` SELF-MATCHES the bash command running it** → `persistent-memory.d/2026-07-06-pkill-f-ratatoskr-web-host-self-matches-the-b.md` - `[2026-07-06]` **Playwright: no python `playwright` module in the venv; use NODE playwright + an explicit `executablePath`** → `persistent-memory.d/2026-07-06-playwright-no-python-playwright-module-in-the.md` - `[2026-07-06]` **The Bash tool's `grep` is a ugrep-wrapper (`--ignore-files -I`) that silently returns NOTHING on some files** → `persistent-memory.d/2026-07-06-the-bash-tool-s-grep-is-a-ugrep-wrapper-ignor.md` - `[2026-07-06]` **`DesignSync` (claude.ai/design MCP) needs claude.ai design scopes before ANY method works** → `persistent-memory.d/2026-07-06-designsync-claude-ai-design-mcp-needs-claude.md` - `[2026-07-13]` **`thinking_enabled=False` on the define was a NO-OP — char-rp-reasoning ignores it** → `persistent-memory.d/2026-07-13-thinkingenabled-false-on-the-define-was-a-no.md` - `[2026-07-13]` **A same-image redeploy does NOT reload a bind-mounted config — the ModelRegistry boot-caches it at `__init__`** → `persistent-memory.d/2026-07-13-a-same-image-redeploy-does-not-reload-a-bind.md` - `[2026-07-15]` **soong-lab bundle `ship.native.motivational.goals/fears` are bare STRINGS, but WT `agents.define` requires OBJECTS** → `persistent-memory.d/2026-07-15-soong-lab-bundle-ship-native-motivational-goa.md` - `[2026-07-15]` **`re.sub`/`re.subn` INTERPRETS backslash-escapes in the REPLACEMENT string** → `persistent-memory.d/2026-07-15-re-sub-re-subn-interprets-backslash-escapes-i.md` - `[2026-07-13]` **Called Deckard "hung" off a short timeout — WRONG (operator correction)** → `persistent-memory.d/2026-07-13-called-deckard-hung-off-a-short-timeout-wrong.md` - `[2026-07-13]` **Resumed-session context-snapshot is IN-MEMORY → lost on a container recreate (agent_not_available on resume)** → `persistent-memory.d/2026-07-13-resumed-session-context-snapshot-is-in-memory.md` - `[2026-07-16]` **`sortable_chunk_fields` advertised WITHOUT the required `type` field = whole-handshake deploy-breaker; only DRIVING the real bind caught it** → `persistent-memory.d/2026-07-16-sortablechunkfields-advertised-without-the-re.md` - `[2026-08-01]` **`local_agents` index schema v1→v2 bump SILENTLY buries pre-cutover consumer agents from the picker** — `load_local_agents` returns `[]` on version mismatch (no migration path); the v0.22.0 restart made Sindra vanish even though she was alive on WT. Fix applied ad-hoc: migrate the v1 row → v2 from authoritative WT data (the v1 `model` field held a stale model name, NOT the current role). A one-time v1→v2 migration guard is the durable fix (unbuilt; operator-flagged). - `[2026-08-01]` **Zonos: mp3/opus `response_format` silently return mislabeled PCM** (no encoder wired) — use `response_format:"wav"` only. And use the GATEWAY :8890, NOT the engine :1920 (rep-penalty bug pads ~70s silence + ignores voice). - `[2026-08-02]` **Zonos hard-caps ONE synthesis at `max_tokens=6144` = 71.2s of audio** (6144 / 86.3Hz codec frame rate; `>6144` → HTTP 400, an architectural sequence limit). 86.3Hz is a **delivery-INDEPENDENT constant** — 6144 tokens is ALWAYS 71.2s regardless of emotion/rate (emotion changes words-per-71.2s, not seconds-per-token). Any turn longer than ~71s REQUIRES client-side chunk-and-concatenate (raw PCM, ONE WAV header — never stitch multiple WAV headers). Fixed in `d59f907` (DEC-10). Don't chase a "raise max_tokens" fix — the gateway rejects it. - `[2026-08-02]` **A GET→POST endpoint switch re-opens untrusted-TYPE crashes that string-only query params silently masked.** Under GET, `p`/`a`/`agent_id` were always `str|None`; under a JSON POST body they can be a huge int (`float()`→OverflowError), an unhashable list/dict (`dict.get`→TypeError), or a lone surrogate (utf-8 encode→UnicodeEncodeError) — each a 500 the old code never saw. Guard EVERY body field when moving a query endpoint to a JSON body. Both heid gates converged on these (all 4 arms). Fixed in `d59f907`. - `[2026-08-03]` **A bare `uv sync` PRUNES this project's dev deps** — pytest/respx/ruff live in `[project.optional-dependencies]` (an EXTRA, not a dependency-group), so `uv sync` (default groups only) removes them from `.venv`, and `uv run pytest` then silently falls back to a user-site pytest (py3.11, `~/lib`) that can't import the `.venv`'s `worldtree_sdk` → 16 collection ModuleNotFoundErrors. Use **`uv sync --all-extras`**. Bit me right after the 1.2.0 lock; the repin itself was never at risk. - `[2026-08-03]` **`tier3 patch` does NOT refresh a live agent's running context** — it updates STORAGE (the define/patch response echoes the new prompt) but the running agent keeps serving the OLD system prompt. To change a live Tier-3 persona reliably, **delete + define (recreate)**, not patch. (Cost a confusing "patched but behavior unchanged" loop on the Donut anti-fabrication change.) - `[2026-08-03]` **A persona-side confidence gate can't stop LLM fabrication — RRF confidence is inflatable by query phrasing.** A "re-search on LOW" retry reformulates the query with related real entities (or just DCC-flavored terms), which scores MEDIUM off THOSE matches, not the subject — manufacturing false grounding to fabricate on. The signal that survives is on-target (does a returned row NAME the subject), which is a TOOL-side check, not something a prompt can enforce against a model with strong genre priors. → #389. _34 older entries (2026-05-* debug-TUI/web era + the 2026-06-14 → 06-18 foot-gun cluster) archived to archival-memory.md._