Skip to content

Improve article intelligence projection and generated article UX#1994

Merged
pethers merged 5 commits intomainfrom
copilot/improve-political-intelligence-quality
Apr 25, 2026
Merged

Improve article intelligence projection and generated article UX#1994
pethers merged 5 commits intomainfrom
copilot/improve-political-intelligence-quality

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 25, 2026

  • Fix Reader Intelligence Guide table headers (Reader need / What you'll get / Source artifact) — column 2 now matches the readerValue content
  • Replace bespoke anchorForTitle slugger with github-slugger (the same library rehype-slug uses) so guide anchors stay in sync with rendered heading IDs across punctuation/Unicode/duplicate cases
  • Replace rehype-slug with a custom rehypeSlugWithPrefix plugin that pre-prefixes heading IDs with rm-, keep rehype-sanitize's DOM-clobbering mitigation enabled (clobberPrefix: 'rm-', id dropped from clobber to avoid double-prefix), and align rehype-autolink-headings hrefs and the aggregator's Reader Intelligence Guide anchors to the same prefix
  • Translate article trust badges and aria-label across all 14 languages via LANGUAGE_META[lang].translations.articleTrust*
  • Wrap rendered <table> elements in <div class="rm-table-wrap"> via a custom rehype plugin and remove display: block from .rm-article-body table to preserve native table layout/semantics for assistive tech; idempotence guard accepts both string and string[] HAST className shapes so raw-HTML wrappers are not double-wrapped
  • Scope @media (prefers-color-scheme: light) rules to html:not([data-theme]) so an explicit data-theme="light" / data-theme="dark" always wins over the OS preference
  • Add github-slugger@^2.0.0 and hast-util-to-string to direct dependencies (no advisory issues)
  • Regenerate 25 analysis/daily/*/article.md aggregations and 50 EN/SV HTML articles to reflect the new prefixed slugs, table wrappers and translated badges
  • Verify build and 2132 tests pass

@github-actions github-actions Bot added documentation Documentation updates html-css HTML/CSS changes translation Translation updates testing Test coverage refactor Code refactoring news News articles and content generation size-xl Extra large change (> 1000 lines) labels Apr 25, 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,html-css,translation,testing,refactor,size-xl,news

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.

@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

Copilot AI requested a review from pethers April 25, 2026 09:35
@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

@pethers pethers marked this pull request as ready for review April 25, 2026 09:37
Copilot AI review requested due to automatic review settings April 25, 2026 09:37
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

This PR updates the article aggregation + rendering pipeline to better project “reader-intelligence-first” narratives and improve the generated article UX, while keeping provenance traceable.

Changes:

  • Reorders AGGREGATION_ORDER and injects a deterministic Reader Intelligence Guide into aggregated article.md.
  • Enhances rendered HTML article headers with a dek (description) and trust/provenance badges, plus CSS updates for the new layout.
  • Tightens provenance/source enumeration by excluding generated article*.md and pass1/ snapshots from artifact lists; updates docs/prompts accordingly.

Reviewed changes

Copilot reviewed 21 out of 97 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/render-lib.test.ts Updates aggregation-order expectations and adds coverage for reader guide text, link-stripping in metadata extraction, and dek rendering.
tests/render-lib-architecture.test.ts Adjusts architecture assertions to match new aggregation ordering and new header CSS hooks.
styles.css Adds styling for article dek + trust badges, refines article container, and light-scheme overrides.
scripts/render-lib/article.ts Renders the dek and trust/provenance badges inside the article header.
scripts/render-lib/aggregator.ts Re-documents and changes aggregation order; adds Reader Intelligence Guide generation and improved inline-markdown→text cleaning.
scripts/render-articles.ts Excludes pass1/ and generated article*.md from artifact enumeration used for source footers / JSON-LD isBasedOn.
political-intelligence.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_sv.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_da.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_no.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_fi.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_de.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_fr.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_es.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_nl.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_ar.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_he.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_ja.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_ko.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
political-intelligence_zh.html Regenerates collection page (counts + new stream listing + updated modified timestamps).
analysis/daily/2026-04-21/realtime-1353/article.md Shows the new Reader Intelligence Guide insertion and reordered sections in a real generated article.
Article-Generation.md Updates narrative-order documentation, fixes description example, and adds the “Future Improvements Roadmap” section + ToC entry.
.github/prompts/06-article-generation.md Updates workflow prompt contract to include reader guide insertion, new ordering, and refined source enumeration rules.

Comment on lines +224 to +230
'## Reader Intelligence Guide',
'',
'Use this guide to read the article as a political-intelligence product rather than a raw artifact dump. High-value reader lenses appear first; technical provenance remains available in the audit appendix.',
'',
'| Reader need | Where to go | Source artifact |',
'|---|---|---|',
...entries,
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The Reader Intelligence Guide table header doesn’t match the row content: the second column currently contains the “readerValue” (what the reader gets), not “Where to go”. This is confusing in the rendered article—either rename the header to reflect the content (e.g. “What you’ll get”) or change the row layout so the “Where to go” column is the anchor link and the first column is the reader need label.

Copilot uses AI. Check for mistakes.
Comment on lines +196 to +203
function anchorForTitle(title: string): string {
return title
.toLowerCase()
.normalize('NFKD')
.replace(/[^\p{L}\p{N}\s-]/gu, '')
.trim()
.replace(/\s+/g, '-');
}
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

anchorForTitle re-implements heading slug generation, but the actual HTML IDs are produced by rehype-slug (GitHub slugger). If these algorithms diverge (punctuation/Unicode/duplicate-heading suffixes), the Reader Intelligence Guide links will be broken. Consider using the same slugger library as rehype-slug, or emit explicit stable IDs for section headings (e.g. based on the artifact filename) and link to those.

Copilot uses AI. Check for mistakes.
Comment thread scripts/render-lib/article.ts Outdated
Comment on lines +145 to +149
<ul class="rm-article-trust-badges" aria-label="Article provenance and quality controls">
<li>Public sources</li>
<li>AI-FIRST review</li>
<li>Traceable artifacts</li>
</ul>
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The new trust-badge copy is hard-coded in English (and so is the aria-label). Since the site renders 14 languages and already has a LANGUAGE_META[lang].translations mechanism in chrome, these strings should be sourced from translations as well; otherwise non-English article pages will show English badges in the header.

Copilot uses AI. Check for mistakes.
Comment thread styles.css Outdated
Comment on lines +12547 to +12551
display: block;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
border: 1px solid color-mix(in srgb, var(--primary-cyan, #00d9ff) 12%, transparent);
border-radius: 8px;
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

Setting .rm-article-body table { display: block; } can break table layout/column sizing and may degrade table semantics for assistive tech. A more robust pattern is to keep the table’s native display and wrap it in a scroll container (or apply overflow to a wrapper element) so responsiveness doesn’t sacrifice table behavior.

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 25, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 25, 2026

@copilot apply changes based on the comments in this thread

Applied all four review points in 36414d7:

  • Reader Intelligence Guide column header is now What you'll get (matches the readerValue content) and the link in column 1 is the reader-need.
  • anchorForTitle now delegates to github-slugger (the same library rehype-slug uses) and rehype-sanitize's clobberPrefix is set to '' so the rendered heading IDs match the guide anchors exactly across punctuation/Unicode.
  • Trust badges and aria-label are sourced from LANGUAGE_META[lang].translations.articleTrust* for all 14 languages (fr/ar correctly placed after fixing a regex that broke on 'Pages d\'index…').
  • Tables are now wrapped in <div class="rm-table-wrap"> via a small rehype plugin; display: block is removed from .rm-article-body table so the native table layout and a11y semantics are preserved while the wrapper handles horizontal overflow.

All 25 aggregations and 50 EN/SV HTML articles regenerated; 2132 tests pass.

@github-actions github-actions Bot added the dependencies Dependency updates label Apr 25, 2026
@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

Copilot reviewed 21 out of 100 changed files in this pull request and generated 3 comments.

Comment thread scripts/render-lib/markdown.ts Outdated
Comment on lines 97 to 103
// Disable rehype-sanitize's default `user-content-` ID prefix so heading
// anchors generated by `rehype-slug` (and matched by the aggregator's
// Reader Intelligence Guide via `github-slugger`) resolve as written.
// The aggregator owns the entire markdown body — there is no untrusted
// user content here that could weaponise DOM-clobbering on element IDs.
clobberPrefix: '',
attributes: {
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

Setting clobberPrefix: '' disables the DOM-clobbering mitigation in rehype-sanitize. Even if content is “repo-owned”, headings/IDs still come from AI-generated artifacts and can be influenced by external inputs; keeping the prefix (or another non-empty prefix) is the safer default. Consider restoring a non-empty clobberPrefix and updating the Reader Intelligence Guide anchor generation to include that prefix so links still resolve.

Copilot uses AI. Check for mistakes.
Comment thread scripts/render-lib/markdown.ts Outdated
Comment on lines +67 to +75
// Skip if already wrapped (idempotent).
if (
parent.type === 'element' &&
(parent as Element).tagName === 'div' &&
Array.isArray((parent as Element).properties?.className) &&
((parent as Element).properties!.className as string[]).includes('rm-table-wrap')
) {
return;
}
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

rehypeWrapTables() checks properties.className only when it is an array. If a table is already wrapped via raw HTML (<div class="rm-table-wrap">), className can be a string in HAST, and this will fail the idempotence check and double-wrap tables. Consider accepting both string and string[] forms when detecting an existing wrapper.

Copilot uses AI. Check for mistakes.
Comment thread styles.css
Comment on lines +12836 to +12867
@media (prefers-color-scheme: light) {
html:not([data-theme="dark"]) .rm-article-body,
html:not([data-theme="dark"]) body.rm-article-body {
color: var(--text-color, #1a1a1a);
background: var(--bg-color, #f8f9fa);
}

html:not([data-theme="dark"]) .rm-article {
background: var(--card-bg, #ffffff);
border-color: var(--card-border, #dee2e6);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.08);
}

html:not([data-theme="dark"]) .rm-article-body p,
html:not([data-theme="dark"]) .rm-article-body li,
html:not([data-theme="dark"]) .rm-article-dek {
color: var(--text-color, #1a1a1a);
}

html:not([data-theme="dark"]) .rm-article-body strong { color: #000000; }
html:not([data-theme="dark"]) .rm-article-body a { color: var(--link-color, #007744); }
html:not([data-theme="dark"]) .rm-article-body a:hover { color: var(--primary-color, #006633); }

html:not([data-theme="dark"]) .rm-site-header,
html:not([data-theme="dark"]) .rm-site-footer {
background: #ffffff;
color: var(--text-secondary, #4a4a4a);
}

html:not([data-theme="dark"]) .rm-site-header {
border-bottom-color: var(--card-border, #dee2e6);
}
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The new @media (prefers-color-scheme: light) rules target html:not([data-theme="dark"]) ..., which also matches html[data-theme="light"]. Because these rules come after the existing html[data-theme="light"] block, they override explicit light-theme styling (e.g. .rm-site-header background gradient becomes plain white) whenever the OS prefers light. If the intent is only an OS-level fallback, scope these selectors to html:not([data-theme]) (so manual theme choice always wins), or align the overridden values with the existing html[data-theme="light"] rules.

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 25, 2026

@copilot apply changes based on the comments in this thread

…string className, scope OS dark/light to no-explicit-theme

Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/6e4d9e98-5993-43a2-8aaa-a8fca0d66ffb

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 25, 2026

@copilot apply changes based on the comments in this thread

Applied all three points in d467d92:

  • Restored a non-empty clobberPrefix (rm-). Heading IDs are now pre-prefixed by a custom rehypeSlugWithPrefix plugin (uses github-slugger, mirrors rehype-slug), and id is dropped from the sanitiser's clobber list so it doesn't double-prefix. name and aria-attribute clobbering protection is preserved, autolink-headings hrefs (href="#rm-…") match the rendered IDs, and the Reader Intelligence Guide stays in sync via ${HEADING_ID_PREFIX}${slug} in the aggregator.
  • rehypeWrapTables idempotence check now accepts both string and string[] HAST className shapes, so raw-HTML <div class="rm-table-wrap"> wrappers no longer get double-wrapped.
  • @media (prefers-color-scheme: light) rules are now scoped to html:not([data-theme]), so an explicit data-theme="light" or data-theme="dark" always wins over the OS preference.

25 aggregations + 50 EN/SV articles regenerated; build, lint and 2132 tests pass.

@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

@pethers pethers merged commit bea7119 into main Apr 25, 2026
27 checks passed
@pethers pethers deleted the copilot/improve-political-intelligence-quality branch April 25, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Dependency updates documentation Documentation updates html-css HTML/CSS changes news News articles and content generation refactor Code refactoring size-xl Extra large change (> 1000 lines) testing Test coverage translation Translation updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants