* fix: stop generating empty CLAUDE.md files - Return empty string instead of "No recent activity" when no observations exist - Skip writing CLAUDE.md files when formatted content is empty - Remove redundant "auto-generated by claude-mem" HTML comment - Clean up 98 existing empty CLAUDE.md files across the codebase - Update tests to expect empty string for empty input Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * build assets * refactor: implement in-process worker architecture for hooks Replaces spawn-based worker startup with in-process architecture: - Hook processes now become the worker when port 37777 is free - Eliminates Windows spawn issues (NO SPAWN rule) - SessionStart chains: smart-install && stop && context Key changes: - worker-service.ts: hook case starts WorkerService in-process - hook-command.ts: skipExit option prevents process.exit() when hosting worker - hooks.json: single chained command replaces separate start/hook commands - worker-utils.ts: ensureWorkerRunning() returns boolean, doesn't block - handlers: graceful fallback when worker unavailable All 761 tests pass. Manual verification confirms hook stays alive as worker. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * context * a * MAESTRO: Mark PR #722 test verification task complete All 797 tests passed (3 skipped, 0 failed) after merge conflict resolution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * MAESTRO: Mark PR #722 build verification task complete * MAESTRO: Mark PR #722 code review task complete Code review verified: - worker-service.ts hook case starts WorkerService in-process - hook-command.ts has skipExit option - hooks.json uses single chained command - worker-utils.ts ensureWorkerRunning() returns boolean Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * MAESTRO: Mark PR #722 conflict resolution push task complete Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
4.0 KiB
Error Handling Anti-Pattern Rules
This folder contains detect-error-handling-antipatterns.ts - run it before committing any error handling changes.
The Try-Catch Problem That Cost 10 Hours
A single overly-broad try-catch block wasted 10 hours of debugging time by silently swallowing errors. This pattern is BANNED.
BEFORE You Write Any Try-Catch
RUN THIS TEST FIRST:
bun run scripts/anti-pattern-test/detect-error-handling-antipatterns.ts
You MUST answer these 5 questions to the user BEFORE writing try-catch:
- What SPECIFIC error am I catching? (Name the error type:
FileNotFoundError,NetworkTimeout,ValidationError) - Show documentation proving this error can occur (Link to docs or show me the source code)
- Why can't this error be prevented? (If it can be prevented, prevent it instead)
- What will the catch block DO? (Must include logging + either rethrow OR explicit fallback)
- Why shouldn't this error propagate? (Justify swallowing it rather than letting caller handle)
If you cannot answer ALL 5 questions with specifics, DO NOT write the try-catch.
FORBIDDEN PATTERNS (Zero Tolerance)
CRITICAL - Never Allowed
// FORBIDDEN: Empty catch
try {
doSomething();
} catch {}
// FORBIDDEN: Catch without logging
try {
doSomething();
} catch (error) {
return null; // Silent failure!
}
// FORBIDDEN: Large try blocks (>10 lines)
try {
// 50 lines of code
// Multiple operations
// Different failure modes
} catch (error) {
logger.error('Something failed'); // Which thing?!
}
// FORBIDDEN: Promise empty catch
promise.catch(() => {}); // Error disappears into void
// FORBIDDEN: Try-catch to fix TypeScript errors
try {
// @ts-ignore
const value = response.propertyThatDoesntExist;
} catch {}
ALLOWED Patterns
// GOOD: Specific, logged, explicit handling
try {
await fetch(url);
} catch (error) {
if (error instanceof NetworkError) {
logger.warn('SYNC', 'Network request failed, will retry', { url }, error);
return null; // Explicit: null means "fetch failed"
}
throw error; // Unexpected errors propagate
}
// GOOD: Minimal scope, clear recovery
try {
JSON.parse(data);
} catch (error) {
logger.error('CONFIG', 'Corrupt settings file, using defaults', {}, error);
return DEFAULT_SETTINGS;
}
// GOOD: Fire-and-forget with logging
backgroundTask()
.catch(error => logger.warn('BACKGROUND', 'Task failed', {}, error));
// GOOD: Ignored anti-pattern for genuine hot paths only
try {
checkIfProcessAlive(pid);
} catch (error) {
// [ANTI-PATTERN IGNORED]: Tight loop checking 100s of PIDs during cleanup
return false;
}
Ignoring Anti-Patterns (Rare)
Only for genuine hot paths where logging would cause performance problems:
// [ANTI-PATTERN IGNORED]: Reason why logging is impossible
Rules:
- Hot paths only - code in tight loops called 1000s of times
- If you can add logging, ADD LOGGING - don't ignore
- Valid examples:
- "Tight loop checking process exit status during cleanup"
- "Health check polling every 100ms"
- Invalid examples:
- "Expected JSON parse failures" - Just add logger.debug
- "Common fallback path" - Just add logger.debug
The Meta-Rule
UNCERTAINTY TRIGGERS RESEARCH, NOT TRY-CATCH
When you're unsure if a property exists or a method signature is correct:
- READ the source code or documentation
- VERIFY with the Read tool
- USE TypeScript types to catch errors at compile time
- WRITE code you KNOW is correct
Never use try-catch to paper over uncertainty. That wastes hours of debugging time later.
Critical Path Protection
These files are NEVER allowed to have catch-and-continue:
SDKAgent.ts- Errors must propagate, not hideGeminiAgent.ts- Must fail loud, not silentOpenRouterAgent.ts- Must fail loud, not silentSessionStore.ts- Database errors must propagateworker-service.ts- Core service errors must be visible
On critical paths, prefer NO TRY-CATCH and let errors propagate naturally.