Skip to content

feat: AFK system#108

Merged
BillChirico merged 4 commits intomainfrom
feat/afk-system
Feb 27, 2026
Merged

feat: AFK system#108
BillChirico merged 4 commits intomainfrom
feat/afk-system

Conversation

@BillChirico
Copy link
Collaborator

Summary

Implements the AFK system requested in #46.

What's included

  • Migration migrations/006_afk.cjs: Creates afk_status and afk_pings tables with appropriate indexes.
  • Command src/commands/afk.js: /afk set [reason] and /afk clear subcommands, both ephemeral, gated on afk.enabled.
  • Handler src/modules/afkHandler.js: Called on every guild message:
    • If sender is AFK → auto-clear, DM them a ping summary
    • If a mentioned user is AFK → reply inline with notice + track ping in DB
    • Rate-limited: max 1 notice per user per channel per 5 minutes
  • Wired into src/modules/events.js (before rate-limit/link-filter block)
  • Config afk.enabled: false added to config.json; afk added to SAFE_CONFIG_KEYS

Tests

23 new tests across tests/commands/afk.test.js and tests/modules/afkHandler.test.js:

  • Config gate (disabled by default)
  • Set AFK stores with reason/default
  • Clear AFK returns ping summary + deletes records
  • Mention of AFK user triggers inline notice
  • Auto-clear on sender message with DM
  • Rate limiting prevents spam
  • Ping tracking inserts to DB
  • Self-mentions and bot mentions skipped

All 1734 existing tests continue to pass.

Closes #46

- Add migration 006_afk.cjs with afk_status and afk_pings tables
- Add /afk set and /afk clear commands with config gate
- Add afkHandler module: auto-clear on message, inline notices, ping tracking, rate limiting
- Wire handleAfkMentions into messageCreate event handler
- Add afk to config.json (disabled by default) and SAFE_CONFIG_KEYS
- Add tests for command and handler (23 tests, all passing)
Copilot AI review requested due to automatic review settings February 27, 2026 15:10
@claude
Copy link

claude bot commented Feb 27, 2026

Claude finished @BillChirico's task in 4m 40s —— View job


Review complete — PR #108 AFK System

  • Read project conventions (AGENTS.md, CLAUDE.md)
  • Read all changed files
  • Analyze changes and CI status
  • Identify remaining issues after fix commits
  • Post inline comments and summary
  • Submit review verdict

Verdict: Approved with 3 minor nitpicks.

All critical and warning issues from previous review rounds have been fixed across commits 0b5e476, 57b425b, and 1c64126:

  • ✅ Memory leak — rate limit Map now auto-evicts via setTimeout
  • ✅ Non-atomic deletes — both afk.js and afkHandler.js use transactions
  • ✅ Ping tracking — INSERT now runs before rate-limit check
  • displayName — uses message.mentions.members (GuildMember)
  • ✅ Permission allowlist — "afk": "everyone" added
  • ✅ Import ordering — Biome-compliant
  • ✅ Documentation — AGENTS.md and README.md updated

3 remaining 🔵 nitpicks (inline comments posted):

  • SELECT * in src/commands/afk.js:58 — only needs existence check (SELECT 1)
  • SELECT * in src/modules/afkHandler.js:78 — only needs existence check (SELECT 1)
  • SELECT * in src/modules/afkHandler.js:152 — only reason and set_at used

CI note: Branch coverage is 79.47% (threshold: 80%). The AFK code itself has excellent coverage (100% branch in afk.js, 95.83% in afkHandler.js). The shortfall comes from pre-existing files (sentry.js 38%, health.js 39%, moderation.js routes 0%, etc.) and is not caused by this PR.

AI fix prompt for remaining nitpicks
Fix the following 3 nitpicks on branch `feat/afk-system` in `VolvoxLLC/volvox-bot`:

1. `src/commands/afk.js:58` — Change `SELECT *` to `SELECT 1` (only existence check needed)
2. `src/modules/afkHandler.js:78` — Change `SELECT *` to `SELECT 1` (only existence check needed)
3. `src/modules/afkHandler.js:152` — Change `SELECT *` to `SELECT reason, set_at` (only those columns are used on lines 158-159)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Warning

Rate limit exceeded

@BillChirico has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 941032d and 1c64126.

📒 Files selected for processing (8)
  • AGENTS.md
  • README.md
  • config.json
  • src/commands/afk.js
  • src/modules/afkHandler.js
  • src/modules/events.js
  • tests/commands/afk.test.js
  • tests/modules/afkHandler.test.js
📝 Walkthrough

Walkthrough

Introduces a complete AFK system allowing users to set away status with optional reasons, automatically notifying those who mention AFK users, tracking pings with rate limiting, and auto-clearing status when users return with a DM summary of pings received.

Changes

Cohort / File(s) Summary
Configuration Setup
config.json, src/api/utils/configAllowlist.js
Added new top-level "afk" config block with enabled flag (default false) and whitelisted it for API access.
Database Migration
migrations/006_afk.cjs
Created afk_status and afk_pings tables to store user AFK records and ping tracking with unique constraints and indexes.
AFK Command
src/commands/afk.js
Implemented /afk slash command with set/clear subcommands, ping summary formatting, and database operations for managing AFK status.
Event Handler Integration
src/modules/afkHandler.js, src/modules/events.js
Added message interception to detect mentions of AFK users, auto-clear on sender's return, rate-limit responses (5-min window per user/channel), and track pings in database.
Test Coverage
tests/commands/afk.test.js, tests/modules/afkHandler.test.js
Comprehensive test suites covering command execution, database interactions, config gating, auto-clear flow, mention handling, and rate limiting enforcement.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: AFK system' directly and concisely summarizes the main change—the addition of a complete AFK system.
Description check ✅ Passed The description comprehensively details the AFK system implementation across migrations, commands, handlers, configuration, and tests, clearly relating to the changeset.
Linked Issues check ✅ Passed All subtasks and acceptance criteria from #46 are met: set/clear commands exist, auto-responses trigger on mentions, pings are tracked in DB, auto-clear with DM summary implemented, rate limiting enforced, and tests validate all requirements.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the AFK system as defined in #46. No unrelated modifications or features have been introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/afk-system

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary — 4 issues found

🔴 Critical (1)

  1. Memory leak in rate limit Map (src/modules/afkHandler.js:19-22) — afkNoticeRateLimit entries are never evicted. Add periodic cleanup via setInterval with .unref().

🟡 Warning (3)

  1. Missing afk permission (config.json:169-171) — afk not in permissions.allowedCommands means it defaults to admin-only per src/utils/permissions.js:96-99. Add "afk": "everyone".
  2. Non-atomic deletes (src/commands/afk.js:79-86, src/modules/afkHandler.js:89-96) — Two separate DELETE queries without a transaction. Wrap in BEGIN/COMMIT to prevent orphaned afk_pings rows.
  3. Documentation not updated — AGENTS.md Key Files table, Database Tables section, and README.md Features section all missing AFK entries. Per AGENTS.md: "Keep docs up to date — this is non-negotiable."

🔵 Nitpick (3)

  1. SELECT * usage (src/commands/afk.js:58, src/modules/afkHandler.js:73,137) — Select only needed columns.

AI fix prompt (copy-paste into an AI agent)

Fix the following issues on branch feat/afk-system in VolvoxLLC/volvox-bot:

  1. src/modules/afkHandler.js — Add a cleanup interval for afkNoticeRateLimit. After line 22, add a setInterval that runs every 10 minutes, iterates over the Map, and deletes entries where Date.now() - timestamp >= RATE_LIMIT_MS. Call .unref() on the timer. Export a stopCleanupTimer() for tests.

  2. config.json — In permissions.allowedCommands, add "afk": "everyone" (after the "tldr" entry).

  3. src/commands/afk.js:79-86 — Wrap the two DELETE queries in a transaction using const client = await pool.connect(); try { await client.query('BEGIN'); ... await client.query('COMMIT'); } catch { await client.query('ROLLBACK'); throw err; } finally { client.release(); }.

  4. src/modules/afkHandler.js:89-96 — Same transaction wrapping as above for the two DELETEs in the auto-clear path.

  5. src/commands/afk.js:58 — Change SELECT * to SELECT 1.

  6. src/modules/afkHandler.js:73 — Change SELECT * to SELECT 1.

  7. src/modules/afkHandler.js:137 — Change SELECT * to SELECT reason, set_at.

  8. AGENTS.md — Add to Key Files table: src/commands/afk.js | AFK slash command — /afk set and /afk clear subcommands and src/modules/afkHandler.js | AFK handler — auto-clear on message, inline AFK notices, ping tracking with rate limiting. Add to Database Tables: afk_status | Active AFK statuses — one row per guild+user and afk_pings | Pings received while AFK — tracked for summary on return.

  9. README.md — Add to Features section: - **💤 AFK System** — Set AFK status with /afk set. Mentioned while away? Get a ping summary when you return.

@greptile-apps
Copy link

greptile-apps bot commented Feb 27, 2026

Greptile Summary

Implements a complete AFK system that allows users to set away status with /afk set [reason] and automatically clears when they return. When AFK users are mentioned, the bot sends inline notices (rate-limited to prevent spam) and tracks pings in the database. Upon return, users receive a DM with a summary of who pinged them.

Key implementation details:

  • Properly uses transactions to atomically delete AFK status and pings, preventing orphaned records
  • Uses message.mentions.members to access GuildMember.displayName (discord.js v14)
  • Rate-limited notices (5 min per user per channel) with automatic cache eviction
  • Config-gated behind afk.enabled (disabled by default)
  • Integrated into message flow before rate-limit/link-filter checks
  • Comprehensive test coverage (23 tests across 670 lines)
  • Documentation updated in AGENTS.md and README.md

Previous review feedback has been properly addressed. All code follows project conventions (Winston logging, ESM modules, safeSend wrappers, config hot-reload pattern).

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • Implementation is clean, well-tested, and follows all project conventions. Previous review feedback (displayName property, transaction atomicity) has been properly addressed. Database schema is sound with appropriate indexes. Error handling is comprehensive with isolated try-catch blocks. No security issues or performance concerns.
  • No files require special attention

Important Files Changed

Filename Overview
migrations/006_afk.cjs Creates afk_status and afk_pings tables with proper constraints and indexes. Schema design is clean with unique constraint on (guild_id, user_id).
src/commands/afk.js Implements /afk set and /afk clear subcommands with proper config gating, transaction-wrapped deletes, and ping summary DMs. Follows project conventions.
src/modules/afkHandler.js Message handler for AFK detection with auto-clear on return, mention tracking, and rate-limited notices (5min window). Uses transactions and GuildMember.displayName correctly.
src/modules/events.js Integrates AFK handler into message flow before rate-limit/link-filter checks. Error handling is isolated so AFK failures don't break other features.
tests/commands/afk.test.js Comprehensive test coverage for command with 299 lines covering config gate, set/clear operations, ping summaries, and transaction rollback scenarios.
tests/modules/afkHandler.test.js Thorough handler tests with 371 lines covering auto-clear, mention detection, rate limiting, ping tracking, and edge cases like self-mentions and bot mentions.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant D as Discord
    participant C as /afk Command
    participant H as afkHandler
    participant DB as PostgreSQL
    
    Note over U,DB: Setting AFK Status
    U->>D: /afk set [reason]
    D->>C: execute(interaction)
    C->>C: Check afk.enabled config
    C->>DB: UPSERT afk_status
    C-->>U: 💤 You are now AFK (ephemeral)
    
    Note over U,DB: Someone Mentions AFK User
    U->>D: Message with @AFKUser
    D->>H: handleAfkMentions(message)
    H->>H: Check afk.enabled config
    H->>DB: SELECT afk_status for @AFKUser
    H->>DB: INSERT afk_pings record
    H->>H: checkNoticeRateLimit()
    H-->>D: 💤 AFKUser is AFK: reason (inline reply)
    
    Note over U,DB: AFK User Returns
    U->>D: Sends any message
    D->>H: handleAfkMentions(message)
    H->>DB: SELECT afk_status for sender
    H->>DB: SELECT afk_pings for sender
    H->>DB: BEGIN TRANSACTION
    H->>DB: DELETE afk_status
    H->>DB: DELETE afk_pings
    H->>DB: COMMIT
    H-->>U: 👋 Welcome back! (DM with ping summary)
Loading

Last reviewed commit: 1c64126

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

11 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements a comprehensive AFK (Away From Keyboard) system for the Discord bot, allowing users to set away status with optional reasons and receive ping summaries when they return. The feature is disabled by default and can be enabled per-guild via the config system.

Changes:

  • Database schema: Creates afk_status and afk_pings tables with appropriate indexes for tracking AFK users and mentions
  • Command interface: Adds /afk set [reason] and /afk clear subcommands with ephemeral responses
  • Message handler: Implements auto-clear on return, inline AFK notices for mentions, ping tracking, and rate-limited notifications (1 per user per channel per 5 minutes)

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
migrations/006_afk.cjs Defines database tables for AFK status tracking and ping history with unique constraints and indexes
src/commands/afk.js Implements /afk set and /afk clear commands with config gating, ephemeral responses, and ping summary generation
src/modules/afkHandler.js Core handler that processes every guild message to auto-clear AFK status and send inline notices when AFK users are mentioned
src/modules/events.js Integrates AFK handler into message flow before rate limiting and link filtering
src/api/utils/configAllowlist.js Adds 'afk' to safe config keys for runtime configuration updates
config.json Adds afk.enabled: false configuration option
tests/commands/afk.test.js Comprehensive command tests covering config gates, set/clear operations, and ping summary building (11 tests)
tests/modules/afkHandler.test.js Handler tests covering config gates, auto-clear, DM handling, mention detection, rate limiting, and edge cases (12 tests)
pnpm-lock.yaml Updates @anthropic-ai/sdk from 0.40.1 to 0.78.0 and related dependencies (unrelated to AFK feature)
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/modules/events.js (1)

6-21: ⚠️ Potential issue | 🟡 Minor

Import ordering in this file is currently CI-blocking.

Line 6 import section needs Biome organize-imports normalization.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/events.js` around lines 6 - 21, Reorder the import block so it
conforms to Biome's organize-imports: group external packages first (e.g.,
"discord.js" imports like Client, Events), then internal project imports; within
groups sort specifiers alphabetically (e.g., info, logError, warn;
getUserFriendlyMessage; safeReply; getConfig; handleAfkMentions; checkLinks;
handlePollVote; checkRateLimit; isSpam, sendSpamAlert; handleReactionAdd,
handleReactionRemove; accumulateMessage, evaluateNow; recordCommunityActivity,
sendWelcomeMessage). Apply consistent grouping/spacing and run Biome
organize-imports to normalize the import ordering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@migrations/006_afk.cjs`:
- Around line 30-35: The current index created with pgm.createIndex('afk_pings',
['guild_id', 'afk_user_id'], { name: 'idx_afk_pings_user' }) should include the
pinged_at column to support ordered lookups and avoid sorts; update the
createIndex call to index ['guild_id', 'afk_user_id', 'pinged_at'] and update
the corresponding pgm.dropIndex call to drop the same composite index name (keep
or adjust the index name 'idx_afk_pings_user' consistently) so the migration and
rollback target the identical index definition.

In `@src/commands/afk.js`:
- Around line 70-86: The read-plus-two-deletes for AFK clearing (the SELECT that
yields pings, and the DELETEs against afk_status and afk_pings) must be executed
in a single DB transaction to avoid partial state on failure; obtain a client
from pool (e.g., const client = await pool.connect()), run
client.query('BEGIN'), perform the SELECT and both DELETEs using that same
client (optionally SELECT ... FOR UPDATE on afk_status/afk_pings to lock rows),
then client.query('COMMIT'), and on any error client.query('ROLLBACK') and
rethrow; ensure you release the client in a finally block so pings, pool.query
calls, interaction.guildId and interaction.user.id are all used against the same
transactional client.

In `@src/modules/afkHandler.js`:
- Around line 9-13: Reorder the import statements to satisfy Biome's
organize-imports rule: group and alphabetize by module path so imports like
buildPingSummary (from '../commands/afk.js'), getPool (from '../db.js'), info
and error as logError (from '../logger.js'), safeSend (from
'../utils/safeSend.js'), and getConfig (from './config.js') are in the correct
sorted/grouped order; update the import block in src/modules/afkHandler.js
accordingly so the CI import-order check passes.
- Around line 19-23: afkNoticeRateLimit currently stores keys forever and can
grow unbounded; change its usage so entries are automatically evicted after
RATE_LIMIT_MS by storing an expiry and scheduling removal: when setting
afkNoticeRateLimit.set(key, true) instead set afkNoticeRateLimit.set(key,
Date.now() + RATE_LIMIT_MS) and schedule a cleanup (e.g. setTimeout(() =>
afkNoticeRateLimit.delete(key), RATE_LIMIT_MS)); alternatively implement a
periodic cleanup loop that removes entries whose stored expiry <= Date.now();
update any checks against afkNoticeRateLimit to compare expiry timestamps
(expiry > Date.now()) rather than truthiness. Ensure all references to
afkNoticeRateLimit and RATE_LIMIT_MS in src/modules/afkHandler.js are updated
accordingly.
- Around line 128-130: The handler only checks message.mentions.users (variable
mentionedUsers) so replies to an AFK user are ignored; modify the flow to also
detect reply targets by checking message.reference (and
message.reference.messageId), fetching the referenced message (e.g., via
message.channel.messages.fetch(message.reference.messageId)) and adding that
referenced message's author to the set of users to inspect for AFK status and
ping tracking; ensure the same logic that sends AFK notices and records pings
for users in mentionedUsers is applied to the referenced author as well.
- Around line 147-163: The code currently returns early when
checkNoticeRateLimit(...) is false or when safeSend(...) fails, which prevents
always recording an afk_pings row; instead, only the channel notice should be
rate-limited. Modify the logic around checkNoticeRateLimit, safeSend, and the
pool.query insert so that the INSERT into afk_pings (using pool.query and the
preview variable) always executes for every ping regardless of rate-limit or
send errors; keep the rate-limit check to gate only the safeSend call (and wrap
safeSend in its own try/catch so failures don’t stop the subsequent pool.query).
Ensure you reference the existing functions/variables checkNoticeRateLimit,
safeSend, preview, pool.query and the afk_pings insert when moving the insert
out of the rate-limit/send branch.

---

Outside diff comments:
In `@src/modules/events.js`:
- Around line 6-21: Reorder the import block so it conforms to Biome's
organize-imports: group external packages first (e.g., "discord.js" imports like
Client, Events), then internal project imports; within groups sort specifiers
alphabetically (e.g., info, logError, warn; getUserFriendlyMessage; safeReply;
getConfig; handleAfkMentions; checkLinks; handlePollVote; checkRateLimit;
isSpam, sendSpamAlert; handleReactionAdd, handleReactionRemove;
accumulateMessage, evaluateNow; recordCommunityActivity, sendWelcomeMessage).
Apply consistent grouping/spacing and run Biome organize-imports to normalize
the import ordering.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e1e0cd and 941032d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • config.json
  • migrations/006_afk.cjs
  • src/api/utils/configAllowlist.js
  • src/commands/afk.js
  • src/modules/afkHandler.js
  • src/modules/events.js
  • tests/commands/afk.test.js
  • tests/modules/afkHandler.test.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Greptile Review
  • GitHub Check: Agent
  • GitHub Check: claude-review
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use ESM modules with import/export syntax; never use require()
Always use node: protocol for Node.js builtins (e.g., import { readFileSync } from 'node:fs')
Always use semicolons in code
Use single quotes for strings (enforced by Biome)
Use 2-space indentation (enforced by Biome)

Files:

  • tests/commands/afk.test.js
  • src/api/utils/configAllowlist.js
  • src/modules/afkHandler.js
  • tests/modules/afkHandler.test.js
  • src/commands/afk.js
  • src/modules/events.js
tests/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.{js,ts,jsx,tsx}: All new code must include tests; test coverage must maintain 80% threshold on statements, branches, functions, and lines
Use Vitest for testing; run pnpm test before every commit and pnpm test:coverage to verify 80% coverage threshold

Files:

  • tests/commands/afk.test.js
  • tests/modules/afkHandler.test.js
src/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{js,ts,jsx,tsx}: Always use Winston for logging via import { info, warn, error } from '../logger.js'; never use console.log, console.warn, console.error, or any console.* method in src/ files
Pass structured metadata to Winston logging calls (e.g., info('Message processed', { userId, channelId }))
Use custom error classes from src/utils/errors.js for error handling
Always log errors with context before re-throwing
Use getConfig(guildId?) from src/modules/config.js to read configuration values
Use setConfigValue(path, value, guildId?) from src/modules/config.js to update configuration at runtime
Use safeSend() utility for all outgoing Discord messages to enforce allowedMentions and prevent mention spam
Use sanitizeMentions() to strip @everyone/@here from outgoing text via zero-width space insertion before sending
Use splitMessage() utility to handle Discord's 2000-character message limit
onConfigChange callbacks receive (newValue, oldValue, fullPath, guildId) as parameters

Files:

  • src/api/utils/configAllowlist.js
  • src/modules/afkHandler.js
  • src/commands/afk.js
  • src/modules/events.js
src/modules/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Check config.yourModule.enabled before processing in module handlers

Files:

  • src/modules/afkHandler.js
  • src/modules/events.js
src/commands/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/commands/**/*.{js,ts,jsx,tsx}: Slash commands must export a data property with a SlashCommandBuilder and an async execute(interaction) function
Export adminOnly = true for moderator-only slash commands
Duration-based commands (timeout, tempban, slowmode) must use parseDuration() from src/utils/duration.js for parsing duration arguments
Always call checkHierarchy(moderator, target) before executing moderation actions to prevent moderating users with equal or higher roles

Files:

  • src/commands/afk.js
src/modules/events.js

📄 CodeRabbit inference engine (AGENTS.md)

Module handler functions must be registered in src/modules/events.js via client.on() event listeners

Files:

  • src/modules/events.js
config.json

📄 CodeRabbit inference engine (AGENTS.md)

Document new config sections and keys in README.md's config reference when updating config.json

Files:

  • config.json
🧠 Learnings (7)
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/**/*.{js,ts,jsx,tsx} : Use `safeSend()` utility for all outgoing Discord messages to enforce allowedMentions and prevent mention spam

Applied to files:

  • src/modules/afkHandler.js
  • src/modules/events.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/modules/{ai,spam,moderation}.js : Per-request modules (AI, spam, moderation) call `getConfig(interaction.guildId)` on every invocation for automatic config hot-reload; `onConfigChange` listeners provide observability only

Applied to files:

  • src/modules/afkHandler.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/commands/**/*.{js,ts,jsx,tsx} : Slash commands must export a `data` property with a SlashCommandBuilder and an async `execute(interaction)` function

Applied to files:

  • src/commands/afk.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/commands/**/*{ban,kick,warn,timeout,mute}*.{js,ts,jsx,tsx} : Moderation commands must follow the pattern: deferReply() → validate → sendDmNotification() → execute Discord action → createCase() → sendModLogEmbed() → checkEscalation()

Applied to files:

  • src/commands/afk.js
  • src/modules/events.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/commands/**/*{ban,kick}*.{js,ts,jsx,tsx} : Moderation commands must DM the target user before executing kicks/bans (as users cannot receive DMs after being kicked/banned)

Applied to files:

  • src/commands/afk.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to src/**/*.{js,ts,jsx,tsx} : Use `sanitizeMentions()` to strip everyone/here from outgoing text via zero-width space insertion before sending

Applied to files:

  • src/modules/events.js
📚 Learning: 2026-02-26T22:59:10.394Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to config.json : Document new config sections and keys in `README.md`'s config reference when updating `config.json`

Applied to files:

  • config.json
🧬 Code graph analysis (5)
tests/commands/afk.test.js (3)
src/commands/afk.js (6)
  • subcommand (131-131)
  • execute (121-149)
  • pool (36-36)
  • pool (55-55)
  • pings (70-76)
  • buildPingSummary (102-113)
src/modules/config.js (1)
  • getConfig (282-313)
src/db.js (1)
  • getPool (142-147)
src/modules/afkHandler.js (5)
src/commands/afk.js (6)
  • guildConfig (122-122)
  • pool (36-36)
  • pool (55-55)
  • pings (70-76)
  • summary (90-90)
  • buildPingSummary (102-113)
src/modules/config.js (2)
  • getConfig (282-313)
  • err (94-94)
src/db.js (1)
  • getPool (142-147)
src/logger.js (1)
  • info (230-232)
src/utils/safeSend.js (1)
  • safeSend (116-123)
tests/modules/afkHandler.test.js (5)
src/commands/afk.js (3)
  • pings (70-76)
  • pool (36-36)
  • pool (55-55)
src/modules/afkHandler.js (4)
  • pings (80-86)
  • pool (68-68)
  • pool (137-140)
  • handleAfkMentions (61-178)
src/modules/config.js (1)
  • getConfig (282-313)
src/db.js (1)
  • getPool (142-147)
src/utils/safeSend.js (1)
  • safeSend (116-123)
src/commands/afk.js (5)
src/index.js (1)
  • interaction (206-206)
src/modules/afkHandler.js (5)
  • pool (68-68)
  • pool (137-140)
  • pings (80-86)
  • summary (104-104)
  • preview (158-158)
src/db.js (1)
  • getPool (142-147)
src/utils/safeSend.js (1)
  • safeReply (138-145)
src/modules/config.js (2)
  • getConfig (282-313)
  • err (94-94)
src/modules/events.js (1)
src/modules/afkHandler.js (1)
  • handleAfkMentions (61-178)
🪛 GitHub Actions: CI
tests/commands/afk.test.js

[error] 1-1: assist/source/organizeImports: Imports are not sorted. Safe fix suggested by Biome.

src/modules/afkHandler.js

[error] 9-9: assist/source/organizeImports: Imports are not sorted. Safe fix suggested by Biome.

tests/modules/afkHandler.test.js

[error] 1-1: assist/source/organizeImports: Imports are not sorted. Organize Imports (Biome) suggested fix.

src/modules/events.js

[error] 6-6: assist/source/organizeImports: Imports are not sorted. Safe fix suggested by Biome.

🔇 Additional comments (5)
src/api/utils/configAllowlist.js (1)

21-21: AFK key allowlist update looks correct.

Line 21 correctly includes 'afk' in SAFE_CONFIG_KEYS, which unblocks safe config reads/writes for this feature.

config.json (1)

169-170: Please verify config docs were updated for afk.enabled.

Lines 169-170 introduce a new top-level config section; I can’t confirm from the provided files whether README.md config reference was updated accordingly.

As per coding guidelines: "Document new config sections and keys in README.md's config reference when updating config.json".

src/modules/events.js (1)

107-116: Good fault isolation around AFK processing.

Lines 107-116 correctly keep AFK failures from interrupting the rest of the MessageCreate pipeline while preserving contextual logging.

tests/commands/afk.test.js (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Test file import ordering is blocking CI.

Line 1 import grouping/order needs Biome organize-imports cleanup to satisfy the pipeline.

⛔ Skipped due to learnings
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to tests/**/*.{js,ts,jsx,tsx} : Use Vitest for testing; run `pnpm test` before every commit and `pnpm test:coverage` to verify 80% coverage threshold
tests/modules/afkHandler.test.js (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Test file import ordering fails current lint step.

Line 1 import block should be reorganized via Biome organize-imports.

⛔ Skipped due to learnings
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Use 2-space indentation (enforced by Biome)
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-26T22:59:10.394Z
Learning: Applies to tests/**/*.{js,ts,jsx,tsx} : Use Vitest for testing; run `pnpm test` before every commit and `pnpm test:coverage` to verify 80% coverage threshold

- fix(afkHandler): evict stale entries from afkNoticeRateLimit Map to
  prevent unbounded memory growth (critical: memory leak)
- fix(config): add 'afk' to permissions.allowedCommands so the command
  is accessible to all members by default (warning)
- docs(AGENTS): add afk.js and afkHandler.js to Key Files table; add
  afk_status and afk_pings to Database Tables (warning: docs)
- docs(README): add AFK System to Features list (warning: docs)
- style: biome formatting (import ordering, code style)
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues remaining after feedback commit

🟡 Ping tracking suppressed by rate limiting (src/modules/afkHandler.js:157-173) — The continue on rate-limit skips the afk_pings INSERT, silently dropping pings from the welcome-back summary. Move the INSERT before the rate-limit check so pings are always recorded.

🟡 Non-atomic deletes (src/commands/afk.js:78-86, src/modules/afkHandler.js:98-106) — Two separate DELETEs without a transaction risk orphaned afk_pings rows on partial failure.

🔵 SELECT * when fewer columns needed (src/commands/afk.js:58, src/modules/afkHandler.js:84,148) — Use SELECT 1 for existence checks and select only reason, set_at where those are the only columns used.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 27, 2026
- afkHandler: replace O(n) eviction loop with setTimeout TTL for rate limit map
- afkHandler: move afk_pings INSERT above rate-limit check so pings always tracked
- afkHandler: use message.mentions.members (GuildMember.displayName) instead of .users
- afk clear: wrap DELETE queries in transaction for atomicity
- update tests to match new members API and transaction flow
Copilot AI review requested due to automatic review settings February 27, 2026 15:36
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 27, 2026
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 remaining issue + 3 nitpicks after feedback commits

🟡 Non-atomic deletes in afkHandler.js auto-clear (src/modules/afkHandler.js:92-100) — The transaction fix was applied to afk.js:handleClear but the auto-clear path in the handler still uses two separate pool.query calls without a transaction. If the second DELETE fails, afk_pings rows are orphaned.

🔵 SELECT * usage (src/commands/afk.js:57, src/modules/afkHandler.js:77,141) — Three queries fetch all columns when only existence checks or specific fields are needed.

🔴 CI failing — Branch coverage is 79.47%, below the 80% threshold. This may be pre-existing from main, but should be verified.


Everything else from previous rounds has been addressed: memory leak fix, atomic deletes in afk.js, ping tracking before rate limit, displayName fix using message.mentions.members, import ordering, permission allowlist, and documentation updates all look good.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All critical and warning issues from previous review rounds have been addressed. The 3 remaining SELECT * nitpicks are non-blocking. CI branch coverage (79.47%) is pre-existing — the AFK code itself has excellent coverage (100% and 95.83% branch). LGTM.

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.

AFK system — auto-respond when mentioned while away

2 participants