Fix SEO meta-description violations on legacy news/index pages#2832
Conversation
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ocs/api + script detour Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
…ERP budget) Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🏷️ Automatic Labeling SummaryThis PR has been automatically labeled based on the files changed and PR metadata. Applied Labels: html-css,i18n,translation,testing,refactor,size-m,news Label Categories
For more information, see |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
This pull request tightens SEO meta-description compliance for legacy news/*.html and localized homepages that can’t be regenerated (source analysis/daily/... deleted) by (a) applying static <meta ...description...> truncations to the deployed HTML and (b) adding renderer-side “never empty description” fallbacks to prevent future content="" emissions.
Changes:
- Update
buildSeoDescription()to synthesise a non-empty, story-relevant description when front-matterdescriptionstrips to empty (fallback to title, then article-type label), while still enforcing per-language hardMax budgets. - Add a chrome-level guard in
renderChromeHead()to ensure<meta name="description">/og:description/twitter:descriptionnever emit empty content when a caller passes blank/whitespace. - Apply static meta-description trims/fixes to affected legacy
news/*pages plusindex_ja.html/index_ko.htmlto stay within SERP hardMax constraints and remove malformed fragments.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/seo-budget-windows.test.ts | Adds coverage for synthesised description fallback behavior when description is empty. |
| tests/render-lib.test.ts | Updates SEO metadata test to expect title-based fallback instead of an empty description after malformed HTML is stripped. |
| tests/i18n-fallback-all-languages.test.ts | Updates 14-language matrix expectations: empty descriptions now fall back to per-language titles. |
| tests/chrome-seo-features.test.ts | Adds regression tests ensuring chrome never emits an empty meta description and mirrors fallback across OG/Twitter tags. |
| scripts/render-lib/chrome/head.ts | Adds defence-in-depth fallback to use page title when opts.description is blank/whitespace. |
| scripts/render-lib/article-seo.ts | Changes buildSeoDescription() to synthesise a non-empty description from title/articleTypeLabel when the stripped description is empty, capped to per-language hardMax. |
| news/2026-04-21-breaking-interpellationssvar-en.html | Static truncation of over-budget <meta name="description"> for legacy page. |
| news/2026-04-17-government-propositions-fr.html | Fixes malformed dangling fragment in description across description/og/twitter tags. |
| news/2026-04-03-breaking-1416-en.html | Static truncation of over-budget description (and OG mirror) to match renderer output. |
| news/2026-03-03-ai-facial-recognition-police-en.html | Static truncation of over-budget <meta name="description"> for legacy page. |
| news/2026-02-21-ai-strategy-nl.html | Static truncation of over-budget description across description/og/twitter tags. |
| news/2026-02-18-evening-analysis-zh.html | Static trim to bring CJK description within hardMax across description/og/twitter tags. |
| index_ko.html | Shortens Korean homepage meta description to fit CJK SERP hardMax while keeping a complete sentence. |
| index_ja.html | Shortens Japanese homepage meta description to fit CJK SERP hardMax while keeping a complete sentence. |
The 29 listed
news/*andindex_*pages are legacy: theiranalysis/daily/<date>/<subfolder>/sources were deleted, so they cannot be regenerated (aggregation requiresexecutive-brief.md). 8 of them carried meta-description violations of the per-language SERP budget contract (scripts/render-lib/aggregator/seo/serp-budgets.ts: Latin 140–200, CJK ja/ko/zh 70–120); the remaining 21 were already compliant. The renderer root cause was fixed earlier on this branch, so this change applies the equivalent corrections statically to the deployed legacy HTML.Changes
description(and mirroredog:descriptionwhere it duplicated) at the word boundary via the renderer's ownbuildSeoDescriptionoutput:news/2026-04-03-breaking-1416-en(208→189)news/2026-02-21-ai-strategy-nl(218→198, incl.twitter:)news/2026-04-21-breaking-interpellationssvar-en(203→197)news/2026-03-03-ai-facial-recognition-police-en(207→197)news/2026-02-18-evening-analysis-zh(121→120) acrossdescription/og:/twitter:.news/2026-04-17-government-propositions-frended in a dangling unclosed(Prop.fragment; stripped to end cleanly at…délinquants.(199→193) across all three tags.name="description"platform pitch to a complete grammatical sentence (dropped the trailing CIA/OSINT clause):index_ko(151→107),index_ja(155→106).og:/twitter:mirrors were already short and left untouched.Truncations reuse the renderer's
buildSeoDescriptionso the static output matches what regeneration would produce.Intentionally not changed
news/2026-03-26-committee-reports-sv= 71,news/2026-04-21-interpellation-debates-sv= 76): advisory-only, not a hard violation. The renderer never pads short descriptions, so padding would mean fabricating content — left as valid complete sentences.Scope
30 changed lines, all
<meta>description tags (name="description",property="og:description",name="twitter:description"); no markup, layout, or content-structure changes.Note: the live site currently shows missing descriptions on these pages due to a stale deploy predating the renderer fix; the next deploy picks up both the renderer fix and these static corrections.