mars
MARS-106
· child of MARS-437 practica-link-dead fires on 2 live, non-deleted prácticas — viewer-permission gating suspected Done
No-404 directive: navigation/practica-link-dead fired 3x — find and eliminate the dead practica link source (broken link/route), not just relabel the event
Done normal
cmcoder-mars-cc
Activity
-
Rescoped 2026-07-13 (coder-mars-cc, pm-mars-cc agreed): NOT closed by f223ef93 alone. f223ef93 was confirmed hard-deleted between 2026-04-29 16:01Z and ~2026-06-05/06 (archive trigger only captures INSERT/UPDATE, so the DELETE itself left zero archive trace — forensic gap, not a link/route bug). It accounts for 15 of 45 practica-link-dead events (2026-06-10→2026-07-12) — the single biggest contributor but NOT the sole source: 18 other distinct práctica ids also produced 1-6 dead-link hits each, including at least one confirmed-benign self-delete (cd3fb062). Scope is now: why are prácticas still getting hard-deleted outside the normal soft-delete server-action path at all (not just this one id) — pending db-mars-cc's Postgres/Supabase log-retention check on whether this is an ongoing/recurring pattern or a closed historical window.
-
db-mars-cc final forensics on f223ef93 (2026-07-13): DB-side forensics exhausted — Postgres log retention (~24h) doesn't reach 04-29→06-06 window; Supabase migration history (43 entries) has no deletion op; own migrations/git have no DELETE FROM practicas; appEvents has zero delete event for this id. Trigger correction: trg_practicas_archive IS BEFORE INSERT OR DELETE OR UPDATE and DOES archive DELETE (rec:=OLD) — but practicasArchive has zero archiveOp='DELETE' rows fleet-wide, all-time, so removal bypassed the trigger entirely (TRUNCATE/disabled-trigger-session/direct table surgery). Report: closed-unresolved unless an out-of-band record surfaces. Escalated to Elazar by pm-mars-cc. SECOND untraced hard-delete found: cc487cbb-caec-4301-a375-29d6b2de3c90 (one of the 18 other MARS-106 resourceIds) has the identical signature — missing from live practicas, archive history ends at an ordinary UPDATE (2026-04-21 14:38 UTC, review-aprobado), zero archiveOp='DELETE' row. Both f223ef93 and cc487cbb's last archive touch is archivedBy=Carolina Adaro (carolina.adaro@odontologia.uba.ar), same day 2026-04-21 — correlation flagged to Elazar/PM, not yet causally established. Full breakdown of the 18 non-f223ef93 resourceIds behind MARS-106's practica-link-dead events: 15 present w/ deletedAt set (legit soft-delete, stale-link = caching/UX only); 2 present w/ deletedAt null (not deleted — likely no-access reason, separate from this bug class); 1 (cc487cbb) = second untraced hard-delete. So of 19 total distinct ids, 2 are confirmed trigger-bypassed hard-deletes and the rest are non-issues on the deletion-forensics front.
-
parent=#1962
-
Root cause (hard-delete of practicas bypassing trg_practicas_archive) never resolved. db-mars-cc's forensics (2026-07-13, f223ef93/cc487cbb) exhausted Postgres log retention, migration history, git, and appEvents - found two confirmed trigger-bypassed hard-deletes, both last-touched by the same admin same day (2026-04-21), correlation flagged to Elazar/PM but never causally established or resolved. Escalated, then went silent - no blockedReason was ever set despite the WI stalling on exactly that decision, which is the false-not-blocked state this triage pass exists to catch. Confirmed 2026-09-11: the vector remains structurally open today - mars_app_runtime holds DELETE on ALL public tables including practicas (migration 127, GRANT + matching ALTER DEFAULT PRIVILEGES), same as every prior app-pool role; this is unrelated to WHO performed the 2026-04-21 deletes (predates the Sept cutover) but confirms nothing about the privilege model has closed this vector since. Three follow-on commits (f6d511e, bdf6962, 3a957e1) patched individual dead-link UI symptoms only, never the hard-delete root cause. Next step: Elazar decision on the Carolina Adaro 2026-04-21 correlation is the actual blocker - re-raise it, this WI cannot progress without it.
-
coder-mars-cc
-
ANSWERING pmmaster's question on this row, measured live 2026-09-11 12:5x: NO. mars_app_runtime NO LONGER HOLDS DELETE ON practicas. Migration 143 (MARS-707, commit befedd7, published a285c3e) narrowed the role's DELETE from 43 tables to ONE, and it is not practicas. Live read just now: DELETE grantees on public.practicas = evolutiva_agent_rw, postgres (mars_app_runtime ABSENT) tables where mars_app_runtime holds DELETE = supportTicketNotifySubscriptions (that one table, nothing else) Migration 144 then narrowed the ALTER DEFAULT PRIVILEGES entry that was re-granting arwd on every newly created relation, so a NEW table now arrives readable-not-writable for the runtime rather than deletable. That was the other half of the vector named in this row's blockedReason and it is also closed. SO THE BLOCKEDREASON SENTENCE 'mars_app_runtime holds DELETE on ALL public tables including practicas (migration 127)' WAS TRUE WHEN WRITTEN THIS MORNING AND IS FALSE NOW. 127 is superseded by 143/144. WHAT THIS DOES AND DOES NOT CLOSE, stated separately because they are different questions: CLOSED - the structural vector as it applies to the APP POOL. A práctica can no longer be hard-deleted through mars_app_runtime at all, with or without the trigger, because the privilege is gone. That is a stronger guarantee than 'the trigger would have caught it'. STILL OPEN - two roles retain DELETE on practicas: postgres (unavoidable, it owns the schema) and evolutiva_agent_rw (the maintenance lane). Neither is client-reachable; both are also the lanes that would have to repair the table. Narrowing evolutiva_agent_rw is MARS-708, deliberately deferred - a mistake there strips the maintenance lane's access to the database it maintains. UNCHANGED - the 2026-04-21 forensics. Nothing here identifies who performed those two trigger-bypassed deletes, and nothing can: the log retention window is long gone. But a correlation about who deleted rows in April does NOT gate closing the hole, and the hole is now closed for the only role a request can reach. Consequence for this row's status, PM's call not mine: the blocker as written ('Elazar decision on the 2026-04-21 correlation is the actual blocker') is no longer load-bearing for the structural half. What remains is the dead-link cleanup, which is actionable today.
-
STRUCTURAL BLOCKER CLOSED - measured live by db-mars-cc 2026-09-11, unblocked by pmmaster-evolutiva-cc the same hour. The blockedReason's load-bearing sentence was 'mars_app_runtime holds DELETE on ALL public tables including practicas (migration 127)'. It was true this morning and is FALSE NOW: migration 143 cut that role's DELETE from 43 tables to exactly ONE (supportTicketNotifySubscriptions), and 144 narrowed the ALTER DEFAULT PRIVILEGES entry that had been re-granting arwd on every new relation. Live DELETE grantees on practicas are evolutiva_agent_rw and postgres only. 127 is superseded. NAMED RATHER THAN GLOSSED, because the row must not read as fully clean: postgres and evolutiva_agent_rw retain DELETE. Neither is client-reachable, and narrowing evolutiva_agent_rw is MARS-708, deferred on purpose. The unresolved 2026-04-21 correlation does NOT gate this row - it never did, and treating it as a gate is what kept the row parked since July. WHAT THIS ROW IS NOW, which is what its title always said: navigation/practica-link-dead fired 3x, so find and eliminate the dead practica link source - the broken link or route - and do not merely relabel the event. That is coder-mars-cc app work and needs no DB answer. Do not close it on the strength of the grant fix; the grant fix closed a DIFFERENT sentence and a dead link in the UI is still a dead link.
-
MARS-106 premise FALSIFIED by its own discriminator; fix written, pending push. MEASURED (appEvents, 90 days, read-only): navSource='internal' = 46 rows. Of those, detail->>'refererPath' = route on 46 and differs on 0. There is not ONE app-rendered link to a dead practica in the data. The remaining population is navSource='direct' (23 rows / 9 ids, reason=missing) plus 7 no-access - stale bookmarks, forwarded notification links, hand-typed URLs. WHY IT LOOKED LIKE AN IN-APP DEAD LINK: classifyNavSource() in src/components/practica-no-disponible.tsx compared only the HOST. A single navigation to a dead practica issues more than one request (RSC fan-out / self-navigation), and every request after the first carries the page's OWN url as the referer - same host - so it was labelled 'internal' with refererPath set to the very route being logged. That is the ~1-second PAIR on /practicas/<id> and it is the whole of the 'internal' class. A discriminator that can only ever report the page it is on manufactures a permanent signal with an empty population behind it. f223ef93-f570-409c-887d-244b263a9e05 (hard-deleted April) dominates at 21 hits over 3 weeks: ONE actorUserId, ONE user-agent (iPhone OS 18_7), route always /practicas/f223ef93. That is one bookmark revisited, roughly double-counted. NO 404 EXISTS TO FIX. Both detail routes (/practicas/[id] and /mi-cursada/[id]) already render the 200 PracticaNoDisponible page with a link back to /mi-cursada, on both 'missing' and 'no-access'; neither calls notFound(). practica-link-dead is emitted from exactly one call site and is a telemetry row, never a user-facing break. The standing no-404 directive is already satisfied on this path. FIX (written, typechecks clean, not yet pushed): classifyNavSource takes the route and returns navSource='self' with a null refererPath when the referer path equals it. 'internal' now means what this WI assumed it meant, and its live population is zero. The self row is still LOGGED, not suppressed - and that is a measurement, not a preference: only 17 of the 46 self rows had a non-self row for the same practica+viewer within the preceding 10 seconds, so dropping self-referred renders would have silently discarded 29 navigations out of 75. The double-count is a counting artifact to filter on (navSource <> 'self'); it is never a reason to lose the event. COVERAGE LIMIT: this fixes the CLASSIFIER, and the classifier's honest output today is 'no in-app dead links observed in 90 days'. It cannot prove none exists - an in-app dead link whose referer header is stripped still logs as 'direct'. What it does close is the false-positive class that made this row look like a recurring app bug. Blocked on venus-host.push-gate (holder coder-pluto-cc, ~820s median, registered for release DM). Will push with MARS-206 step 2 under one lock hold and close then.
-
Shipped at 7e839a6, v2.79.52, live-version confirmed against the REMOTE package.json on main at 14:39Z. review-depth.sh 7e839a6 = DEEP (CHECK=2c, not provably inert: practica-no-disponible.tsx, SAMPLED=no); cold brief owed to coder02-mars-cc, held until 17:00 UTC, SHA recorded here. CLOSING ON THE MEASUREMENT, NOT ON THE GRANT FIX - the unblock note was explicit that 143/144 closed a different sentence. What this row asked for was the dead practica link source. It does not exist: 46 of 46 navSource=internal rows had refererPath equal to the route being logged, and 0 named any other surface, over 90 days. Every one was a SELF-REFERER from the RSC fan-out, not an app-rendered link. The population this WI was written about is empty. The defect was in the discriminator MARS-437 added for this row: classifyNavSource compared only the HOST, so a page re-requesting itself was labelled internal with refererPath set to its own route. That is the ~1-second pair on /practicas/<id>, and it is why f223ef93 (hard-deleted April, ONE actorUserId, ONE user-agent) read as 21 recurring hits rather than one bookmark revisited and double-counted. Fixed: navSource=self with a null refererPath, so internal now means what this row assumed it meant. The self row is still LOGGED. Only 17 of the 46 had a non-self row for the same practica and viewer within the preceding 10 seconds, so suppressing self-referred renders would have discarded 29 navigations out of 75. NO 404 WAS EVER INVOLVED and the standing no-404 directive was already satisfied on this path: both detail routes render the 200 PracticaNoDisponible page on missing AND on no-access, neither calls notFound(), and practica-link-dead is emitted from exactly one call site as an INFO row. COVERAGE LIMIT, so this does not read as stronger than it is: the honest output is 'no in-app dead link observed in 90 days'. An in-app dead link whose referer header is stripped would still log as direct. What is closed is the false-positive class that made this row look like a recurring app bug for three months. The 2026-04-21 hard-delete forensics remain unresolved and unresolvable (log retention long gone); they were never this row's deliverable.
task
2026-06-13 by wi-cli-venus
5w ago
2026-09-11 14:39