| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
Sorry, something went wrong.
PR Summary by QodoFix Pad.check context so err.stack includes pad/revision details 🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes AI Description
|
Sorry, something went wrong.
Code Review by Qodo🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (1) 📜 Skill insights (0) 1. Cleanup assumes contiguous revisions 📎 Requirement gap ☼ Reliability Description Code Evidence Agent prompt 2. Stack context can duplicate 🐞 Bug ◔ Observability Description Code Evidence Agent prompt Context Tip of the day 💡 Did you know, you can turn on the rule miner and Qodo learns your standards from review history |
Sorry, something went wrong.
| } catch (err:any) { | ||
| err.message = `(pad ${this.id} revision ${r}) ${err.message}`; | ||
| throw err; | ||
| throw addErrorContext(err, `(pad ${this.id} revision ${r})`); | ||
| } |
There was a problem hiding this comment.
1. Cleanup assumes contiguous revisions 📎 Requirement gap ☼ Reliability
deleteRevisions() computes a contiguous revision range to load and delete, but it does not tolerate missing revision numbers, so gaps can cause it to throw and abort rather than reliably retaining the requested keepRevisions. Because it also calls pad.check() and propagates its assertion failures when revision metadata is missing, the cleanup cannot complete in a controlled manner as required.Agent Prompt
## Issue description Cleanup revision deletion/retention is not gap-tolerant: `deleteRevisions()` iterates over a computed contiguous revision range and can throw when a revision record is missing, and the admin cleanup flow also calls `pad.check()` which asserts on missing timestamps, causing the cleanup operation to abort. Update the cleanup logic so it can complete in a controlled manner and still enforce (or clearly define) `keepRevisions` even when intermediate revision entries are missing. ## Issue Context Compliance requirements (PR Compliance IDs 1 and 2) state that cleanup must not abort due to missing `pad:<id>:revs:<n>` records and must support retaining `X` revisions despite discontinuities in revision numbering. The current behavior fails these requirements because gaps lead to thrown errors during `pad.getRevision(rev)` iteration and/or assertion failures from `pad.check()`. ## Fix Focus Areas - src/node/utils/Cleanup.ts[43-69] - src/node/utils/Cleanup.ts[52-69] - src/node/utils/Cleanup.ts[65-68] - src/node/db/Pad.ts[998-1000] - src/node/db/Pad.ts[1004-1012] - src/tests/backend/specs/padCheckErrorContext.ts[83-92]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Sorry, something went wrong.
| if (oldMessage && typeof err.stack === 'string' && err.stack.includes(oldMessage)) { | ||
| err.stack = err.stack.replace(oldMessage, err.message); | ||
| } |
There was a problem hiding this comment.
2. Stack context can duplicate 🐞 Bug ◔ Observability
addErrorContext() always replaces oldMessage inside err.stack even if err.stack is generated after err.message is updated (lazy stack formatting), which can cause the context prefix to be duplicated in the stack header. This risks corrupting/duplicating the most important diagnostic line for errors thrown during pad.check() (including DB read failures).Agent Prompt
### Issue description
`addErrorContext()` sets `err.message` and then conditionally does `err.stack.replace(oldMessage, err.message)` based on `err.stack.includes(oldMessage)`. If `err.stack` is lazily rendered (common), the first access inside `addErrorContext()` can already include the *new* prefixed message, which still contains `oldMessage` as a substring, so the replace duplicates the prefix.
### Issue Context
This helper is used in `Pad.check()` to add pad/revision/chat context to errors coming from multiple sources (assertions and DB reads). We want to update the stack header **only when the stack still reflects the old message**.
### Fix Focus Areas
- src/node/db/Pad.ts[54-72]
Suggested approach:
- After updating `err.message`, only run the `replace(oldMessage, err.message)` when the stack does **not** already contain the new message, for example:
- `if (oldMessage && typeof err.stack === 'string' && err.stack.includes(oldMessage) && !err.stack.includes(err.message)) { ... }`
- (Optional) Consider capturing the current `err.stack` into a local before modifying `err.stack` to avoid multiple getter evaluations.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Sorry, something went wrong.
pad.check() prefixes failures with `(pad <id> revision <n>)` so admins know which record is bad, but it only assigned to `err.message`. `err.stack` is rendered from the message when the error is constructed, so the stack kept showing the original, context-free text. Both places that report a failed check log `err.stack` -- Cleanup .checkTodos and the admin `cleanupPadRevisions` handler -- so the revision number never reached the log. The reporter on #8134 had to bisect their database by hand to find the missing revision: [ERROR] adminSettings - Error in pad eu-<id>: AssertionError: The expression evaluated to a falsy value: assert(timestamp != null) at Pad.check (src/node/db/Pad.ts:969:9) Fix it at the source with an addErrorContext() helper so every reporter of a check() failure benefits, including plugins that log err.stack. Refs #8134 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| Back | FazBrowse Home | New Git URL |
Problem
pad.check() carefully prefixes failures with (pad <id> revision <n>) so an admin knows which record is bad — but it only assigns to err.message. err.stack is rendered from the message when the error is constructed, so the stack keeps showing the original, context-free text.
Both places that report a failed check log err.stack:
…so the revision number never reaches the log. The reporter on #8134 had to bisect their database by hand to work out which revision was missing:
[ERROR] adminSettings - Error in pad eu-<id>: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: assert(timestamp != null) at Pad.check (/opt/etherpad-lite/src/node/db/Pad.ts:969:9) at async deleteRevisions (/opt/etherpad-lite/src/node/utils/Cleanup.ts:48:3)Nothing there says revision 600, even though check() knew.
Fix
Fix it at the source rather than at each log site: an addErrorContext() helper that prefixes the message and rewrites the matching text in err.stack. All three context-adding sites in Pad.check() (revision load, revision replay, chat message) now go through it, so every reporter of a check() failure benefits — including plugins that log err.stack themselves.
The helper replaces only the first occurrence (the stack's header line) and no-ops on an empty message, which would otherwise match at offset 0 and corrupt the stack.
Tests
src/tests/backend/specs/padCheckErrorContext.ts builds a pad in exactly the shape from #8134 — head pointing past a revision whose pad:<id>:revs:<n> record is absent — and asserts the context reaches err.stack, isn't duplicated, and that the original assertion text and stack frames survive. Also covers the chat-message path and the deleteRevisions() entry point from the issue report.
Verified red→green: 4 of the 7 fail without the Pad.ts change, all 7 pass with it. Full backend suite: 1628 passing, 0 failing.
Scope
Diagnostics only — this does not repair pads with a missing revision, and does not address how the hole forms. Both are tracked separately off #8134.
Refs #8134
🤖 Generated with Claude Code