Captures this session's durable state: the RP-voice rebuild (chatterbox->dots
v0.22.2, config-driven voices + two-voice dialogue/narration split v0.22.3) and
the personal WT :8081 deadlock recovery + root-cause routing to worldtree-dev
(WT #401). New substrate foot-guns: dots :8198 is a fleet switchboard, dots'
language validator is an alias-mapper, per-origin TTS toggle, WT hang signature,
dots-streaming-pcm-not-headerless. Three detail files added under
persistent-memory.d/.
Condensed the volatile Current state / in-flight section from 153 lines to a lean
session-end state (418->279 total): dropped the superseded 2026-08-02 historical
in-flight block (overwritten per the snapshot skill, not archived), preserved all
durable substrate (foot-guns, deps/pins, deferred-queued items, surfaces). Recent
decisions + Tried-and-abandoned untouched. Everything this session shipped + pushed
(HEAD prior 93011dc); nothing in flight on our side. Memory-only snapshot — no bump.
Companion to lexical_recall_gate.py for the #397 order_by="chapter" flag (deployed
personal b184). Drives narrative/temporal queries and measures three axes end-to-end:
- ADOPTION: does the agent invoke order_by="chapter" for a temporal query? (schema
teaches it; usage varies — the #397 analog of query-formulation variance)
- MECHANISM (flag applied): are served hits' provenance.chapter monotonically
non-decreasing (earliest first)?
- VALUE (flag not applied): the relevance baseline is NOT chapter-sorted — the
applied-vs-not monotonicity gap is the flag's payoff.
Built against the real live shapes (order_by enum ["chapter"], result carries
ordered_by, provenance.chapter), not guessed. Baseline @ b184 (--runs=3, 15 trials):
adoption 47%, flag-applied->monotone 100%, not-applied->monotone 0%. So the mechanism
is a clean discriminator; the residual is adoption (same class as the crown's
query-formulation variance — the irreducible prompt-side gap).
Diagnostics fixture, no production runtime — no version bump. persistent-memory
snapshot alongside (commit-along).
Generalizes the crown repro (Worldtree #400 / thread 01KZETD98T) beyond its anchor
into a before/after regression instrument for the class property: when the corpus
holds a chunk whose text literally carries a queried surface form, a natural query
should serve >=1 such chunk at a usable rank.
- Anchors tagged stress (common word + competing dense cluster, e.g. crown) vs
control (distinctive name — should sit ~0% miss).
- Binary per trial: does a natural query serve >=1 term-containing chunk within
top-10 (USABLE_K)? Ranks >=8 flagged KNIFE-EDGE (the RRF fused-rank 9-11 window
residual worldtree-dev's decomposition measured).
- Real-world end-to-end: drives the agent (it composes its own reference_knowledge
query, as in production); --runs samples query-formulation variance to estimate a
true miss-rate.
- Extensible anchor list; --anchor filters.
This is the deciding instrument for the rerank_hybrid_floor lever: its stress-class
miss-rate (alongside brokkr's fleet demotion rate) rules the floor in or out after
the BM25 stemming fold deploys. Pre-fold baseline captured today (the "before"):
control 0% miss / stress[crown] 100% miss / 0% knife-edge, 11 trials.
Diagnostics fixture, no production runtime — no version bump. persistent-memory
snapshot committed alongside (commit-along).
The long-turn "swaps to German" garble was NOT a language leak (infra-ops's
initial framing) and NOT the sampling entropy my interim curb targeted. The real
cause, signal-measured by infra-ops: the Chatterbox Turbo model over-runs its
generation TAIL — a long single generation degrades into garble/dead-air in its
final ~2-3s (voiced-tail zero-crossing rate 1.58x the middle). The gateway's
unbounded chunk-size ratchet built 300-600 char mega-chunks that landed in that
zone, and streaming concatenated each bad tail.
My interim curb (top_k 1000->80, top_p 0.95->0.85, temp 0.8->0.5) made it WORSE:
tight sampling pulls the degradation onset to a shorter length (~200 chars vs
~300 at defaults), so it fights the server-side fix rather than helping.
Fixed server-side (infra-ops, chatterbox-fast image :v2): a max_chunk_chars=250
cap bounds each generation below the ~300-char onset -> clean prosodic chunks
(verified ZCR 1.58x -> 0.64x; operator ear-confirmed clean audio + clean joins).
Consumer side, this commit:
- Revert the sampling knobs: gateway_body back to {text, voice, format, stream},
send full text with the gateway's default sampling. The server chunks at 250.
- Keep the /api/tts empty-200 -> 503 guard as hygiene (DEC-9a; the shared-3090
OOM that produced empty 200s is also resolved — Zonos moved off the card).
Contract DEC-9 rewritten with the resolved root cause + the two wrong hypotheses;
DEC-9a marked kept-as-hygiene. 520 green.
Repoint the TTS client from the Zonos gateway (:8890 /v1/audio/speech) to
chatterbox-fast (:8197 /tts — bespoke non-OpenAI {text,voice,format,stream}
schema, no auth, 24kHz, infra-ops-verified). tts.py stays the single swap seam.
Dropped, no backward-compat (pre-v1):
- Affect (DEC-7): the Turbo checkpoint has no emotion knob, so PadState,
EmotionDials, pad_to_dials, the /api/tts p/a fields, and the browser pad
argument are deleted. Voice is now flat.
- Client-side chunking (DEC-10): chatterbox has no per-synth cap and chunks
internally, so chunk_text/tts_stream_long/_pcm_after_header are deleted; a
single tts_stream call voices a whole turn, the mid-stream yielded_any degrade
folded into it.
- Language pin (DEC-9): no language field; re-purposed to sampling curbs (below).
Fixed / added:
- Browser Web Audio sample rate 44100 -> 24000 (the chatterbox rate).
- Default voice Cora -> glados_25s; donut registered lowercase at /refs/donut.wav.
- English-drift curb: Turbo is multilingual-leaky and wanders off English on a
long generation (the gateway scheduler ratchets chunk size unbounded). Tighten
sampling in gateway_body: top_k 1000->80, top_p 0.95->0.85, temperature
0.8->0.5. These reduce drift probability; the guaranteed fix is a server-side
max-chunk cap (infra-ops, greenlit).
- OOM guard (DEC-9a): a long generation can OOM the shared 3090, returning 200
with a 0-byte body; /api/tts surfaces an empty 200 as 503 rather than
committing silent audio.
Contract donut_voiced_interview.contract.md amended: migration banner, DEC-1/3/8
amended, DEC-7/9/10 retired with historical notes, DEC-9a added.
Tests rewritten to the new wire; 520 green. Live-smoked against the gateway
(24kHz synth + endpoint proxy + web console). persistent-memory.md committed
alongside (commit-along).
Captures the anti-fabrication persona + the tested-and-rejected retry-on-LOW (RRF confidence
is inflatable by query phrasing; robust fix is tool-side = #389), the b170 corpus updates
(artifact type #387, character-death extraction, participant metadata #390 — Jack + the
artifacts ground now), and the operator-directed R42 spin-off (probe harness 04e0293 shipped
to brokkr-smithy-dev as R42's official harness + the #389 acceptance gate). Two peer-pinged
follow-ups pending (R42 Phase-1 arm-1 alignment; #389 gate re-run). Foot-guns: tier3 patch
doesn't refresh live context (recreate); a persona confidence-gate can't stop fabrication.
reference_knowledge grounding validated end-to-end (0/5 -> 5/5 across a 3-round verify;
#384 metadata-mismatch + #385 density both closing), sdk repinned 1.2.0 (ae49dcf), and the
artifact-coverage gap filed as WT #387 (schema not artifact-aware; my coverage-probe offer
parked, operator picks when it runs).
1.2.0 adds response-side allocation caps + a new exported `ResponseTooLarge`
(a ProtocolError, NOT a ConnectionDropped — retrying an oversized response is
futile; caps: 2xx body 108,004,096 B, SSE frame 540,000 B, both calibrated to
a 2.5.0 server, which worldtree-dev runs, so safe on legal traffic). Absorbed
WT spec 2.4.0/2.5.0 (zero-schema, no generated-type change).
We catalogue SDK errors explicitly, so ResponseTooLarge needs a home: added
`SseResponseTooLarge` (sse_client), mapped from `wtsdk.ResponseTooLarge` in
`wt.stream_turn` + `wt.stream_admin_events` (above the ApiError default — it's a
ProtocolError, not an ApiError), and caught in the two stream endpoints so an
oversized SSE frame surfaces as a labeled error, never an uncaught 500 or a
futile reconnect. The 108MB read-body cap is unreachable on legal traffic (a
108-megabyte transcript page is absurd), so reads inherit the SDK refusal
unwrapped. +2 adapter-mapping tests; 548 green. Done during the DCC-fix wait.
Slice 1 of the auto-TTS/voiced-KB-character build (operator ask "add auto-tts
to the web gui"): the donut_voiced_interview contract (validated), the Princess
Donut persona (corpus-grounded from a Mimir DCC pull), and ratatoskr:donut
defined on :8081 (server-side; in the picker). Slices 2 (Zonos auto-TTS) + 3
(retire-ready KB-bridge) are TO BUILD.
Snapshot captures the full build state + design (Zonos gateway :8890, voice
"donut" registered, affect-driven emotion dials; the worldtree-dev-ruled
consumer-side retrieval + memory_context pinning bridge, retire-ready) for the
post-clear resume, plus the arcs since v0.22.0 (SDK 1.1.2 repin, bifrost 1.1.5,
canonical sync, release-only versioning, the Sindra saga + local-index
schema-burial foot-gun, the Mimir #382 reference-consumer finding). Handoff at
/tmp/ratatoskr-dev-handoff.md. Release-only cadence: no tag.
Slice-7 teardown landed (ec68b1f); the whole #20 cutover is done. Collapsed
the now-complete cutover in-flight block to a COMPLETE summary + foot-gun
carry-forward, added the slice-7 Recent-decisions entry + detail file, and
flagged the two operator-gated post-ship actions (push + althing announce).
Archival drain deferred (file ~33 over soft cap; standing-posture entries
interleave the settled ones — a dedicated pass, not a milestone-checkpoint cut).
Slice-6 (admin: bifrost inspection + admin-events SSE) done through the full House
Code Discipline, v0.21.19–.20, suite 494 green, live-proven (real session.created
event re-wrapped end-to-end on :8081), both heid gates cleared. Current state advanced
to slice-7 (teardown, LAST) next; Recent-decisions index entry + detail file added;
substrate at v0.21.20. Consumer client layer now fully cut over (6/7 slices).
persistent-memory.md stays ~345 lines (over the ~300 soft cap): dominated by the
non-archivable Current state block + <30-day July entries (guarded), so archival can't
reach the 250 target — left as-is per the stop-where-the-guards-stop rule.
Slice-5 (characters + me/capabilities/models) done through the full House Code
Discipline, tags v0.21.16–.18, suite 488 green, live-smoke-proven on :8081/b128,
both heid gates cleared. Current state / in-flight advanced to slice-6 (admin) next;
Recent-decisions index entry + detail file added; substrate at v0.21.18.
persistent-memory.md stays ~333 lines (over the ~300 soft cap): the length is
dominated by the non-archivable Current state / in-flight block plus <30-day July
entries (guarded), so archival can't reach the 250 target — left as-is per the
stop-where-the-guards-stop rule.
Slice-2 (sessions/turn) done end-to-end through the House Code Discipline; both heid
gates triaged+fixed. Captures the KEY ADAPTER FACTS foot-guns for slices 3-7 (open-world
dicts, body-derived turn_id, ConnectFailed(0) transport normalization, consumer_key
bound-only, nested-detail error_code parsing) + the two-lens gate value proof. Slice-3
(persona/authored-history) next.
Re-snapshot for fresh context. Cutover slice-1 half-landed: worldtree-sdk==1.0.0
integrated + DEC-5 install-verified + committed (29c4fda), suite 534 green; the
ratatoskr.wt adapter (auth/transport split, error-map default) is the next step.
Substrate: unpushed cutover chain (e45640c contract, snapshot, 29c4fda dep) noted;
origin still at b1fbadd. Handoff aimed at the adapter. Index ~19 over soft cap;
archival deferred (guard-protected recents leave little to move — next run.)
Captures the SDK cutover as the active migration: contract done + heid-reviewed,
DEC-5 registry gate cleared, slice-1 foundation the next step. Plus ephemeral-Echo
(v0.21.2 #19) + reference-consumer parity arc in Recent decisions; tier3 model→role
deferred to slice-4 / worldtree-dev deploy flag. Handoff written for slice-1.
Operator ruled: no arbo fork, no SillyTavern-on-Rata; both app products move to
a new repo (template-dev standing up). Rata does NOT fork and reverts to its core
(Worldtree debug surface + Bifrost reference impl + Conversation-API SDK #371
seed/future-consumer). Retires the 2026-07-17 fork-Rata-for-arbo NEXT-MAJOR plan;
resolves the arbo-vs-SDK open question the prior snapshot flagged.
Capture this session's durable state: the "fork Rata for a SillyTavern-style
app?" question resolved to don't-fork — Worldtree owns an official Conversation
API SDK (WT #371), seeded from Rata's client spine; the app is a fresh TS
sibling. New Current-state thread + Recent-decisions entries + a full-arc detail
file; arbo-fork decision preserved with the arbo-vs-SDK priority flagged as an
open operator question. Auto-archived 35 settled 2026-06-14..06-18 entries
(19 Recent, 16 Tried) to archival-memory.md. Handoff refreshed.
Move the consolidated #368 in-flight narrative (diagnosis -> two-channel
investigation -> both scrubs -> marker repro -> enforcement read) out of
persistent-memory.md Current state into the silo-test detail file, leaving
a compact pointer. Index 439 -> 339 lines.
- #368 (user,character) memory silo test DONE + PASSED live (WT b127):
write-side conjunctive {end_user,agent_self} scoping + read-side cross-
character isolation both proven end-to-end; betty (throwaway) deleted,
Sindra intact. Full record in persistent-memory.d/2026-07-18-368-silo-
test-passed.md. Retired the stale "silo test in progress" in-flight blocks.
- Two-tier migration: split 152 over-threshold dated entries into
persistent-memory.d/ detail files, leaving one-line pointers in the index
(startup load ~196KB -> ~53KB; bodies now load on demand).
- Tier-3 stores scrubbed clean (memory 0 / affect 0, provider restarted
empty); persistent-memory + detail file updated to reflect the scrub.
Current state now leads with the (user,character) memory silo test:
store born-fresh, throwaway betty ready, Sindra off-limits, waiting on
WT #368 fix deploy. tier3 CLI fixed (v0.21.1). Handoff written for the
post-clear session.
Re-scrubbed store born-fresh; created throwaway ratatoskr:betty for the
Alice/Betty silo demo (MUST delete after; Sindra off-limits). Found
tier3 CLI drift vs live b125 (/agents/define now needs role not model).
Test runs post WT-fix-deploy: Sindra coffee / Betty tea -> verify silo.
WT folded F1/F2/F3 into contract rev 1.3 (3e3f629) with new tests each;
our read-path conformance cited. Backfill live-verify (synthetic legacy
corpus, pre-flip) queued for when the backfill lands. #368 done from
ratatoskr's side end to end.
Fresh Sindra session promoted the rhodochrosite marker to our store
scoped {end_user}-only (chunk 647aeac6) = pre-fix channel-1 baseline.
WT correction: consumer agents write only to our store (no server-side
chroma); Sindra IS Bifrost-attached unlike foundational Lofn. Decisive
server-side grep still pending. ETA: contract to us today, ship ~7/19.
Operator ruled full memory scrub both sides. Our memory.db wiped to 0
chunks, :8392 restarted born-empty (no backup, direct go); Sindra
pristine-baseline note marked obsolete. Marker repro (rhodochrosite,
fresh Sindra session) queued for after both scrubs confirmed; personal
is b125; current Lofn chunks are the feedback loop, mis-write unproven.
GET /search proves the name was introduced ONLY to Sindra, ZERO to
Lofn (0 user msgs across all Lofn sessions), yet Lofn recites it —
incl. a pre-existing session predating my captures. Cross-agent leak
via WT person-prime (#349), agent-axis-less query. Missing agent-axis
is channel-2's load-bearing fix. Rev 1.2 contract inbound for our read.
Both fresh Lofn turns (direct + combined) recited the name with a
bifrost handshake but ZERO memory-calls to us. Turn-context bleed never
traverses our Tier-3 retrieval; it's WT-internal assembly. Two channels:
Tier-3 semantic recall (our provider, closed by conjunctive scope_any)
+ WT-internal (active turn-context path, WT-side fix). Exhibits pinned to #368.
Operator ruled Option 1; no amnesia cliff (backfill from agent_id
metadata). Confirmed our _scope_subset enforces conjunctive scope_any
(fix rides scope_any alone). Labeled Lofn capture recites the name;
direct-bind turn got it WITHOUT querying our store -> WT-internal read
path also in play. ratatoskr is the enforcement half; contract inbound.