fix(reactions): apply each mark once per turn #480

Merged
coilyco-ops merged 1 commit from eng/mark-the-turn-once into main 2026-08-13 14:21:18 +00:00
Member

Reactions: confirmed, fixed

reactFromContext(toolCtx, reactionTool) sits inside the tool loop, so it fired once per tool call. Discord dedupes the visible reaction — same user, same emoji is a server-side no-op — so the member saw one 🔨 and the service paid one HTTP request per tool call for it. The turn recorded on the Deep values file spent fourteen tool calls, which is fourteen requests against the reaction rate limit for one visible mark.

A turn now holds one applied set, in onceReactor, and a repeat is dropped before it reaches the transport.

The agent's own marks resolve through the same set rather than keeping their own, so a turn that reaches both reportUndelivered and failTurn asks for once. That was a second instance of the same shape, on a rarer path.

The set is marked before the attempt, not after. A reaction the bot has no ADD_REACTIONS permission for fails every time it is tried, so marking after a successful call would leave exactly the failing case retrying fourteen times. One attempt, one log line.

Edits: already guarded, unchanged

turnProgress.Stage returns early when the phrase has not changed, and a changed phrase still has to clear turnProgressEvery since the last edit. Nine rounds of tool-then-thinking produce edits at the throttle, not per round. Nothing to fix, so nothing here touches it.

Tests

Four, and they assert what reached the transport rather than what the emoji list ends up looking like — the visible result was already correct, so an assertion on it would have passed before the fix.

I mutated the guard to repeat := false and confirmed three of the four go red, and that no pre-existing reaction test does. TestADifferentReactionStillReachesTheMessage stays green under that mutation by design: it is the bound that stops this from suppressing marks it should not.

closes #460

## Reactions: confirmed, fixed `reactFromContext(toolCtx, reactionTool)` sits inside the tool loop, so it fired once per tool call. Discord dedupes the visible reaction — same user, same emoji is a server-side no-op — so the member saw one 🔨 and the service paid one HTTP request per tool call for it. The turn recorded on the Deep values file spent fourteen tool calls, which is fourteen requests against the reaction rate limit for one visible mark. A turn now holds one applied set, in `onceReactor`, and a repeat is dropped before it reaches the transport. The agent's own marks resolve through the same set rather than keeping their own, so a turn that reaches both `reportUndelivered` and `failTurn` asks for ❌ once. That was a second instance of the same shape, on a rarer path. **The set is marked before the attempt, not after.** A reaction the bot has no `ADD_REACTIONS` permission for fails every time it is tried, so marking after a successful call would leave exactly the failing case retrying fourteen times. One attempt, one log line. ## Edits: already guarded, unchanged `turnProgress.Stage` returns early when the phrase has not changed, and a changed phrase still has to clear `turnProgressEvery` since the last edit. Nine rounds of tool-then-thinking produce edits at the throttle, not per round. Nothing to fix, so nothing here touches it. ## Tests Four, and they assert what reached the transport rather than what the emoji list ends up looking like — the visible result was already correct, so an assertion on it would have passed before the fix. I mutated the guard to `repeat := false` and confirmed three of the four go red, and that no pre-existing reaction test does. `TestADifferentReactionStillReachesTheMessage` stays green under that mutation by design: it is the bound that stops this from suppressing marks it should not. closes #460
Merge pull request 'fix(mentions): resolve names in prose only, so a link survives' (#472) from eng/mentions-skip-link-spans into main
All checks were successful
ci / image-build (pull_request) Successful in 21s
ci / test (pull_request) Successful in 33s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
73d2d9fca4
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!480
No description provided.