Two user-reported problems from the muscle-protein-synthesis session, both diagnosed from the live data (chat_mtxeml9e_6118e59f). The freeze: after probe_done, the open session never showed the teacher's wake turn — only navigating away and back loaded it. Not an agent-switch problem: the server-side handoff worked perfectly (write-ahead persist, liveness registry, the sidebar's busy dot saw the wake the whole time). The gap was client attach: the only mid-session wake detector the open page has is the jobs poll, and probe-phase sessions have zero job traffic, so that poll is OFF; the post-turn adoption poll read turnInFlight=false at ~0ms (the wake fires at ~0.75-1.2s, after the pump's grace), adopted, and stopped. Fix: the post-turn adoption effect now keeps a short WATCH WINDOW after adopting (~4s, 8x500ms) — if turnInFlight flips true, it hands off to the existing wake-adoption poll (busy shimmer, adopt at finish). The mermaid failures: four failed plan_init calls, all caused by ONE hidden rule — underscores are forbidden in node ids (mps_translation, net_balance, per_meal). The id regex rejected '_' BEFORE the slug check, so the specific, actionable message never fired; the generic 'can't read the edge — expected a[title] --> b[title]' lied (the syntax was exactly that), and the teacher spent three attempts hunting punctuation it suspected (colons, commas, multi-word labels) — visible in its own reasoning trail. Per the user's principle — enforce only the slugs, free everything else: underscores are first-class slug chars; the id CANDIDATE class is broad so every bad id reaches the specific slug message; chained edges (a --> b --> c) expand to pairs; ==>, -.-> are edge synonyms; any direction header accepted (we layout ourselves); id["title"] quote pairs are stripped. The tool description, zod describe, and the teacher's planning prompt now state the one strict rule instead of the old subset liturgy. Verified: tsc, 305/305 (the exact muscle-protein mermaid is now a passing test), lint, build; real-browser puppeteer smoke on live GLM — the teacher's wake turn appeared in the open page ~50s after the probe concluded with ZERO navigation, verdict gate + first teach check + plan window all live in-page (the single console 404 is the app's missing favicon, environmental noise).
Prompt fragments
System prompts are composed at agent construction (src/agent/teacher-agent.ts), one composition per agent — the probe/teach split (docs/probe-teach-split.md):
src/agent/system-prompt.md— the SHARED base: the teaching philosophy (both principles), accuracy, quiz-option construction, the question tools, formatting. Owned by the master seam; do not edit from a worker.- Every numeric-prefix
*.mdfragment in the agent's directory (prober/orteacher/), in sorted filename order, joined with---separators. The loader enforces the numeric prefix (\d*-*.md) — other files (like this README) never enter the model's prompt.
Rules for adding a fragment:
- Name it with a numeric order prefix, inside the right agent directory.
- One fragment per workstream — your brief tells you which filename you own.
- Document YOUR agent's tools/behaviors exactly; reference tool input field names verbatim (they must match the zod schemas).
- Keep it tight: fragments are always in context. No restating the base prompt.
- The two agents share one transcript but never one toolset — never reference the other agent's tools as if you had them.