Conversation
- 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)
|
Claude finished @BillChirico's task in 4m 40s —— View job Review complete — PR #108 AFK System
Verdict: Approved with 3 minor nitpicks. All critical and warning issues from previous review rounds have been fixed across commits
3 remaining 🔵 nitpicks (inline comments posted):
CI note: Branch coverage is 79.47% (threshold: 80%). The AFK code itself has excellent coverage (100% branch in AI fix prompt for remaining nitpicks |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughIntroduces 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
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Review Summary — 4 issues found
🔴 Critical (1)
- Memory leak in rate limit Map (
src/modules/afkHandler.js:19-22) —afkNoticeRateLimitentries are never evicted. Add periodic cleanup viasetIntervalwith.unref().
🟡 Warning (3)
- Missing
afkpermission (config.json:169-171) —afknot inpermissions.allowedCommandsmeans it defaults to admin-only persrc/utils/permissions.js:96-99. Add"afk": "everyone". - 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 orphanedafk_pingsrows. - 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)
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:
-
src/modules/afkHandler.js— Add a cleanup interval forafkNoticeRateLimit. After line 22, add asetIntervalthat runs every 10 minutes, iterates over the Map, and deletes entries whereDate.now() - timestamp >= RATE_LIMIT_MS. Call.unref()on the timer. Export astopCleanupTimer()for tests. -
config.json— Inpermissions.allowedCommands, add"afk": "everyone"(after the"tldr"entry). -
src/commands/afk.js:79-86— Wrap the two DELETE queries in a transaction usingconst client = await pool.connect(); try { await client.query('BEGIN'); ... await client.query('COMMIT'); } catch { await client.query('ROLLBACK'); throw err; } finally { client.release(); }. -
src/modules/afkHandler.js:89-96— Same transaction wrapping as above for the two DELETEs in the auto-clear path. -
src/commands/afk.js:58— ChangeSELECT *toSELECT 1. -
src/modules/afkHandler.js:73— ChangeSELECT *toSELECT 1. -
src/modules/afkHandler.js:137— ChangeSELECT *toSELECT reason, set_at. -
AGENTS.md— Add to Key Files table:src/commands/afk.js | AFK slash command — /afk set and /afk clear subcommandsandsrc/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+userandafk_pings | Pings received while AFK — tracked for summary on return. -
README.md— Add to Features section:- **💤 AFK System** — Set AFK status with /afk set. Mentioned while away? Get a ping summary when you return.
|
| 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)
Last reviewed commit: 1c64126
There was a problem hiding this comment.
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_statusandafk_pingstables with appropriate indexes for tracking AFK users and mentions - Command interface: Adds
/afk set [reason]and/afk clearsubcommands 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.
There was a problem hiding this comment.
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 | 🟡 MinorImport 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
config.jsonmigrations/006_afk.cjssrc/api/utils/configAllowlist.jssrc/commands/afk.jssrc/modules/afkHandler.jssrc/modules/events.jstests/commands/afk.test.jstests/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 withimport/exportsyntax; never userequire()
Always usenode: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.jssrc/api/utils/configAllowlist.jssrc/modules/afkHandler.jstests/modules/afkHandler.test.jssrc/commands/afk.jssrc/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; runpnpm testbefore every commit andpnpm test:coverageto verify 80% coverage threshold
Files:
tests/commands/afk.test.jstests/modules/afkHandler.test.js
src/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{js,ts,jsx,tsx}: Always use Winston for logging viaimport { info, warn, error } from '../logger.js'; never useconsole.log,console.warn,console.error, or anyconsole.*method in src/ files
Pass structured metadata to Winston logging calls (e.g.,info('Message processed', { userId, channelId }))
Use custom error classes fromsrc/utils/errors.jsfor error handling
Always log errors with context before re-throwing
UsegetConfig(guildId?)fromsrc/modules/config.jsto read configuration values
UsesetConfigValue(path, value, guildId?)fromsrc/modules/config.jsto update configuration at runtime
UsesafeSend()utility for all outgoing Discord messages to enforce allowedMentions and prevent mention spam
UsesanitizeMentions()to strip@everyone/@here from outgoing text via zero-width space insertion before sending
UsesplitMessage()utility to handle Discord's 2000-character message limit
onConfigChangecallbacks receive(newValue, oldValue, fullPath, guildId)as parameters
Files:
src/api/utils/configAllowlist.jssrc/modules/afkHandler.jssrc/commands/afk.jssrc/modules/events.js
src/modules/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Check
config.yourModule.enabledbefore processing in module handlers
Files:
src/modules/afkHandler.jssrc/modules/events.js
src/commands/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/commands/**/*.{js,ts,jsx,tsx}: Slash commands must export adataproperty with a SlashCommandBuilder and an asyncexecute(interaction)function
ExportadminOnly = truefor moderator-only slash commands
Duration-based commands (timeout, tempban, slowmode) must useparseDuration()fromsrc/utils/duration.jsfor parsing duration arguments
Always callcheckHierarchy(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.jsviaclient.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 updatingconfig.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.jssrc/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.jssrc/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'inSAFE_CONFIG_KEYS, which unblocks safe config reads/writes for this feature.config.json (1)
169-170: Please verify config docs were updated forafk.enabled.Lines 169-170 introduce a new top-level config section; I can’t confirm from the provided files whether
README.mdconfig reference was updated accordingly.As per coding guidelines: "Document new config sections and keys in
README.md's config reference when updatingconfig.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 | 🟡 MinorTest 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 thresholdtests/modules/afkHandler.test.js (1)
1-1:⚠️ Potential issue | 🟡 MinorTest 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)
There was a problem hiding this comment.
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.
- 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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Summary
Implements the AFK system requested in #46.
What's included
migrations/006_afk.cjs: Createsafk_statusandafk_pingstables with appropriate indexes.src/commands/afk.js:/afk set [reason]and/afk clearsubcommands, both ephemeral, gated onafk.enabled.src/modules/afkHandler.js: Called on every guild message:src/modules/events.js(before rate-limit/link-filter block)afk.enabled: falseadded toconfig.json;afkadded toSAFE_CONFIG_KEYSTests
23 new tests across
tests/commands/afk.test.jsandtests/modules/afkHandler.test.js:All 1734 existing tests continue to pass.
Closes #46