plans: bus stranded-delivery brief from row 59 review (Note B)

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]>
This commit is contained in:
2026-10-11 18:38:56 -05:00
co-authored by Claude Opus 5.5
parent 424ada49c0
commit d45ed67ca7
@@ -0,0 +1,78 @@
# 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 no `delivered`
or `read` row.
- `#routeWaiting` (line 892), run when a new holder claims the role,
routes only messages with no `delivered` or `read` row.
- `message.read` (line 784) refuses `not-recipient` unless the latest
`delivered` row 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
only
- `packages/bus/src/views.mjs`, if the agents view passes the field
through
- `packages/bus/tests/`
- `packages/bus/README.md`, the delivery paragraph and the agents read
only
- `agents/darkwing/work/queue-<row>/`
### What ships
- A stranded message is one addressed to a role, with a `delivered` row
whose run no longer holds that role, and no `read` row.
- The agents read gives each role a `stranded` list: 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.