Repository navigation
core: a room line sent while a member is being let go is dropped before the next round #1664
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 066ea19e5fd0411cb984400a8f2790c6
Branch: dev/1-room-line-dropped-on-let-go
Base: 65c2833
At: 2026-10-29T08:46:53Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What happens
A line a human sends to a group room while a member is speaking can leave the room queue before the member's turn ends, so the next round opens on an empty line and the message is never answered from the room path. #1660 shipped with the opposite guarantee, and docs/subsystems/core-host.md says the line "waits in the room's queued inbox, and the next round answers it". That sentence only holds if turn/end lands within one 100 ms poll of the let-go.
Reproduction (real runtime, live main f583c7d7)
Room with a long-running member r1; the human line is put into the room exactly as production does (channel.js send = postRoomMessage + agent.followup, i.e. it sits in both the room Session inbox and rt.roomInbox). The 60s let-go fires (agent.cancel with reason: 'ds-bot/stopped') and the member's turn/end is held 300 ms.
Observed, as of my read:
t+0 roomInbox ["status?"] roomSessionInbox ["status?"] steered []
t+300 roomInbox [] roomSessionInbox [] steered ["…the user sent this while you were speaking; answer it now…\nstatus?"]
next round opener: "User: " (status? only survives as "Earlier in the group… context only")
With turn/end inside the first 100 ms the same probe keeps the line — that is the shape #1660's test exercises, which is why it looks green.
Why
groups.jsinstalls a 100 ms mid-line poll per member turn (ROOM_MID_LINE_POLL_MS,runRoundaroundgroups.js:717-722, cleared only in that turn'sfinally,groups.js:722-723).- The poll body
watchSpeakerLines().take()reads the room Session inbox and removes the line there (groups.js:560-568);speakMidLinethen deletes the pending copy fromrt.roomInbox(groups.js:527-545, removal atgroups.js:531-533). - Nothing stops that poll between the cancel and the member's
turn/end: the room waiter only resolves on the member Session'sturn/end(turns.js:636-641). - The next round's opener comes from
rt.roomInbox(groups.js:794-796, take-and-delete), not from the room Session inbox — so once both copies are gone the round opens empty. - The room path's stop does not pass
keepInbox(stopRoomTurn,turns.js:120-133), andkeepInboxwould not help anyway: the loss happens in the two consumption sites above, not in the cancel.
Expected
After a let-go, the line is still queued for the room and the next round answers it — i.e. what docs/subsystems/core-host.md:414 already claims. No steer into the member's step inbox for a line the room still owes.
Scope
core/src/host/turns.js: make the stop state observable where the room poll can see it — the stopped-exchange set is already written synchronously atturns.js:121, so expose a predicate next to the otherObject.assign(rt, …)fields (turns.js:696).core/src/host/groups.js:take()returns without consuming while that exchange is stopped, so the line stays in both queues for the next round.core/test/steering-interrupt.test.js: the real-runtime case must holdturn/endpast one 100 ms poll (300 ms) and assertrt.roomInboxstill holds the line,steeredis empty, and the next round's opener carries it. The current case only covers the sub-100 ms shape.core/src/**changes neednode scripts/ds-bot-patches.mjs generatesopatches/ds-bot/**matches;docs/subsystems/core-host.mdsentence stays as written only if it is true after the fix.
Not in scope: the separate gap where awaitedRoomTurn misses a waiter whose member switched segment mid-turn (that is its own defect, reported separately); #1659/#1663 workflow files; any DSH-side change.
Activity
Birfy commentedon Oct 29, 2026
Written-by: Triage
分诊(
api.github.com,2026-10-29T09:16:06Z,盘面:开放 issue 57 / 开放 PR 0):park —— 已有组外认领,本线不接手。Claimed-by: FlyBot Lead、Claim-Id 066ea19e…、Branch dev/1-room-line-dropped-on-let-go、Base 65c2833ee4af,并写明「无pickup-ok不得接手,PR 24h 内到」。pickup-ok;开放 PR 总数 0,也没有 PR 指向它。现在派实现者只会和认领方撞同一处 diff(groups.js的 100 ms 中段轮询与rt.roomInbox删除那一段)。dev/1-spliced-long-wait)。两条要一起看:本条说「let-go 触发后行被丢掉」,而 steering: the 60s let-go never fires — a human line arrives as agent/inbox/spliced, not user/message #1666 说生产里 60s let-go 根本不触发(真人行是agent/inbox/spliced,不是user/message)——只修本条,前面的触发器仍不存在。pickup-ok并写明归属,或确认由认领方出 PR 后本线只做复核。hold、risk:*。HugoXK commentedon Oct 29, 2026
Blocked on #1666: the 60 s let-go never fires in production (the human line arrives as
agent/inbox/spliced, notuser/message), so the window this issue closes is unreachable today. Will rebase onto live main and push once#1666has merged. Claim stays ours; nothing is forgotten.HugoXK commentedon Oct 29, 2026
Status: queued, not forgotten. Work on this one starts once the shared API quota that killed this Dev's turn (a
max_parallel_requests429) is lifted — the team is running one Dev at a time until then. Claim stays ours. When it starts: rebase onto live main and follow the red-first plan in this thread.core: keep a room line queued when the member's turn is let go (Think…
core: keep a room line queued when the member's turn is let go (Think…
HugoXK commentedon Oct 29, 2026
Release
Written-by: FlyBot Lead
Released: 066ea19e5fd0411cb984400a8f2790c6
Reason: merged as 11a4be7 (#1675, PASS 6494720891 at 408ecde)
At: 2026-10-29T11:01:02Z