basquetWi + New ticket
mars MARS-577

route.ts: /api/log-error outer catch swallows its own failures, no appEvents row

Backlog normal cmcoder03-mars-cc

route.ts outer catch (~470-487) returns {ok:false} on any failure and writes no appEvents row — no logEvent call, no alert. The app's own client-error reporter silently discards the client's error report when the endpoint itself fails. Violates evolutiva-commons §No Silent Failures. Fix: wrap outer catch to still emit an appEvents error-tier row (best-effort, must not throw) before returning ok:false.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 2026-07-30
  • wi-cli-venus assigned · 7w ago
    coder-mars-ca / coder
  • wi-cli-venus assigned · 6w ago
    coder-mars-cc / coder
  • wi-cli-venus assigned · 5w ago
    coder03-mars-cc / coder
  • wi-cli-venus note · 5w ago
    DISPATCHED to coder03-mars-cc 2026-09-11 by coder-mars-cc (PM seat), with cold-start context because coder03 runs the /clear-between-items worker pattern (Elazar GO via pmmaster, Mars is the pilot). LINE NUMBERS IN THE DESCRIPTION ARE STALE. The description says ~470-487; the outer catch is now at src/app/api/log-error/route.ts:513-530 (file is 531 lines). Verified by reading it today. The description is otherwise accurate. THE DEFECT, confirmed by reading: the outer catch sets lookupError from the thrown error and returns a LogErrorResponse with ok:false, serverMatchStatus:'lookup-failed'. There is NO logEvent call anywhere in that catch. So when Mars's own client-error reporter fails, the client's error report is discarded and NOTHING records that it happened - no appEvents row, no alert, no rail page. That is precisely evolutiva-commons SS-No Silent Failures: 'a catch that neither logs appEvents nor rethrows is banned'. THE FIX: emit an error-tier appEvents row from inside that catch BEFORE returning ok:false. Constraints that matter, in order of how easy they are to get wrong: 1. IT MUST NOT THROW. The whole point is that this path already failed; a logEvent that rejects would turn a handled failure into an unhandled 500. Use the best-effort shape the codebase already uses: await logEvent({...}).catch(() => {}). Reference implementation two files over: src/app/api/image/[id]/route.ts:15-24 safeLogImageEvent, which wraps logEvent in try/catch with an nsf-allow comment explaining why a telemetry failure must never break the product path. 2. THE PUSH GATE'S no-silent-failure LINT WILL FLAG THE EMPTY .catch ARM unless it carries an comment stating why swallowing is correct there. Copy the shape from the same reference - the comment is the artifact, not a formality. 3. Do NOT change the response body shape. LogErrorResponse is a satisfies-typed contract consumed by the client reporter; adding or renaming a field is a separate change with its own blast radius. 4. Keep the existing lookupError assignment - it is read by the response. ACCEPTANCE: force the catch to fire (temporarily throw inside the try) and confirm an error-tier appEvents row lands with the route and the error name, then revert. A control that has not been seen to fail is a green line, not a control - do not close this on 'the code looks right'. SCOPE: one file. Do not touch src/lib/self-check-*.ts or src/app/api/internal/self-check/ - coder02-mars-cc holds those for MARS-720 and two lanes on one file is banned. Depth: run scripts/review-depth.sh on the pushed SHA and follow its DEPTH line; cold-brief the other push-lane agent per the review protocol. Push under the flock per mars-commons; --only this one file plus whatever the version bump needs.
  • wi-cli-venus note · 5w ago
    DISPATCHED to coder03-mars-cc 2026-09-11 by coder-mars-cc (PM seat), with cold-start context because coder03 runs the /clear-between-items worker pattern (Elazar GO via pmmaster; Mars is the fleet pilot). This note is written to be sufficient from an EMPTY window - if it is not, that is my defect, say so. LINE NUMBERS IN THE DESCRIPTION ARE STALE. The description says ~470-487; the outer catch is now at src/app/api/log-error/route.ts:513-530 (file is 531 lines). Verified by reading it today. The description is otherwise accurate. THE DEFECT, confirmed by reading rather than inherited: the outer catch sets lookupError from the thrown error and returns a LogErrorResponse with ok:false and serverMatchStatus "lookup-failed". There is NO logEvent call anywhere in that catch. So when Mars's own client-error reporter fails, the client's error report is discarded and NOTHING records that it happened - no appEvents row, no alert, no rail page. That is exactly what evolutiva-commons bans: a catch that neither logs appEvents nor rethrows. THE FIX: emit an error-tier appEvents row from inside that catch BEFORE returning ok:false. Constraints, ordered by how easy each is to get wrong: 1. IT MUST NOT THROW. The point is that this path has ALREADY failed; a logEvent that rejects would convert a handled failure into an unhandled 500 - strictly worse than the bug. Use the best-effort shape the codebase already uses: await logEvent({...}).catch(() => {}). Reference implementation two files over: src/app/api/image/[id]/route.ts:15-24, safeLogImageEvent, which wraps logEvent in try/catch and carries an nsf-allow comment explaining why a telemetry failure must never break the product path. 2. THE PUSH GATE'S no-silent-failure LINT WILL FLAG AN EMPTY CATCH ARM unless it carries an nsf-allow comment saying why swallowing is correct there. Copy the shape from the same reference. The comment is the artifact, not a formality. 3. DO NOT CHANGE THE RESPONSE BODY SHAPE. LogErrorResponse is a satisfies-typed contract consumed by the client reporter; adding or renaming a field is a separate change with its own blast radius. 4. KEEP the existing lookupError assignment - the response reads it. ACCEPTANCE, and this is not optional: force the catch to fire (temporarily throw inside the try), confirm an error-tier appEvents row lands carrying the route and the error name, then revert. A control that has not been seen to fail is a green line, not a control. Do not close this on "the code looks right". SCOPE: one file. Do NOT touch src/lib/self-check-registry.ts, src/lib/self-check-probes.ts, src/lib/self-check-registry.test.ts or src/app/api/internal/self-check/route.ts - coder02-mars-cc holds those for MARS-720, and two lanes on one file is banned. PUSH: scripts/review-depth.sh on the pushed SHA decides review depth - take it from the DEPTH line, never call the tier by eye. Cold-brief the other push-lane agent per the review protocol. Push under the flock per mars-commons, --only this one file. Then close this row yourself with the SHA and version, and /clear before you pick up the next item.
  • wi-cli-venus note · 4w ago
    Fleet-wide STOP (Elazar direct, relayed pmmaster 2026-09-11 23:56). Not done, not started - was queued behind MARS-161. Next action on resume: /api/log-error outer catch route.ts:513-530, ref src/app/api/image/[id]/route.ts:15-24 for best-effort logging shape, acceptance = force the catch and see the appEvents row land.
task
2026-07-30 by wi-cli-venus
5w ago