# A closed decision reaches the role that raised it (2026-10-14) Filed by Sage on Mos's report of 2026-10-14. Gitea #1609, Vikunja #205. ## A closed decision sends the raising role a message ### Problem Jason resolved decision 03130d08-ddce-480d-a601-e59f64744fc3 (the PM's `prd.approve` for Q139/Q140, gated, routed to human) `yes` from the CLI at 2026-10-14T16:15:35.512Z. The bus db has the `decision_events` row (op resolved, by jason, via cli) and event 346, its `human.input` answer. No message cites the decision, and the PM had no turn after it: the newest message was still 75 (pm to human, 16:12:19Z) when Sage read the db at 16:23Z. The cause is in `packages/bus/src/broker.mjs` (cc48b124f, live; refactor is the same): - `decision.resolve` and `decision.withdraw` write the `decision_events` row and, for a human, a `human.input` event `{kind:'answer'}`. They write no message. - `message.receive` reads only `messages` addressed to the role. - `packages/harness/src/runner.mjs` takes a turn only for a message that `message.receive` returns. So a role learns an answer only when some unrelated message gives it a turn. `raise_decision`'s tool text (`packages/harness/src/tools.mjs:135`) already says "The answer arrives as a message." This row makes the broker keep that promise, for every routed decision. The fix goes in the broker, not the runner. A message is what every transport already receives, routes to the role's current holder, and strands visibly in `agents` when nobody reads it. A second wake path in the runner would need its own delivery record. ### Owner and reviewer - Owner: darkwing, after row 113. - Reviewers: filbert (decision 130, not a sandbox row) and sage. ### Files owned - `packages/bus/src/broker.mjs` - `packages/bus/tests/` (a new `decision-close.test.mjs`, or changes to `decisions.test.mjs` and `messages.test.mjs`) - `packages/bus/README.md`, the `decision.resolve`, `decision.withdraw` and `message.receive` rows and the decision section - `packages/harness/tests/`, only for the runner case in item 4 - `agents/darkwing/work/queue-115/` ### What ships 1. `decision.resolve` and `decision.withdraw` send the raising role a message when someone other than the raising run closes the decision: - It's written in the same transaction as the `decision_events` row, so a refused or rolled-back close writes no message. - `to_role` is the decision's `raised_by_role`. It's the role, not the run, because runs end. When no run holds the role, the message waits for the next claim like any other. - Class `DECISION`, `decision` set to the decision id, `in_reply_to` null. - Sender: a human close is stored `from_role 'human'`, `from_run 'human-cli'`. A role close is stored as that role and run. The sender must be a real address, because the runner sends its answer to `from_role` and a refused send leaves the message unread. - Routed with a `routed` delivery like `message.send`'s. - Body, one fixed form the broker writes: `Decision on was resolved by : (