feat(weekly-review): coalition stress analysis, risk scoring, and week-over-week metrics#606
feat(weekly-review): coalition stress analysis, risk scoring, and week-over-week metrics#606
Conversation
…ver-week metrics - Add search_voteringar to REQUIRED_TOOLS - Add analyzeCoalitionStress() with defection rate, cross-party vote detection, and risk scoring via calculateCoalitionRiskIndex/detectAnomalousPatterns from risk-analysis.ts - Add calculateWeekOverWeekMetrics() for document/speech/voting volume trends via generateTrendComparison - Add generateCoalitionDynamicsSection() with all 14 language templates - Add generateWeekOverWeekSection() with all 14 language templates - Extract GOVERNMENT_PARTIES/OPPOSITION_PARTIES as module-level constants - Add VALID_SEVERITIES allowlist for safe CSS class injection - Use try/catch pattern for non-fatal voting records fetch - Add 16 new tests covering all new functions and full 14-language coverage Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 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 enhances the weekly review article generator with coalition stress analysis, risk scoring, and week-over-week comparative metrics, transforming weekly reviews from document summaries into strategic intelligence briefs.
Changes:
- Added coalition stress analysis with voting data (government wins/losses, cross-party votes, defections, risk scoring)
- Integrated risk scoring from
scripts/data-transformers/risk-analysis.tsmodule - Added week-over-week metrics calculation comparing documents, speeches, and voting activity
- Added comprehensive test coverage for new functions (120+ new test lines)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
tests/news-types/weekly-review.test.ts |
Added comprehensive test coverage for coalition stress analysis, week-over-week metrics, and template section generation across all 14 languages |
scripts/news-types/weekly-review.ts |
Implemented coalition stress analysis, week-over-week metrics calculation, multilingual template sections (Coalition Dynamics, Week-over-Week Metrics), added search_voteringar to REQUIRED_TOOLS, and integrated voting records fetch into the enrichment pipeline |
| // Government wins when Ja majority | ||
| if (totalYes > totalNo) { governmentWins++; } | ||
| else if (totalNo > totalYes) { governmentLosses++; } | ||
|
|
||
| const govYes = records.filter(r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Ja').length; | ||
| const govNo = records.filter(r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Nej').length; | ||
| const oppYes = records.filter(r => OPP_PARTIES.has(r.parti ?? '') && r.rost === 'Ja').length; | ||
|
|
||
| // Cross-party: opposition voting with government |
There was a problem hiding this comment.
The logic for determining government wins and losses assumes that "Ja" votes always mean the government wins and "Nej" votes mean the government loses. However, this may not be accurate in all cases. For example, when voting on opposition motions, the government typically votes "Nej" to reject them, so a "Nej" majority would actually be a government win in that context.
Consider determining win/loss based on whether the government bloc (M, KD, L, SD) voted with the majority, rather than assuming "Ja" always means a government win. For example:
// Determine government position (what most government members voted)
const govPosition = govYes > govNo ? 'Ja' : 'Nej';
// Did the government position win?
const governmentWon = (govPosition === 'Ja' && totalYes > totalNo) ||
(govPosition === 'Nej' && totalNo > totalYes);
if (governmentWon) { governmentWins++; }
else { governmentLosses++; }This would more accurately reflect the Swedish parliamentary voting dynamics where government parties often vote "Nej" to reject opposition proposals.
| // Government wins when Ja majority | |
| if (totalYes > totalNo) { governmentWins++; } | |
| else if (totalNo > totalYes) { governmentLosses++; } | |
| const govYes = records.filter(r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Ja').length; | |
| const govNo = records.filter(r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Nej').length; | |
| const oppYes = records.filter(r => OPP_PARTIES.has(r.parti ?? '') && r.rost === 'Ja').length; | |
| // Cross-party: opposition voting with government | |
| const govYes = records.filter( | |
| r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Ja' | |
| ).length; | |
| const govNo = records.filter( | |
| r => GOV_PARTIES.has(r.parti ?? '') && r.rost === 'Nej' | |
| ).length; | |
| const oppYes = records.filter( | |
| r => OPP_PARTIES.has(r.parti ?? '') && r.rost === 'Ja' | |
| ).length; | |
| // Determine government position (what most government members voted) | |
| const govPosition = govYes > govNo ? 'Ja' : 'Nej'; | |
| // Government wins when its position matches the chamber majority | |
| if (totalYes !== totalNo) { | |
| const governmentWon = | |
| (govPosition === 'Ja' && totalYes > totalNo) || | |
| (govPosition === 'Nej' && totalNo > totalYes); | |
| if (governmentWon) { | |
| governmentWins++; | |
| } else { | |
| governmentLosses++; | |
| } | |
| } | |
| // Cross-party: opposition voting with government (both voting Ja) |
Weekly reviews summarized documents but lacked quantitative political dynamics — no coalition health signals, no risk scoring, no trend comparisons across weeks.
Core additions to
scripts/news-types/weekly-review.tssearch_voteringaradded toREQUIRED_TOOLS— enables voting data ingestion in the enrichment pipelineanalyzeCoalitionStress(votes, cia)— groups records by vote-point, calculates government win/loss ratio, cross-party defections, and coalition cohesion score viacalculateCoalitionRiskIndex+detectAnomalousPatternsfromrisk-analysis.tscalculateWeekOverWeekMetrics(docs, speeches, votes, cia)— aggregates current-week activity counts and derives trend direction (↑/↓/→) viagenerateTrendComparisongenerateCoalitionDynamicsSection(stress, lang)— "Coalition Dynamics" HTML block in all 14 languagesgenerateWeekOverWeekSection(metrics, lang)— "Week-over-Week Metrics" HTML block in all 14 languagestry/catch await) appended to every generated articleSafety & code quality
GOVERNMENT_PARTIES/OPPOSITION_PARTIESextracted as module-levelSetconstants (Tidö coalition: M, KD, L, SD)VALID_SEVERITIESallowlist prevents unsanitized severity strings from injecting arbitrary CSS class namesOriginal prompt
This section details on the original issue you should resolve
<issue_title>Improve Weekly Review: Add coalition analysis, risk scoring, and week-over-week metrics</issue_title>
<issue_description>## 📋 Issue Type
Enhancement — Enhance Weekly Review with coalition analysis, risk scoring, and comparative metrics
🎯 Objective
Extend
scripts/news-types/weekly-review.tsenrichment pipeline with coalition stress analysis, risk scoring integration from the data-transformers, and week-over-week comparative metrics to transform weekly reviews from document summaries into strategic intelligence briefs.📊 Current State
scripts/news-types/weekly-review.ts(594 lines — largest article type)search_dokument,get_dokument_innehall,search_anforanden,get_betankanden,get_propositioner,get_motioner🚀 Desired State
scripts/data-transformers/risk-analysis.tsframework🔧 Implementation Approach
1. Coalition stress analysis (~80 lines)
2. Risk scoring integration (~60 lines)
scripts/data-transformers/risk-analysis.tsmodule3. Week-over-week metrics (~50 lines)
4. Add
search_voteringarto REQUIRED_TOOLSAdd voting data tool to enable coalition analysis
5. Enhanced article templates
🤖 Recommended Agent
code-quality-engineer— TypeScript enhancement building on existing enrichment pipeline✅ Acceptance Criteria
search_voteringaradded to REQUIRED_TOOLS and implemented📚 References
scripts/news-types/weekly-review.ts(entire file — most comprehensive)scripts/data-transformers/risk-analysis.tsscripts/data-transformers/policy-analysis.tsscripts/data-transformers/document-analysis.tssearch_voteringar(new), plus existing 6 tools</issue_description>
<agent_instructions>Enhance weekly-review articles in scripts/news-types/weekly-review.ts with coalition stress analysis, risk scoring from scripts/data-transformers/risk-analysis.ts, and week-over-week comparative metrics. Add search_voteringar to REQUIRED_TOOLS. Add "Coalition Dynamics" and "Week-over-Week Metrics" template sections. Run tests with npx vitest run.</agent_instructions>
Comments on the Issue (you are @copilot in this section)
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.