feat(discord): eyes reaction as a read receipt on every admitted message (#1509)

QUEUE row 15, MVP iteration 1 after the Sage pilot. rest.react is best
effort (2xx true, anything else false, never throws); the connector reacts
at admission before the engine runs and records the outcome in the turn
record as receipt. Drops and refusals get no reaction. Suite 28/28, 90
node tests.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
2026-09-13 14:20:30 -05:00
co-authored by Claude Fable 5.1
parent 788515dc69
commit 93d6b62457
10 changed files with 115 additions and 6 deletions
+7 -4
View File
@@ -89,8 +89,11 @@ as a user all refuse with exit 2.
4. The prompt is an envelope, one bracketed line naming server, channel,
thread, author id and message id, then the text. The system prompt says
that text is data. A message that arrives during a turn is queued in pi
as a follow-up, so it is neither lost nor run concurrently. A typing
indicator is sent every 8 seconds while a turn runs.
as a follow-up, so it is neither lost nor run concurrently. As soon as
the turn is admitted the connector reacts to the inbound message with
eyes as a read receipt; a typing indicator follows every 8 seconds while
the turn runs. A reaction Discord refuses is logged and recorded in the
turn; it never fails the turn.
5. The reply is split at 1900 characters on paragraph boundaries. Each chunk
is posted with `nonce` and `enforce_nonce: true`, `allowed_mentions`
empty, and the first chunk as a reply to the inbound message. An intent
@@ -98,8 +101,8 @@ as a user all refuse with exit 2.
or `unknown` line after it. A chunk that is not confirmed stops the rest
of that reply.
6. One write-once record per turn lands in `turns/<message id>.json`: ids,
timing, usage, delivery outcome, and the error on a failed turn. A failed
turn posts one fixed line, never model output.
timing, usage, read-receipt outcome, delivery outcome, and the error on
a failed turn. A failed turn posts one fixed line, never model output.
On start, every `intent` or `unknown` delivery is reconciled by sending the
same nonce again; Discord returns the existing message instead of posting