diff --git a/docs/consultations/gemini-arbiter-discord-roles-round-2-2026-04-13.md b/docs/consultations/gemini-arbiter-discord-roles-round-2-2026-04-13.md index 298d03e..dba318f 100644 --- a/docs/consultations/gemini-arbiter-discord-roles-round-2-2026-04-13.md +++ b/docs/consultations/gemini-arbiter-discord-roles-round-2-2026-04-13.md @@ -62,4 +62,76 @@ Thanks again Gemini — your Round 1 answers saved us from building the wrong th --- -*[Gemini's response will be added here after consultation]* +## Gemini's Response (April 13, 2026) + +**Summary:** Single process, module singleton for shared client, concurrent startup with 503 fallback, clean immediate cutover from Carlbot (no parallel overlap), Discord is source of truth for roles, feature-flag the welcome listener for zero-overlap cutover. + +--- + +### Part 1: discord.js + Express Startup Structure + +**Non-blocking Initialization** +Start them concurrently. Do not block Express while waiting for Discord's `ready` event. Bind routes, call `app.listen()`, then call `client.login()`. If a Pterodactyl webhook fires before the Discord client is ready, catch that state, return `503 Service Unavailable` or `202 Accepted`, queue the action, and log a warning. + +**Process Architecture: Single vs. Separate** +At your current scale, keep it as a **single process**. + +| Architecture | Tradeoffs | Verdict | +| :--- | :--- | :--- | +| **Single Process** (arbiter-3) | Trivial state sharing, simple systemd config. A fatal Discord error crashes the API and vice versa. | **Highly Recommended.** | +| **Separate Processes** | Total fault isolation. Requires IPC or Redis for cross-process communication. | **Overkill.** Re-evaluate at 50+ servers. | + +**Shared State** +Use a **module-level singleton**. Create a dedicated module (e.g., `src/discord/client.js`) that initializes and exports the `discord.js` Client instance. `src/routes/webhook.js` simply requires it and calls methods directly. + +--- + +### Part 2: Migrating from Carlbot Step-by-Step + +**Reaction Roles → Button Roles Migration** +Do not run in parallel — it will confuse the community. Clean, immediate cutover sequence for the week of April 20: + +1. Deploy Arbiter's new role logic to production (systemd restart) +2. Disable Carlbot's Reaction Roles module for `#get-roles` in the Carlbot dashboard +3. Delete the old Carlbot `#get-roles` message entirely +4. Trigger Arbiter's initial `POST` of the new button-based message via script or endpoint + +**Role Data Continuity** +Arbiter does **not** need to reconcile existing role assignments. Discord is the source of truth. When a member clicks a button, the interaction payload includes `interaction.member.roles`. Arbiter checks if the target role ID is in that array — if yes, remove it; if no, add it. Existing members' roles carry over seamlessly and invisibly. + +**Welcome Message Cutover** +Exact sequence to prevent double-welcome-messages: + +1. Deploy Arbiter with the `guildMemberAdd` listener disabled (or behind a feature flag) +2. Disable Carlbot's Welcome module in its dashboard +3. Immediately enable the `guildMemberAdd` listener in Arbiter +4. Restart `arbiter-3` + +If someone joins during the 5-second restart window they may miss a welcome — vastly preferable to double-spamming the channel. + +--- + +**Gemini's follow-up question:** Are you planning to handle potential Discord API rate limits natively within Arbiter's webhook routes, or would you like Code to implement a simple queuing system for those message edits? + +--- + +## Conclusion + +Complete architecture locked. Code has everything needed to build without ambiguity. + +**Architecture decisions:** +- Single process, concurrent startup (`app.listen()` then `client.login()`) +- 503/202 fallback if webhook fires before Gateway ready +- `src/discord/client.js` module singleton shared across Express routes +- Ephemeral replies (flag 64) for per-user role confirmation +- Persistent embed, edit-in-place, 404 → repost fallback +- Feature flag on `guildMemberAdd` for zero-overlap welcome cutover +- No role reconciliation needed — read `interaction.member.roles` on demand + +**Gemini's rate limit question:** Needs a decision before filing the Code bridge request — simple native handling or a queue? + +**Next Steps:** +1. Decide on rate limit handling (native vs. queue) +2. File Code bridge request with complete implementation spec +3. Leave Carlbot running through April 15 launch +4. Week of April 20: execute clean cutover sequence