|
| 1 | +# Dispatch system |
| 2 | + |
| 3 | +The dispatch system gates which issues and messages the bot investigates. Instead of processing all eligible items immediately, maintainers can review and approve them first. |
| 4 | + |
| 5 | +## Dispatch modes |
| 6 | + |
| 7 | +| Mode | Behavior | |
| 8 | +|------|----------| |
| 9 | +| **auto** (default) | All eligible issues are processed immediately. No approval gate. | |
| 10 | +| **approval** | Detection issues are created in the target repo. A maintainer must react with an approval emoji before the bot investigates. | |
| 11 | +| **countdown** | Like approval, but with staged warnings. Auto-dispatches after all warning stages elapse (default: 3 stages, 24h apart = 72-hour minimum). | |
| 12 | +| **triage** | Interactive Discord-based triage. Help requests are posted to a private admin channel with action buttons. Maintainers control the entire lifecycle from Discord. See [Triage mode](#triage-mode) below. | |
| 13 | + |
| 14 | +Set the mode via CLI (`--dispatch-mode <mode>`) or in `config.json`: |
| 15 | + |
| 16 | +```json |
| 17 | +{ |
| 18 | + "dispatch": { |
| 19 | + "mode": "auto", |
| 20 | + "discord_mode": "triage", |
| 21 | + "warnings_required": 3, |
| 22 | + "warning_interval_hours": 24, |
| 23 | + "approve_reactions": ["+1", "rocket"], |
| 24 | + "cancel_reactions": ["-1"], |
| 25 | + "max_detections_per_cycle": 10, |
| 26 | + "close_on_dispatch": true |
| 27 | + } |
| 28 | +} |
| 29 | +``` |
| 30 | + |
| 31 | +## Detection issues (approval / countdown modes) |
| 32 | + |
| 33 | +In `approval` and `countdown` modes, detection issues are created in the target repo (default: `game-ci/help-bot`) with labels `help-bot`, `detection`, and the source repo name. |
| 34 | + |
| 35 | +Maintainer actions on detection issues: |
| 36 | +- React with approval emoji (thumbs up or rocket) to approve immediately |
| 37 | +- React with cancel emoji (thumbs down) to cancel |
| 38 | +- Post any comment to approve (bot-generated warning comments are excluded) |
| 39 | + |
| 40 | +Only reactions/comments from collaborators listed in `config.json` `github.collaborators` are valid. |
| 41 | + |
| 42 | +### Staged countdown safety |
| 43 | + |
| 44 | +The countdown mode prevents bulk auto-dispatch if the bot hasn't run for a while. Only one stage can advance per cycle: |
| 45 | + |
| 46 | +``` |
| 47 | +Cycle 1: Create detection issue -> stage 0 (pending) |
| 48 | +Cycle N: 24h elapsed -> post Warning 1 -> stage 1 |
| 49 | +Cycle N+: 24h elapsed -> post Warning 2 -> stage 2 |
| 50 | +Cycle N+: 24h elapsed -> post Warning 3 -> stage 3 |
| 51 | +Cycle N+: 24h elapsed -> auto-dispatch |
| 52 | +``` |
| 53 | + |
| 54 | +A maintainer can react to approve or cancel at any point during the countdown. |
| 55 | + |
| 56 | +## Discord dispatch |
| 57 | + |
| 58 | +In `auto`, `approval`, and `countdown` modes, Discord dispatch is never fully automatic -- even with `dispatch.mode: "auto"`, Discord sources are forced to at least `"approval"` mode via `dispatch.discord_mode`. |
| 59 | + |
| 60 | +For full Discord-native control, use `triage` mode instead. |
| 61 | + |
| 62 | +## Triage mode |
| 63 | + |
| 64 | +Triage mode moves the entire approval and review workflow into Discord. When a help request is detected (from any monitored Discord channel, thread, or forum post), the bot posts an interactive triage notification to a private admin channel. Maintainers control every step via buttons. |
| 65 | + |
| 66 | +```bash |
| 67 | +gameci-help-bot live --dispatch-mode triage |
| 68 | +``` |
| 69 | + |
| 70 | +### Triage flow |
| 71 | + |
| 72 | +``` |
| 73 | +Help request detected (Discord message, thread, forum post, or GitHub issue) |
| 74 | + | |
| 75 | + v |
| 76 | +Bot posts triage notification to #triage channel |
| 77 | + (orange embed with source content, author, channel link) |
| 78 | + Buttons: [Investigate] [Ignore] |
| 79 | + Bot also posts a brief acknowledgment reply to the user |
| 80 | + | |
| 81 | + +-- Maintainer clicks [Ignore] |
| 82 | + | Embed turns gray, marked as ignored |
| 83 | + | |
| 84 | + +-- Maintainer clicks [Investigate] |
| 85 | + | |
| 86 | + v |
| 87 | + Embed turns blue "INVESTIGATING" |
| 88 | + Bot status changes to DND with "Investigating #channel @author" |
| 89 | + Claude runs investigation (source code search, docs, cross-references) |
| 90 | + | |
| 91 | + v |
| 92 | + Embed turns green "READY" with response preview |
| 93 | + Buttons: [Send Response] [View Investigation] [Re-investigate] [Discard] |
| 94 | + Bot status returns to online |
| 95 | + | |
| 96 | + +-- [View Investigation] |
| 97 | + | Creates a thread on the triage message (or uses existing) |
| 98 | + | Posts the full response for maintainer review |
| 99 | + | |
| 100 | + +-- [Re-investigate] |
| 101 | + | Reads maintainer messages from the thread as instructions |
| 102 | + | Re-runs investigation with previous response marked as rejected |
| 103 | + | and maintainer guidance appended to the prompt |
| 104 | + | |
| 105 | + +-- [Send Response] |
| 106 | + | Posts the approved response to the original source |
| 107 | + | (Discord reply to the user's message) |
| 108 | + | Embed turns gray "SENT" |
| 109 | + | |
| 110 | + +-- [Discard] |
| 111 | + Embed turns gray, response discarded |
| 112 | +``` |
| 113 | + |
| 114 | +### Providing instructions for re-investigation |
| 115 | + |
| 116 | +After an investigation completes (embed is green "READY"): |
| 117 | + |
| 118 | +1. Click **View Investigation** to see the full response in a thread |
| 119 | +2. Reply in that thread with plain English instructions (e.g., "focus on macOS code signing" or "the user is on Unity 2022 LTS, check version-specific issues") |
| 120 | +3. Click **Re-investigate** -- the bot reads all non-bot messages from the thread and includes them as `## Maintainer Guidance` in the prompt. The previous response is marked as rejected so Claude generates a fresh answer. |
| 121 | + |
| 122 | +You can post multiple instruction messages and re-investigate as many times as needed. Each re-investigation produces a new response file with a `-reinvN` suffix. |
| 123 | + |
| 124 | +### Triage configuration |
| 125 | + |
| 126 | +Add a `triage_channel_id` to your guild config and list Discord user IDs for triage access: |
| 127 | + |
| 128 | +```json |
| 129 | +{ |
| 130 | + "discord": { |
| 131 | + "triage_user_ids": ["YOUR_DISCORD_USER_ID"], |
| 132 | + "guilds": [ |
| 133 | + { |
| 134 | + "name": "my-server", |
| 135 | + "guild_id": "...", |
| 136 | + "triage_channel_id": "...", |
| 137 | + "channels": [...] |
| 138 | + } |
| 139 | + ] |
| 140 | + } |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +| Config key | Description | |
| 145 | +|------------|-------------| |
| 146 | +| `discord.triage_user_ids` | Array of Discord user IDs (snowflakes) allowed to use triage buttons. Checked alongside `github.collaborators`. | |
| 147 | +| `guild.triage_channel_id` | Discord channel ID of the private admin channel where triage notifications are posted. | |
| 148 | +| `dispatch.discord_mode` | Set to `"triage"` to enable triage mode, or pass `--dispatch-mode triage` on the CLI. | |
| 149 | + |
| 150 | +### Access control |
| 151 | + |
| 152 | +Button clicks are verified against two lists: |
| 153 | +- `github.collaborators` -- GitHub usernames (matched against Discord username) |
| 154 | +- `discord.triage_user_ids` -- Discord user IDs (exact snowflake match) |
| 155 | + |
| 156 | +Non-authorized users get an ephemeral "Only maintainers can use triage controls" reply. |
| 157 | + |
| 158 | +### Supported source types |
| 159 | + |
| 160 | +Triage mode handles messages from: |
| 161 | +- **Text channels** -- Regular channel messages |
| 162 | +- **Threads** -- Messages inside threads (resolved to parent channel config) |
| 163 | +- **Forum posts** -- Forum channel posts (resolved to parent forum channel config) |
| 164 | +- **GitHub issues/PRs** -- (via cycle-based detection, routed to the same triage UI) |
| 165 | + |
| 166 | +## Dispatch pipeline in cycle mode |
| 167 | + |
| 168 | +The dispatch gate runs after issue filtering and security scanning, before LLM invocation: |
| 169 | + |
| 170 | +1. `createDetections()` -- creates detection issues for new eligible issues |
| 171 | +2. `cleanupStaleDetections()` -- cancels detections for issues no longer eligible |
| 172 | +3. `checkApprovals()` -- checks reactions/comments, advances countdown stages |
| 173 | +4. If no approved issues, skip LLM entirely |
| 174 | +5. After investigations complete, `markDispatched()` updates state and `closeDispatchedDetections()` closes detection issues with cross-links |
| 175 | + |
| 176 | +## Source files |
| 177 | + |
| 178 | +| File | Purpose | |
| 179 | +|------|---------| |
| 180 | +| `src/dispatch/types.ts` | Type definitions: `DispatchMode`, `DetectionRecord`, `DispatchConfig` | |
| 181 | +| `src/dispatch/orchestrator.ts` | Main entry point: `runDispatch()`, `runDiscordDispatch()` | |
| 182 | +| `src/dispatch/detection.ts` | Creates detection issues (GitHub + Discord) | |
| 183 | +| `src/dispatch/approval.ts` | Checks reactions/comments, advances countdown stages | |
| 184 | +| `src/dispatch/lifecycle.ts` | Post-dispatch cleanup: mark dispatched, close detections | |
| 185 | +| `src/dispatch/sanitize.ts` | Security helpers for untrusted content | |
| 186 | +| `src/triage/types.ts` | `TriageRecord`, button ID helpers, guild shortname mapping | |
| 187 | +| `src/triage/notification.ts` | Embed builder, button rows, post/update triage messages | |
| 188 | +| `src/triage/handler.ts` | InteractionCreate handler, button routing, thread posting | |
| 189 | +| `src/triage/investigation.ts` | Claude investigation wrapper, maintainer instruction fetching | |
| 190 | +| `src/triage/send.ts` | Post approved responses to original source | |
0 commit comments