Skip to content

Comments

feat: add election calendar with CII scoring integration#221

Open
Jacob-Strokus wants to merge 2 commits intokoala73:mainfrom
Jacob-Strokus:main
Open

feat: add election calendar with CII scoring integration#221
Jacob-Strokus wants to merge 2 commits intokoala73:mainfrom
Jacob-Strokus:main

Conversation

@Jacob-Strokus
Copy link

  • Add src/config/elections.ts with 25 global elections for 2026-2027
  • Integrate election proximity boost into Country Instability Index scoring
    • Election day: +15 pts, imminent (1-7d): +10, elevated (7-30d): +5
    • Significance multipliers: high=1.0, medium=0.6, low=0.3
    • Post-election uncertainty period (3 days): +8 pts
  • Display election badges in CII panel with days-until countdown
  • Add buildElectionBadge() using h() DOM helper (compatible with i18n refactor)
  • Export election utilities from config/index.ts
  • Add .cii-election-badge styles

Summary

Type of change

  • Bug fix
  • New feature
  • New data source / feed
  • New map layer
  • Refactor / code cleanup
  • Documentation
  • CI / Build / Infrastructure

Affected areas

  • Map / Globe
  • News panels / RSS feeds
  • AI Insights / World Brief
  • Market Radar / Crypto
  • Desktop app (Tauri)
  • API endpoints (/api/*)
  • Config / Settings
  • Other:

Checklist

  • Tested on worldmonitor.app variant
  • Tested on tech.worldmonitor.app variant (if applicable)
  • New RSS feed domains added to api/rss-proxy.js allowlist (if adding feeds)
  • No API keys or secrets committed
  • TypeScript compiles without errors (npm run typecheck)

Screenshots

image

- Add src/config/elections.ts with 25 global elections for 2026-2027
- Integrate election proximity boost into Country Instability Index scoring
  - Election day: +15 pts, imminent (1-7d): +10, elevated (7-30d): +5
  - Significance multipliers: high=1.0, medium=0.6, low=0.3
  - Post-election uncertainty period (3 days): +8 pts
- Display election badges in CII panel with days-until countdown
- Add buildElectionBadge() using h() DOM helper (compatible with i18n refactor)
- Export election utilities from config/index.ts
- Add .cii-election-badge styles
@vercel
Copy link

vercel bot commented Feb 22, 2026

Someone is attempting to deploy a commit to the Elie Team on Vercel.

A member of the Team first needs to authorize it.

@Jacob-Strokus
Copy link
Author

auth pls

@vercel
Copy link

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Feb 22, 2026 3:40am

Request Review

Copy link
Owner

@koala73 koala73 left a comment

Choose a reason for hiding this comment

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

Thanks for the initiative on this — election proximity as a CII scoring signal is a great idea and the integration architecture (config → scoring → badge) is clean. However, the election data needs significant corrections before we can merge.

Findings

P1 - High

Most election dates are inconsistent with IFES/official election cycles as of February 2026. This creates incorrect instability boosts and rank distortion.

PR entry Validation result
elections.ts:55 (Mexico 2026-06-07) IFES shows 2024 national election and 3-year/6-year legislative terms — 2026 is off-cycle (next legislative cycle is 2027 for deputies).
elections.ts:63 (Philippines 2026-05-11) IFES shows legislative election held 2025-05-12 — 2026 is off-cycle.
elections.ts:47 (Iran presidential 2026-06-18) IFES shows presidential election held 2024-07-05 and 4-year presidential term — 2026 is off-cycle.
elections.ts:151 (Germany 2027-09-26) Bundestag election was held 2025-02-23 and term is 4 years — regular cycle points to 2029, not 2027.
elections.ts:183 (India 2027-05-01) IFES shows 2024 Lok Sabha election and 5-year lower-house terms — 2027 is off-cycle absent early dissolution.
elections.ts:175 (South Korea presidential 2027-03-09) IFES shows presidential election held 2025-06-03 with 5-year term — 2027 is off-cycle.
elections.ts:217 (Norway 2027-09-13) IFES shows parliamentary election held 2025-09-08 and 4-year terms — 2027 is off-cycle.
elections.ts:241 (Liberia 2027-10-12) IFES shows 2023 presidential election and 6-year presidential terms — 2027 is off-cycle.
elections.ts:249 (Chile 2027-11-21) IFES shows presidential election held in 2025 and 4-year term — 2027 is off-cycle.
elections.ts:71 (Colombia 2026-03-08) ✅ Consistent (IFES confirms 2026-03-08 legislative election).
elections.ts:99 (US 2026-11-03) ✅ Consistent (IFES confirms 2026-11-03 midterm date).
elections.ts:81 (Brazil 2026-10-04) ✅ Consistent (IFES confirms 2026-10-04).

Timezone correctness bug: new Date('YYYY-MM-DD') is parsed at UTC midnight, then day distance uses local now with Math.floor. In US time zones this can become previous-day local time and produce early/late boosts (off-by-one day).

P2 - Medium

  • elections.ts:321 applies a post-election boost for -3 days, but elections.ts:371 (getElectionProximity) never returns a post-election proximity state. Result: score can be boosted while UI badge disappears, making the score jump non-explainable to users.
  • No tests were added for new election scoring/time boundaries (especially timezone/day-window edges), despite new ranking logic in country-instability.ts:651.

P3 - Low

  • CIIPanel.ts:66 hardcodes badge labels (TODAY, Xd) instead of using t() i18n like the rest of the panel.

Recommendation

The architecture and CII integration are solid — please:

  1. Rebuild the election calendar using IFES Election Guide as the source of truth
  2. Fix the UTC timezone bug in getDaysUntilElection()
  3. Add a post-election proximity state to match the scoring boost
  4. Add i18n keys for badge labels

Sources

P1 - High Priority:
- Remove off-cycle elections: Iran 2026-06-18, Mexico 2026-06-07, Philippines 2026-05-11
- Fix dates per IFES Election Guide:
  - Germany: 2027-09-26 → 2029-02-23 (4y term from 2025)
  - South Korea presidential: 2027-03-09 → 2030-06-03 (5y term)
  - India: 2027-05-01 → 2029-05-01 (5y term from 2024)
  - Norway: 2027-09-13 → 2029-09-10 (4y term)
  - Liberia: 2027-10-12 → 2029-10-09 (6y term)
  - Chile: 2027-11-21 → 2029-11-18 (4y term)
- Fix UTC timezone bug in getDaysUntilElection() to prevent off-by-one errors

P2 - Medium Priority:
- Add 'post-election' proximity state to ElectionProximity type
- getElectionProximity() now returns post-election for days -1 to -3
- Matches existing postElection scoring boost in getElectionCIIBoost()

P3 - Low Priority:
- Replace hardcoded badge labels with i18n keys via t()
- Add components.cii.election keys to all 16 locale files
  (en, fr, es, ar, ja, de, it, pt, ru, zh, pl, nl, sv, tr, th, vi)
Copy link
Author

@Jacob-Strokus Jacob-Strokus left a comment

Choose a reason for hiding this comment

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

Pushed changes to correct election calendar data

stevetodman pushed a commit to stevetodman/worldmonitor that referenced this pull request Feb 22, 2026
P1 - High Priority:
- Remove off-cycle elections: Iran 2026-06-18, Mexico 2026-06-07, Philippines 2026-05-11
- Fix dates per IFES Election Guide:
  - Germany: 2027-09-26 → 2029-02-23 (4y term from 2025)
  - South Korea presidential: 2027-03-09 → 2030-06-03 (5y term)
  - India: 2027-05-01 → 2029-05-01 (5y term from 2024)
  - Norway: 2027-09-13 → 2029-09-10 (4y term)
  - Liberia: 2027-10-12 → 2029-10-09 (6y term)
  - Chile: 2027-11-21 → 2029-11-18 (4y term)
- Fix UTC timezone bug in getDaysUntilElection() to prevent off-by-one errors

P2 - Medium Priority:
- Add 'post-election' proximity state to ElectionProximity type
- getElectionProximity() now returns post-election for days -1 to -3
- Matches existing postElection scoring boost in getElectionCIIBoost()

P3 - Low Priority:
- Replace hardcoded badge labels with i18n keys via t()
- Add components.cii.election keys to all 16 locale files
  (en, fr, es, ar, ja, de, it, pt, ru, zh, pl, nl, sv, tr, th, vi)
Copy link
Owner

@koala73 koala73 left a comment

Choose a reason for hiding this comment

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

Follow-up Review — Fix Commit 2cd6f1b

Thanks for the quick turnaround. The 4 items from the original review are addressed:

Original Item Status
Off-cycle elections (Iran/Mexico/Philippines) ✅ Removed
UTC timezone bug ✅ Fixed with Date.UTC() normalization
Missing post-election proximity state ✅ Added to type + getElectionProximity()
Hardcoded badge labels (i18n) ✅ Now uses t() across all 16 locales

However, verifying the remaining election dates against IFES/official sources reveals 6 more incorrect entries and 2 mislabeled ones:

P1 — Wrong dates (must fix)

Entry PR Date Reality Issue
Australia 2026-05-21 parliamentary Last federal election: May 3, 2025 (3yr max term) Next is ~2028. No 2026 federal election exists. Remove.
Japan 2026-07-25 parliamentary ("Upper House") Last HC election: July 20, 2025 (3yr cycle) Next HC is ~2028. A snap Lower House election was held Feb 8, 2026 — different chamber. Remove or correct to Lower House 2026-02-08 if retroactive entries are wanted.
Georgia 2026-10-26 presidential Georgia switched to indirect presidential elections in 2024 (electoral college). Next: ~2029. Oct 26 was the 2024 parliamentary election date, not a 2026 event. Remove.
Rwanda 2027-07-15 presidential Last presidential: July 15, 2024 (5yr term per 2015 amendment) Next is 2029, not 2027. Remove or correct to 2029.
Iran legislative 2027-03-01 Last Majlis election: March 1, 2024 (4yr term) Next is ~2028, not 2027. Correct to 2028.
UK 2027-12-17 parliamentary Last election: July 4, 2024. Latest possible: Aug 15, 2029. No evidence supports a 2027 election. Speculative date with no source. Remove or add caveat that this is a guess.

P2 — Mislabeled (should fix)

Entry Issue Fix
Czech Republic 2026-10-15 Labeled as parliamentary but the Chamber of Deputies was elected in 2025 (4yr term → ~2029). October 2026 has Senate + municipal elections (1/3 Senate renewal). Change type to 'local' or add a 'senate' type, and update notes.
Kazakhstan 2026-03-19 March 15, 2026 is a constitutional referendum, not a parliamentary election. If the referendum passes, parliament dissolves July 1 and new parliamentary elections follow ~Aug 2026. Either change to referendum date (Mar 15) with correct type, or change to the expected parliamentary election (~Aug 2026).

P2 — Still missing (from original review)

  • No tests for election scoring/timezone/day-window boundary logic. Given 9 of 25 original entries had wrong dates, automated validation would catch future drift.

Summary

Status Count
Original issues fixed 4/4 ✅
New wrong dates found 6
Mislabeled entries 2
Tests still missing 1

The corrected entries (Germany 2029, SK presidential 2030, India 2029, Norway 2029, Liberia 2029, Chile 2029) all verified correctly — good work on those. The 2026 entries that survived from the original commit are the ones that need attention now.

Recommendation: Cross-reference every remaining entry against IFES Election Guide before the next push.

Copy link
Owner

@koala73 koala73 left a comment

Choose a reason for hiding this comment

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

Final Review — PR #221

Thanks for fixing the original issues quickly — the UTC timezone fix, post-election proximity state, i18n badge labels, and removal of the 3 off-cycle elections are all solid. The architecture (config → scoring → badge) remains clean.

However, the following date/label issues must be resolved before merge:


P1 — Blocking (affects Tier1 CII scoring)

These are Tier1 countries where incorrect dates will trigger election boosts prematurely via getElectionCIIBoost() in country-instability.ts:648:

# File Issue
1 elections.ts:172 UK hardcoded to 2027-12-17 ("expected by December 2027"), but UK Electoral Commission states only "no later than 15 August 2029." No evidence supports a 2027 election. Will trigger GB election boost ~2 years too early. Remove or move to 2029 with speculative caveat.
2 elections.ts:236 Iran legislative set to 2027-03-01, but IFES shows the last Majlis election was 2024. Iran Constitution Art. 63 sets a 4-year term → next ~2028. Correct to 2028.

P2 — Should Fix (incorrect data, lower scoring impact)

# File Issue Fix
1 elections.ts:68 Australia 2026-05-21APH Library places the next federal election in the 2027–2028 window. No 2026 election exists. Remove or correct to ~2028.
2 elections.ts:86-88 Japan 2026-07-25 labeled "Upper House" — IFES shows 2026 was House of Representatives (snap), while HC was 2025 (next HC ~2028). Remove or correct chamber/date.
3 elections.ts:109-110 Georgia 2026-10-26 as direct presidential — IFES confirms president is indirectly elected by electoral college (since 2024), 5-year term → next ~2029. Remove.
4 elections.ts:212 Rwanda 2027-07-15 presidential — IFES shows 2024 election with 5-year term → next ~2029. Remove or correct to 2029.
5 elections.ts:101-102 Czech Republic 2026-10-15 labeled parliamentaryIFES identifies the 2026 event as Senate (1/3 renewal), not full parliamentary. Change type to 'local' and update notes.
6 elections.ts:117-118 Kazakhstan 2026-03-19 labeled parliamentaryIFES lists this as a constitutional referendum (March 15). Parliamentary elections would follow ~Aug 2026 if passed. Change to referendum with correct date, or move to expected parliamentary date.

Assumptions

  1. Severity is based on scoring impact: only Tier1 countries (US, GB, FR, DE, etc.) meaningfully affect the election boost path in country-instability.ts:648.
  2. Where sources provide cycle/term constraints rather than a declared polling day, corrections are inferred and should be marked tentative in the data notes.

Overall the feature is well-designed and close to mergeable. Once the dates above are corrected against the linked IFES sources, this is good to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants