Cross-app nav-link normalization: one criteria for sidebar/navbar links per role in mars+pluto+venus
Elazar 2026-07-12: analyze sidebar vs navbar links per role in each app (are they the same?), converge ONE cleaner criteria across mars/pluto/venus, implement in all three. Driven+coordinated by coder-mars-cc with coder-venus-cc + coder-pluto-cc; NO pm/audit participation in design phase; read-only DB allowed, minimal DMs/turns/tokens. Plan goes to Elazar first, then pm-mars-cc gets input and coordinates objections check with pm-venus-cc/pm-pluto-cc. Mars baseline: single-source nav (buildNav in app-sidebar.tsx renders SAME links to desktop sidebar + mobile drawer; mobile header = hamburger+logo only); sections Trabajo/Equipo/Administrar + fixed tail Notificaciones/Perfil/Cerrar sesion; known wart: /alumnos duplicated in Equipo+Administrar for roster-admin teachers; section order swaps by primaryRole. Related: MARS-77 (per-role regroup Stage A, still open - this WI sets the fleet criteria MARS-77 executes under).
Activity
-
pluto reply: (1) single-source already (buildSections in app-sidebar.tsx, desktop+mobile share SidebarContent; tail Notificaciones/Perfil/Soporte/Cerrar sesion; AUTHENTICATED_HOME_ROUTE in navigation.ts). (2) Warts: role-string gates (alumno /mi-cursada, bedelia carga-anual) mixed w/ userCan; label forks by cap; dup-href already guarded by Set; C5 never verified formally. (3) Votes: all YES; C2 amendment - allow role-membership gates ONLY where link semantics = the role itself (own-work lane), hasCap for everything else; C3 tail = notifications/profile/support(optional per app)/signout. Pending: venus.
-
venus reply: single-source YES (src/lib/nav-sections.ts buildNavSections -> sidebar + header/mobile drawer; tail lives in app-header.tsx OUTSIDE manifest). Warts: /practicas/nueva duplicated (Alumno+Academico sections, C4 hit); gating raw role-strings except isCorrectionApprover cap precedent; sections role-named not taxonomy-named; tail outside manifest invisible to C5; participaciones deliberately non-nav. Votes: all YES; amendments: C3 labels stay local w/ documented mapping; C5 verify-set = manifest + fixed tail + explicit non-nav allowlist. => 3/3 converged. Consolidated criteria C1-C6 + pluto C2/C3 amendments + venus C3/C5 amendments. Plan going to Elazar.
-
criteria converged 3/3; plan to Elazar for GO, then PM input round
-
Elazar scope expansion 2026-07-12: (A) nav de-confusion WITHOUT model refactor (Usuarios/Docentes/Alumnos triple confusing; full refactor vetoed on token budget) - cheap label/merge proposals per app; Mars Administrar ~10 links too many. (B) venus /admin/errores useless as-is (make actionable or remove) + /admin/inicio 11-step setup UI made for nobody (retire UI, keep workflow as in-repo doc if agent-useful). (C) route-usage telemetry, self-hosted on venus.pensanta.com postgres (no vercel/supabase/3rd-party): draft = shared usage schema, server-side pageview log {app, routePattern normalized no-PII, userIdHash, role, ts}, batched fire-and-forget, NOT appEvents (would flood zero-noise baseline); usageDaily rollup; >=30d collection before retire/merge decisions (/equipo-academico, Gestion academica candidates). Transport lean: direct pg pool via DATABASE_URL_USAGE. Sent to coder-venus/pluto for one-reply votes.
-
pluto expansion reply: (A) labels+grouping only, zero routes: C3 headers; rename /admin 'Admin'->'Plataforma' (vs Gestion academica=/administrar roster-ops); drop /admin/usuarios-inactivos direct link (reachable via dashboard card); net -1 link +1 rename. (C) YES schema/fields/not-appEvents/90d/30d + mars authors, apps vendor. Transport objection (mild): direct pg from 3 Vercel serverless apps = connection churn (Pluto Fluid OFF, 1 conn/invocation) -> if direct it MUST be pooled (pgbouncer/supavisor-style), else prefer tiny ingest API on venus (one fetch keepalive, shared bearer env). Caveat: fire-and-forget dies at serverless response end - primitive must use next/server after()/waitUntil or accept sampling loss. Pending: venus reply.
-
venus expansion reply: (A) Administracion 10->8, labels only: Usuarios->'Cuentas y roles', Alumnos->'Alumnos (cursada)', drop Errores, Panel absorbed as section landing; optional sub-headings Personas/Datos/Sistema. (B) /admin/errores REMOVE (579-line page, zero drill-through, agents triage via SQL + error rail; actionable version would violate no-raw-IDs UI rule); /admin/inicio RETIRE UI, checklist -> venus/pm/reference repo doc (all step actions doable via /admin/lookups + admin pages). (C) YES schema/shape/rollup/retention/window + mars authors. Transport: prefers tiny bearer'd ingest API on venus (~40 lines, one choke point, no fleet pg creds in 3 Vercel envs); direct pg would require pgbouncer prereq. Caveat: filter/mark RSC prefetch requests or layout-render hits overcount. => DECISION (driver): ingest API transport (both coders prefer it); primitive uses next after(); prefetch-filtered. Plan finalized, going to Elazar for GO before PM round.
-
pm-enamel-cc pinged (Elazar considering enamel/coder-enamel-cc as ingest-API owner, host venus, DNS telemetry.pensanta.com TBD). Replied: no existing ingest API to duplicate; NO objection to enamel owning the SERVICE; conditions: wire contract per EVO-51 spec (batched POST, normalized routePattern no-PII, shared bearer), app-side primitive stays mars-authored/vendored (after() + prefetch filter), usageDaily rollup + 90d retention, coordinate schema location with one-db owners (usage schema should live in the consolidated 'telemetry' Postgres, not a new db). Will spec endpoint contract with coder-enamel-cc once Elazar confirms ownership.
-
Ownership confirmed: coder-enamel-cc owns ingest API service under EVO-51 conditions; DNS telemetry.pensanta.com + Caddy via nw-venus-cc (pm-enamel routes after Elazar GO). Endpoint contract v1 spec'd to coder-enamel-cc: POST /v1/usage, per-app bearer bound to app name, batched JSON {app, events[{routePattern normalized no-ids, userIdHash sha256+salt 16hex app-side, primaryRole, ts}]} cap 50/64KB, 204/401/400 no partial accept, async write after respond, schema 'usage' INSIDE ONEDB telemetry pg (coordinate bin-whey/nw-whey before create), usageEvents append-only + usageDaily rollup, raw 90d/rollup forever, no dedup, non-goals: no dashboards/no client beacon. Awaiting coder-enamel OK + Elazar GO on overall plan.
-
coder-enamel-cc OK on contract v1 + 3 amendments, all accepted -> contract FINAL: (1) app set extensible via server token registry, no hard mars|pluto|venus enum in wire contract (enamel will emit too eventually); (2) 403 valid-bearer-but-app-mismatch, 401 unknown/missing bearer; (3) server ts sanity clamp (reject ts>now+5min or older than 7d). All builds gated on Elazar GO.
-
Mars implementation LANDED: commit 4e9b9de v2.24.40 — usage-telemetry primitive (src/lib/usage-telemetry.ts, mounted via (protected)/template.tsx) + nav: Usuarios->'Cuentas y roles', C4 dedup Alumnos/Comisiones vs Equipo. Pre-push hook fail root-caused: MARS-408 lint runs --strict (exits 1 despite WARN banner); fixed via inline nsf-allow markers on the two contract-bound swallows. Pluto nav shipped 0a4e7f7 v2.5.7; awaiting enamel ingest URL+bearers. pm-venus dedicated-Postgres flag relayed to coder-enamel-cc.
-
audit-mars-ca BLOCK:4e9b9de (High privacy: non-uuid dynamic segments exported verbatim). Fixed same turn: c3cf2ba v2.24.41 fail-closed ROUTE_PATTERNS manifest ([unmatched] fallback), static-over-dynamic precedence bug also caught+fixed, 16-case harness all pass, response.ok delivery-health warn added. No data leaked (env-gated, ingest not live). Pluto+Venus alerted to re-vendor from c3cf2ba (Pluto 4b3f377 had vendored the pre-fix version).
-
audit PASS:c3cf2ba. Enamel ingest LIVE (telemetry.pensanta.com/v1/usage, webusage schema, e2e verified). Mars: 3 USAGE_TELEMETRY_* Vercel prod envs set (URL + bearer + generated salt, sensitive); activate on NEXT Mars deploy - no manual redeploy per git->Vercel rule. v2.24.41 confirmed live. Pluto+venus bearers going to their coders directly.
-
Mars 645bb91 v2.24.44: normalization now derives from the MARS-155 build route manifest via new matchRouteTemplate() (zero-drift, venus a17996d idea upstreamed; my interim gen-route-manifest.mjs generator abandoned after discovering it clobbered the existing MARS-155 route-manifest.ts). This deploy also ACTIVATES Mars telemetry (envs bake in). Cold brief sent to audit-mars-ca. Pluto active-ready v2.5.10; venus a17996d + envs going in. All 3 apps converged on derived manifests.
-
audit PASS:645bb91; live probe confirms v2.24.44 serving (dpl_Dfscdm6xKMvF9CTy4kdQtZUiLHVr) - Mars telemetry ACTIVE. Venus confirmed its generated manifest already excludes its [...notFoundPath] catch-all (fail-closed parity). All 3 apps live w/ derived manifests. WI stays inProgress: ~30d collection, then route retire/merge review (suspects: /equipo-academico, Gestion academica).
-
coder-mars-ca / coder
-
coder-mars-cc / coder
-
coder-mars-ca
-
2026-10-04 retire/merge review (read-only): webusage usageDaily spans 2026-07-12..10-03; raw latest 10-04. Past 30d raw: Mars 4616 views/359 hashed users, Pluto 3997/264, Venus 874/30. Ingest /healthz dbOk=true, 0 failed/lost since 09-12, but fire-and-forget events are not a clickstream and older outages cannot be excluded. Pluto /equipo-academico: 0 hits in 84d despite /admin 79 hits/2 users and /practicas 941 hits; route still implements unique AcademicHierarchyCollapsible and has contextual link from adjuntos-table. Recommend remove only the Pluto sidebar shortcut, retain route/contextual link, subject to Elazar product decision. Pluto /administrar: 1 root hit (09-12) and /administrar/docentes 4; root redirects to docentes, so root count understates use. Keep roster navigation until role-cap reachability is verified; consider merging into Panel Admin only for users who can access /admin, retaining fallback for roster-only roles. /admin/usuarios-inactivos direct nav was already removed, card remains; no further retirement there. Mars/Pluto/Venus desktop/mobile render one nav builder per app (Mars/Pluto shared component, Venus buildNavSections); three-section taxonomy and cap gates are present. Do not retire Mars /examenes or Venus low-volume admin routes based on 30d counts: seasonal workflows and small authorized cohorts. No code changes; EVO-51 remains inProgress pending Elazar decision on Pluto shortcut and cap-preserving merge.
-
2026-10-06 oldest assigned non-blocked row intake. Subject still exists in current source: Mars src/components/app-sidebar.tsx buildNav renders Trabajo/Equipo/Administrar with same desktop/mobile links and dedupes /alumnos; Pluto src/components/app-sidebar.tsx buildSections still offers /equipo-academico to fullAccess and /administrar to manageRoster; Venus src/lib/nav-sections.ts buildNavSections still offers role-gated Panel Admin/Alumno/Académico/Ayuda. Prior implementation/telemetry review (2026-10-04 event) already shipped shared nav taxonomy and found 0 Pluto /equipo-academico hits in 84d while its unique AcademicHierarchyCollapsible/contextual route remains; /administrar root redirects to docentes and its low raw root count underreports use. Proposed final product choice to Elazar before build: remove only Pluto's /equipo-academico sidebar shortcut, retain route/contextual link; retain /administrar access for roster-only roles, and consider merging its shortcut into Panel Admin only where that dashboard is reachable. No code edit until required Elazar plan decision and PM objection check (row's original gate); low traffic alone does not authorize deleting routes.
-
Remaining scope is a product/navigation decision, not an available code fix: per Elazar's original sequence the proposed Pluto /equipo-academico shortcut retirement and /administrar-vs-Panel-Admin merge go to Elazar first, then PM Mars coordinates Venus/Pluto objections. Current 2026-10-06 source/telemetry review recorded in progress event. Retain existing routes and role reachability until that decision; no DB/credential dependency.
-
coder-mars-cc