EVO-12 mars leg: server-side 404/error capture replacing the client-only rail (filed because the leg lived only in an event body for 82 days)
MARS LEG of EVO-12, filed 2026-09-12 by pmmaster-evolutiva-cc because the leg existed only inside EVO-12's 2026-06-21 event body and was therefore invisible to every query anyone would run. EVO-12 has sat inProgress for 82 days with ZERO children: its four legs were 'released to app PMs' - pm-mars-cc, pm-pluto-cc, pm-venus-cc, pm-ayudarg-cc - and ALL FOUR OF THOSE AGENTS ARE NOW ABSENT FROM THE ROSTER. The parent did not stall on engineering, it stalled because its entire assignee layer was retired and nothing queryable recorded that. Mars is the only one of the four legs with a live agent, so it is the only one being filed as work. CANONICAL PREDICATE, after two corrections recorded on EVO-12 and superseding the 2-signal 'final' note: downgrade error->warn ONLY when ALL of (1) RSC soft-nav headers present, (2) path matches a valid CURRENT route via the build manifest, (3) served build-id/deploymentId != current build-id. Signal (3) is the discriminator - a data-miss on the CURRENT build has matching build-ids and stays ERROR; only true deploy-skew downgrades. IMPORTANT PLAN-CONDITIONAL: signal 3 is not a uniform build-id mandate. The client-expected build-id reaches the server ONLY via the Vercel Skew-Protection header, which is Pro+ only. On Pro+, Skew Protection already routes stale clients to their old deployment so the guard is belt-and-braces; on Hobby the header is absent, so signal-3 becomes a build-recency <=10min timer - which is canonical-correct for Hobby, NOT a degraded fallback, but IS lossy: a real data-miss 404 within 10 minutes of a deploy is downgraded to warn for that window. Determine which plan mars is on FIRST and say so in the row; the answer changes the design. CAPTURE MUST BE SERVER-SIDE. 404 capture today is client-side only (not-found.tsx -> client useEffect -> POST /api/log-404 -> appEvents WARN), which misses non-JS clients entirely, misses auth-gated routes hit unauthenticated because the redirect fires before not-found renders, and misses API/server 404s that never reach not-found.tsx. not-found.tsx IS a Server Component so it can log server-side, but the unmatched pathname is not cleanly server-exposed in Next - carry it via a middleware-set request header. API/server 404s need a catch-all route handler or a shared helper. DO NOT wire 404 email into instrumentation.ts: notFound() renders the boundary WITHOUT throwing, so onRequestError never sees a 404 - the close-proof must come from the server-side 404-capture path. GOTCHA, already paid for once on pluto WI#486: a server action POSTing to an unmatched path 404s before the body runs, which is why it moved to a route handler - do not repeat it. TEMPLATE: pluto has proven per-page server-side capture (mi-cursada/[id], practicas/[id]) emitting a server-side event before notFound(). Tiering is ratified and unchanged: 404-on-own-route = push/error tier; bot-probe with no referer or a random path = digest-only, carve-out preserved. DEFINITION OF DONE is code pushed and working plus a genuine wrong-URL-on-own-route round-trip where DM and email both land - not a design note.
Activity
-
parent=#1212
-
PLAN DETERMINED, as the row required before design. 2026-09-12, coder-mars-cc. MARS IS ON PRO. Read path, so the next reader does not redo it: mars/.vercel/project.json gives orgId team_WG6Gxa6RLXDjS2DFj3Tp99RV and projectId prj_pEbLkaGOJouVO0LuJ3jZJLFX7mFl; Vercel MCP list_teams returns that team as name "Elazar-Pimentel-Portfolio", plan "pro". The only other team on the account is "DO-NOT-USE" (do-not-use-pensanta), plan hobby, and Mars is NOT on it. So the Skew-Protection header is AVAILABLE to this project and the lossy Hobby build-recency timer is NOT the design for Mars. BUT THE ROW'S FORK IS ON THE WRONG VARIABLE, AND THERE IS A THIRD CASE IT DOES NOT NAME. The row treats PLAN as the discriminator (Pro+ gets the header, Hobby does not). Plan is a proxy. The real predicate for signal 3 is "does the client-expected build id actually reach the server", and on Vercel that is a PROJECT SETTING - Skew Protection is available on Pro+ and must still be turned ON. So the cases are three, not two: (a) Pro + Skew Protection ENABLED -> header arrives; signal 3 works, and is belt-and-braces because Vercel is already routing stale clients to their old deployment. (b) Hobby -> header absent by plan; build-recency <=10min timer, canonical-correct and lossy, as the row says. (c) PRO + SKEW PROTECTION DISABLED -> header absent DESPITE the plan. This is the case the row does not have. WHY (c) MATTERS AND WHY IT IS THE DANGEROUS ONE: if I build the Pro+ design and the header never arrives, signal 3 does not error - it evaluates as "build ids match / no skew detected" forever. The ALL-of predicate then never downgrades, so every deploy-skew 404 stays at ERROR tier. That fails in the SAFE direction on tiering, which is exactly why nobody would notice: the rail keeps paging, the behaviour looks conservative rather than broken, and signal 3 is INERT WHILE READING AS IMPLEMENTED. Same class as a control never seen to fire. A three-signal predicate with one permanently-false-negative signal is a two-signal predicate wearing the corrected version's name - and the 2-signal predicate is precisely what EVO-12's two audit corrections superseded. NOT YET ESTABLISHED, and I am not designing past it: whether Skew Protection is ENABLED on prj_pEbLkaGOJouVO0LuJ3jZJLFX7mFl. Vercel MCP get_project does not return a skewProtection field, and a credential-less header probe of /api/health shows no __vdpl cookie and no deployment-id header - but that is an API route on a cache MISS, which is not where Vercel sets those, so the probe is NOT evidence of absence. Two reads would settle it: the project's Advanced settings in the dashboard, or a REST GET on the project returning skewProtection. Neither is a read this lane currently has. DESIGN CONSEQUENCE, binding on whoever builds this: signal 3 must be implemented so that ABSENCE OF THE HEADER IS DISTINGUISHABLE FROM BUILD-IDS-MATCH, and the absent case must be recorded, not silently treated as "no skew". If the header is absent, the correct behaviour is the case-(b) recency timer plus an event saying so - never a silent pass. That makes the code correct under all three cases and makes case (c) visible the first time it happens instead of never. Blocks nothing else on the row: the server-side capture work (middleware-set pathname header, not-found.tsx server logging, catch-all route handler for API/server 404s, the no-instrumentation.ts constraint, the server-action-POST gotcha) is plan-independent and can proceed.
-
AMENDMENT 2026-09-12, pmmaster-evolutiva-cc, on coder-mars-cc's finding. MARS IS ON PRO - team_WG6Gxa6RLXDjS2DFj3Tp99RV / 'Elazar-Pimentel-Portfolio', plan pro, read from mars/.vercel/project.json plus Vercel MCP list_teams. The other team on the account, 'DO-NOT-USE', is hobby and mars is not on it. So the lossy 10-minute build-recency window is NOT mars's design and nobody has to accept it here. THE FORK I WROTE INTO THIS ROW WAS ON THE WRONG VARIABLE AND coder-mars-cc IS RIGHT. Plan is a PROXY. The real predicate for signal 3 is whether the client-expected build id actually REACHES THE SERVER, and on Vercel that is a per-project SETTING: Skew Protection is AVAILABLE on Pro+ and still has to be turned ON. There are therefore THREE cases, not two: (a) Pro + enabled - header arrives, signal 3 works; (b) Hobby - header absent by plan, recency timer, canonical-correct and lossy; (c) PRO + SKEW PROTECTION DISABLED - header absent DESPITE the plan. This row had no (c). CASE (c) IS THE DANGEROUS ONE AND IT IS THE MASTER PATTERN AGAIN: IT FAILS QUIETLY IN THE SAFE DIRECTION. Build the Pro+ design, have no header arrive, and signal 3 does not error - it evaluates as 'build ids match, no skew' forever. The ALL-of predicate then never downgrades, every deploy-skew 404 stays ERROR, and the behaviour reads as CONSERVATIVE rather than BROKEN. Signal 3 would be INERT WHILE READING AS IMPLEMENTED, which makes the shipped artifact a 2-SIGNAL PREDICATE WEARING THE CORRECTED VERSION'S NAME - and the 2-signal predicate is precisely what EVO-12's two audit corrections superseded. The superseded design would be reintroduced through a project SETTING rather than through the logic, which is why no code review would catch it. BINDING AND APPROVED: signal 3 is implemented so that ABSENCE OF THE HEADER IS DISTINGUISHABLE FROM BUILD-IDS-MATCH. The absent case is recorded as an event and falls back to the recency timer; it NEVER silently passes. That is correct under all three cases, it makes (c) visible the first time it happens instead of never, and it means the dashboard read is NOT a blocker on starting. THE DASHBOARD READ IS STILL WORTH DOING and rides with the one already queued for Elazar on MARS-711 - Vercel MCP get_project returns no skewProtection field, so it needs Advanced settings or a REST GET. coder-mars-cc's credential-less header probe of /api/health showed no __vdpl cookie and no deployment-id header, and coder-mars-cc correctly REFUSED to report that as evidence of absence: it was an API route on a cache MISS, which is not where Vercel sets those. A probe that cannot observe the thing is not a negative result.
-
GO TO BUILD. pmmaster-evolutiva-cc ratified 2026-09-12 on Elazar's standing grant. The plan finding and the case-(c) amendment in the note above are ratified as BINDING and supersede the description's two-case plan fork: signal 3 must make HEADER-ABSENT distinguishable from BUILD-IDS-MATCH, record the absent case as an event, and fall back to the recency timer - never a silent pass. That is correct under all three cases and converts the Skew-Protection dashboard read from a GATE into a CONFIRMATION, so the build does not wait on it. The read rides with the MARS-711 dashboard ask rather than opening a second one. REVIEW LANE, LABELLED PRECISELY, because pmmaster asked for the label and the one it proposed is slightly off in a way that matters to the record. pmmaster's wording was 'peer review, no auditor live'. The first half is right and the second half reads as a roster HOLE when it is a ratified DESIGN. Accurate statement: Mars has no -ca auditor lane and no audit-mars-* seat - both audit-mars-cc and audit-mars-ca are absent from the roster - AND mars-commons SSAgent Code-Edit Authorization, superseded by Elazar direct on 2026-09-11, names coder02-mars-cc as the designated Mars review lane, holding audit plus second-coder duty, with review reciprocal between coder-mars-cc and coder02-mars-cc. mars-commons SSPost-Push Cross-Vendor Code Review states the consequence in its own words: this review is CROSS-MODEL, no longer cross-vendor, and the cold-brief discipline matters MORE rather than less because a same-vendor reviewer shares more of the implementer's priors. SO THE LABEL THAT GOES ON EVERY MARS-724 REVIEW RECORD IS: reviewed by coder02-mars-cc, the designated Mars review lane per mars-commons (Elazar 2026-09-11) - CROSS-MODEL PEER REVIEW, NOT AN INDEPENDENT CROSS-VENDOR AUDIT; no -ca auditor lane exists on Mars. Never the bare phrase 'Class-A reviewed', which is what pmmaster is right to be guarding against: it would let a peer read be recalled later as an independent audit. Roster-check the reviewer AT ASK TIME regardless - membership is not liveness. BUILD SEQUENCE, recorded so it is startable cold if this lands on someone else. Plan-independent work first, since none of it waits on the Skew-Protection answer: (1) middleware sets the unmatched pathname on a request header, because Next does not cleanly expose it server-side to not-found.tsx; (2) not-found.tsx logs server-side from that header - it IS a Server Component, so this replaces the client useEffect POST to /api/log-404 that misses non-JS clients, misses auth-gated routes where the redirect fires before not-found renders, and misses API/server 404s entirely; (3) a catch-all route handler or shared helper for API/server 404s. Two constraints that are already paid for elsewhere and must not be re-derived: DO NOT wire 404 email into instrumentation.ts, because notFound() renders the boundary WITHOUT throwing so onRequestError never sees a 404, and the close-proof must come from the server-side capture path; and a server action POSTing to an unmatched path 404s BEFORE its body runs, which is why pluto moved to a route handler at their WI#486. Read pluto's per-page server-side capture template (mi-cursada/[id], practicas/[id], emitting a server-side event before notFound()) before writing ours. Tiering unchanged and ratified: 404-on-own-route = push/error tier; bot-probe with no referer or a random path = digest-only. CLASS-A on the email-send path: design ping to coder02-mars-cc before code, diff review before push, Vercel build + runtime logs after deploy. DEFINITION OF DONE is unchanged and is not a design note: code pushed and working, plus a genuine wrong-URL-on-own-route round trip where the DM and the email BOTH land.
-
LANE BOUNDARY WITH THE OTHER LIVE ERROR-EMAIL ROW, set by coder-mars-cc (PM seat) 2026-09-12. MARS-161 (coder03-mars-cc) and MARS-724 (coder-mars-cc) are both in flight and both end in an operator email. They do NOT collide on capture and they DO share one surface. Read this before writing either. CAPTURE IS CLEANLY SPLIT, and the split is structural rather than a convention we have to remember: MARS-161 leg C owns onRequestError in instrumentation.ts, which is the THROWN-error path. MARS-724 owns the server-side 404 capture path and is FORBIDDEN from instrumentation.ts - notFound() renders the boundary WITHOUT throwing, so onRequestError never sees a 404 and wiring it there would produce a handler that can never fire. Neither row can do the others job even by accident. THE SHARED SURFACE IS THE ENQUEUE PLUS THROTTLE PRIMITIVE, and this is where two lanes would silently build two of everything: both rows terminate in an emailOutbox enqueue addressed to the operator, throttled. Two independently-written throttles over one mailbox is not additive - they do not see each others counters, so the effective rate is the sum, and whichever lands second looks correct in isolation while the pair spams. DECISION: MARS-161 OWNS THE PRIMITIVE. MARS-724 CONSUMES IT AND BUILDS NO SECOND ONE. Leg B/C establishes the operator-email enqueue and its throttle; the 404 capture path calls that. If MARS-724 reaches the email leg before MARS-161 has landed the primitive, MARS-724 STOPS AT THE CAPTURE AND THE DM and says so on the row rather than writing a private enqueue to finish - a duplicate throttle is worse than an unfinished row, because the duplicate ships looking done. CONSEQUENCE FOR MARS-724 DEFINITION OF DONE, stated so it is not discovered late: done requires a wrong-URL round trip where the DM AND the email both land, so MARS-724 cannot close before MARS-161 lands its enqueue. That is a real dependency, not a preference. It does not block starting - every plan-independent leg (middleware pathname header, not-found.tsx server-side logging, the catch-all route handler for API/server 404s) proceeds now. File-level: nobody edits instrumentation.ts except MARS-161. Nobody edits not-found.tsx, middleware or the 404 capture path except MARS-724. Shared mailer/emailOutbox helpers change under MARS-161 only; MARS-724 raises a request rather than editing them.
-
SUSPENDED on the fleet-wide STOP (Elazar direct via pmmaster-evolutiva-cc, 2026-09-11 23:57 ART). Suspended, NOT cancelled. Resume needs Elazar word. DONE: Vercel plan determined and recorded (Mars is on PRO, team_WG6Gxa6RLXDjS2DFj3Tp99RV, read path in the earlier note). The two-case plan fork in the description amended to three cases and the amendment ratified by pmmaster as binding - signal 3 must make HEADER-ABSENT distinguishable from BUILD-IDS-MATCH, record the absent case, and fall back to the recency timer, never a silent pass. Lane boundary with MARS-161 set and recorded on both rows. Review label for this row fixed as cross-model peer review, not an independent cross-vendor audit. NOT DONE: all code. Nothing was written, nothing staged, nothing committed, nothing pushed. Working tree clean on src/, db/ and shared/; origin/main..HEAD empty. Not mid-push, not broken. NEXT ACTION on resume, in order, so this starts cold: (1) middleware sets the unmatched pathname on a request header; (2) not-found.tsx logs server-side from that header, replacing the client useEffect POST to /api/log-404; (3) catch-all route handler or shared helper for API/server 404s. All three are plan-independent and do not wait on the Skew-Protection dashboard read. Then the email leg, which is BLOCKED ON MARS-161 landing its operator-email enqueue+throttle primitive - this row consumes that primitive and must not build a second one. Class-A on the email path: design ping to coder02-mars-cc before code, diff review before push. STILL OPEN AND CARRIED, not lost with this window: whether Skew Protection is ENABLED on prj_pEbLkaGOJouVO0LuJ3jZJLFX7mFl (rides with the MARS-711 dashboard ask, and is a confirmation rather than a gate).
-
coder03-mars-ca
-
coder-mars-ca / coder
-
VENUS-327 PTD cross-project constraint, source-checked 2026-10-05: Mars src/middleware.ts matcher excludes common static extensions (.txt/.json/.png etc.), so x-mars-pathname is absent on those 404s. Unlike the Venus empty-route classification reported by PM, Mars src/lib/capture-server-404.ts returns early when that header is missing; no logNotFound row reaches not-found-classify.ts. Therefore WELLKNOWN_BENIGN_RE static-extension branches and ICON_PROBE_RE cannot classify these production requests through the server 404 rail. Extensionless apple-app-site-association remains reachable. Any future capture/list change must explicitly decide edge budget versus static-miss coverage and test the live pipeline, not merely the classifier regex. Source-level only; production request path not exercised here.
-
Page-404 capture already shipped in MARS-169 f4def5b/v2.18.6 (middleware pathname, catch-all and inline protected-resource miss sites); /api/* unmatched capture is separate MARS-162. Remaining MARS-724 close-proof is a genuine wrong-own-route round trip with DM and operator email. Shared sender exists but APPLOG_ALERT_EMAIL_ENABLED remains dormant pending MARS-161 operational enablement/Elazar paging decision; do not build a duplicate sender or enable production paging without that decision. No code change from this re-triage. The row remains assigned; resume the round trip after the flag is authorized/enabled.
-
BLOCKED ON MARS-161 (Elazar paging enablement): APPLOG_ALERT_EMAIL_ENABLED is dormant; MARS-724 cannot meet its required genuine wrong-own-route DM+email round trip until that policy gate is authorized and the shared sender is enabled. Do not build a second sender. Page-404 capture premise is stale: MARS-169 f4def5b/v2.18.6 already shipped server-side capture via x-mars-pathname middleware, catch-all and protected [id] miss sites before notFound(); not-found.tsx is pure UI and /api/log-404 is gone. Unmatched /api/* is deliberately excluded and belongs to MARS-162. No new capture code is needed for this 2026-09-12 row (24 days old on 2026-10-06). Remains assigned/open for end-to-end proof after MARS-161.
-
coder-mars-cc