June 19, 2026
TKT-1070 lands: recursive turn chain + multi-surface sync
TKT-1070: MessageProcessor becomes a recursive continuation chain
TKT-1070: MessageProcessor becomes a recursive continuation chain. Each step that emits tool calls writes its own assistant row (anchoring those calls), dispatches and blocks on every call, then spawns a hidden-input continuation MP that rebuilds the request from the DB and recurses. A step with no tool calls is the turn’s end message and its text propagates back up the stack. There is no iteration cap — depth is bounded only by when the model stops emitting tool calls, with Python’s recursion limit as the backstop. Every process() call runs end-to-end under a per-channel in-memory lock, so two same-channel turns can never both advance the cursor or fire a compaction; different channels run in parallel. tool_calls no longer carries turn_id/channel columns — a turn’s calls are derived by joining transcript. Async tool results and delegate returns are each a NEW turn with their own turn_id. The background auto-compaction step, iteration cap, and act-narration event are removed; mid-turn assistant text is now a durable interleaved transcript row broadcast live on the user channel.
Followup refactor (-1326 LOC, MessageProcessor down to ~600 lines) repudiates carrying per-turn state across MP-chain instances. Skill-suggestion receives only trigger_channel + trigger_turn_id and derives its act-trail and query from the DB; per-ability budget counts tool_calls rows via ActTrail.fetch_by_turn; touched-pattern decay derives the touched set from the turn’s rows. MetricsAccumulator and the stale turn_id_model / channel_lock / multistep_chain_probe tests are deleted. Docstrings across touched configs, abilities, services and tests are collapsed to summary lines (logic byte-identical, verified by token-stream diff).
TKT-1088: WebSocket broker now holds a set of live connections and fans every broadcast out to all of them, pruning any socket whose send fails. disconnect(ws) removes one specific socket so closing a tab never blacks out the others. User messages echo on the channel (sender dedups via a client-minted echo_id; peers render the bubble) and assistant replies broadcast — both sides of the conversation appear on every surface. The live per-turn ACT trail stays device-local by design; idle peers drop content-free ACT frames client-side as a render policy, not server routing. Feature tests cover backend fan-out/echo (5, zero mocks) and Playwright two-surface sync.
TKT-821: memory recall no longer hard-truncates episode gists, violating the no-truncation contract. Three production hot-paths — recall_episodes, _search_episodes_by_location, and _render_episode’s 160-char one-liner — all now project the full gist verbatim. The recall block stays bounded only by selection caps (limit=10, _MAX_FACTS=5, _MAX_EPISODES=3) and the request-level cap; nothing clips the text mid-sentence. Feature tests use the real EpisodicService write path, real MemoryAbility.run + ToolDispatcher render, and real UserConfig MessageProcessor flashback (zero mocks).
Vue interface: progressive per-step turn rendering — each chain step streams live as its own prose bubble with its tool group nested beneath, collapsing to summary-only when superseded; the refresh path reconstructs the same bubble-then-collapsed-summaries shape. Turn-based TTS now speaks the WHOLE turn (every Chalie row concatenated) via a new turnSpeechText action and a shared chalieFormPlaintext helper; intra-turn spacing tightens to line-height gaps while the spine stays at inter-turn width. ArticleCard is deleted — news/search tools are text-only and the dispatcher no longer mints card tags — and the six registry entries plus ArticlePayload re-export are dropped. TKT-960 Delegate provider selector is ported to Vue: getDelegate/setDelegate mirroring the vision pattern, setDelegate(null) clears the explicit pin, /delegate route + sidebar/command-palette/topbar nav.
Build: Vue app dists are now committed so source installs ship ready assets (TKT-993 re-applied on rc-0.9.0) — frontend/apps/{interface,brain}/dist directories are un-ignored and a fresh pnpm -r build is committed. The Dockerfile frontend-builder stage is dropped since the GitHub tarball already contains dist; it collapses to a single python:3.12-slim stage with no Node/pnpm, and .dockerignore now excludes everything since the build context is no longer COPYed from.
Skills fix: skills.sqlite is the shipped artifact and must contain ONLY curated skills. The CLI _build path (the only full-rebuild path) must never read user skills, or rebuilding on any dev machine leaks that machine’s personal skills into the shipped DB. _build/_check are curated-only; _load_user_skills + _USER_SKILLS_DIR + _SOURCE_USER are deleted, and the rebuilt DB holds 73 curated, 0 user skills. A separate commit regenerates the SHA sidecar to match after a prior full-rebuild had left three personal user-skill SHAs (Daily Morning Briefing, Research Competitor Product, Weekend Trip Planner) baked in.
VoicePlayerDialog had author display: flex overriding the UA’s dialog:not([open]) { display: none }, so the closed
-
TKT-1070: recursive MP chain replaces the turn loop; per-step assistant rows share a turn_id; per-channel in-memory lock serializes same-channel turns; tool_calls now derived by joining transcript
-
TKT-1088: WebSocket broker set-based fan-out; user messages echo with echo_id dedup; ACT trail frames dropped client-side by idle peers as a render policy
-
TKT-821: memory recall no longer hard-clips episode gists — full gist projected verbatim across recall_episodes, _search_episodes_by_location, and _render_episode
-
Skills DB curated-only — CLI _build never reads user skills; leaked SHA sidecar with three personal skills regenerated curated-only (73 curated, 0 user)
-
Vue interface: progressive per-step rendering, turn-based TTS via turnSpeechText + shared chalieFormPlaintext, ArticleCard deleted, TKT-960 Delegate provider selector ported to /delegate route
-
Build: Vue dists committed; Dockerfile collapsed to a single python:3.12-slim stage with no Node/pnpm; TKT-1070 refactor trims net -1326 LOC