Skip to content

Add pending-action timeout handling, update env docs, and expand smoke/unit tests - #97

Merged
gamblecodezcom merged 3 commits into
mainfrom
codex/perform-full-audit-and-implementation-for-runewager-bot
Feb 26, 2026
Merged

Add pending-action timeout handling, update env docs, and expand smoke/unit tests#97
gamblecodezcom merged 3 commits into
mainfrom
codex/perform-full-audit-and-implementation-for-runewager-bot

Conversation

@gamblecodezcom

@gamblecodezcom gamblecodezcom commented Feb 26, 2026

Copy link
Copy Markdown
Owner

User description

Motivation

  • Ensure pending user input states time out and recover cleanly after 15 minutes to avoid stuck workflows.
  • Document runtime environment keys required by 2.0 features and add missing .env.example entries used by core flows.
  • Improve test coverage by validating callback handler coverage, critical command families, pending-action escapes, and environment documentation.

Description

  • Introduce evaluatePendingActionTimeout(user, now) in index.js and use it in the text message handler to centralize pending-action timeout logic and clear expired states.
  • Keep the 15-minute timeout behavior (PENDING_ACTION_TIMEOUT_MS) and reply users with a Main Menu when their pending step expires.
  • Add corresponding helper implementation to the unit test file and new unit tests that validate seeding createdAt, expiration behavior, and fallback type labels.
  • Update .env.example with TELEGRAM_CHANNEL_LINK, TELEGRAM_GROUP_LINK, HTTPS_KEY_PATH, HTTPS_CERT_PATH, and BOT_PRIVACY_MODE entries.
  • Update CLAUDE.md with a Runewager 2.0 agent contract and update RUNEWAGER_FUNCTIONALITY_MAP.md to document pending-action timeout enforcement and smoke-test expectations.
  • Extend test/smoke.test.js with tests that assert the presence of a catch-all callback fallback, critical 2.0 command families are registered and wired, pending-action escape routes exist, and that .env.example documents core runtime vars used by the codebase.

Testing

  • Ran unit tests (npm test / node test runner) including new evaluatePendingActionTimeout unit tests, and all unit tests passed.
  • Ran smoke tests (test/smoke.test.js) which include callback coverage, registered command parity, critical command families, pending-action escape checks, and .env.example documentation checks, and they passed.
  • No automated tests failed after these changes.

Codex Task


CodeAnt-AI Description

Add automatic pending-action timeouts and stronger smoke tests; document required env keys

What Changed

  • Pending user input states now record a creation time, automatically expire after 15 minutes, clear the pending state, and prompt the user with a Main Menu recovery panel when expired.
  • Text input handler now uses centralized timeout evaluation so expired pending steps trigger a clear message and recovery buttons instead of leaving workflows stuck.
  • Added unit tests that validate seeding of pending timestamps, expiration behavior, and fallback type labels; expanded smoke tests to:
    • require REGISTERED_COMMANDS parity with command handlers (except start),
    • ignore catch-all callback fallbacks for coverage matching,
    • assert presence of critical 2.0 command families,
    • verify pending-action escape routes (/cancel, /menu, /start, /help),
    • check that .env.example documents core runtime environment keys.
  • .env.example updated with TELEGRAM_CHANNEL_LINK, TELEGRAM_GROUP_LINK, HTTPS_KEY_PATH, HTTPS_CERT_PATH, and BOT_PRIVACY_MODE entries; documentation updated to reflect enforced pending-action timeout behavior.

Impact

✅ Fewer stuck workflows due to expired pending steps
✅ Clearer recovery for users when input times out
✅ .env.example documents runtime keys used by core flows

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features

    • Pending actions now timeout after 15 minutes with Main Menu recovery panel
    • Added slash-command escape routes (/cancel, /menu, /start, /help) to safely exit pending states
    • New environment configuration variables for Telegram links and HTTPS settings
  • Chores

    • Enhanced test coverage for command validation and configuration verification

@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@gamblecodezcom has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 6 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 90cbcd0 and fb8c503.

📒 Files selected for processing (6)
  • .env.example
  • CLAUDE.md
  • RUNEWAGER_FUNCTIONALITY_MAP.md
  • index.js
  • test/smoke.test.js
  • test/unit.test.js
📝 Walkthrough

Walkthrough

Configuration and test infrastructure updates add environment variables to .env.example, establish map-first governance in CLAUDE.md, document pending-action timeout behavior in the functionality map, centralize timeout logic via new evaluatePendingActionTimeout helper in index.js, and introduce comprehensive smoke and unit tests for coverage validation.

Changes

Cohort / File(s) Summary
Configuration & Governance
.env.example, CLAUDE.md, RUNEWAGER_FUNCTIONALITY_MAP.md
Added environment variables (TELEGRAM_CHANNEL_LINK, TELEGRAM_GROUP_LINK, HTTPS_KEY_PATH, HTTPS_CERT_PATH, BOT_PRIVACY_MODE); established map-first contract in CLAUDE.md; documented pending-action timeout (15-min expiry, createdAt tracking, recovery panel) and smoke-test parity checks for commands and .env documentation in functionality map.
Core Timeout Logic
index.js
Introduced evaluatePendingActionTimeout(user, now) helper function to centralize pending-action timeout evaluation, replacing inline logic in text event handler. Encapsulates createdAt initialization, expiry detection, state clearing, and expiredType derivation.
Test Coverage
test/smoke.test.js, test/unit.test.js
Added smoke tests for catch-all callback fallback detection, critical 2.0 command families parity, pending-action escape routes (/cancel, /menu, /start, /help), and .env.example key documentation. Added unit tests verifying createdAt seeding, 15-minute expiry and state clearing, and fallback expiredType behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

size:L

Poem

🐰 Behold! The timeout logic hops anew,
Pending states now clear when fifteen minutes flew,
With smoke tests and maps, the map-first way,
Escape routes shine bright—/cancel saves the day!
Configuration spreads its leafy .env tree. 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the three main changes: pending-action timeout handling, environment documentation updates, and expanded test coverage.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 codex/perform-full-audit-and-implementation-for-runewager-bot

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.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Feb 26, 2026
@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Side-effect
    The new helper mutates the incoming user object: it writes createdAt when missing and sets user.pendingAction = null when expired. This behavior can be surprising to callers and tests rely on it; verify production call sites expect the mutation and that state persistence follows the same convention.

  • Robustness
    The code converts createdAt with Number(user.pendingAction.createdAt || 0). If createdAt is an invalid string or non-numeric value this may produce NaN and lead to unexpected behavior. Consider validating/coercing createdAt to a safe integer before arithmetic.

  • Boundary Semantics
    The expiration test uses an inclusive comparison (<=) for the 15-minute window. Confirm whether the intended semantics are that exactly 15 minutes is still valid (non-expired) or should be treated as expired, and make that explicit in code/tests for consistency.

  • Fragile catch-all detection
    The test that asserts a catch-all bot.action handler relies on a simple string/regex match (/bot.action(\s*/.*//). This will miss other catch-all forms (e.g. /^.*$/ or /.+/ with flags) and will be brittle if whitespace/flags change. Consider a robust parser-based detection or broaden the pattern matching to avoid false negatives or missed catch-all handlers.

  • Command handler detection gap
    The assertion that checks each critical command's handler only looks for direct uses with single- or double-quoted literals (bot.command('x' / bot.command("x"). Commands declared with backticks (template literals without interpolation) or with variable-driven wrappers may be missed, causing false failures. Consider normalizing search or using a regex that matches any quote type or parse string literals.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
test/unit.test.js (2)

177-192: Add docstring for evaluatePendingActionTimeout.

Other helper functions in this file have docstrings. Per coding guidelines, every function must have a complete docstring describing purpose, parameters, and return value.

Proposed docstring
+/**
+ * evaluatePendingActionTimeout — Checks if a user's pendingAction has expired.
+ *
+ * Seeds createdAt on first check if missing. Clears pendingAction and returns
+ * expiredType if the action is older than 15 minutes.
+ *
+ * `@param` {Object} user - User object with optional pendingAction property.
+ * `@param` {number} [now=Date.now()] - Current timestamp for testing.
+ * `@returns` {{ hadPending: boolean, expired: boolean, expiredType: string|null }}
+ */
 function evaluatePendingActionTimeout(user, now = Date.now()) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit.test.js` around lines 177 - 192, Add a full docstring above the
evaluatePendingActionTimeout function that concisely describes its purpose
(checks whether a user's pendingAction exists and whether it has timed out),
lists parameters (user object and optional now timestamp in ms, defaulting to
Date.now()), and explains the return shape ({ hadPending: boolean, expired:
boolean, expiredType: string|null}) plus behavior (sets createdAt if missing,
clears user.pendingAction when expired and derives expiredType from
pendingAction.type or 'current action'). Include param and return descriptions
consistent with other helper docstrings in the file.

359-366: Consider adding a boundary test for exactly 15 minutes.

The current tests check expiration at 15 minutes + 1ms. Adding a test at exactly 15 minutes would confirm the <= boundary behavior (should NOT expire).

Proposed boundary test
+test('pending action does not expire at exactly 15 minutes', () => {
+  const now = 1700000900000;
+  const user = { pendingAction: { type: 'await_tip_add_text', createdAt: now - (15 * 60 * 1000) } };
+  const out = evaluatePendingActionTimeout(user, now);
+  assert.equal(out.expired, false);
+  assert.equal(out.hadPending, true);
+  assert.ok(user.pendingAction !== null, 'pendingAction should still exist');
+});
+
 test('pending action timeout expires after 15 minutes and clears state', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit.test.js` around lines 359 - 366, Add a boundary unit test that
verifies a pending action exactly 15 minutes old does not expire: call
evaluatePendingActionTimeout with now and a user whose pendingAction.createdAt
equals now - (15 * 60 * 1000) and assert that returned expired is false,
expiredType is undefined (or unchanged), and user.pendingAction remains intact;
reference evaluatePendingActionTimeout, pendingAction, and expiredType to locate
where to add this test.
.env.example (1)

28-33: Consider alphabetizing and documenting BOT_PRIVACY_MODE values.

The new environment variables break alphabetical ordering (flagged by dotenv-linter). Also, BOT_PRIVACY_MODE lacks documentation of valid values—consider adding a comment similar to LOG_LEVEL.

Proposed reordering and documentation
-
-TELEGRAM_CHANNEL_LINK=https://t.me/runewager
-TELEGRAM_GROUP_LINK=https://t.me/runewagerchat
-HTTPS_KEY_PATH=
-HTTPS_CERT_PATH=
-BOT_PRIVACY_MODE=private
+
+# BOT_PRIVACY_MODE valid values: private, group (default: private)
+BOT_PRIVACY_MODE=private
+HTTPS_CERT_PATH=
+HTTPS_KEY_PATH=
+TELEGRAM_CHANNEL_LINK=https://t.me/runewager
+TELEGRAM_GROUP_LINK=https://t.me/runewagerchat
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example around lines 28 - 33, Reorder the block of env entries so
variables are alphabetized and add a comment explaining valid values for
BOT_PRIVACY_MODE; specifically, move TELEGRAM_CHANNEL_LINK and
TELEGRAM_GROUP_LINK (and HTTPS_CERT_PATH / HTTPS_KEY_PATH) into alphabetical
order and add a one-line comment above BOT_PRIVACY_MODE (e.g.,
"BOT_PRIVACY_MODE=private|public — controls whether the bot responds only to
direct messages or all group messages") following the style of the existing
LOG_LEVEL comment; update the .env.example entry BOT_PRIVACY_MODE to include the
documented allowed values.
test/smoke.test.js (2)

7-25: Docstrings are boilerplate and don't describe actual function behavior.

The docstrings for helper functions (collectJsFiles, walk, extractLiteralIds, etc.) use generic template text about "Runewager logic" and "menu/command or utility flow composition," which doesn't apply to these static-analysis utilities. As per coding guidelines, docstrings should describe purpose, parameters, and return values.

For example, collectJsFiles recursively collects .js files from a directory while skipping certain folders—this isn't captured by the current docstring.

📝 Example: More accurate docstring for collectJsFiles
 /**
- * collectJsFiles executes its scoped Runewager logic and participates in menu/command or utility flow composition.
- *
- * Parameters: See the function signature for exact argument names and accepted values.
- *
- * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers.
- *
- * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression.
- *
- * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable.
- *
- * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions.
- *
- * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid.
- *
- * System fit: This function is part of the Runewager command/callback/state orchestration pipeline.
+ * Recursively collects all .js files from a directory tree.
+ *
+ * `@param` {string} rootDir - The root directory to start scanning from.
+ * `@returns` {string[]} Array of absolute paths to .js files found.
+ *
+ * Skips: .git, node_modules, data, logs, test directories and symbolic links.
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/smoke.test.js` around lines 7 - 25, The current docstrings are
placeholder boilerplate and must be replaced with concise, accurate descriptions
for each helper: update collectJsFiles to state it recursively collects .js
files from a given directory while skipping node_modules/.git/.cache (or other
ignored folders), list its parameters (rootDir: string, options?:
{ignorePatterns?: string[]}), and describe the returned array of file paths
(string[] or Promise<string[]>); similarly update walk to describe its traversal
algorithm, input parameters and whether it yields or returns entries, and update
extractLiteralIds to explain it parses AST nodes to extract literal id strings
and its return type; ensure each docstring mentions side effects (none) and
error behavior (throws on invalid path), and attach accurate types/return
information and examples where helpful for collectJsFiles, walk, and
extractLiteralIds so readers understand purpose, inputs, outputs, and edge
cases.

415-430: Consider adding BOT_PRIVACY_MODE to the core vars list.

The PR objectives indicate BOT_PRIVACY_MODE was added to .env.example. If it's used in index.js via process.env.BOT_PRIVACY_MODE, consider adding it to the core array for completeness. If it's optional or used differently, the current list is acceptable.

Additionally, the check at line 428 only catches direct process.env.VAR access patterns. If any core variables are accessed via destructuring (e.g., const { VAR } = process.env), they would be missed. This is likely fine for smoke testing purposes but worth noting.

💡 Optional: Add BOT_PRIVACY_MODE if applicable
     'PROMO_ENTRY_IMAGE_URL', 'DISCORD_VERIFY_IMAGE_URL', 'DISCORD_CODE_GENERATION_IMAGE_URL', 'INTRO_GIF_URL',
-    'HTTPS_KEY_PATH', 'HTTPS_CERT_PATH', 'WEBAPP_HMAC_KEY', 'TIPS_GROUP',
+    'HTTPS_KEY_PATH', 'HTTPS_CERT_PATH', 'WEBAPP_HMAC_KEY', 'TIPS_GROUP', 'BOT_PRIVACY_MODE',
   ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/smoke.test.js` around lines 415 - 430, The test's core runtime-vars list
in the test function (the core array used to build missingDoc via
source.includes(`process.env.${k}`)) omits BOT_PRIVACY_MODE; if index.js
references process.env.BOT_PRIVACY_MODE, add 'BOT_PRIVACY_MODE' into the core
array so the smoke test verifies it's documented in .env.example (refer to the
core variable array and the missingDoc calculation that filters by
source.includes(`process.env.${k}`)); no other behavior changes required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@index.js`:
- Around line 402-404: Replace the raw internal pending-action key with a
user-facing label before returning: create or use a small mapping (e.g.
ACTION_LABELS) that maps internal keys like "await_tip_add_text" to readable
strings, then set expiredType = ACTION_LABELS[user.pendingAction.type] ||
'current action' (or similar default) instead of directly using
user.pendingAction.type; keep clearing user.pendingAction as-is and return the
hadPending/expired flags with the mapped expiredType.

---

Nitpick comments:
In @.env.example:
- Around line 28-33: Reorder the block of env entries so variables are
alphabetized and add a comment explaining valid values for BOT_PRIVACY_MODE;
specifically, move TELEGRAM_CHANNEL_LINK and TELEGRAM_GROUP_LINK (and
HTTPS_CERT_PATH / HTTPS_KEY_PATH) into alphabetical order and add a one-line
comment above BOT_PRIVACY_MODE (e.g., "BOT_PRIVACY_MODE=private|public —
controls whether the bot responds only to direct messages or all group
messages") following the style of the existing LOG_LEVEL comment; update the
.env.example entry BOT_PRIVACY_MODE to include the documented allowed values.

In `@test/smoke.test.js`:
- Around line 7-25: The current docstrings are placeholder boilerplate and must
be replaced with concise, accurate descriptions for each helper: update
collectJsFiles to state it recursively collects .js files from a given directory
while skipping node_modules/.git/.cache (or other ignored folders), list its
parameters (rootDir: string, options?: {ignorePatterns?: string[]}), and
describe the returned array of file paths (string[] or Promise<string[]>);
similarly update walk to describe its traversal algorithm, input parameters and
whether it yields or returns entries, and update extractLiteralIds to explain it
parses AST nodes to extract literal id strings and its return type; ensure each
docstring mentions side effects (none) and error behavior (throws on invalid
path), and attach accurate types/return information and examples where helpful
for collectJsFiles, walk, and extractLiteralIds so readers understand purpose,
inputs, outputs, and edge cases.
- Around line 415-430: The test's core runtime-vars list in the test function
(the core array used to build missingDoc via
source.includes(`process.env.${k}`)) omits BOT_PRIVACY_MODE; if index.js
references process.env.BOT_PRIVACY_MODE, add 'BOT_PRIVACY_MODE' into the core
array so the smoke test verifies it's documented in .env.example (refer to the
core variable array and the missingDoc calculation that filters by
source.includes(`process.env.${k}`)); no other behavior changes required.

In `@test/unit.test.js`:
- Around line 177-192: Add a full docstring above the
evaluatePendingActionTimeout function that concisely describes its purpose
(checks whether a user's pendingAction exists and whether it has timed out),
lists parameters (user object and optional now timestamp in ms, defaulting to
Date.now()), and explains the return shape ({ hadPending: boolean, expired:
boolean, expiredType: string|null}) plus behavior (sets createdAt if missing,
clears user.pendingAction when expired and derives expiredType from
pendingAction.type or 'current action'). Include param and return descriptions
consistent with other helper docstrings in the file.
- Around line 359-366: Add a boundary unit test that verifies a pending action
exactly 15 minutes old does not expire: call evaluatePendingActionTimeout with
now and a user whose pendingAction.createdAt equals now - (15 * 60 * 1000) and
assert that returned expired is false, expiredType is undefined (or unchanged),
and user.pendingAction remains intact; reference evaluatePendingActionTimeout,
pendingAction, and expiredType to locate where to add this test.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47d668e and 90cbcd0.

📒 Files selected for processing (6)
  • .env.example
  • CLAUDE.md
  • RUNEWAGER_FUNCTIONALITY_MAP.md
  • index.js
  • test/smoke.test.js
  • test/unit.test.js

Comment thread index.js Outdated
@codeant-ai

codeant-ai Bot commented Feb 26, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

…ndary tests, env cleanup, catch-all detection, command handler detection, full map/doc sync
@gamblecodezcom
gamblecodezcom merged commit f1e8f65 into main Feb 26, 2026
1 check passed
@gamblecodezcom
gamblecodezcom deleted the codex/perform-full-audit-and-implementation-for-runewager-bot branch February 26, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant