feat/ui-impact
needs attentionviewing older commitf29cc5b · fullpre-PRreviewed 2026-07-23 23:07 UTC9H · 17M · 11L · 2I- Purpose
- Enterprise customers need visibility into energy contract anomalies so they can act (aclaraciones, renegotiations) and quantify the financial impact.
- Goal
- Complete Energía module: new Finding FCIS entity with 10 anomaly detectors, read-only findings API, and 8 Energía UI screens wired to real data with $-layer impact UX.
- Sub-goals
- SG-1: Finding domain entity (DB schema, FCIS files, decisions, shell, queries, mapper)
- SG-2: Detection engine — 8 corpus-verified detectors (estimated readings, FP penalties, demand oversizing, VAT recomputes, YoY spikes)
- SG-3: Read-only findings API (ts-rest, energia-module-gated)
- SG-4: UI screens wired to real findings data (Hallazgos, Resumen, Demanda, Pagos, Medición, ESG)
- SG-5: $-layer UX — hard vs indicative impact per finding
- What
- 65 files, +24456 lines. New utility_contract_findings DB table (migration 0058), finding FCIS entity in domains/utility, /findings REST API, and all major Energía screens replaced with real-data-driven components. Demo mode updated to be fully interactive.
- Why
- Core commercial feature for Batu for Enterprise — the Energía module is the primary differentiator. Allows customers to identify and act on energy contract anomalies detected from their CFE bill history.
- Areas
- domains/utility/src/finding/+3980−0apps/platform/src/app/.../energia/+4200−3apps/platform/src/api/+350−1packages/database/+13455−0packages/api/src/schemas/+150−0scripts/energia/+181−0
- Blast
- 65 files, +24456/-4 across 6 areas. New DB table, new API surface, new module gate. Isolated to Energía module — no changes to existing bill/contract/site flows.
Findings · 10
correctness5
detectEstimatedReadings: median includes estimated bills, biasing deviation check
domains/utility/src/finding/finding.decisions.ts:467
Median baseline contaminated by estimated readings — chronic estimation suppresses severity escalation.
detectFpChronicPenalty: legado gap makes non-adjacent bills appear consecutive in streak
domains/utility/src/finding/finding.decisions.ts:668
Legado bills silently removed before streak check; penalty period interrupted by legado shows as unbroken.
Shell: optimistic-lock rejection silently drops candidate — not counted in unchanged
domains/utility/src/finding/finding.shells.ts:2145
Version conflict rejection is silent. Caller sees ok() but finding may remain stale for a full billing cycle.
kwh_per_day SQL: period_end inclusive convention assumed but not asserted
domains/utility/src/finding/finding.queries.ts:1812
Off-by-one risk in all detectors using kwhPerDay if CFE period_end is exclusive.
Hallazgos useFindings limit:200 silently truncates for orgs with >200 findings
apps/platform/src/app/[locale]/(dashboard)/energia/hallazgos/page.tsx:1585
Summary card totals are wrong for large orgs; no pagination or truncation warning.
conventions3
Shell DB errors can throw unhandled exceptions — violates Result<T,E> contract
domains/utility/src/finding/finding.shells.ts:100
No try/catch in shell; any DB exception propagates as an unhandled rejection.
finding.queries.insert() throws domain error instead of returning Result
domains/utility/src/finding/finding.queries.ts:316
Queries must return Entity | null; throwing bypasses the shell's error union.
Hardcoded Spanish strings throughout hallazgos/page.tsx — missing i18n
apps/platform/src/app/[locale]/(dashboard)/energia/hallazgos/page.tsx:13
Multiple JSX strings hardcoded in Spanish; must move to messages/{locale}.json + useTranslations().
tests2
No handler-level tests — auth, entitlement, error-mapping paths untested
apps/platform/src/api/handlers/finding.handler.ts
Contract test validates shapes only; auth gate, module entitlement, error→HTTP mapping could regress silently.
transitionFindingStatusShell has no integration test
domains/utility/src/finding/__tests__/finding.integration.test.ts
Full status-transition write path has no DB-level test; outbox write regression undetectable.
History · 15 commits
- 96ca7d7needs attentionincremental0H · 9M · 12L2026-07-25 16:40
- 25516f7needs attentionincremental5H · 7M · 8L2026-07-25 03:29
- a7f8d64needs attentionincremental0H · 4M · 5L2026-07-25 01:56
- 7fc4ef0needs attentionincremental2H · 6M · 8L2026-07-24 21:04
- 027e5eaneeds attentionincremental4H · 9M · 8L2026-07-24 20:04
- 95a101eneeds attentionincremental3H · 6M · 5L2026-07-24 16:09
- 5d0d186needs attentionincremental1H · 3M · 5L2026-07-24 15:36
- c3c5121needs attentionincremental2H · 1M · 5L2026-07-24 15:17
- ded4e61needs attentionincremental2H · 3M · 9L2026-07-24 14:22
- 312a1f4needs attentionincremental1H · 4M · 4L2026-07-24 04:01
- b48af56needs attentionincremental1H · 6M · 6L2026-07-24 03:14
- 6d07cc8needs attentionincremental2H · 4M · 5L2026-07-24 00:50
- 261b55eneeds attentionincremental5H · 11M · 6L2026-07-24 00:38
- 5b8a252needs attentionincremental3H · 6M · 9L2026-07-24 00:19
- f29cc5bneeds attentionfull9H · 17M · 11L2026-07-23 23:07current