11 KiB
| title | type | status | date |
|---|---|---|---|
| Visualize and Report Migration-Anti-Democratic Overlap Findings | feat | active | 2026-05-08 |
Visualize and Report Migration-Anti-Democratic Overlap Findings
Summary
Turn the Direction 3 analysis (migration as the dominant vehicle for anti-democratic rhetoric in right-wing motions) into a publishable artifact: committed script, visualizations, mechanism-coded extreme motions, and a findings report.
Problem Frame
The Direction 3 analysis script analysis/right_wing/direction3_migration_antidemocratic.py has been written and run successfully against all 2,986 scored right-wing motions. It uncovered strong evidence that migration is the primary carrier of anti-democratic extremity (45% of ≥4.0-scored motions are migration-related). However, the findings currently exist only as console output. They need to be preserved, visualized, deepened with mechanism coding, and compiled into a shareable report.
Requirements
- R1. The analysis script is committed to the feature branch.
- R2. Five focused charts visualize the key findings for immediate readability.
- R3. The 212 motions scoring ≥3.5 extremity are mechanism-coded via lightweight LLM batch.
- R4. A markdown report compiles numbers, charts, and mechanism coding into a narrative.
- R5. All artifacts are saved under
reports/right_wing_migration_antidemocratic/.
Scope Boundaries
- No new LLM pipeline infrastructure (reuses existing
ai_provider.chat_completion_json_parallelpattern fromextremity_scorer.py). - No changes to the database schema.
- No Streamlit UI integration (this is a research artifact, not a UI feature).
- No anti-democratic scoring pipeline for the full 2,986 motions (that would be Direction 2, deferred).
Deferred to Follow-Up Work
- Full anti-democratic scoring pipeline (Direction 2): separate plan if mechanism coding validates the concept.
- Streamlit tab to expose right-wing analysis tables: separate UI work.
Context & Research
Relevant Code and Patterns
analysis/right_wing/direction3_migration_antidemocratic.py— the analysis script to commitanalysis/right_wing/extremity_scorer.py— LLM batch pattern withchat_completion_json_parallelanalysis/right_wing/derive_categories.py— two-phase LLM approach (derive taxonomy, then apply)scripts/motion_drift.py— chart generation pattern using matplotlib, saved toreports/analysis/config.py—CANONICAL_RIGHT,CANONICAL_LEFT,PARTY_COLOURS
Institutional Learnings
docs/solutions/best-practices/svd-labels-voting-patterns-not-semantics.md— SVD labels should reflect voting patterns, not semantic content. Same discipline applies here: mechanism coding should reflect procedural/institutional characteristics, not just topic keywords.
Key Technical Decisions
- Matplotlib for charts: The repo already uses matplotlib in
scripts/motion_drift.pyandexplorer.py. No new charting library. - Reuse existing LLM batch infrastructure: The mechanism coder will call
ai_provider.chat_completion_json_parallelwith a JSON schema, same pattern as extremity/sentiment scoring. Batch size 10, ~22 batches for 212 motions. - Mechanism taxonomy (6 classes): punitive, exclusionary, sovereignty-claiming, procedural-breaking, institutional-dismantling, none. Chosen to capture the observed framing evolution from "keep them out" to "dismantle the system that lets them in."
- Reports directory:
reports/right_wing_migration_antidemocratic/mirrors thereports/drift/pattern.
Open Questions
Resolved During Planning
- Q: Which visualization library? Matplotlib — already used in the repo.
- Q: How many mechanisms to code? 6-class taxonomy, validated against the 5.0-scored motion sample.
Deferred to Implementation
- Q: Exact chart styling and color palette — depends on what looks good when rendered; iterate visually.
- Q: Whether to include migration-adjacent motions in the mechanism coding — start with pure migration (404), expand to adjacent (55) if time permits.
Implementation Units
- U1. Commit Direction 3 Analysis Script
Goal: Save the working analysis script to the feature branch.
Requirements: R1
Dependencies: None
Files:
- Create:
analysis/right_wing/direction3_migration_antidemocratic.py
Approach:
- The script already exists and produces correct output. Stage and commit it with a conventional message.
Test scenarios:
- Test expectation: none — this is a standalone analysis script with no testable behavior changes.
Verification:
- Script is committed to
feat/right-wing-motion-analysisand runs without errors.
- U2. Generate Five Key Visualizations
Goal: Produce charts that make the Direction 3 findings immediately readable.
Requirements: R2, R5
Dependencies: U1
Files:
- Create:
analysis/right_wing/visualize_direction3.py - Output:
reports/right_wing_migration_antidemocratic/*.png
Approach:
- Write a script that queries the scored data and generates 5 charts:
- Stacked bar: Category breakdown of ≥4.0 extremity motions (migration's 44.8% dominance)
- Line chart: Migration motion volume + avg extremity by year (2018–2026)
- Horizontal bar: Party avg extremity on migration (Wilders 3.79, Eerdmans 2.69, etc.)
- Grouped bar: Migration sentiment by extremity bucket (the −0.717 drop)
- Treemap or stacked bar: Migration + migration-adjacent by category (15.4% total footprint)
- Follow the matplotlib patterns from
scripts/motion_drift.pyandexplorer.py. - Save charts to
reports/right_wing_migration_antidemocratic/.
Patterns to follow:
scripts/motion_drift.py— chart saving withplt.savefig(), DPI settingsexplorer.py— color palette usinganalysis/config.PARTY_COLOURS
Test scenarios:
- Happy path: script runs and produces 5 PNG files in the reports directory.
- Edge case: empty result set for a chart component should render gracefully (e.g., skip treemap segment with zero count).
Verification:
- 5 PNG files exist in
reports/right_wing_migration_antidemocratic/and render legible charts.
- U3. Mechanism-Code the 212 Extreme Motions
Goal: Classify the anti-democratic mechanism for each motion scoring ≥3.5 extremity.
Requirements: R3
Dependencies: U1
Files:
- Create:
analysis/right_wing/mechanism_coder.py - Create:
data/mechanism_codes.json(or table:right_wing_mechanisms)
Approach:
- Query the 212 motion IDs with title, year, and category from
right_wing_motions+extremity_scores. - Use
ai_provider.chat_completion_json_parallelwith a JSON schema:{"mechanism": "punitive|exclusionary|sovereignty-claiming|procedural-breaking|institutional-dismantling|none", "confidence": 1-5, "rationale": "string"} - Batch size 10, ~22 batches. Skip already-coded motions for resumability.
- Store results in a new table
right_wing_mechanisms(motion_id, mechanism, confidence, rationale) withCREATE TABLE IF NOT EXISTS+INSERT OR REPLACE.
Execution note: Start with a small validation batch (10 motions) and spot-check the taxonomy before running the full 212.
Patterns to follow:
analysis/right_wing/extremity_scorer.py— batch loop,chat_completion_json_parallel, resumability patternanalysis/right_wing/derive_categories.py— two-phase validation (small sample first, then apply)
Test scenarios:
- Happy path: all 212 motions are coded with a valid mechanism and confidence 1–5.
- Edge case: LLM returns invalid JSON → retry or log error, don't crash.
- Edge case: script interrupted mid-batch → rerunning skips already-coded motions.
- Integration: mechanism table can be joined back to
right_wing_motionsfor reporting.
Verification:
right_wing_mechanismstable has 212 rows with no NULL mechanisms.- Spot-check 10 random rows: rationale is coherent and mechanism assignment is defensible.
- U4. Compile Findings Report
Goal: Write a markdown narrative pulling together numbers, charts, and mechanism coding.
Requirements: R4, R5
Dependencies: U2, U3
Files:
- Create:
reports/right_wing_migration_antidemocratic/findings_report.md
Approach:
- Structure the report around the 5 analytical sections from Direction 3:
- Overlap quantification (migration's 44.8% share of high extremity)
- Party strategy (PVV/Wilders dominance, JA21 volume-vs-intensity tradeoff)
- Framing shift (2018–2020 direct exclusion → 2023–2025 institutional dismantling)
- Cross-category adjacency (55 migration-adjacent motions, veiligheid/justitie as primary spillover)
- Sentiment divergence (migration as the only negative-sentiment category, −0.717 at high extremity)
- Embed the 5 charts using relative paths.
- Include a mechanism-coding summary table (distribution of the 6 mechanisms across categories and parties).
- Conclude with the bottom-line hypothesis confirmation.
Patterns to follow:
reports/drift/report.md— existing report format in the repo
Test scenarios:
- Happy path: report renders correctly in a markdown viewer with all images loading.
- Edge case: report references charts that don't exist → verify all image paths are valid.
Verification:
reports/right_wing_migration_antidemocratic/findings_report.mdexists and is a complete, readable narrative.- All chart references resolve to existing PNG files.
System-Wide Impact
- Interaction graph: None — this is a research artifact pipeline. No callbacks, middleware, or UI changes.
- Error propagation: LLM batch failures in U3 should log errors per-batch, not crash the script.
- State lifecycle risks: The
right_wing_mechanismstable is idempotent (INSERT OR REPLACE). Rerunning is safe. - API surface parity: No public API changes.
- Integration coverage: U3's integration with the LLM provider is the only cross-layer concern; verify the batch loop handles rate limits gracefully.
- Unchanged invariants: Database schema, existing right-wing analysis tables, Streamlit UI, and agent_tools surface remain untouched.
Risks & Dependencies
| Risk | Mitigation |
|---|---|
| LLM API costs for 212 motions exceed budget | Validate on 10-motion sample first; abort if cost-per-motion is unexpectedly high. |
| Mechanism taxonomy doesn't map cleanly to the data | Start with 6 classes; if LLM struggles, collapse to 4 or add an "other" catch-all. |
| Charts look unprofessional or cluttered | Iterate on 1–2 charts first, get feedback, then apply style to all 5. |
| Report becomes too long or unfocused | Cap at ~2,000 words; use summary tables and embedded charts to carry the narrative. |
Documentation / Operational Notes
- The report is intended for internal research consumption and potential external sharing. No operational rollout needed.
- If the mechanism coding validates the anti-democratic concept, it becomes the evidence base for a future Direction 2 plan (full anti-democratic scoring pipeline).
Sources & References
- Origin analysis:
analysis/right_wing/direction3_migration_antidemocratic.py - Related plan:
docs/plans/2026-05-05-001-feat-right-wing-motion-analysis-plan.md - Chart patterns:
scripts/motion_drift.py,explorer.py - LLM batch patterns:
analysis/right_wing/extremity_scorer.py,analysis/right_wing/derive_categories.py