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.
255 lines
12 KiB
255 lines
12 KiB
---
|
|
title: "Overton Window Analysis: Improvements and Extensions"
|
|
type: feat
|
|
status: active
|
|
date: 2026-05-26
|
|
origin: 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.py` — `load_party_scores_all_windows_aligned()`
|
|
|