Confirmations: settle+annotate auto-allowed intents; GUI wake retry loop#26
Confirmations: settle+annotate auto-allowed intents; GUI wake retry loop#26ThinkOffApp wants to merge 1 commit into
Conversation
… post; wake retries on GUI failure
Two field defects from 2026-07-07:
1. Dead approve buttons: the bash gate defaults to allow after its timeout,
but the daemon never learned — intents stayed pending forever and every
later /approve tap was a silent no-op (~8 wasted taps in one day).
New: POST /intent/:id/expire marks the intent decision=auto-allowed,
resolves waiters, pushes action-status 'expired', and posts a threaded
reply on the exact confirmation message ('auto-allowed, buttons
inactive'). The groupmind announcer now captures the created message id
(composeAnnouncers collects per-channel results onto the intent) to
make the threaded annotation possible.
2. Silent-hour wake failure: a failed GUI nudge (locked screen) was never
retried — new messages went unanswered for an hour. claude-gui-wake.sh
now spawns a lock-guarded detached retry loop (60s interval, max 30).
Verified live: gate test intent auto-allowed after 8s with annotation
reply landing on the right message; wake retry exercised during the
15:42-16:54 incident.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b180b7d383
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| i.status = 'decided'; | ||
| i.decision = 'auto-allowed'; |
There was a problem hiding this comment.
Settle backing actions when expiring intents
When /intent/:id/expire is called for an intent created by /actions/request, this only marks the intent as decided; the corresponding entry in the actions map remains pending until its separate expires_at timer. That leaves /actions/:nonce reporting pending while /intents reports auto-allowed, and later Approve/Deny taps cannot settle or run the action because decideIntent now rejects the already-decided intent. Either reject action-backed intents here or settle the action record in the same path.
Useful? React with 👍 / 👎.
| const data = JSON.stringify({ | ||
| room: info.room, | ||
| body, | ||
| metadata: { reply_to: info.messageId }, | ||
| }); |
There was a problem hiding this comment.
Send reply_to as a message field
For the timeout-allow annotation, this nests reply_to inside metadata, but the GroupMind message shape treats reply_to as a sibling of metadata (see skills/thinkoff-agent-platform/SKILL.md lines 109 and 118). In the /intent/:id/expire path the note will therefore not be threaded on the original confirmation card, so users tapping the stale Approve/Deny buttons still won't see the intended no-op explanation in context.
Useful? React with 👍 / 👎.
Two field defects from today, both verified live on the Mini:
Dead approve buttons — the precommand gate times out and defaults to allow, but the daemon never learned: intents stayed
pendingforever, chat buttons stayed live, and every later/approvetap was a silent no-op (~8 wasted taps today). NewPOST /intent/:id/expire(called by the gate on timeout-allow) settles the intent asauto-allowed, pushes action-statusexpired, and posts a threaded reply on the exact confirmation message. The groupmind announcer now captures the created message id to make that reply possible (composeAnnouncerscollects per-channel results onto the intent).Silent-hour wake failure — a GUI nudge that fails (locked screen) was never retried; the room went unanswered for an hour.
claude-gui-wake.shnow spawns a lock-guarded detached retry loop (60 s × 30).Client side (gate script, in
~/.claude/scripts, not this repo) gained heredoc-body stripping so file contents being written can't trip risky patterns — 12-case unit suite passes.🤖 Generated with Claude Code