Build: e6384e8 (origin/main) · surfaced by the 5-persona playtest on the BUILT dist/WorldOS.app.
The #1 satisfaction-killer
The DM turn takes ~60-90s, and during it the player sees a waiting indicator but NO content appearing. The scene does not visibly build — it lands all-at-once at turn-END. Impatient personas read this as "broken" and quit:
- adversarial-QA gave up at 1m23s on the cold-open
- narrative-player gave up at ~90s on turn 2
- patient newbie waited it out (8/10)
The cross-persona satisfaction gate (≥7/10 across all 5) is blocked on this single issue.
Root cause: /chat delivers each beat all-at-once (no streaming)
The resolver (qa/ui_playtest.sh dm_turn() / qa/lib_beat_driver.sh) runs the DM as one blocking claude -p ... --output-format stream-json call and only appends the final result to the two-sided chat log (chatlog dm "$DMSG") after the whole turn returns. The viewer's /chat poll therefore sees zero new items for the entire turn, then the complete beat. This is documented in viewer/openworlds/app.jsx (lines 82-92): "the /chat tail carries NO streaming/partial/heartbeat signal — the runners append ONE {role:dm} line only after the whole turn's result is in."
Fix options (bounded vs rewrite)
The DM logs narration during its turn via log_event(kind="narration"/"dialogue"), which the engine writes to campaigns/<id>/sessions/<sid>.jsonl immediately (servers/engine/store.py append_log). The viewer already tails that log via /events. So incremental streaming-lite is bounded — surface those mid-turn session-log narration entries to the live chronicle as they're logged (clearing the "narrating…" indicator on first arrival), turning a 90s blank wait into 90s of text appearing. No engine write-semantics change, no SSE, no resolver rewrite.
Cheaper mitigations already partly shipped in #385 (dynamic/reassuring waiting state: rotating cold-open flavor, elapsed clock, a11y proof-of-life).
Acceptance
On the next full-arc playtest against the BUILT app, no persona gives up on beat latency — scene text is visibly appearing within ~15-30s of a turn starting, not a blank wait to turn-end.
Build:
e6384e8(origin/main) · surfaced by the 5-persona playtest on the BUILTdist/WorldOS.app.The #1 satisfaction-killer
The DM turn takes ~60-90s, and during it the player sees a waiting indicator but NO content appearing. The scene does not visibly build — it lands all-at-once at turn-END. Impatient personas read this as "broken" and quit:
The cross-persona satisfaction gate (≥7/10 across all 5) is blocked on this single issue.
Root cause:
/chatdelivers each beat all-at-once (no streaming)The resolver (
qa/ui_playtest.shdm_turn()/qa/lib_beat_driver.sh) runs the DM as one blockingclaude -p ... --output-format stream-jsoncall and only appends the final result to the two-sided chat log (chatlog dm "$DMSG") after the whole turn returns. The viewer's/chatpoll therefore sees zero new items for the entire turn, then the complete beat. This is documented inviewer/openworlds/app.jsx(lines 82-92): "the /chat tail carries NO streaming/partial/heartbeat signal — the runners append ONE {role:dm} line only after the whole turn's result is in."Fix options (bounded vs rewrite)
The DM logs narration during its turn via
log_event(kind="narration"/"dialogue"), which the engine writes tocampaigns/<id>/sessions/<sid>.jsonlimmediately (servers/engine/store.pyappend_log). The viewer already tails that log via/events. So incremental streaming-lite is bounded — surface those mid-turn session-log narration entries to the live chronicle as they're logged (clearing the "narrating…" indicator on first arrival), turning a 90s blank wait into 90s of text appearing. No engine write-semantics change, no SSE, no resolver rewrite.Cheaper mitigations already partly shipped in #385 (dynamic/reassuring waiting state: rotating cold-open flavor, elapsed clock, a11y proof-of-life).
Acceptance
On the next full-arc playtest against the BUILT app, no persona gives up on beat latency — scene text is visibly appearing within ~15-30s of a turn starting, not a blank wait to turn-end.