← all branches

content/auto-draft

needs attentionviewing older commit
5c9de97 · incrementalPR #304reviewed 2026-07-14 17:02 UTC0H · 5M · 7L · 2I
The branch
Purpose
Auto-drafted blog post on the GDMTH electricity tariff — part of the CFE informational content cluster targeting Mexican energy managers and solar installers.
Goal
Publish tarifa-gdmth.mdx with all visual components live (replacing TODO placeholders) and editorial copy accuracy-checked.
Sub-goals
  • SG-1: Content accuracy — voltage range precision ('más de 1 kV y menos de 69 kV'), tariff reform date ('2017-2018'), component definitions clarified
  • SG-2: Visual components — activate GdmthBillCallouts hero and add BillCostBreakdownChart overview section
  • SG-3: Chart legibility — shared TOU color palette (GREEN/AMBER/HELIOTROPE), dashed block separators, improved captions
  • SG-4: Accessibility — WCAG AA link contrast fix in blog-content.css
The changes (whole branch)
What
Activated the GdmthBillCallouts hero component (previously a TODO comment), added BillCostBreakdownChart as an overview section, introduced a shared TOU color palette, refactored DemandVsConsumptionChart / TouBlocksChart / SolarBillImpactChart with better color consistency and captions, fixed blog link contrast (foreground text + brand underline).
Why
The blog post was drafted with TODO placeholders for the hero visual; this commit makes it publication-ready by activating all components and correcting factual details caught in an adversarial copy review.
Areas
apps/web/content/blog/tarifa-gdmth.mdx+2000apps/web/src/components/blog/charts.tsx+43846apps/web/src/app/(marketing)/blog/[slug]/page.tsx+22apps/web/src/styles/blog-content.css+82apps/web/content/calendar.yml+11
Blast
5 files, +649/-51 across apps/web content + components. No backend, no API, no auth. Pure marketing site content change.
contains-factual-claims visual-components-activated
typecheck· not run in this reviewci· no CI checks returned for PR 304coderabbit· no .coderabbit.yaml in repo

Findings · 14

correctness3

medium

GdmthBillCallouts: GREEN callout anchors to wrong row (kW intermedia, not kW punta)

apps/web/src/components/blog/charts.tsx:602

The GREEN callout for 'Demanda facturable' uses `cardY: rowMid(4)` — the 'kW intermedia' row (244 kW). But the callout text reads 'la de punta alimenta el cargo de capacidad.' The capacidad charge is driven by the punta-block demand, which is row index 5 ('kW punta', 44 kW). The connector dot visually points to the wrong line, directly contradicting the label it introduces. Fix: change `rowMid(4)` to `rowMid(5)`.

low

DemandVsConsumptionChart: last ToU band ends at hour 23 (scale mismatch with TouBlocksChart)

apps/web/src/components/blog/charts.tsx:100

The x-scale uses `(hour / 23) * plotW`, so x(23) is the right edge and the last band `{ from: 22, to: 23 }` covers only 1/23 of the chart. TouBlocksChart uses `(hour / 24) * plotW` and shows the intermedia tail from 22:00 to 24:00 correctly. The two sibling charts are visually inconsistent about the same block schedule. Extend the last band to `to: 24` and adopt `(hour / 24) * plotW` to match.

info

GdmthBillCallouts: CYAN callout anchors to kWh intermedia row as representative for all three energy lines

apps/web/src/components/blog/charts.tsx:601

The CYAN connector points to row 1 (kWh intermedia) while the callout describes 'Tres líneas, una por bloque'. Anchoring to the middle of a three-row group is a common callout convention and not strictly wrong, but may look imprecise since the CYAN tint already spans rows 0–2. Consider anchoring to rowMid(1) as-is (group midpoint) or adding a bracket spanning all three rows for clarity.

conventions3

medium

Multi-line docstrings on 6 chart components violate one-line comment rule

apps/web/src/components/blog/charts.tsx

CLAUDE.md: 'Never write multi-paragraph docstrings or multi-line comment blocks — one short line max.' Six components have multi-line block comments added or expanded in this diff: TOU constant (4 lines), SolarBillImpactChart (4 lines), DemandaFacturableSolarChart (5 lines), BillCostBreakdownChart (3 lines), GdmthBillCallouts (5 lines), DemandVsConsumptionChart (4 lines). Each should be collapsed to a single-line comment or dropped — the component name and aria-label already carry the semantic meaning.

low

Inline comments describe WHAT, not WHY (numerous instances)

apps/web/src/components/blog/charts.tsx

CLAUDE.md: 'Only add a comment when the WHY is non-obvious.' Multiple inline structural comments added in this diff describe structure already visible in the JSX: '// ToU bands behind the curve', '// faint separators at block boundaries', '// energy annotation', '// billable-demand envelope (what you actually pay)', '// measured peak (flat)', '// energy-derived demand (declining)', '// region annotations', '// bill card', '// group tints', '// table header', '// rows', '// callouts + connectors', '// sub-labels for the demand split', '// family labels + brackets', '// the bar', '// legend'. Remove them.

low

peakOf() sentinel returns {hour:0, kw:-1} when no hours match — renders marker above chart

apps/web/src/components/blog/charts.tsx

If the period predicate matches no LOAD_KW slot (impossible with the current 24-slot fixed schedule but fragile if the schedule changes), `peakOf` returns `kw: -1` and renders a demand dot above the chart area at y(-1). This is not a TypeScript error. A defensive guard or a return type of `{hour: number; kw: number} | null` with a null-skip in the render path would make the intent explicit.

tests2

low

Blog route /blog/tarifa-gdmth missing from E2E smoke suite

e2e/web/marketing.spec.ts:17

The ROUTES array still omits /blog and /blog/tarifa-gdmth with a stale comment 'not built yet'. With this diff activating GdmthBillCallouts (previously a TODO) and registering two new chart components in the MDX map, a crash in the React tree (broken import, MDX parse error) would go undetected. Adding `{ path: '/blog/tarifa-gdmth', name: 'tarifa-gdmth blog post' }` to ROUTES is a one-liner that closes the gap.

info

No snapshot/visual-regression tests for new SVG chart components

apps/web/src/components/blog/charts.tsx

BillCostBreakdownChart and GdmthBillCallouts are purely presentational static SVGs with no state, data fetching, or user interaction. TypeScript catches type mismatches at build time. The project has no pre-existing snapshot baseline for any blog chart, so there is no bar being raised. Not a gap relative to project norms.

improvement6

medium

Duplicated segment-bar rendering logic between BillCostBreakdownChart and SolarBillImpactChart

apps/web/src/components/blog/charts.tsx

Both components define the same three-segment array (Energía/VIOLET/60%, Capacidad/GREEN/30%, Distribución/CYAN/10%) and the same `start(i)` / `center(i)` helper pattern. The bar rendering loop (rect + percentage text + optional SunMark) is structurally identical, differing only in bar height and whether a SunMark is rendered. A shared internal `SegmentBar` primitive accepting segs + barY + barH + an `isImpacted` predicate would make a future composition change (e.g. adding a fourth charge) a single-source edit.

medium

GdmthBillCallouts: boxMid magic number (co.y + 29) silently coupled to undeclared box height 58

apps/web/src/components/blog/charts.tsx:635

The callout box height is `height={58}` in the rect and the accent bar, while `const boxMid = co.y + 29` hard-codes half of 58 without naming the constant. Changing the box height requires updating three values. Extract `const CALLOUT_H = 58` and derive `boxMid = co.y + CALLOUT_H / 2`.

medium

GdmthBillCallouts: callout y-coordinates (96, 190, 272) are opaque magic numbers

apps/web/src/components/blog/charts.tsx:601

The three `y` offsets are manually chosen with no derivation from card geometry (cardX=24, y0=102, rowH=28). When card dimensions or row count change, these silently misalign. Deriving them from `rowMid(n) - CALLOUT_H / 2` clamped to the card's vertical range would make them self-correcting.

low

segCenter / center helpers use optional chaining that is unreachable

apps/web/src/components/blog/charts.tsx

`segs[i]?.pct ?? 0` in `segCenter` and `center` helpers is only called with valid indices from a .map() callback — the optional access is dead code that adds visual noise. With `noUncheckedIndexedAccess` the guard is required by the compiler, but a typed helper or explicit cast would express the intent more clearly.

low

TouBlocksChart label 'Intermedio' vs TOU object key 'intermedia' — minor lexical mismatch

apps/web/src/components/blog/charts.tsx

The TOU palette key is `intermedia` but the block label displayed in TouBlocksChart is `'Intermedio'`. DemandVsConsumptionChart also uses `Intermedio` in the axis label. The CFE convention uses 'intermedia' for the period name and 'intermedio' for the adjectival form — both are used in the same file, which could confuse future maintainers mapping color keys to displayed text.

low

CSS: blog link hover color change has no transition — flashes abruptly

apps/web/src/styles/blog-content.css

`.blog-content a:hover` switches `text-decoration-color` from brand-heliotrope to foreground instantly. Adding `transition: text-decoration-color 0.15s ease` to `.blog-content a` makes the interaction feel intentional with minimal cost.

History · 14 commits

  1. c27ea57needs attentionincremental3H · 5M · 4L2026-08-04 17:46
  2. ff69645needs attentionincremental0H · 6M · 8L2026-07-28 18:21
  3. 0257d74safeincremental0H · 0M · 0L2026-07-20 23:00
  4. 0795a9dsafeincremental0H · 0M · 2L2026-07-20 22:42
  5. 5c57414needs attentionincremental2H · 7M · 10L2026-07-20 22:29
  6. 5a57a8fneeds attentionincremental0H · 5M · 8L2026-07-20 17:14
  7. cc9056eneeds attentionfull1H · 3M · 9L2026-07-20 16:40
  8. 8b79d33needs attentionincremental5H · 7M · 11L2026-07-14 18:10
  9. f0c337cneeds attentionincremental1H · 1M · 5L2026-07-14 17:15
  10. 5c9de97needs attentionincremental0H · 5M · 7L2026-07-14 17:02current
  11. 92cce08needs attentionincremental1H · 4M · 3L2026-07-14 02:00
  12. b7dd610needs attentionincremental0H · 6M · 7L2026-07-14 01:43
  13. 8c43554needs attentionfull0H · 2M · 1L2026-07-14 01:15
  14. 2149391blockedfull8H · 6M · 7L2026-07-10 17:30