← all branches

content/auto-draft-fix

needs attention
024e25c · fullpre-PRreviewed 2026-08-04 17:37 UTC0H · 1M · 3L · 13I
The branch
Purpose
Draft + fix a new pillar-cluster blog post on 'demanda contratada CFE' with accompanying SVG charts, following the content pipeline auto-draft workflow.
Goal
Publish a complete, SEO-ready blog post targeting the 'demanda contratada CFE' informational keyword, with code-generated charts that distinguish the four demand concepts readers confuse.
Sub-goals
  • SG-1: New MDX post demanda-contratada-cfe.mdx with full content (FAQ, Fuentes, cross-links)
  • SG-2: Hero chart ContractedDemandLadder distinguishing contratada/medida/derivada/facturable
  • SG-3: Three supporting charts: DemandUtilizationChart, PeakTimeShareHistogram, LoadFactorComparisonChart, PuntaDemandHeatmap
  • SG-4: Register new charts in page.tsx mdxComponents
  • SG-5: Advance calendar.yml status idea→review
The changes (whole branch)
What
Added 225-line MDX blog post, 457 lines of new SVG chart components (5 components), registered them in blog page mdxComponents, and flipped calendar status.
Why
Content pipeline scheduled this keyword as next priority in calendar.yml; the branch fixes a prior draft and adds the missing demand-visualization charts.
Areas
apps/web/content/blog/demanda-contratada-cfe.mdx+2250apps/web/src/components/blog/charts.tsx+4570apps/web/src/app/(marketing)/blog/[slug]/page.tsx+22apps/web/content/calendar.yml+11
Blast
4 files, +685/−3 lines; confined to apps/web content and components — no backend, no schema, no infra.
no-pr-yet gh-auth-expired
gh-ci· GitHub CLI auth invalid (devops-batu token expired) — CI status unavailablecoderabbit· No .coderabbit.yaml in repo

Findings · 14

correctness2

low

LoadFactorComparisonChart — 'same energy' claim is inaccurate (3030 vs 2930 kWh)

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

The two demand profiles have different hourly totals: peaky sums to 3030, flat to 2930 — a 3.4% gap. The subtitle 'Mismo consumo mensual, dos formas de consumirlo' is therefore inaccurate. Adjust one array so they match, or soften the subtitle to 'consumo similar'.

info

PeakTimeShareHistogram — toLocaleString('es-MX') may fall back on minimal-ICU Node builds

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

On a Node.js build without full ICU, 'es-MX' silently falls back to 'en-US', rendering 13,523 vs 13.523. Use `Intl.NumberFormat('es-MX').format(saving)` for explicitness, or verify full ICU is present in the build target.

security1

info

Security: clean

No security findings. All chart components are pure SVG with hardcoded data; no dangerouslySetInnerHTML, no user input, no credentials.

conventions4

medium

CTAs use plain markdown links, not the required Button component

apps/web/content/blog/demanda-contratada-cfe.mdx:217

The blog authoring standard requires CTAs to use `<Button variant="cta">` / `<Button variant="secondary">` from `@batu/ui`. Lines 217-219 use plain `→ [text](/path)` markdown links instead. Either add explicit JSX Button elements in the MDX or map a custom CTA component in mdxComponents.

low

Multi-line comment blocks on new chart components violate the no-docstring rule

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

Five new charts open with multi-paragraph `/** ... */` JSDoc blocks. The project rule says 'never write multi-paragraph docstrings or multi-line comment blocks'. Collapse to a single-line comment or remove entirely.

low

app.cfe.mx in Fuentes is plain text, not a hyperlink

apps/web/content/blog/demanda-contratada-cfe.mdx:227

Citations in Fuentes should be linkable where a canonical URL exists. Change to `[app.cfe.mx](https://app.cfe.mx/Aplicaciones/CCFE/Tarifas/TarifasCRENegocio/Tarifas/GranDemandaMTH.aspx)` for reader UX and GEO extractability.

info

TODO screenshot comment present — track in Linear before traffic scales

apps/web/content/blog/demanda-contratada-cfe.mdx:211

One `{/* TODO: screenshot real de la tabla de recibos... */}` placeholder exists. Per convention this is acceptable for a pending product screenshot, but it should be tracked in Linear so it's added before the post accumulates significant organic traffic.

tests1

info

No render smoke tests for mdxComponents registrations

apps/web/src/app/(marketing)/blog/[slug]/page.tsx

New chart components are registered in mdxComponents with no runtime assertion they render without throwing. TypeScript catches wiring errors at compile time; a Playwright smoke test on /blog/demanda-contratada-cfe would catch runtime errors. Consistent with existing pattern — no action required unless the team adds coverage for all blog routes.

improvement4

info

PuntaDemandHeatmap legend label field declared but never rendered

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

The `legend` array carries `label` strings ('bajo', '', '', '', 'pico') but the `.map()` only renders the color swatch — the label field is never used. Either drop the `label` key or render the labels alongside the swatches.

info

CAP_RATE 386.37 is function-scoped but also cited in MDX prose — sync risk on rate change

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

When CFE publishes a new resolution, this rate must be updated in both `PeakTimeShareHistogram` (local const) and `demanda-contratada-cfe.mdx` (prose on lines ~45 and 228). Extracting to a named export in a shared tariff module would prevent drift.

info

19 figcaptions repeat identical style object — candidate for a shared constant

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

Every chart repeats `style={{ fontSize: '0.8rem', color: MUTED, marginTop: '0.5rem' }}` on its figcaption. A module-level `CAPTION_STYLE` constant or a `.chart-caption` CSS class would eliminate the repetition.

info

Import line in page.tsx is ~460 chars — expanding to multi-line would improve diff readability

apps/web/src/app/(marketing)/blog/[slug]/page.tsx:10

Adding one chart currently produces a massive single-line diff. Multi-line named imports would make each new chart a clean one-line addition.

seo2

low

Sitemap priority is flat 0.7 for all blog posts regardless of pillar vs cluster

apps/web/src/app/sitemap.ts

Pillar posts (which aggregate more authority) could reasonably get 0.8. Sitemap priority is a weak signal but aligning it to content hierarchy is good hygiene. Not blocking for this PR.

info

Article JSON-LD has no image field — limits Top Stories eligibility

apps/web/src/app/(marketing)/blog/[slug]/page.tsx

Google's Article rich result guidelines recommend an `image` field. Adding `image: { '@type': 'ImageObject', url: 'https://batuenergy.com/og-image.png', width: 1200, height: 630 }` to the articleSchema would apply to all blog posts and improve rich result eligibility.