From d2e814161f4af9b937fc3608233344aa6f86346b Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Thu, 24 Sep 2026 11:09:59 -0700 Subject: [PATCH] M4b spec: approvals from non-approvers in direct messages go to an approver, with who asked and what Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/specs/2026-09-24-m4b-approvals.md | 33 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/specs/2026-09-24-m4b-approvals.md b/docs/specs/2026-09-24-m4b-approvals.md index 887a46e..7e2923a 100644 --- a/docs/specs/2026-09-24-m4b-approvals.md +++ b/docs/specs/2026-09-24-m4b-approvals.md @@ -1,6 +1,8 @@ # M4b design: approvals over Mattermost -Status: approved by the owner, 2026-09-24, with P16 applied to the brief. It builds on M4a +Status: approved by the owner, 2026-09-24, with P16 applied to the brief. Changed after the review +of the same day (owner's decision): approvals asked by non-approvers in direct or group messages +are redirected to an approver with who asked and their message (section 6). It builds on M4a (`docs/specs/2026-09-23-m4a-gateway.md`, section 12 there is the agreed outline) and M3a's approval path (`docs/specs/2026-09-18-m3a-decision-path.md`, section 6). Owner's decisions of 2026-09-24, changing the outline: **no reactions**, answers are commands only; an `[approvals] users` list @@ -161,10 +163,33 @@ One thread per accepted `gateway.sock` connection. It reads frame 1 (bounded by checks the ids in it, and decides **where**: - If the session is `mm-` and `state.in_flight` holds a turn of that session, the approval - goes into that turn's thread (its channel and root). This covers direct messages and channels. + goes into that turn's thread (its channel and root), **unless** the turn was asked by someone + who is not an approver in a direct or group message: no approver could answer it there. (In a + channel an approver can reply in the thread, so it stays.) +- A redirected approval (asked by a non-approver in a direct or group message) goes to the first + approver's direct channel as a new thread whose **first post** says who asked, where, and what + they asked (review of 2026-09-24, owner's requirement: the approver must know who is asking, + their prompt, and what Boxmaker is trying to do): + + ````text + **Approval 3** was asked by @alex in a direct message with the bot. Their message: + ``` + Read the file /srv/notes/q3.txt and summarise it. + ``` + ```` + + The message is the text of the turn that asked (a burst, joined), escaped and fenced like the + arguments; it is context, not what is approved, so it is cut at 2,000 characters with + `(… more characters)` after the fence. The approval's own posts follow in that thread, and + the asking thread gets one line: `waiting for approval : it was sent to an approver`. - Otherwise (`bxctl chat`, a session no longer in flight, later scheduled jobs), it goes to the - first approver's direct channel (`POST /channels/direct`), as a new top-level post whose own - thread is where it is answered. + first approver's direct channel as a new thread whose first post says + `**Approval ** was asked in session ``, which gatewayd does not follow now (a + restart, or a session from outside Mattermost).`, followed by the approval's posts. + +`gatewayd` knows who asked from the posts it queued: for each session it keeps the author of the +last message queued, the channel's type, and, when a turn starts, that turn's text; it forgets them +when the turn ends. They are not in the state file: after a restart the turn is interrupted anyway. ### The text