Skip to content

feat(weekly-review): coalition stress analysis, risk scoring, and week-over-week metrics#606

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/enhance-weekly-review-analysis
Draft

feat(weekly-review): coalition stress analysis, risk scoring, and week-over-week metrics#606
Copilot wants to merge 2 commits intomainfrom
copilot/enhance-weekly-review-analysis

Conversation

Copy link
Contributor

Copilot AI commented Feb 26, 2026

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.ts

  • search_voteringar added to REQUIRED_TOOLS — enables voting data ingestion in the enrichment pipeline
  • analyzeCoalitionStress(votes, cia) — groups records by vote-point, calculates government win/loss ratio, cross-party defections, and coalition cohesion score via calculateCoalitionRiskIndex + detectAnomalousPatterns from risk-analysis.ts
  • calculateWeekOverWeekMetrics(docs, speeches, votes, cia) — aggregates current-week activity counts and derives trend direction (↑/↓/→) via generateTrendComparison
  • generateCoalitionDynamicsSection(stress, lang) — "Coalition Dynamics" HTML block in all 14 languages
  • generateWeekOverWeekSection(metrics, lang) — "Week-over-Week Metrics" HTML block in all 14 languages
  • Pipeline Step 6 — non-fatal voting records fetch (try/catch await) appended to every generated article

Safety & code quality

  • GOVERNMENT_PARTIES / OPPOSITION_PARTIES extracted as module-level Set constants (Tidö coalition: M, KD, L, SD)
  • VALID_SEVERITIES allowlist prevents unsanitized severity strings from injecting arbitrary CSS class names
  • Voting fetch failures are non-fatal — pipeline continues with empty records rather than hard-erroring
// Step 6: non-fatal voting fetch
let votingRecords: unknown[] = [];
try {
  votingRecords = (await client.fetchVotingRecords({ rm: '2025/26', limit: 50 })) as unknown[];
} catch (err: unknown) {
  console.error('Failed to fetch voting records:', err);
}
const coalitionStress = analyzeCoalitionStress(votingRecords as VotingRecord[], ciaContext);
const weekMetrics = calculateWeekOverWeekMetrics(documents, speeches, votingRecords as VotingRecord[], ciaContext);
Original 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.ts enrichment 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

  • File: scripts/news-types/weekly-review.ts (594 lines — largest article type)
  • REQUIRED_TOOLS: 6 tools — search_dokument, get_dokument_innehall, search_anforanden, get_betankanden, get_propositioner, get_motioner
  • Enrichment pipeline: Document search → Full text retrieval (concurrency-3) → Speech attachment → CIA context → typed metadata
  • Gap: Despite being the most comprehensive generator, weekly reviews lack coalition stress metrics, risk scoring, and week-over-week trend comparisons
  • Impact: Reviews summarize what happened but don't quantify political dynamics or track evolving patterns

🚀 Desired State

  • Coalition stress indicators calculated from voting patterns (defection rates, abstentions)
  • Risk scoring integrated from scripts/data-transformers/risk-analysis.ts framework
  • Week-over-week comparison (document volumes, voting activity, speech frequency)
  • Party discipline metrics (how often party members vote against party line)
  • Opposition alliance detection (cross-party motion co-sponsorship)
  • "Political Temperature" index — composite metric of parliamentary intensity
  • Historical comparison with same week in previous years

🔧 Implementation Approach

1. Coalition stress analysis (~80 lines)

// Fetch voting data for coalition stress indicators
const weekVotes = await mcpClient.call('search_voteringar', {
  rm: currentRiksmote,
  from_date: weekStart,
  to_date: weekEnd
});
// Calculate defection rates per party
const coalitionStress = analyzeCoalitionStress(weekVotes);
  • Track government vs opposition voting alignment
  • Identify votes where coalition partners diverged
  • Calculate a "coalition cohesion score"

2. Risk scoring integration (~60 lines)

  • Leverage existing scripts/data-transformers/risk-analysis.ts module
  • Apply risk scoring framework to weekly document activity
  • Flag high-risk policy areas (emerging controversies, constitutional issues)

3. Week-over-week metrics (~50 lines)

  • Compare document volumes: propositions, motions, betänkanden counts
  • Compare speech activity: total anföranden, party distribution
  • Compare voting activity: total votes, contentious votes ratio
  • Generate trend indicators (↑ increasing, ↓ decreasing, → stable)

4. Add search_voteringar to REQUIRED_TOOLS

Add voting data tool to enable coalition analysis

5. Enhanced article templates

  • Add "Coalition Dynamics" section
  • Add "Week-over-Week Metrics" comparison table
  • Add "Risk Indicators" sidebar
  • Add "Political Temperature" composite index
  • Update all 14 language templates

🤖 Recommended Agent

code-quality-engineer — TypeScript enhancement building on existing enrichment pipeline

✅ Acceptance Criteria

  • Coalition stress analysis implemented with defection rate metrics
  • Risk scoring integrated from data-transformers module
  • Week-over-week comparative metrics calculated and rendered
  • search_voteringar added to REQUIRED_TOOLS and implemented
  • Article templates include "Coalition Dynamics" and "Metrics" sections
  • All 14 language templates updated
  • Retrospective tone maintained (analytical, evidence-based)
  • Article quality validation passes
  • No regression in existing weekly review generation
  • Performance acceptable (< 30 seconds for full enrichment + new analysis)

📚 References

  • File: scripts/news-types/weekly-review.ts (entire file — most comprehensive)
  • Risk analysis: scripts/data-transformers/risk-analysis.ts
  • Policy analysis: scripts/data-transformers/policy-analysis.ts
  • Document analysis: scripts/data-transformers/document-analysis.ts
  • MCP Tools: search_voteringar (new), plus existing 6 tools
  • CIA methodology: Hack23/cia DATA_ANALYSIS_INTOP_OSINT.md (voting pattern analysis)
    </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.

…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>
Copilot AI changed the title [WIP] Enhance weekly review with coalition analysis and risk scoring feat(weekly-review): coalition stress analysis, risk scoring, and week-over-week metrics Feb 26, 2026
@pethers pethers requested a review from Copilot February 27, 2026 02:13
@github-actions github-actions bot added testing Test coverage refactor Code refactoring size-l Large change (250-1000 lines) labels Feb 27, 2026
@github-actions
Copy link
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
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 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.ts module
  • 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

Comment on lines +469 to +477
// 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
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
// 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)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactoring size-l Large change (250-1000 lines) testing Test coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve Weekly Review: Add coalition analysis, risk scoring, and week-over-week metrics

3 participants