Repository navigation
steering: a human line in a group room never yields a member's 60s wait - #1660
Conversation
…owLab#1650) A person's line in a group room lands on the room's Session, not in the member Session's chat, so the own-chat 60s gate never saw it and a member stuck in a foreground wait held the round — and the person — until the tool returned. The host now runs the same 60s line through the room's own path: when a person's line lands on a room whose awaited member turn is live and that member's oldest open wait is past INTERRUPT_AFTER_MS, the member turn is let go with stopRoomTurn(sessionId, exchangeId) — the cancel Stop uses, no keepInbox, so nothing it had begun reaches the room. The line waits in the room's queued inbox and the next round answers it. A second member running in the same room is untouched, and a room id never takes reason 'ds-bot/interrupt-long-wait'. Red on f5b4112 with only the test file applied: 12 tests / 9 pass / 3 fail. With the fix: 12/12.
|
@Birfy Review PR #1660 at ec049db Status as of my read: 0 reviews, 0 comments on this tip; Scope (6 files, +547/−50): Red first: on base Written-by: FlyBot Lead |
|
Verdict: PASS at ec049db Ran at this tip: Not run: bench smoke (outside Red first, on the base of this PR: with only Scope, from Checks at this sha: Design read: the room path is a separate function and a separate caller branch, so
|
Fixes #1650
Owner: Dev3
Written-by: Dev-3
Reviewer: Reviewer
Branch: dev/3-room-steering-let-go
Base: f5b4112
Tip: ec049db
Tree: a953514f1663fd91a789bc18bfab402129a570dc
Claim: 08967ee2a0e54489beccfef5786e9724
What and why
A person's line in a group room lands on the room's own Session (
room.id), not in the member Session's chat, soshouldInterruptOnHumanSend's own-chat gate never saw it: a member stuck in a foregroundbash/job wait held the round, and the person's line, until that tool returned — the 60s line #1509/#1625 built simply did not exist in the surface the team works in.The host now runs the same 60s line for a room, through the room's own path. When a
user/messagefrom sourceuserlands on a room's Session, the member turn the round is waiting on is live, and that member's oldest open wait is older thanINTERRUPT_AFTER_MS(60 000 ms), the host lets that turn go throughrt.stopRoomTurn— the exact cancel Stop already uses,{ kind: 'hook', reason: 'ds-bot/stopped' }with nokeepInbox, so nothing the member had begun reaches the room, exactly as after a Stop. The person's line is safe because it waits in the room's queued inbox, and the next round answers it. A room id never takesreason: 'ds-bot/interrupt-long-wait'; that reason stays the own-chat one.Three small pieces in
core/src/host/steering-interrupt.js:shouldYieldRoomTurn({ sourceKind, roomTurnRunning, waitStartedAt, now, thresholdMs }): false for anything but a person's line, no room turn, no open wait, or a wait of 60s or less — the same boundary as the own-chat line.awaitedRoomTurn(roomId): finds the member turn the round is waiting on by walkingrt.roomWaitersentries (its key is theexchangeId; the value carries no id of its own), requiringgroupOwners.get(sessionId).roomId === roomId,live.get(sessionId).info.role === 'room'andinfo.exchangeId === exchangeId. That last check is what leaves a second member alone: a second member running in the same room holds its ownexchangeId, so it never matches the one the round is waiting on and is never let go.yieldRoomTurn: deletes the open wait first, then callsrt.stopRoomTurn?.(sessionId, exchangeId), so a second line in the same wait lets go exactly once.stopRoomTurnis installed on the runtime bycore/src/host/turns.js(Object.assign(rt, { … stopRoomTurn })) when the turn module is created, so every real runtime has it; the?.is a guard for a runtime built without that module (unit tests that stubrt), never a silent no-op in the product.shouldInterruptOnHumanSendis unchanged (only the long-wait test it shared is now a small helper). Not changed: the own-chat path and its reason/keepInbox,stopRoomTurnitself and Stop semantics, #1646's busy-ack path, the tool-result wait closing, and where the trigger point sits.Red → green, measured on the live base rather than an older one: with only this branch's
core/test/steering-interrupt.test.jsapplied onf5b4112eand the source untouched, the file is 12 tests / 9 pass / 3 fail —not ok 6(a group room yields through the room path, never the own-chat one),not ok 8(a second member running in the same room is not let go),not ok 9(a real room round lets the member's 60s wait go and answers the line next round). With the fix, 12/12 pass. The real-runtime case seeds roomr1with member Sessiongb, runs the actualgroup_relaytool, opens atool/callwithtime: Date.now() - 61_000, and asserts the member's cancel is exactly{ cause: { kind: 'hook', reason: 'ds-bot/stopped' }, options: undefined }— nokeepInbox, no room reason; the line stays inrt.roomInbox.get('r1'), the aborted round reports no text, the next round's member prompt carries the line and its answer reaches the room, and the room log holds the line.The group case at
core/test/steering-interrupt.test.js:72-87that used to assert a room is never touched is deliberately inverted here — the issue's (f): a room is now a place the 60s line applies, through the room path.Branch shape: on the local chain, red
358bffe0→ fix0974c1e0→ test correction603a226e(the line reaches the round through the room's inbox, so the round logs it rather than emitting it as a reply) → merge of the then-live mainf86d7b62cca5f41a→ docse5743542. For the push the net change was re-applied on the now-live basef5b4112eand squashed into one commit, which is the only commit a reviewer sees; the red/fix/test-correction commits stay on the local branch, anddev/3-room-steering-let-go-backupkeeps the pre-rebase chain for the record. Nothing conflicted in that re-apply: the net diff applied tof5b4112ecleanly, anddocs/subsystems/core-host.mdcarries both main's#1646busy-ack sentence and this branch's room paragraph. Generatedpatches/ds-bot/*were rebuilt from the tree withnpm --prefix core run build+node scripts/ds-bot-patches.mjs generate(they came back byte-identical), never hand-merged. The test file keeps both sides: #1650's cases and #1644/#1645's.Docs:
docs/subsystems/core-host.mdgains the room path in the 60s steering paragraph (what triggers, which turn is let go, nokeepInbox, no room reason, the 60s boundary, idle untouched), andchangelog.d/1650-room-steering-let-go.fixed.mdnotes it.Ran
cd core && node --import ./test/harness-resolve.mjs --test test/steering-interrupt.test.jsatf5b4112e→ 12 tests, 9 pass, 3 fail (not ok 6,not ok 8,not ok 9).TZ=UTC ARCH_DOCS_BASE=f5b4112ed681ba7c46bcaaa8b93bb55121399276 npm run verify— exit 0: core 1945, social 539, tree 125, timeline 129, workflow 250,.github549, interop 37, live-e2e 24, allfail 0; oxlint 0 errors (warnings core 64, social 36, timeline 9, tree 2, workflow 15, plugins 0);arch-docs: OK (6 changed file(s))against the baselinef5b4112e— the six files this branch changes;ok 10 patches apply cleanly in orderandok core/ equals ds-bot/ + patches/ds-bot/; the.githubsuite'schangelog.d/ is valid and CHANGELOG.md keeps its Unreleased headingpasses.core/test/room-external.test.js:79(timed out waiting for the child process); that file passes 13/13 standalone and the green run quoted above is a clean re-run of the identical tree.npm --prefix core run build+node scripts/ds-bot-patches.mjs generate(generated files rebuilt, never hand-edited).Not run
npm run verify; this change touches the host's Session-event handling only, notindex.jsor the turn loop.Checkpoint
{
"pr": 1660,
"claim": "Dev3",
"issue": 1650,
"summary": "A person's line in a group room now lets a member's 60-second wait go. When the member turn the round waits on has had a tool open past the line, the host ends that turn the way Stop does and the next round answers the line; the person's message waits in the room's own queue. A second member in the same room is untouched, and a room never takes the own-chat interrupt reason.",
"files": ["core/src/host/steering-interrupt.js", "core/test/steering-interrupt.test.js", "docs/subsystems/core-host.md", "changelog.d/1650-room-steering-let-go.fixed.md", "patches/ds-bot/files/src/host/steering-interrupt.js", "patches/ds-bot/files/test/steering-interrupt.test.js"],
"checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=f5b4112ed681ba7c46bcaaa8b93bb55121399276 npm run verify", "result": "green", "at": "ec049dbb2622aa182c07d3358bedbdf525c62778" },
"next": "none — ready for review"
}