fix(bridge): subscribe before respond on ask resume; edit answered ask to ✅; separate resumed text - #8
Merged
Conversation
…k to ✅; separate resumed text (#6) Three fixes for issue #6 (final reply never renders after an ask is answered): 1. render_until_settled now re-subscribes to the session's WS channel BEFORE POST /respond — the same subscribe-before-execute invariant the initial run relies on. A server-side resubscribe REPLACES the channel's forwarder with a fresh broadcast cut, so subscribing after respond left a window where the resumed run's events (or, with the WS mid-reconnect, the entire run through Complete) were emitted into no subscription at all — the render task then waited forever on an idle channel and the final reply never rendered. A failed subscribe still records the answer (the old degradation path). 2. The answered ask message is now edited to '{ask text}\n\n✅ {answer}' (best-effort, gated on edit_message) — the chat shows what was chosen and the stale buttons can't be pressed again. 3. StreamingRenderer::resume inserts a paragraph break between pre-pause text and the resumed run's tokens — previously the final reply glued straight onto the question ('Pick one:OASIS'), reading as missing. finalize_success trims trailing whitespace for the no-tokens case. Test hooks: FakeBambooApi grows an ordered subscribe/respond op log (the per-method vecs can't express cross-method ordering); the fake buttons_and_edit_capabilities now actually sets edit_message like its name claims, putting the callback-resolution test on the streaming renderer. Closes #6 Claude-Session: https://claude.ai/code/session_014iw5PBsSzDFHus1GfkAK4y
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6 — final reply never renders after an ask is answered.
Root cause
render_until_settledresolved an answered ask as respond → subscribe. A server-side resubscribe (bamboows_v2::subscribe) REPLACES the channel's forwarder and takes a fresh broadcast-bus cut — nothing is replayed. So every event the resumed run emitted betweenPOST /respondand the subscribe frame was lost; and when the WS was mid-reconnect (Subscribe commands queue unprocessed during backoff), the WHOLE resumed run throughCompletecould land in the gap. The new receiver then never yields, the render task waits forever, the status card stays '⏸ Waiting for your input…', and the final reply never renders — silently, exactly the #6 symptom. The button-callback e2e (2026-07-15) won this race by milliseconds, which is why it rendered while the earlier text-path run didn't.Fixes
{ask text}\n\n✅ {answer}(best-effort,edit_message-gated). Closes the follow-up gap noted on bridge: final reply never renders after an ask is answered — run resumes and completes at bamboo, chat shows nothing #6: the chat shows what was chosen, and the now-stale buttons can't be pressed again.render_askreturns the sentMessageRefinstead of discarding it.StreamingRenderer::resumeinserts\n\nbetween pre-pause text and the resumed run's tokens; previously the final reply glued onto the question (Pick one:OASIS), reading as missing even when the race was won.finalize_successtrims trailing whitespace for the no-more-tokens case.Tests
paused_run_renders_buttons_with_nonce_and_resolves_via_callbacknow asserts cross-method call order[subscribe, subscribe, respond]via a new ordered op log onFakeBambooApi(the per-method vecs can't see interleaving), and that the ask message got the✅ Approveedit.streaming_mode_resume_keeps_editing_the_same_status_messagenow pins the separator.buttons_and_edit_capabilities()actually setsedit_message: trueas its name always claimed, so the callback-resolution test exercises the streaming renderer.Not fixed here (separate issue to file): resynced asks (
resync_pending_asks) are parked without anask_resolutionsender, so an answer after a magpie restart falls throughtry_resolve_pending_askinto the normal message path and starts a new run instead of resolving the parked question.https://claude.ai/code/session_014iw5PBsSzDFHus1GfkAK4y