basquetWi + New ticket
pluto PLUTO-163

Adopt fleet viewport/client-env telemetry standard (Elazar directive 2026-06-20): capture ONCE PER LOGIN (not per-page/per-tuple, low volume), store role[] on the row + viewportWidth + orientation to appEvents. Pluto currently has ZERO viewport telemetry (no capture code, 0 rows 30d). Converge on Mars's schema (reference impl). Enables the docente/admin/stakeholder viewport x role cohort number that Pluto could not produce for bs-mqmxqxwop02. Coordinate column/category names with mars+venus so all 3 are uniform.

Done normal unassigned

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Questions

No questions.

Activity

  • wi-cli-venus created · 2026-06-20
  • wi-cli-venus commented · 2026-06-20
    pm-venus coordinating the canonical schema (Mars reference-impl pull in flight: cadence + appEvents column/category/action + role[] storage). HOLD scoping until pm-venus relays the agreed shape; do NOT ping mars (venus owns it). Hard constraints from Elazar: (1) capture ONCE PER LOGIN, not per-page/per-tuple; (2) role stored ON the row (Mars currently JOINs role live → the std ADDS role-on-row for all 3 apps). Build to the relayed canonical shape so all 3 are byte-uniform.
  • wi-cli-venus statusChanged · 2026-06-20
    Scoped to canonical fleet schema v1 (pm-venus decision 19:49). Pluto build spec: (1) add 'client-env' to APP_EVENT_CATEGORIES (src/lib/log-categories.ts typed union) + db-pluto seeds lookupOptions grupo=appEventCategory row 'client-env' (category is TYPED, not free-text — both surfaces). (2) ViewportReporter 'use client' mounted in src/app/(protected)/layout.tsx (auth-gated → roles populated, post-auth, no unauth noise). (3) Client computes BANDED env only: viewportBand (32px bucket, byte-match mars band fn e.g. '384-415'), dprBucket ('1'|'1.5-2'|'3+'), orientation. (4) Dedup ONCE-PER-LOGIN: localStorage key 'pluto:client-env:'+loginId, loginId=supabase session id; absent→emit+set, present→skip. (5) Server action resolves roles[] live via getCurrentUser (userRoles, NOT JWT per §Role Resolution) + parses request UA→osFamily/deviceType banded, then emits logEvent({level:'info',category:'client-env',action:'viewport',actorUserId,detail:{viewportBand,dprBucket,orientation,deviceType,osFamily,roles}}). (6) PRIVACY HARD INVARIANT (WI#32-equiv): loginId is a client-side dedup key ONLY, NEVER written to the row; raw UA/exact px/session id discarded after banding. (7) jsonb detail → no DDL, no new index. Bands MUST be byte-identical to fleet canonical (mars-derived) for cross-app aggregation. Dispatched coder-pluto + audit-pluto privacy design-ping.
  • wi-cli-venus commented · 2026-06-20
    Audit (audit-pluto-cc) signed off privacy DESIGN as sound; pre-push diff gate locked: (a) loginId never persisted [not in INSERT col/detail/logger arg/action string]; (b) detail keys subset {viewportBand,dprBucket,orientation,deviceType,osFamily,roles}, no raw UA/exact px/raw dpr surviving; (c) roles via getCurrentUser/userRoles not JWT; (d) mount strictly (protected)/layout.tsx, no unauth second mount; (e) localStorage loginId guard must gate the write. v1-accepted residual: banded combo + rare role can near-uniquely fingerprint a single row, OK because no persisted stable key links rows (no longitudinal join). audit aro_join'd for pre-push diff review.
  • wi-cli-venus commented · 2026-06-20
    Scaffold complete + tsc clean (coder-pluto-cc), gate-compliant by construction. 5 files: log-categories.ts ('client-env' active, lookup row 38ed632b live), client-env-bands.ts NEW (orientationOf done; viewportBand/dprBucket/deviceTypeFromUA/osFamilyFromUA = throwing PENDING stubs), client-log-actions.ts (reportClientEnv server action: receives only {viewportBand,dprBucket,orientation}, roles via getCurrentUser, UA parsed in-scope+dropped, logEvent forceSync:true, NO loginId param), viewport-reporter.tsx NEW (session_id client-only localStorage dedup, never sent to server, try/catch-wrapped), (protected)/layout.tsx single mount. BLOCKED only on canonical band boundaries (venus reconciling 3-app on NAMED Tailwind breakpoints vs 32px numeric; dprBucket >=2.5->3/>=1.5->2/else->1). On relay: fill 4 fn bodies -> build -> SHA to audit pre-push diff -> post-push Vercel+live-version -> FINISHED.
  • wi-cli-venus completed · 2026-06-20
    Shipped 0fa42b1 / v1.73.14, audit PASS:0fa42b1. Once-per-login viewport+role telemetry built to canonical fleet schema v1: detail jsonb {viewportBand(32px lossy bucket),dprBucket,orientation,deviceType(mobile/desktop, tablet→mobile),osFamily(iOS/Android/ChromeOS/Windows/macOS/Linux/Desconocido, Android-before-Linux),roles[]}; category='client-env' (union+lookup row 38ed632b), action='viewport', forceSync:true awaited-in-body (bypasses info-verbosity gate). Privacy gate (a)-(e) verified from disk: session_id client-side localStorage dedup key only (never persisted), banded-only detail, roles via getCurrentUser (live userRoles not JWT), single (protected)/layout mount, localStorage gate fires once-per-login. Audit extra: appEvents ip/userAgent land NULL (reportClientEnv passes neither); view-as can't emit a row. Deploy READY/production, live /api/app-version=1.73.14 (flipped from .13, no frozen-prod), no runtime errors 20m post-deploy. CAVEAT: first actual client-env row awaits a real authed page-load (info+forceSync needs a live browser) — persistence-in-prod confirmed on first login, not yet observed. 5 files: log-categories.ts, client-env-bands.ts(NEW), client-log-actions.ts, viewport-reporter.tsx(NEW), (protected)/layout.tsx.
task
2026-06-20 by wi-cli-venus
6w ago
2026-06-20 23:09