Skip to content

docs: 14-language title/description/SEO cascade from executive brief#2521

Merged
pethers merged 3 commits into
mainfrom
copilot/improve-article-generation-html
May 16, 2026
Merged

docs: 14-language title/description/SEO cascade from executive brief#2521
pethers merged 3 commits into
mainfrom
copilot/improve-article-generation-html

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 16, 2026

Improve Article-Generation.md — 14-language title, description and SEO metadata

Why

PR #2521 documented a 4-step per-language SEO cascade where executive-brief_<lang>.md H1 + BLUF supplies the localized <title> / <meta description>. Code review found chain step #2 was aspirational — the localized brief existed as a validator-enforced artifact (scripts/validate-executive-brief-translations.ts) but no render-lib code consumed it at HTML-render time. This continuation makes the documented cascade real, with a bounded-context implementation, tight tests, and doc/runtime parity.

What changed

  • Architecture / bounded context — new pure-function module scripts/render-lib/aggregator/seo/localized-brief.ts (~180 lines) implementing cascade chain step Sync styles.css from Hack23/homepage #2:
    • extractLocalizedBriefSeo({ briefMarkdown, subfolder }) returns { title, description } candidates from executive-brief_<lang>.md
    • Reuses existing pure functions (readFirstHeading, cleanArticleTitle, readBlufParagraph, readFirstParagraph, truncateToSentenceBoundary) so per-language extraction shares the English-side cleaning logic verbatim (no duplicated tradecraft)
    • isBannedLocalizedBriefH1() enforces parity with scripts/agentic/analysis-gate.ts § checkExecutiveBrief — rejects REPLACE THIS H1, Executive Brief Template, AI_MUST_REPLACE, AI-generated political intelligence, and bare boilerplate Executive Brief (case- and emoji-tolerant)
    • All-or-nothing-per-field semantics so a clean BLUF localizes the description even when the brief H1 is template stub
    • Exported from both aggregator/index.ts and the top-level render-lib/index.ts barrel
  • Validation / wire-upscripts/render-lib/article-merge.ts:
    • MergeLocalizedInput gains optional localizedBriefMarkdown + subfolder fields
    • When the brief yields a publishable H1 / BLUF, those override the per-type agent's article.<lang>.md front-matter title: / description: (independent fields)
    • Banned / empty brief falls through cleanly to chain step Bump actions/cache from 5.0.2 to 5.0.3 #3 (article front-matter) — no behaviour change for callers that omit the brief
  • Wire-upscripts/render-articles.ts renderOne() reads executive-brief_<lang>.md next to article.md and forwards it to the merger
  • QA — new pure-function tests in tests/localized-brief-seo.test.ts (18 cases): banned H1 variants, bare boilerplate, empty BLUF, first-paragraph fallback, sentence-boundary truncation, slug collision, all-empty inputs
  • QA — extended merge tests in tests/article-merge.test.ts (+5 cases): brief overrides FM, banned brief preserves FM title but localizes description, empty brief preserves both FM fields, omitted/empty localizedBriefMarkdown is a no-op
  • Doc parityArticle-Generation.md cascade rules now point at the new bounded-context module so the document and runtime agree; per-type workflow rule downgraded from MUST translate from brief to defence-in-depth runtime merger does it anyway
  • Validate — all 546 targeted tests pass (localized-brief-seo, article-merge, render-lib*, chrome-seo-features, jsonld-and-markdown-pipeline, structured-data, sitemap-generation, hreflang-validation, validate-article); tsc -p tsconfig.scripts.json --noEmit clean; ESLint clean on all touched files

Files

NEW   scripts/render-lib/aggregator/seo/localized-brief.ts     (+183)
NEW   tests/localized-brief-seo.test.ts                        (+264)
EDIT  scripts/render-lib/article-merge.ts                       (+50 / -2)
EDIT  scripts/render-lib/aggregator/index.ts                    (+13)
EDIT  scripts/render-lib/index.ts                               (+11)
EDIT  scripts/render-articles.ts                                (+16 / -2)
EDIT  tests/article-merge.test.ts                              (+114)
EDIT  Article-Generation.md                                     (+6 / -6)

Stacks cleanly on PR #2518 (executive-brief tradecraft) and PR #2519 (per-type workflow ownership): the cascade documented in PR #2521 now has a runtime implementation that defends against translator stubs leaking into SERP titles.

@github-actions github-actions Bot added documentation Documentation updates size-m Medium change (50-250 lines) labels May 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🏷️ Automatic Labeling Summary

This PR has been automatically labeled based on the files changed and PR metadata.

Applied Labels: documentation,size-m

Label Categories

  • 🗳️ Content: news, dashboard, visualization, intelligence
  • 💻 Technology: html-css, javascript, workflow, security
  • 📊 Data: cia-data, riksdag-data, data-pipeline, schema
  • 🌍 I18n: i18n, translation, rtl
  • 🔒 ISMS: isms, iso-27001, nist-csf, cis-controls
  • 🏗️ Infrastructure: ci-cd, deployment, performance, monitoring
  • 🔄 Quality: testing, accessibility, documentation, refactor
  • 🤖 AI: agent, skill, agentic-workflow

For more information, see .github/labeler.yml.

Copilot AI requested a review from pethers May 16, 2026 11:10
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions github-actions Bot added testing Test coverage refactor Code refactoring size-l Large change (250-1000 lines) labels May 16, 2026
@pethers pethers marked this pull request as ready for review May 16, 2026 11:29
Copilot AI review requested due to automatic review settings May 16, 2026 11:29
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements cascade chain step #2 of the per-language SEO cascade documented in Article-Generation.md: a new pure-function module reads executive-brief_<lang>.md H1 + BLUF and overrides the per-type agent's article.<lang>.md front-matter title: / description: at HTML-render time, with banned-phrase parity to analysis-gate.ts § checkExecutiveBrief.

Changes:

  • New scripts/render-lib/aggregator/seo/localized-brief.ts (pure functions extractLocalizedBriefSeo + isBannedLocalizedBriefH1) plus barrel re-exports.
  • article-merge.ts accepts optional localizedBriefMarkdown + subfolder and overlays brief-derived fields onto the localized front-matter; render-articles.ts reads executive-brief_<lang>.md next to article.md and forwards it.
  • New tests/localized-brief-seo.test.ts (18 cases) + extended tests/article-merge.test.ts (+5 cases); Article-Generation.md cascade section rewritten to match the runtime.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
scripts/render-lib/aggregator/seo/localized-brief.ts New pure module: brief H1+BLUF → localized SEO candidates, with banned-phrase rejection.
scripts/render-lib/article-merge.ts Optional localizedBriefMarkdown/subfolder inputs; overlays brief-derived title/description over FM.
scripts/render-articles.ts renderOne() reads executive-brief_<lang>.md next to article.md and forwards to merger.
scripts/render-lib/aggregator/index.ts Re-exports the new SEO module from aggregator barrel.
scripts/render-lib/index.ts Re-exports the new SEO module from top-level render-lib barrel.
tests/localized-brief-seo.test.ts New 18-case pure-function test suite for cascade chain step #2.
tests/article-merge.test.ts +5 cases covering brief overrides, banned/empty-brief fall-through, missing input.
Article-Generation.md Expanded cascade documentation with 4-step precedence chain table and 8-surface SEO derivation table.

@pethers pethers merged commit bb9c442 into main May 16, 2026
18 checks passed
@pethers pethers deleted the copilot/improve-article-generation-html branch May 16, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation updates refactor Code refactoring size-l Large change (250-1000 lines) size-m Medium change (50-250 lines) testing Test coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants