fix: graceful error handling for /undo (issue #17)#19
Conversation
Replace raw console.error in all hooks with a configurable Logger that respects config.logLevel (default: warn). Hook errors are classified as warn (operational) or debug (cosmetic), so at default settings most noise disappears after /undo. - Add Logger utility (src/utils/logger.ts) with debug/info/warn/error - Add PendingMessageRepository.deleteBySessionId() for future undo cleanup - Wire logger through all 5 hooks and PlatformIngestionRuntime - Update all affected tests Closes clopca#17
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds a Logger utility and threads Logger instances through plugin, worker, runtime, hooks, and session lifecycle; replaces console.* with logger.warn/debug; introduces observations.message_id, ObservationRepository.softDeleteByMessageId, and pending message deletion APIs with accompanying tests and migration. ChangesLogger Implementation and Hook Integration
Message ID and /undo Cleanup
🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add 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 |
Greptile SummaryThis PR introduces a configurable
Confidence Score: 3/5Safe to merge for the noise-reduction goal, but the optional-logger pattern in compaction and context-inject creates a silent error-swallowing path that differs from every other hook in this PR. The compaction and context-inject hooks now silently swallow all errors when no logger is provided, which is a regression from the original always-visible console.error behavior. Every other hook in this PR makes logger required, making this inconsistency appear unintentional. src/hooks/compaction.ts and src/hooks/context-inject.ts — the optional logger parameter should be aligned with the required pattern used in every other hook in this PR. Important Files Changed
|
| debug(message: string, ...args: unknown[]): void { | ||
| if (this.shouldLog("debug")) { | ||
| console.error(`[open-mem] ${message}`, ...args); | ||
| } | ||
| } | ||
|
|
||
| info(message: string, ...args: unknown[]): void { | ||
| if (this.shouldLog("info")) { | ||
| console.error(`[open-mem] ${message}`, ...args); | ||
| } | ||
| } | ||
|
|
||
| warn(message: string, ...args: unknown[]): void { | ||
| if (this.shouldLog("warn")) { | ||
| console.error(`[open-mem] ${message}`, ...args); | ||
| } | ||
| } | ||
|
|
||
| error(message: string, ...args: unknown[]): void { | ||
| if (this.shouldLog("error")) { | ||
| console.error(`[open-mem] ${message}`, ...args); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
All levels route to
console.error (stderr)
debug, info, warn, and error all call console.error, so every log message — regardless of level — is written to stderr. The JSDoc acknowledges this as intentional, but it means a log aggregator or monitoring tool that distinguishes fd2 from fd1 will classify every logger.debug(...) call as an error-level event. Using console.warn for the warn level and console.debug/console.log for lower levels would be more semantically correct.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/utils/logger.ts
Line: 40-63
Comment:
**All levels route to `console.error` (stderr)**
`debug`, `info`, `warn`, and `error` all call `console.error`, so every log message — regardless of level — is written to stderr. The JSDoc acknowledges this as intentional, but it means a log aggregator or monitoring tool that distinguishes fd2 from fd1 will classify every `logger.debug(...)` call as an error-level event. Using `console.warn` for the `warn` level and `console.debug`/`console.log` for lower levels would be more semantically correct.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed in 2bf1552 — Logger now routes debug/info to console.log (stdout), warn to console.warn, error to console.error. Tests updated to verify correct console method routing.
| deleteBySessionId(sessionId: string): number { | ||
| const result = this.db.all<{ id: string }>( | ||
| `DELETE FROM pending_messages | ||
| WHERE session_id = ? | ||
| AND status IN ('pending', 'failed') | ||
| RETURNING id`, | ||
| [sessionId], | ||
| ); | ||
| return result.length; | ||
| } |
There was a problem hiding this comment.
deleteBySessionId is unused and untested
The method is described as "for future undo cleanup integration" but is not called anywhere in this PR, and no tests were added for it. Adding a test that verifies the method deletes only pending/failed rows and leaves processing/completed rows untouched would prevent an undetected regression if the row status values change.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/db/pending.ts
Line: 125-134
Comment:
**`deleteBySessionId` is unused and untested**
The method is described as "for future undo cleanup integration" but is not called anywhere in this PR, and no tests were added for it. Adding a test that verifies the method deletes only `pending`/`failed` rows and leaves `processing`/`completed` rows untouched would prevent an undetected regression if the row status values change.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed — deleteBySessionId is now wired into all session lifecycle handlers (session.created, session.idle, session.completed/session.ended). Tests (3 test cases) already added in previous commit covering: status filtering (pending+failed removed, processing+completed retained), empty session handling (returns 0), and cross-session isolation.
- Logger: debug/info → console.log (stdout), warn → console.warn, error → console.error - Tests: pass Logger to all hook call sites (was made required) - Tests: capture console.log/warn/error for Logger verification - Fix extra bracket in crud.test.ts
Address review feedback — deleteBySessionId is now called in: - session.created: cleanup stale pending/failed from previous session lifecycle - session.idle: cleanup orphaned messages (covers /undo scenario) - session.completed/ended: final cleanup after processing Also updated session-events test mock to include deleteBySessionId.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/db/schema.ts (1)
35-40: ⚡ Quick winMigration array ordering: version 2 appears before version 1.
While the database migration framework (line 448 of
src/db/database.ts) explicitly sorts migrations by version before execution, the current array ordering in the MIGRATIONS constant harms readability. Consider reordering migrations sequentially by version to match execution order and improve maintainability.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/db/schema.ts` around lines 35 - 40, The MIGRATIONS array currently lists the entry with version: 2 before the one with version: 1 which hurts readability; reorder the objects in the MIGRATIONS constant so migrations are listed sequentially (place the version: 1 migration before the version: 2 migration) to match execution order, leaving the migration SQL strings and index creation (message_id column / idx_observations_message_id) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/db/schema.ts`:
- Around line 35-40: The MIGRATIONS array currently lists the entry with
version: 2 before the one with version: 1 which hurts readability; reorder the
objects in the MIGRATIONS constant so migrations are listed sequentially (place
the version: 1 migration before the version: 2 migration) to match execution
order, leaving the migration SQL strings and index creation (message_id column /
idx_observations_message_id) unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d9a69fbb-12ff-4bf5-ad12-43b21fb02086
📒 Files selected for processing (6)
src/db/observations.tssrc/db/pending.tssrc/db/schema.tssrc/hooks/chat-capture.tssrc/types.tstests/db/schema.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/db/pending.ts
ab933c7 to
85d2b39
Compare
- Add message_id column to observations table (migration v2) - Store messageID from chat.message hook in observations - Add ObservationRepository.softDeleteByMessageId() for undo handling - Handle message.removed events in createEventHandler to soft-delete observations tied to the removed message - Remove deleteBySessionId from session.idle (message.removed is more precise, avoids aggressive pending message cleanup) - Update schema idempotency test for 2 migrations - Add 8 tests for message.removed handling (repository + event handler)
Summary
Loggerutility that respectsconfig.logLevel(default:warn)console.error("[open-mem] ...")calls in hooks with level-gated logger methodswarn(operational) ordebug(cosmetic) — at default settings, most noise after/undodisappearsPendingMessageRepository.deleteBySessionId()for future undo cleanup integrationProblem
After
/undoin OpenCode, error logs appear from open-mem because hooks have no undo awareness and use rawconsole.errorfor all errors. The existingconfig.logLevelfield was defined but never enforced.Changes
src/utils/logger.tssrc/db/pending.tsdeleteBySessionId()for orphan cleanupsrc/hooks/tool-capture.tsconsole.error→logger.warnsrc/hooks/chat-capture.tsconsole.error→logger.warnsrc/hooks/session-events.tsconsole.error→logger.warn/logger.debugsrc/hooks/context-inject.tsconsole.error→logger.warnsrc/hooks/compaction.tsconsole.error→logger.warnsrc/index.tssrc/adapters/platform/runtime.tssrc/platform-worker.tsVerification
tsc --noEmitcleanbun run buildcleanCloses #17
Summary by CodeRabbit
New Features
Chores
Tests