PLUTO-54 ·
plutoBlind logging: capture detail in practicaCreateFailed, user-context in serverError, email in loginDeniedNoProfile
- Ref
PLUTO-54(#926)- Project
pluto- Status
- done
- Priority
- normal
- Type
- bug
- Assigned
- —
- Created by
- wi-cli-venus
- Created
- 2026-06-12T05:50:21.432Z
- Updated
- 2026-06-12T06:27:22.576Z
- Closed
- 2026-06-12T06:27:22.576Z
Questions
No questions.
Event log
-
From appEvents gaps (db analysis). (1) practicaCreateFailed: 9 failures (1 user, 2026-06-03/04) logged with EMPTY detail+route — blind failure; capture the actual error in the create handler. (2) serverError: 75 events with NO actorUserId — 500 handler fires without session context; attempt to read user session. (3) loginDeniedNoProfile: 202 events log no attempted email/domain — can't identify blocked users; log the email. Also verify the import-telemetry-as-error bug (88 success breadcrumbs thrown as Error, v0.7.13 Mar-18) is gone in current version.
-
ADD #5 (from PLUTO-55 root-cause): error-card.tsx logClientError records the digest ONLY — drops errorName/errorMessage/errorStack. Its paired serverError (instrumentation.ts) DOES capture errorMessage, so the CLIENT side is where diagnosis is lost (this is why the /practicas/nueva 2026-04-06 burst is un-diagnosable, errorMessage=NULL). Fix: capture errorName/Message/Stack in logClientError too. Pairs with #2 (serverError user-context).
-
SCOPE NARROWED (coder code-verified — db's appEvents gaps mostly didn't hold). #1 practicaCreateFailed: NOT blind, logCaughtError already stores errorName/Message/Stack; captured msg was PLUTO-9 (empty-DOB), fixed 06-07, zero since. #3 loginDeniedNoProfile: NOT blind, all 207 events log email+provider (db's '202 log nothing' is wrong). #4 import-as-error: already fixed (PLUTO-3), zero since 03-18. #5 error-card logClientError: REAL gap but PROD-CONSTRAINED — Next.js redacts client error.message/stack in prod (only digest exposed, by design); the digest already pairs to the serverError row which HAS full message+stack. Infeasible as framed -> reframed to a convenience join VIEW = PLUTO-59 backlog. NET: implement ONLY #2 (serverError anonymous 500s: decode sb-auth cookie JWT best-effort for sub+email into detail, no DB hit, logging-grade). Close 54 after #2 ships.
-
Audit pre-push correction (audit-pluto-cc-mqajejyhlxpe): #2 uses supabase.auth.getClaims(), which VERIFIES the JWT signature locally against JWKS (Pluto is on the asymmetric publishable key). Earlier framing 'no signature verify, treat as unverified' was wrong. A forged/tampered cookie fails verification, so a spoofed identity is never attributed at all (no actor logged) - criterion 3 holds MORE strongly than 'wrong log line'. Non-blocking: getClaims fetches JWKS over network on first call per process, cached after, so a cold lambda 500 does one extra round-trip inside the wrapped best-effort handler - fine for logging-grade. Audit PASSED diff; coder cleared to push.
-
Shipped #2: serverError de-anonymization. instrumentation.ts onRequestError now best-effort decodes the sb-auth cookie via supabase.auth.getClaims() (verifies JWT sig against asymmetric JWKS; forged cookie -> no actor attributed) to enrich appEvents serverError rows with actorUserId/actorAuthId/actorEmail. SHA 2154bd7 / v1.67.26. Audit PASS:2154bd7 - deploy READY, live version+deploymentId matched, zero runtime errors in 20min window. Enrichment observable on the next real 500. Scope: #1/#3/#4 closed already-done this session; #5 (clientError.digest<->serverError.detail convenience view) split to PLUTO-59.