You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
motief/docs/plans/2026-05-26-001-overton-impr...

12 KiB

title type status date origin
Overton Window Analysis: Improvements and Extensions feat active 2026-05-26 docs/plans/2026-05-25-001-overton-window-analysis-gaps-plan.md

Overton Window Analysis: Improvements and Extensions

Summary

The current Overton window analysis is methodologically strong — multi-indicator, 2D extremity decomposition, causal timing, mechanism classification. But it has structural gaps that limit interpretability. This plan addresses six gaps: (1) right-wing party differentiation (PVV vs FVD vs JA21 vs SGP — who filed the motions?), (2) coalition coding fix (split 2024 into Rutte IV / Schoof periods), (3) voting margin analysis (the 96% ceiling makes pass rate useless — use actual voor/tegen percentages instead), (4) SVD temporal trajectory (plot the spatial drift over 10 annual windows), (5) mechanism classification validation (second classifier for inter-rater reliability), and (6) predictive modeling (what motion features predict centrist support?). Each unit is independent and can be executed in parallel.

Problem Frame

The synthesis report establishes that the Overton window did not shift right — right-wing parties moderated toward it. But the analysis treats right-wing parties as a bloc, uses a binary coalition coding that misattributes early 2024 motions, relies on pass rate as a success metric despite its 96% ceiling, and has no SVD visualization of the spatial drift. The mechanism classification (200 motions, single classifier) lacks inter-rater validation. Most critically, we have no predictive model: we can describe what happened but not what features predict which motions will gain centrist support.

Requirements

  • R1. Break down centrist support, extremity, and mechanism patterns by right-wing party (PVV, FVD, JA21, SGP) to identify which party drives the moderation effect
  • R2. Fix coalition coding by splitting 2024 into pre-Schoof (Rutte IV, Jan-Jun) and post-Schoof (Schoof, Jul-Dec) periods
  • R3. Replace pass rate with voting margin analysis (actual voor/tegen percentages) as the primary success metric
  • R4. Visualize SVD spatial drift over 10 annual windows showing centrist and right-wing trajectories
  • R5. Validate mechanism classification with a second classifier and compute inter-rater reliability (Cohen's kappa)
  • R6. Build a predictive model for centrist support using motion features (category, extremity scores, submitter party, mechanism, text features)

Scope Boundaries

  • In scope: Quantitative analysis of existing data, new visualizations, predictive modeling
  • Out of scope: Qualitative interviews, media analysis, public opinion data, international comparison
  • Deferred: Cross-domain interaction analysis (migration × security), network/gateway motion analysis, submitter-level MP analysis

Key Technical Decisions

  • Party differentiation: Use voting_results JSON from motions table to extract per-party vote counts. Compute party-specific centrist support separately for PVV, FVD, JA21, SGP motions.
  • Coalition coding: Split 2024 at July 1, 2024 (Schoof cabinet formation). Motions dated before July 2024 use Rutte IV coalition; after use Schoof coalition.
  • Voting margin: Compute margin = (voor - tegen) / (voor + tegen + afwezig) per motion. This gives a continuous [-1, 1] scale instead of binary pass/fail.
  • SVD trajectory: Use existing load_party_scores_all_windows_aligned() to get 2D positions for all parties across 10 windows. Plot as trajectory arrows.
  • Mechanism validation: Use a second LLM (different model or different prompt) to classify the same 200 motions. Compute Cohen's kappa.
  • Predictive model: Use logistic regression or random forest with features: category, stijl_extremiteit, materiele_impact, submitter_party, mechanism, text_length, keyword_count.

Implementation Units

U1. Right-Wing Party Differentiation

Goal: Break down all key metrics by right-wing party to identify which party drives the moderation effect.

Requirements: R1

Dependencies: None

Files:

  • Create: analysis/right_wing/party_differentiation.py
  • Output: reports/overton_window/party_differentiation.md
  • Output: reports/overton_window/party_differentiation_figure.png

Approach:

  • Parse voting_results JSON from motions table to identify the submitter party for each right-wing motion
  • Compute per-party: motion volume, mean centrist_support, mean extremity (2D), mechanism distribution
  • Stratify by period (pre vs post-2024)
  • Test whether PVV's moderation is distinct from FVD/JA21/SGP
  • Plot: 4-panel figure with (a) volume over time, (b) centrist support over time, (c) extremity over time, (d) mechanism distribution

Patterns to follow:

  • analysis/right_wing/overton_breakpoint_analysis.py — party-level analysis patterns
  • analysis/right_wing/classify_motions.py — submitter parsing from title

Test scenarios:

  • Happy path: Script produces per-party metrics for PVV, FVD, JA21, SGP across all years
  • Edge case: Multi-submitter motions (use first submitter)
  • Edge case: Parties with <10 motions in a year → exclude from party-level analysis

Verification:

  • Report contains per-party tables for volume, centrist support, extremity, mechanisms
  • Figure shows whether moderation is PVV-specific or party-general

U2. Coalition Coding Fix

Goal: Split 2024 into pre-Schoof (Rutte IV) and post-Schoof (Schoof) periods to eliminate coalition coding ambiguity.

Requirements: R2

Dependencies: None

Files:

  • Modify: analysis/right_wing/overton_breakpoint_analysis.py (coalition coding logic)
  • Modify: analysis/right_wing/temporal_trajectory.py (quarterly analysis)
  • Output: Updated reports with corrected coalition coding

Approach:

  • Define coalition periods: Rutte IV (2022-Oct to 2024-Jul), Schoof (2024-Jul to present)
  • Update is_opposition logic to use motion date for period detection
  • Re-run opposition-only analysis with corrected coding
  • Compare results with original binary coding

Patterns to follow:

  • analysis/right_wing/overton_breakpoint_analysis.py — existing coalition coding at line ~200

Test scenarios:

  • Happy path: Opposition-only analysis shows corrected centrist support trajectory
  • Edge case: Motions in July 2024 (transition month) → assign to Schoof
  • Integration: Results should be consistent with temporal trajectory findings

Verification:

  • Opposition-only centrist support trajectory is recalculated with corrected coding
  • Report explicitly states the coding change and its impact on findings

U3. Voting Margin Analysis

Goal: Replace binary pass/fail with continuous voting margin as the primary success metric.

Requirements: R3

Dependencies: None

Files:

  • Create: analysis/right_wing/voting_margin.py
  • Output: reports/overton_window/voting_margin.md
  • Output: reports/overton_window/voting_margin_figure.png

Approach:

  • Compute margin = (voor - tegen) / (voor + tegen + afwezig) for each right-wing motion
  • Analyze margin distribution by centrist support quartile
  • Test whether higher centrist support → higher margin (not just pass/fail)
  • Stratify by period (pre vs post-2024)
  • Plot: margin distribution by centrist support quartile, with period comparison

Patterns to follow:

  • analysis/right_wing/success_correlation.py — existing pass rate analysis

Test scenarios:

  • Happy path: Script computes margins for all right-wing motions, produces distribution figure
  • Edge case: Motions with 0 votes → exclude
  • Edge case: Motions with unanimous support → margin = 1.0

Verification:

  • Report contains margin distribution by centrist support quartile
  • Figure shows whether centrist support predicts voting margin (continuous) better than pass rate (binary)

U4. SVD Temporal Trajectory Visualization

Goal: Visualize SVD spatial drift over 10 annual windows showing centrist and right-wing party trajectories.

Requirements: R4

Dependencies: None

Files:

  • Create: analysis/right_wing/svd_trajectory_viz.py
  • Output: reports/overton_window/svd_trajectory_figure.png

Approach:

  • Use load_party_scores_all_windows_aligned() to get 2D positions for all parties across 10 windows
  • Plot: 2D compass with trajectory arrows for centrist parties (VVD, D66, CDA, NSC, BBB, CU) and right-wing parties (PVV, FVD, JA21, SGP)
  • Color by party, arrow direction shows temporal progression
  • Annotate windows with year labels

Patterns to follow:

  • analysis/right_wing/overton_svd_drift.py — existing SVD drift analysis
  • explorer.py — compass plotting with PARTY_COLOURS

Test scenarios:

  • Happy path: Figure shows clear trajectory arrows for all parties
  • Edge case: Missing party in a window → skip that arrow segment

Verification:

  • Figure shows whether centrist parties moved left while right-wing parties moved right
  • Trajectory arrows are clearly labeled with year markers

U5. Mechanism Classification Validation

Goal: Validate mechanism classification with a second classifier and compute inter-rater reliability.

Requirements: R5

Dependencies: None

Files:

  • Create: analysis/right_wing/mechanism_validation.py
  • Output: reports/overton_window/mechanism_validation.md

Approach:

  • Use a second LLM (different model or different prompt) to classify the same 200 motions
  • Compute Cohen's kappa for inter-rater reliability
  • Report disagreements and resolve them
  • Update mechanism classification with validated results

Patterns to follow:

  • analysis/right_wing/mechanism_classification.py — existing classification

Test scenarios:

  • Happy path: Second classifier produces classifications for all 200 motions
  • Edge case: Disagreements → report and resolve

Verification:

  • Report contains Cohen's kappa score
  • Disagreements are documented and resolved

U6. Predictive Modeling

Goal: Build a predictive model for centrist support using motion features.

Requirements: R6

Dependencies: U1 (party differentiation), U3 (voting margin)

Files:

  • Create: analysis/right_wing/predictive_model.py
  • Output: reports/overton_window/predictive_model.md
  • Output: reports/overton_window/predictive_model_figure.png

Approach:

  • Features: category, stijl_extremiteit, materiele_impact, submitter_party, mechanism, text_length, keyword_count
  • Target: centrist_support (binary: >0.5 = high, <=0.5 = low)
  • Models: logistic regression (interpretable), random forest (accuracy)
  • Evaluate: accuracy, precision, recall, AUC-ROC
  • Feature importance: which features best predict centrist support?

Patterns to follow:

  • analysis/right_wing/extremity_rescore_2d.py — batch processing patterns

Test scenarios:

  • Happy path: Model achieves AUC-ROC > 0.7
  • Edge case: Missing features → impute with median/mode

Verification:

  • Report contains model performance metrics and feature importance
  • Figure shows ROC curve and feature importance plot

System-Wide Impact

  • No database changes: All analysis uses existing tables
  • No UI changes: All outputs are markdown reports and PNG figures
  • No agent_tools changes: Analysis scripts are standalone
  • Reproducibility: All scripts are deterministic given the same database state

Risks & Dependencies

Risk Mitigation
Party differentiation may show PVV dominates everything Report per-party sample sizes; exclude parties with <10 motions
Coalition coding fix may not change findings Report both codings and compare
Voting margin may be correlated with pass rate Compute correlation; if r>0.95, margin adds no value
SVD trajectory may be too cluttered Use separate panels for centrist and right-wing
Mechanism validation may show low agreement Report kappa; if <0.6, revise taxonomy
Predictive model may overfit Use cross-validation; report train/test split

Sources & References

  • Current synthesis: reports/overton_window/overton_window_synthesis.md
  • Temporal trajectory: reports/overton_window/temporal_trajectory.md
  • Mechanism classification: reports/overton_window/mechanism_classification.md
  • SVD drift: analysis/right_wing/overton_svd_drift.py
  • Party positions: analysis/explorer_data.pyload_party_scores_all_windows_aligned()