Skip to content

feat(procevent): add Discord mention watch adapter for Firstcrew channel - #81

Merged
Ivory2024 merged 5 commits into
mainfrom
codex/discord-mention-watch-adapter-20261002
Oct 3, 2026
Merged

Ivory2024 merged 5 commits into
mainfrom
codex/discord-mention-watch-adapter-20261002

Conversation

@Ivory2024

@Ivory2024 Ivory2024 commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Intent

Add a Firstmate process-event adapter that wakes on human mentions of the Claude bot in the Firstcrew Discord channel, with approved channel-only scope and durable capture.

What Changed

  • Add bin/fm-procevent-discord-mention.py and bin/fm-procevent-discord-mention.sh, a process-event adapter that polls the approved Firstcrew Discord channel and durably captures human mentions of the Claude bot.
  • Wire the new adapter into bin/fm-watch.sh and document the adapter's config in docs/configuration.md.
  • Add tests/fm-procevent-discord-mention.test.sh covering the adapter, and record the design in docs/plans/discord-mention-watch-adapter-20261002.md.

Risk Assessment

✅ Low: Both prior rounds' fixes (terminal PollError on pagination-cap-exceeded in Python, and matching shell classifier entry) are correctly and minimally applied; pagination control flow traced and sound; remaining diff (fm-watch.sh ensure hook, docs, tests) is consistent with existing sibling adapter patterns and exercises real adapter behavior rather than source-text matching.

Testing

Built disposable FM_HOME/state under /tmp, ran the Python adapter in its built-in FM_DISCORD_TEST_MODE fixture mode and the shell wrapper's classify/terminal subcommands directly against produced result files; both review-round fixes (PollError pagination-cap-exceeded raised before the cursor silently advances, and the shell terminal classifier retiring the source on that error) verified live, plus happy-path mention capture and classifier regressions on missing-token/http-429 all passed. Lab directory removed after capturing evidence; worktree left clean.

  • Live validation: ✅ go - 5 of 5 scenarios driven live against the product
Scenario Result Live Evidence
pagination backlog exceeding MAX_PAGES raises terminal pagination-cap-exceeded instead of silently skipping mentions ✅ pass live result_cap_exceeded.json: {"status":"poll-error","error":"pagination-cap-exceeded"}
shell terminal classifier retires source on pagination-cap-exceeded result ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_cap_exceeded.json exits 0 (terminal=yes)
genuine bot mention in channel is captured as status mention with message/author fields ✅ pass live result_mention.json shows status mention, message_id 5, author alice, content 'hey claude'
existing terminal errors (e.g. missing-token) still classified terminal after the allowlist addition (regression) ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_missing_token.json exits 0
non-terminal error (http-429) still classified non-terminal, not over-broadened by the fix (regression) ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_429.json exits nonzero
Evidence: pagination-cap-exceeded poll result

Source: pagination-cap-exceeded poll result

{"schema":"firstmate.discord-mention-result.v1","status":"poll-error","error":"pagination-cap-exceeded"}
Evidence: mention happy-path result

Source: mention happy-path result

{"schema":"firstmate.discord-mention-result.v1","status":"mention","channel_id":"1551134713727426570","guild_id":null,"message_id":"5","cursor_after":"5","author_id":"1","author_name":"alice","timestamp":"t","content":"hey claude","attachments":[]}
Evidence: missing-token terminal regression result

Source: missing-token terminal regression result

{"status":"poll-error","error":"missing-token"}
Evidence: http-429 non-terminal regression result

Source: http-429 non-terminal regression result

{"status":"poll-error","error":"http-429"}

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (2) ✅
  • ⚠️ bin/fm-procevent-discord-mention.py:142 - new_messages() walks backward via before until oldest <= cursor or a short page signals end-of-history, but it also stops when pages hits MAX_PAGES (100 pages × 100 msgs = 10,000 messages) without ever reaching the cursor. In that case the returned batch does not actually cover (cursor, oldest_fetched]; poll() (line ~223: cursor = message_id(messages[-1])) then advances the checkpoint straight to the newest fetched id regardless, so any genuine bot mention sitting in the unfetched gap between the old cursor and oldest_fetched is permanently skipped with no error or trace — next poll starts from the new, higher cursor and never looks back. Concrete trigger: the watcher is down (or the channel sees a burst) long enough that more than ~10,000 messages accumulate since the last successful checkpoint; a mention inside that backlog never surfaces. The fix is mechanical and local to this function (e.g. raise a terminal PollError, mirroring the existing pagination-did-not-advance case, when the MAX_PAGES cap is hit without oldest <= cursor, instead of silently trusting the batch as complete) and does not require new state or a new subsystem.

🔧 Fix applied.
1 error still open:

  • 🚨 bin/fm-procevent-discord-mention.sh:85 - Fix round d9f2e77 added a new python-side terminal PollError code pagination-cap-exceeded (bin/fm-procevent-discord-mention.py:157) to close the prior finding's silent-skip gap, but did not add that code to this shell script's terminal subcommand jq allowlist (line 85), which is the separate classifier fm-procevent.sh:336 (adapter_result_is_terminal) uses to decide whether to retire the registered source after a captured poll-error result. Concrete sequence: the watcher accumulates a 10,000+ message backlog, new_messages() raises pagination-cap-exceeded (terminal=True in Python), poll() emits a poll-error result immediately — but fm-procevent.sh's jq check at line 85 does not match pagination-cap-exceeded, so adapter_result_is_terminal returns false, the source is NOT retired, and it stays armed. Every subsequent reconcile cycle re-polls from the same stuck, never-advanced cursor, reproduces the identical cap-exceeded error, and is captured again — forever — without ever reaching the captain-relevant terminal-retirement path that missing-token, invalid-cursor, pagination-did-not-advance, etc. all get. This defeats the purpose of the fix (surfacing the gap so it gets human attention) and leaves the adapter silently looping on a known-bad state. Minimal remedy: add .error == "pagination-cap-exceeded" to the jq condition at line 85, mirroring the existing pagination-did-not-advance entry; mechanical, no new state or subsystem required.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 5 of 5 scenarios driven live against the product
Scenario Result Live Evidence
pagination backlog exceeding MAX_PAGES raises terminal pagination-cap-exceeded instead of silently skipping mentions ✅ pass live result_cap_exceeded.json: {"status":"poll-error","error":"pagination-cap-exceeded"}
shell terminal classifier retires source on pagination-cap-exceeded result ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_cap_exceeded.json exits 0 (terminal=yes)
genuine bot mention in channel is captured as status mention with message/author fields ✅ pass live result_mention.json shows status mention, message_id 5, author alice, content 'hey claude'
existing terminal errors (e.g. missing-token) still classified terminal after the allowlist addition (regression) ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_missing_token.json exits 0
non-terminal error (http-429) still classified non-terminal, not over-broadened by the fix (regression) ✅ pass live bin/fm-procevent-discord-mention.sh terminal result_429.json exits nonzero
  • python3 bin/fm-procevent-discord-mention.py (FM_DISCORD_TEST_MODE=1, 10200-message fixture) -> poll-error/pagination-cap-exceeded
  • bin/fm-procevent-discord-mention.sh terminal <result> on pagination-cap-exceeded result
  • bin/fm-procevent-discord-mention.sh classify <result> on pagination-cap-exceeded result
  • python3 bin/fm-procevent-discord-mention.py (fixture with bot mention) -> status mention
  • bin/fm-procevent-discord-mention.sh terminal on missing-token result (regression)
  • bin/fm-procevent-discord-mention.sh terminal on http-429 result (regression, expect non-terminal)
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

…ce=bin/fm-discord-lib.sh` directive before `source "$SCRIPT_DIR/fm-discord-lib.sh"` in bin/fm-procevent-discord-mention.sh:11, causing SC1091 "does not exist" since ShellCheck could not resolve path without hint (sibling scripts fm-discord-poll.sh, fm-discord-notify.sh, etc. all carry this directive). Behavior portable serial 3 failed because docs/plans/discord-mention-watch-adapter-20261002.md (added in PR) was tracked but missing from docs/documentation-audiences.json, failing tests/fm-documentation-audiences.test.sh's completeness check; classified it maintainer-architecture, matching sibling internal decision docs. Verified: shellcheck clean on changed file, fm-documentation-audiences.test.sh, fm-vendor-auth-probe.test.sh, fm-harness-adapter-references.test.sh, and fm-procevent-discord-mention.test.sh all pass
@Ivory2024
Ivory2024 merged commit 7e5c4fd into main Oct 3, 2026
19 checks passed
@Ivory2024
Ivory2024 deleted the codex/discord-mention-watch-adapter-20261002 branch October 3, 2026 02:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant