Fleet appEvents schema standardization: single log(entry) entrypoint (no level-wrappers) + promote hot fields to real columns, minimize jsonb-blob reliance
Elazar fleet directive 2026-07-07 (aro:evolutiva-management DM mra6kqclbkjq). Every Evolutiva app appEvents table must share ONE field schema and stop leaning on the jsonb detail blob for frequently-queried values. ONE public logging entrypoint log(entry) — NO wrapper fns (no log.info/log.warn/log.error/auditLog/errorLog); level passed as data in entry.level (TRACE/DEBUG/INFO/WARN/ERROR/FATAL); status=SUCCESS/FAILURE. Frequently-queried values become REAL COLUMNS (OTel-style: event, service, component, operation, requestId, traceId, spanId, sessionId, userId, actorId, version, environment, status, durationMs, errorType/errorCode/errorMessage/stackTrace); metadata json ONLY for irregular event-specific data. camelCase TS / snake_case SQL; timestamp+id generated inside log(); logging never throws into main flow (catch+console fallback). Codex prompt id=f3m8wm is SQLite-shaped (INTEGER pk, TEXT ts) — ADAPT the shape onto the live Supabase appEvents (uuid pk, timestamptz, camelCase), do NOT spin a parallel app_log SQLite table. RECONCILE with: (1) MARS-107 (existing Mars appEvents-conform-to-fleet-standard WI incl promoted cols httpStatus/durationMs/path/failureCode) — this directive extends its schema leg; (2) MARS-408 logError/logWarn/logInfo thin level-wrappers — directive says collapse them to single log({level,...}); (3) evolutiva-appevents-standard.md SSOT + new vAppEvents25/50/100 lean views. Mars leg; fleet convergence coordinated on aro:evolutiva-management.
Activity
-
Elazar directive 2026-07-07 (fleet, appEvents standardization): ONE canonical category for every user-facing-feedback event — toasts, native HTML5 validation hints, inline validation feedback all share ONE top-level category tag, with the MECHANISM (toast | native-validation | inline-hint) as a sub-field (detail key or dedicated column), never a divergent top-level category string. Trigger: venus was emitting 3 different category strings (nativeValidation:rangeOverflow, toast, toast-shown) for the same concept, so a DB/LLM query has to know all variants or silently misses rows. Applies to MARS-412's native-'invalid' capture too: it must write the unified category, not a per-constraint action string. Two capture-quality rules surfaced: (a) do NOT log the browser's default validationMessage (locale-dependent English like 'Please select a value that is no more than 2026') — log the constraint code + app's own Spanish string; (b) do NOT log the React-generated DOM id as the field — log the semantic field name/label. Category name deferred to the fleet standard (Elazar OK with 'toast' as umbrella or a neutral name). Build timing put to Elazar: post-Jul-10 fold vs now.
-
Elazar ruling 2026-07-07: canonical user-feedback category = `toast` (umbrella), mechanism in a sub-field. venus does (b) NOW (unify emission + backfill existing rows, simple UPDATE); Mars + Pluto code-convergence rides the post-Jul-10 pass but build to this locked standard. Fleet codification routed to bin-whey-cc → evolutiva-commons (§UI-And-Errors/friction-telemetry). Mars leg (MARS-411 + MARS-412 native-invalid capture) must: emit category=toast + detail.mechanism (toast|native-validation|inline-hint), log constraint-code+Spanish string not browser validationMessage, log semantic field not the React DOM id.
-
Cross-project guard from venus VENUS-188 (2026-07-07): when collapsing feedback categories to the `toast` umbrella, ANY downstream query/view/cron that filters appEvents by the OLD category strings (nativeValidation:*, toast-shown, uxFriction, etc.) MUST be co-updated in the SAME change — else the ux-pain-digest / alert-rail queries silently miss the relabeled rows. venus audit is blocking its backfill until those consumers are co-updated. Mars convergence (post-Jul-10) must inventory Mars's own category-keyed consumers (ux-pain digest cron, any vAppEvents* view or alert query keying on a feedback category) and co-update them with the relabel + backfill.
-
Fleet enhancement (Elazar 2026-07-07, relayed via venus VENUS-193): promote the feedback MECHANISM sub-discriminator from detail->>'mechanism' jsonb to a FIRST-CLASS INDEXED column across all appEvents tables. Agreed uniform column name fleet-wide = `feedbackMechanism` (values toast|native-validation|inline-hint). Bare `mechanism` rejected (vague-public-name per §Naming). Mars: Class-A schema → mars-db, folds into this WI's promoted-columns scope (alongside MARS-107's httpStatus/durationMs/path/failureCode), post-Jul-10. Uniform contract: category=`toast` umbrella + indexed feedbackMechanism column; detail jsonb reserved for irregular extras only.
-
Value-vocabulary clarification (venus, agreed 2026-07-07): the feedbackMechanism COLUMN NAME is uniform fleet-wide, but its VALUE vocabulary is PER-APP (same rule as lookupOptions — UX/clinically-bound sets differ). NO shared value enum, NO CHECK constraint on feedbackMechanism (that's a native-enum-in-disguise, banned per evolutiva-commons §Database). Mars set = toast|native-validation|inline-hint; venus = toast|guardrail|action-error|native-validation|client-validation. Only the column name + its indexed/first-class status is the shared contract.
-
STATUS CORRECTED backlog -> blocked by pmmaster-evolutiva-cc. Found by coder02-enamel-cc's read-only sweep: this row is gated on the identical open call as MARS-107 - the SSOT-commit plus priority decision - and MARS-107 was corrected to blocked on 2026-09-11 while this one was not. So a structurally blocked row has been sitting backlog and PICKABLE, which is worse than blocked: the next agent with capacity takes it, discovers the gate, and the time is spent twice. Two rows with one gate and two different statuses is the same defect this fleet keeps finding - the real state was knowable and the queryable field did not carry it. blockedReason set so the waiting condition survives in a field rather than in this event body; a deferred status would CLEAR it, which is precisely how TERRA-36 sat eleven days behind two gates that had both already been met.
-
Same gate as MARS-107: awaiting Elazar's SSOT-commit decision plus the priority call. MARS-107 was corrected to blocked 2026-09-11; this row was missed.
-
Unblocked, SPLIT and ruled by pmmaster-evolutiva-cc 2026-10-06. Both stated gates are gone: the SSOT exists (shared/md/evolutiva-appevents-standard.md, 46846 bytes, git-tracked since 2026-07-30) and the priority call is mine, not Elazar's - it stays p2. What the block got wrong is that this row has TWO legs with different blockers, and holding the whole thing on the DDL leg froze a leg that needs no DB at all. LEG 1, SHIPS NOW, coder lane, no DDL: collapse the logging surface to ONE public entrypoint log(entry) with level passed as data; retire the logError/logWarn/logInfo level-wrappers; timestamp+id generated inside log(); logging NEVER throws into the main flow (catch + console fallback). That is TypeScript only, reversible in one commit, and it is the half that makes every later schema change land in one place instead of four call-site families. LEG 2, STAYS BLOCKED: promoted real columns, categoryId FK, backfill, append-only trigger, tiered retention, canonical views. Not on SSOT or priority - on the fact that Mars has no write-capable DB seat (db-mars-cc retired; the remaining seats are read-only). Same blocker as MARS-107, MARS-776 and migration 183; escalated once for all of them, not per row. CONFLICT RESOLVED, and someone would otherwise have built then deleted code: MARS-107 specifies ADDING logError/logWarn/logInfo wrappers, this directive says COLLAPSE them to log({level,...}). The directive is later (Elazar 2026-07-07) and wins. MARS-107's wrapper leg is struck - do not implement it. MARS-408 (the wrapper row) is superseded by Leg 1 and should be cancelled by whoever owns it. Do NOT spin a parallel app_log table; adapt onto live Supabase appEvents (uuid pk, timestamptz, camelCase).
-
coder-mars-cc / coder
-
CORRECTION by pmmaster-evolutiva-cc, same session, minutes after the unblock note above. That note says 'MARS-408 (the wrapper row) is superseded by Leg 1 and should be cancelled'. WRONG - MARS-408 is 'No-silent-failure contract (Mars lane)', status=done, coder-mars-cc, and has nothing to do with level-wrappers. I took the reference from THIS row's own description text, which cites MARS-408 as the logError/logWarn/logInfo wrapper row, and repeated it without opening it. Do not cancel MARS-408. Everything else in the unblock note stands: the wrapper leg of MARS-107 is struck, log(entry) is the single entrypoint, and if a separate live wrapper row exists it has not been identified - find it by title, not by the number quoted here or there. The general failure is worth more than the fix: a row's description is a claim about OTHER rows as well as its own subject, and those claims rot exactly like any other cross-reference. Verify a cited ref by opening it before acting on it - a stale number reads as authoritative because it is specific.