|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
# Persistent memory — ratatoskr
|
|
|
|
|
|
|
|
|
|
_Last updated: 2026-08-09_
|
|
|
|
|
_Last updated: 2026-08-13_
|
|
|
|
|
|
|
|
|
|
> **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
|
|
|
|
@@ -44,23 +44,27 @@ upstream API key stays server-side (INV-003).
|
|
|
|
|
|
|
|
|
|
## Current state / in-flight
|
|
|
|
|
|
|
|
|
|
_As of 2026-08-09:_
|
|
|
|
|
_As of 2026-08-13:_
|
|
|
|
|
|
|
|
|
|
**Nothing in flight on ratatoskr's side — this session's three arcs all shipped + pushed (HEAD `93011dc`, origin synced). The live tails are all upstream (worldtree-dev), not ours.** Details in Recent decisions; the durable substrate below.
|
|
|
|
|
**Nothing in flight on ratatoskr's side. The RP-voice stack was rebuilt this session (chatterbox→dots, then config-driven voices + a two-voice dialogue/narration split) — all shipped + PUSHED (HEAD `5c3d0ad`, origin synced, tags `v0.22.2`/`v0.22.3`). The one open tail is upstream: WT #401 (worldtree-dev owns the personal-WT deadlock root-cause).** Details in Recent decisions; durable substrate below.
|
|
|
|
|
|
|
|
|
|
- **TTS migrated Zonos→chatterbox-fast + German-drift fixed** — live on `ratatoskr-web` **pid 2214344** (`:8765`). `tts.py` is the single swap seam: chatterbox-fast `http://10.100.79.3:8197/tts`, bespoke `{text,voice,format,stream}`, 24kHz, NO affect, NO client chunking (`RATATOSKR_TTS_URL` overrides). Drift fixed server-side (chatterbox `:v2` `max_chunk_chars=250`); consumer sends full text + default sampling. FOOT-GUN: `ratatoskr-web` is a bare detached process, no supervisor → re-stales on reboot/crash; systemd unit offered, operator declined.
|
|
|
|
|
- **Crown-recall arc CLOSED** (b185 identity-anchor rerank enrichment; gate verdict 79%→12% stress miss). Upstream tail: b185 promotion beyond personal/demo. If the operator ever pulls a prompt-side lever at the bare-query/adoption residual (the irreducible ceiling shared with #397), worldtree-dev asks us to re-point the gate.
|
|
|
|
|
- **Two diagnostic gates in-repo** — `docs/diagnostics/lexical_recall_gate.py` (exact-term recall class instrument) + `temporal_order_gate.py` (#397 order_by=chapter). The before/after instruments for any future retrieval lever; #397 CLOSED, #400 closes on brokkr's no-harm post-half.
|
|
|
|
|
- **TTS = dots-tts + config-driven voices + two-voice split** — live on `ratatoskr-web` **pid 2290701** (`:8765`, dots + `voices.json` loaded). Backend is **dots-tts** via the fleet **switchboard** `http://10.100.79.3:8198/v1/audio/speech` (OpenAI-shaped `{input,voice,response_format,stream}`, 48kHz mono s16le, streaming placeholder-header WAV). `tts.py` is the single swap seam (`RATATOSKR_TTS_URL` overrides), NO affect. Per-agent voices live in **`~/.config/ratatoskr/voices.json`** (donut→donut single; sindra→miranda dialogue + emmie narration); an agent with a `narration_voice` gets the quote-split two-voice stitch (`tts_stream_stitched`, `src/ratatoskr/voices.py`).
|
|
|
|
|
- **Personal WT :8081 recovered + root-cause routed to WT #401** — it deadlocked after ~4 days (event-loop wedge from a background `context_promotion` sqlite error); infra-ops `docker restart`'d it, worldtree-dev owns the diagnosis. Ratatoskr auto-recovered (degrade path held; no ratatoskr restart). Only possible follow-up = a consumer-side repro if worldtree-dev asks.
|
|
|
|
|
|
|
|
|
|
**Deferred / queued (non-urgent, pre-existing — tracked, NOT this-session):** TUI rip (`tui.py`+`tests/test_tui.py` delete cleanly, but `cli.py` is SHARED — relocate `USER_AGENT`/`ParsedArgs`/`_format_*` first; breaking public-surface removal → minor bump, operator approval); #368 backfill live-verify (synthetic legacy corpus); SDK **#371** (Rata = seed donor + future consumer; next = WT codegen spike; Rata's repin rides the later Python milestone; divergences D-1 unknown-SSE-skip / D-2 open-world-enums / D-3 typed-410); P06 referential-frame A/B/C probe (waits WT b122); R39 Phase-2 matched-quartets (confirmatory); bifrost snapshot-cursor adoption (normative, non-blocking).
|
|
|
|
|
**Deferred / queued (non-urgent, pre-existing — tracked, NOT this-session):** heid gates on the two-voice feature SKIPPED in-session (offered, not run — optional cross-frontier gate if wanted); TUI rip (`tui.py`+`tests/test_tui.py` delete cleanly, but `cli.py` is SHARED — relocate `USER_AGENT`/`ParsedArgs`/`_format_*` first; breaking public-surface removal → minor bump, operator approval); #368 backfill live-verify (synthetic legacy corpus); SDK **#371** (Rata = seed donor + future consumer; next = WT codegen spike; divergences D-1 unknown-SSE-skip / D-2 open-world-enums / D-3 typed-410); P06 referential-frame A/B/C probe (waits WT b122); R39 Phase-2 matched-quartets (confirmatory); bifrost snapshot-cursor adoption (normative, non-blocking).
|
|
|
|
|
|
|
|
|
|
**Live substrate / foot-guns:** branch `main`, HEAD `93011dc` pushed; origin `git@gitea.phasefinal.com:vh/ratatoskr.git`. Deps: **`worldtree-sdk==1.2.0`** (gitea PyPI, `[tool.uv.sources]`; new `SseResponseTooLarge` at the stream surfaces), **`bifrost==1.1.5`**/wire v0.7, WT openapi vendored 2.3.0, conversation-api-spec v1.1. **`uv sync --all-extras`** — dev deps are a `[project.optional-dependencies]` EXTRA; plain `uv sync` PRUNES pytest/respx. Personal WT on **b185** (`http://10.250.50.152:8081`, both instances). Surfaces: combined **`:8392`** provider (memory+affect) + **`:8765`** web — detached background processes; `env.sh` sets the REQUIRED `RATATOSKR_MEMORY_EMBEDDING_DIM=1024`; keys mode-600 in `~/.config/ratatoskr/provider.env` + `RATATOSKR_ADMIN_API_KEY`. **FOOT-GUN: check owner-scoped agents via `GET /agents/<owner>:<name>` with the OWNER key (`WORLDTREE_API_KEY`), NOT the admin key (admin → false 404).** SDK-adapter foot-guns (cumulative): SDK reads = open-world dicts → presenters degrade-not-crash at 3 guard levels; all transport failures → `ConnectFailed(status=0)` (every caller `except ConnectFailed`); `local_agents` index v1→v2 bump SILENTLY DROPS pre-cutover agents (`load_local_agents` returns [] on version mismatch). `graphify-out/` runs dirty (auto-regen on commit hook, never stage). v1 = full Worldtree I/O coverage, cuts when WT tags 1.0 (`docs/coverage-map.md`).
|
|
|
|
|
**Live substrate / foot-guns:** branch `main`, HEAD `5c3d0ad` PUSHED; origin `git@gitea.phasefinal.com:vh/ratatoskr.git`; version **v0.22.3**. Deps: **`worldtree-sdk==1.2.0`**, **`bifrost==1.1.5`**/wire v0.7, WT openapi vendored 2.3.0, conversation-api-spec v1.1. **`uv sync --all-extras`** — dev deps are a `[project.optional-dependencies]` EXTRA; plain `uv sync` PRUNES pytest/respx. Personal WT on **b185** (`http://10.250.50.152:8081`) — **FOOT-GUN: it can deadlock into a live-socket/dead-worker hang (WT #401); symptom = TCP port open but ALL routes return 000 ("server disconnected without response"); fix = infra-ops `docker restart`, ratatoskr auto-recovers.** Surfaces: combined **`:8392`** provider (memory+affect) + **`:8765`** web (pid 2290701) — detached bare processes, no supervisor → re-stale on reboot (relaunch `source env.sh && setsid .venv/bin/ratatoskr-web --host 0.0.0.0 --port 8765`); `env.sh` sets REQUIRED `RATATOSKR_MEMORY_EMBEDDING_DIM=1024`; keys mode-600 in `~/.config/ratatoskr/provider.env`. **dots-tts `:8198` is now a fleet SWITCHBOARD** (fronts dots on `:8202`; +3.3ms; engine swaps = instant `.env` flips; v4 engine adds an optional `language` field). **FOOT-GUN: dots' `language` validator is an alias-mapper NOT a gatekeeper** — word-junk ('klingon') maps to a tag + generates; only structurally-invalid tokens (empty/punctuation/overlong) 400 → validate ourselves if we ever send `language`. **FOOT-GUN: browser auto-TTS is opt-in (`localStorage['ratatoskr-tts']='1'`), PER-ORIGIN** — localhost vs LAN-IP have separate storage, so the toggle doesn't carry between them. **FOOT-GUN: check owner-scoped agents via `GET /agents/<owner>:<name>` with the OWNER key, NOT admin (admin → false 404).** SDK-adapter foot-guns (cumulative): SDK reads = open-world dicts → presenters degrade-not-crash at 3 guard levels; all transport failures → `ConnectFailed(status=0)`; `local_agents` index v1→v2 SILENTLY DROPS pre-cutover agents. `graphify-out/` runs dirty (never stage). v1 = full Worldtree I/O coverage (`docs/coverage-map.md`).
|
|
|
|
|
|
|
|
|
|
## 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-12]` **Personal WT :8081 deadlocked after ~4 days → routed to worldtree-dev as WT #401; ratatoskr degrade path held.** Live-socket/dead-worker event-loop wedge (background `context_promotion` sqlite "unable to open database file"); recovered by infra-ops `docker restart`; ratatoskr auto-recovered (12/12 502 → 8/8 200, no ratatoskr restart). → `persistent-memory.d/2026-08-12-wt-401-personal-deadlock.md`
|
|
|
|
|
- `[2026-08-12]` **Config-driven voices + two-voice dialogue/narration split SHIPPED (v0.22.3, `5c3d0ad`).** `~/.config/ratatoskr/voices.json` (per-agent voice + optional `narration_voice`); new `src/ratatoskr/voices.py`; `tts_stream_stitched` replaces `tts_stream`; contract DEC-11 + INV-TTS-5/6/7. → `persistent-memory.d/2026-08-12-config-voices-two-voice.md`
|
|
|
|
|
- `[2026-08-12]` **dots-tts `:8198` became a fleet SWITCHBOARD (fronts dots `:8202`, +3.3ms); engine swaps are now instant `.env` flips.** v4 engine adds an optional `language` field; byte-compatible, no ratatoskr change. FOOT-GUN: dots' `language` validator is an alias-mapper not a gatekeeper (word-junk generates, doesn't 400) — validate ourselves if we ever send it.
|
|
|
|
|
- `[2026-08-11]` **Sindra voiced with the dots `miranda` voice (`3e69bc9`, no bump).** Ratatoskr-side per-agent voice map (resolved at `/api/tts` by `agent_id`); superseded next day by the config-driven map (DEC-11).
|
|
|
|
|
- `[2026-08-11]` **TTS migrated chatterbox-fast→dots-tts (v0.22.2, `38b78d8`), operator-directed after an A/B win.** OpenAI-shaped `/v1/audio/speech`, SR 24000→48000, default voice glados_25s→glados, serialized single-consumer; affect stays dropped; chatterbox `:8197` reclaimed. → `persistent-memory.d/2026-08-11-tts-dots-migration.md`
|
|
|
|
|
- `[2026-08-08]` **Crown-recall RESOLVED at b185 — identity-anchor rerank enrichment closed the class (gate: 79%→12% stress miss).** worldtree-dev shipped a rerank-input identity anchor (from character/terms metadata) + chain-wide tie-determinism (`50ecec7`) instead of the floor lever; `lexical_recall_gate --anchor crown --runs=8` at b185 = 12% miss / 0% knife-edge / item @rank 0 (vs 79% post-fold b184). Floor packet does NOT reopen; 12% residual = bare-query formulation ceiling. Arc complete our side; efficacy delta on WT #400.
|
|
|
|
|
- `[2026-08-07]` **Crown-recall traced to a general RETRIEVAL-CLASS limitation (exact-lexical match on an indexed surface form buried by dense-semantic neighbors), NOT persona/extraction/synonymy.** worldtree-dev decomposition (WT #400): no-stemming tokenizer + RRF top-10 knife-edge + reranker ownership-demotion. Operator-greenlit evidence-gated sequence (ship stemming fold → gate measures residual → hold `rerank_hybrid_floor` lever). Shipped `docs/diagnostics/lexical_recall_gate.py` (class acceptance instrument); pre-fold baseline control 0% / stress[crown] 100% miss. Awaiting worldtree-dev fold+#397 deploy ping for the pre/post delta. Thread `01KZETD98T`; siblings WT #399 (filed), #397 (committed, not deployed).
|
|
|
|
|
- `[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.
|
|
|
|
@@ -233,6 +237,7 @@ _For per-issue TDD implementation notes, Volva findings, and contract amendments
|
|
|
|
|
Log of approaches that were tried and rejected, with rationale. Future-self
|
|
|
|
|
defense against re-attempting the same cul-de-sac.
|
|
|
|
|
|
|
|
|
|
- `[2026-08-11]` **dots streaming `pcm` is NOT headerless — only NON-stream `pcm` is raw s16le.** `response_format:"pcm"` + `stream:true` still emits a RIFF placeholder-header WAV (dots always headers a stream). So the two-voice stitch (`tts_stream_stitched`) can't use "pcm for spans 2..N" to skip header-stripping — it streams every span as `wav` and strips the leading header on later spans (accumulate-until-`data`, INV-TTS-7). Don't chase the pcm shortcut for streaming.
|
|
|
|
|
- `[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.)
|
|
|
|
|