0048 — Asking Smith about a decision is a deferral, and the answer still lands on the raiser's row
- Status: Accepted 2026-10-08. Built in propflowai #17892 (the control) and agent-smith #843 (Smith's prompt).
- Date: 2026-10-08
- Deciders: Gera (asked for it). Fede is open to object.
- Systems:
decision-blocks(the answer path), propflowai/agents?tab=Decisions, Agent Smith's Slack DM (smith-slack-socket, app A0BESM30BME),~/.local/bin/blocked.
The problem
Gera, 2026-10-08: "sometimes I have more like follow-ups — it'll tell me to do something but I don't know exactly how to do it, so I want to be able to start the conversation [with Agent Smith about that specific question]… whenever we are done with the verdict, the session that was asking should be able to see when we're done and then pick up."
A decision on /agents had two ways out: answer it, or pick a standing answer (I'm not sure — go find out, and since agentflow #313 Take it to the engineering bridge). Both are answers. Each one resolves the row and wakes the raiser. Gera had no way to say "not yet, let me talk this through first". The obvious build, a third standing option, would have been wrong for the same reason: the raiser would wake to a non-answer and the row would close.
Options considered
- A. A standing option "Ask Agent Smith". Ruled out. Every option on the list is recorded as the choice, so this would close the row and wake the raiser with nothing to act on.
- B. The page posts the question to Smith. Ruled out. Smith ignores every bot-authored Slack post (
slack_socket.py, thebot_idearly return)./api/agents/smith/messagecan only signal an existing Smith thread and refuses to mint one, andmessage_smith.pycannot open a threaded conversation. - C. Mark the row "asked Smith" with
waiting_on. Ruled out.waiting_onmeans "this row is a waiter queued behind another session's block". Every sweep excludes it (state == "open" and not waiting_on), and the page treats a waiter as unanswerable. Reusing it would take the question out of Gera's queue and out of the nag path. - D (this decision). The page hands Gera a message to send as himself. The block is left untouched.
The decision
- Asking writes nothing. The control on an open decision (open, unsettled,
waitingOnHuman) copies a paste-ready message and opens Gera's DM with the Agent Smith app. Gera pastes and sends it, and Smith acts on every human message in its own DM. The block stays open, and the raiser keeps waiting on the path it already has:blocked check, the 600s sweep, and the per-row Temporal driver. - The message opens with the literal
Decision <id>. Smith's prompt keys on it: the DM is Gera asking for help with one decision, not answering it. - The answer lands on the raiser's row, never anywhere new. When Gera states a verdict, one of two things records it, and the raiser wakes through the existing answer path. There is no new polling.
- Gera picks it on /agents himself.
- Or Smith runs the line the message carries:
blocked resolve <id> --sid <raiser-sid> [--qid <q>] --answered --choice '<their words>' --by <decider>, where<decider>is whoever sent the DM (any admin can use the control, so it is never assumed to be Gera). That is the argv Smith's own decision-block driver already uses.--sidis not optional, becauseblockedreads the row from the caller's ledger directory.--answeredis not optional either, becauseresolverefuses without a reason.
- No marker in part 1. The page does not show "asked Smith". If a marker is wanted later, it needs its own field, never
waiting_on.
Consequences
- A decision can now be talked through before it is answered, and the waiting session is not disturbed while that happens.
- The record names the relay honestly. A Smith-recorded answer carries
answeredBy: <decider>, andby/relayed_byhold the sidblockedran as, which with--sidis the raiser's sid rather than Smith's own. So the ledger does not say Smith relayed it. Accepted for part 1. It is worth fixing inblockedif anyone audits who typed answers in. - The message reaches Smith only because a human sends it. If Gera copies it and never sends it, nothing happens and the block simply stays open. That is the correct failure direction.
- This is a new relation between
decision-blocksand Smith's Slack surface, so thedecision-blocksentry in SYSTEMS.md cites this ADR.