bus: a closed decision sends the raising role a message (#1609)
Row 115. When a decision closes by resolve or withdraw, and the closer is a human or another run, the broker routes a DECISION message to the raising role's holder: "Decision <id> on <action> was resolved by <by>: <choice> (<text>)" or "withdrawn by <by>", plus the note if there is one. A seen op sends nothing. #request falls back to the human.input that closed the decision, filtered to resolved and withdrawn. Candidate manifest 1910eb5a672e670cb7c8a197ee3fdd888412dd803fe52a0a15680103c26c078c from Darkwing's round 2 packet (40e5917f9), on BASE94ece491f. Filbert approved in 28428 and Sage in 28427. Sage reran the full gate at the landing target with the candidate applied. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -266,6 +266,42 @@ test("a message read a day after it was sent shows the time it was sent", async
|
||||
assert.ok(Date.parse(reply.at) - Date.parse(sentAt) >= 86_000_000);
|
||||
});
|
||||
|
||||
// Row 115 (#1609): the human closing the role's decision gives the role a turn. The runner is unchanged;
|
||||
// the header cites the decision and the close's human.input answer as the request.
|
||||
test("a decision the human resolves becomes a turn citing the decision and the answer", async (t) => {
|
||||
const ctx = await setup(t);
|
||||
const r = startRunner(ctx.runDir, ctx.cap);
|
||||
t.after(() => r.child.kill("SIGKILL"));
|
||||
await until(() => ctx.store.get("SELECT 1 FROM role_claims WHERE role='coder' AND op='claim'"));
|
||||
const d = ctx.call(ctx.cap, "decision.raise", {
|
||||
action: "deploy",
|
||||
target: "release-1",
|
||||
question: "Ship release-1?",
|
||||
options: [{ key: "yes", text: "Allow" }, { key: "no", text: "Decline" }],
|
||||
recommendation: "yes",
|
||||
blocking: false,
|
||||
});
|
||||
assert.equal(d.route_to, "human");
|
||||
ctx.call(ctx.human, "decision.resolve", { id: d.id, choice: "yes" });
|
||||
const m = ctx.store.get("SELECT id,at FROM messages WHERE class='DECISION' AND decision=?", d.id);
|
||||
const answer = ctx.store.get("SELECT id FROM events WHERE kind='human.input' AND subject=?", d.id).id;
|
||||
const [reply] = await until(() => {
|
||||
const got = ctx.call(ctx.human, "message.receive");
|
||||
return got.length ? got : null;
|
||||
});
|
||||
assert.equal(reply.from_role, "coder");
|
||||
assert.equal(reply.class, "RESULT");
|
||||
assert.equal(reply.in_reply_to, m.id);
|
||||
assert.ok(
|
||||
reply.body.endsWith(
|
||||
`\nMessage ${m.id} from human, sent ${m.at}, class DECISION, citing decision ${d.id}, request ${answer}:\n\n` +
|
||||
`Decision ${d.id} on deploy was resolved by jason: yes (Allow).`,
|
||||
),
|
||||
reply.body,
|
||||
);
|
||||
await until(() => ctx.store.get("SELECT 1 FROM deliveries WHERE message=? AND op='read'", m.id));
|
||||
});
|
||||
|
||||
test("a failed state read fails the turn: no adapter runs, the sender hears why, the message is read", async (t) => {
|
||||
const ctx = await setup(t);
|
||||
ctx.inbox = [];
|
||||
|
||||
Reference in New Issue
Block a user