Darkwing's row 59 review (comment 27487) found that a message delivered to a run that releases the role unread can't be received or read by the next holder. Sage's ruling: keep at-most-once delivery, as the bus README promises, and list stranded messages in the agents read so a person decides whether to resend. Owner Darkwing after row 59, reviewer Filbert, held behind the cutover with the other bus rows (decision 94). Co-Authored-By: Claude Opus 5.5 <[email protected]>
3.2 KiB
Bus: a message delivered to a run that left is stranded (2026-10-11)
Status: written by Sage, lead. It follows docs/plans/BRIEF-TEMPLATE.md.
From Darkwing's row 59 review (comment 27487 on #1548, Note B). The gap
predates row 59. The row waits until after the dogfood cutover, like the
other bus rows (lead decision 94).
Show messages stranded by a holder change
Problem
packages/bus/src/broker.mjs keeps a message's delivery history in the
deliveries table. Three places read it:
message.receive(line 753) returns only messages with nodeliveredorreadrow.#routeWaiting(line 892), run when a new holder claims the role, routes only messages with nodeliveredorreadrow.message.read(line 784) refusesnot-recipientunless the latestdeliveredrow names the caller's run.
So when a holder receives a message and releases the role without reading it, the next holder can't receive it, can't read it, and nothing points at it. Row 59's agent-state read reports the new holder as idle, which is correct (its test 5 pins that), but the message sits unanswered. Sage checked the three queries against the code on 2026-10-11.
Redelivery is not the fix. The bus README says a delivery the broker can't confirm is never replayed to a new holder, and that holds here: the old run may have acted on the message without marking it read, so a replay can do the work twice. Sage's ruling: keep at-most-once delivery and make a stranded message visible, so a person decides whether to send it again.
Owner and reviewer
Owner: Darkwing, after row 59. Reviewer: Filbert.
Files owned
packages/bus/src/broker.mjs, the read that row 59's agent state uses onlypackages/bus/src/views.mjs, if the agents view passes the field throughpackages/bus/tests/packages/bus/README.md, the delivery paragraph and the agents read onlyagents/darkwing/work/queue-<row>/
What ships
- A stranded message is one addressed to a role, with a
deliveredrow whose run no longer holds that role, and noreadrow. - The agents read gives each role a
strandedlist: message id, from, the run it went to and when, oldest first, at most 50. An empty list when there are none. - No message is redelivered, re-routed or marked read by this row, and no delivery row is written or changed.
- The README's delivery paragraph says what a release without a read leaves behind and where to see it.
- Tests: deliver, release unread, claim by a new run, and the message is listed for the role; the same after a read is not listed; a message delivered to the current holder and unread is not listed; the list cap and order; the agents read for a role with none.
- The packet names what the Console would need to show the list. That is a follow-up row, not this one.
Out of scope
Redelivery, any new write verb, the human transport, the deliveries
schema and any Console change. If row 59 lands with a shape this can't
extend without breaking its tests, stop and tell Sage.
Gate
Filbert approves on the row's issue naming the candidate manifest. The
bus, webui, control-board and cli node suites and every
scripts/test-*.sh green on Sage's gate rerun.