![]()
๐๏ธ Comprehensive Political Data Architecture for Democratic Transparency
๐๏ธ 50+ Years Historical Data ยท 15 CIA Data Subsystems ยท 14-Language Support
๐ Document Owner: CEO | ๐ Version: 1.3 | ๐
Last Updated: 2026-05-06 (UTC)
๐ Review Cycle: Annual | โฐ Next Review: 2027-05-06
๐ข Owner: Hack23 AB (Org.nr 5595347807) | ๐ท๏ธ Classification: Public
This document defines the data model for the Riksdagsmonitor platform, documenting entity relationships, data structures, CIA product schemas, and data quality metrics for Swedish Parliament political data spanning 50+ years.
| Document | Focus | Description |
|---|---|---|
| ๐๏ธ Architecture | ๐๏ธ C4 Models | System context, containers, components |
| ๐ Data Model | ๐ Data | Entity relationships and data dictionary |
| ๐ Flowchart | ๐ Processes | Business and data flow diagrams |
| ๐ State Diagram | ๐ States | System state transitions and lifecycles |
| ๐ง Mindmap | ๐ง Concepts | System conceptual relationships |
| ๐ผ SWOT | ๐ผ Strategy | Strategic analysis and positioning |
| ๐ก๏ธ Security Architecture | ๐ Security | Current security controls and design |
| ๐ Future Security | ๐ฎ Security | Planned security improvements |
| ๐ฏ Threat Model | ๐ฏ Threats | STRIDE/MITRE ATT&CK analysis |
| ๐ง Workflows | ๐ง DevOps | CI/CD automation and pipelines |
| ๐ก๏ธ CRA Assessment | โ๏ธ Compliance | EU Cyber Resilience Act conformity |
| ๐ Future Architecture | ๐ฎ Evolution | Architectural evolution roadmap |
| ๐ Future Data Model | ๐ฎ Data | Enhanced data architecture plans |
| ๐ Future Flowchart | ๐ฎ Processes | Improved process workflows |
| ๐ Future State Diagram | ๐ฎ States | Advanced state management |
| ๐ง Future Mindmap | ๐ฎ Concepts | Capability expansion plans |
| ๐ผ Future SWOT | ๐ฎ Strategy | Future strategic opportunities |
Riksdagsmonitor maintains a comprehensive data architecture integrating 50+ years of Swedish Parliament data (1971-2026) with 15 data subsystems from the CIA platform, surfaced through the cia-data/ tree in this repository and re-exported as typed subpaths (./cia/*, ./dashboards/*, ./shared/*, ./ui/*) in the public riksdagsmonitor npm package (SLSA provenance attested). This document defines all data entities, relationships, schemas, pipelines, and integration patterns following Hack23 AB's ISMS standards (ISO 27001:2022, NIST CSF 2.0, CIS Controls v8.1, GDPR, NIS2).
Key Statistics:
cia-data/ (anomaly, coalition, committee, distribution, election, election-cycle, ministry, parties, party, percentile, politician, pre-election, risk, seasonal, voting) with 50+ CSV data filesTable: person_data
Records: 2,494 (349 active MPs)
Source: Swedish Riksdag API + CIA Platform
Update Frequency: Daily
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
person_id | VARCHAR(20) | PK | Unique person identifier (Swedish personal number format) | Riksdag API |
first_name | VARCHAR(100) | Given name | Riksdag API | |
last_name | VARCHAR(100) | Family name | Riksdag API | |
party | VARCHAR(10) | FK | Party abbreviation (S, M, SD, C, V, MP, KD, L) | Riksdag API |
gender | VARCHAR(10) | Gender classification | Riksdag API | |
born_year | INTEGER | Year of birth | Riksdag API | |
status | VARCHAR(50) | Current status (Tjรคnstgรถrande riksdagsledamot, Ledig, etc.) | Riksdag API | |
district | VARCHAR(100) | Electoral district (valkrets) | Riksdag API | |
img_url | VARCHAR(255) | Profile image URL | Riksdag API | |
last_activity_date | TIMESTAMP | Last recorded activity | CIA Platform | |
total_votes | INTEGER | Lifetime vote count | CIA Platform | |
total_documents | INTEGER | Documents authored | CIA Platform | |
risk_score | DECIMAL(5,2) | Risk assessment score (0-100) | CIA Platform | |
risk_level | VARCHAR(20) | Risk classification (LOW, MEDIUM, HIGH, CRITICAL) | CIA Platform | |
annual_absence_rate | DECIMAL(5,2) | Absence percentage (last 12 months) | CIA Platform | |
annual_rebel_rate | DECIMAL(5,2) | Rebellion rate against party (last 12 months) | CIA Platform |
Indexes:
person_idparty โ sweden_political_party.party_idstatus, party, risk_levelBusiness Rules:
status = 'Tjรคnstgรถrande riksdagsledamot'risk_score >= 50Table: sweden_political_party
Records: 40 (12 riksdag parties, 28 historical)
Source: Swedish Riksdag API + Election Authority
Update Frequency: Monthly (on party changes)
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
party_id | VARCHAR(10) | PK | Party abbreviation (S, M, SD, C, V, MP, KD, L) | Riksdag API |
party_name | VARCHAR(200) | Full party name (Swedish) | Riksdag API | |
party_name_en | VARCHAR(200) | Full party name (English) | Translation | |
founded_year | INTEGER | Year party was founded | Historical data | |
dissolved_year | INTEGER | Year party dissolved (NULL if active) | Historical data | |
ideology | VARCHAR(100) | Political ideology classification | Analysis | |
color | VARCHAR(7) | Brand color (hex code) | Party branding | |
website | VARCHAR(255) | Official website URL | Party data | |
riksdag_status | VARCHAR(20) | Status (RIKSDAG, HISTORICAL, EXTRA_PARLIAMENTARY) | Analysis | |
total_members_current | INTEGER | Current member count | CIA Platform | |
avg_win_rate | DECIMAL(5,2) | Average vote win rate (%) | CIA Platform | |
avg_discipline_score | DECIMAL(5,2) | Party discipline metric (%) | CIA Platform |
Indexes:
party_idriksdag_status, founded_yearBusiness Rules:
Party Descriptions:
| Party | Full Name (Swedish) | Full Name (English) | Ideology |
|---|---|---|---|
| S | Socialdemokraterna | Social Democrats | Social democracy |
| M | Moderaterna | Moderate Party | Liberal conservatism |
| SD | Sverigedemokraterna | Sweden Democrats | National conservatism |
| C | Centerpartiet | Centre Party | Agrarian liberalism |
| V | Vรคnsterpartiet | Left Party | Democratic socialism |
| MP | Miljรถpartiet | Green Party | Green politics |
| KD | Kristdemokraterna | Christian Democrats | Christian democracy |
| L | Liberalerna | Liberals | Social liberalism |
Table: committee_document_data
Records: 8,740 committee documents
Source: Swedish Riksdag API
Update Frequency: Daily
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
committee_id | VARCHAR(10) | PK | Committee abbreviation (AU, FiU, UU, etc.) | Riksdag API |
committee_name | VARCHAR(200) | Full committee name (Swedish) | Riksdag API | |
committee_name_en | VARCHAR(200) | Full committee name (English) | Translation | |
document_id | VARCHAR(50) | FK | Document identifier | Riksdag API |
document_type | VARCHAR(50) | Document type (bet, utskskr, etc.) | Riksdag API | |
published_date | DATE | Publication date | Riksdag API | |
title | TEXT | Document title | Riksdag API | |
summary | TEXT | Document summary | Riksdag API | |
assigned_members | JSON | Array of person_ids assigned | CIA Platform |
Indexes:
committee_id + document_iddocument_id โ document_data.document_idpublished_date, document_typeSwedish Riksdag Committees (15):
| Code | Swedish Name | English Name | Jurisdiction |
|---|---|---|---|
| AU | Arbetsmarknadsutskottet | Labour Market Committee | Employment, labour law |
| CU | Civilutskottet | Civil Affairs Committee | Justice, civil law |
| FiU | Finansutskottet | Finance Committee | Budget, taxation |
| FรถU | Fรถrsvarsutskottet | Defence Committee | Defence, military |
| JuU | Justitieutskottet | Justice Committee | Criminal law, courts |
| KU | Konstitutionsutskottet | Constitutional Committee | Constitution, governance |
| KrU | Kulturutskottet | Cultural Affairs Committee | Culture, media, religion |
| MJU | Miljรถ- och jordbruksutskottet | Environment and Agriculture Committee | Environment, farming |
| NU | Nรคringsutskottet | Industry and Trade Committee | Business, energy |
| SkU | Skatteutskottet | Tax Committee | Tax policy |
| SoU | Socialutskottet | Social Affairs Committee | Healthcare, welfare |
| SfU | Socialfรถrsรคkringsutskottet | Social Insurance Committee | Social insurance |
| TU | Trafikutskottet | Transport Committee | Infrastructure, transport |
| UU | Utrikesutskottet | Foreign Affairs Committee | Foreign policy, EU |
| UtbU | Utbildningsutskottet | Education Committee | Education, research |
Table: document_data
Records: 109,259
Source: Swedish Riksdag API
Update Frequency: Daily
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
document_id | VARCHAR(50) | PK | Unique document identifier (e.g., H901FiU1) | Riksdag API |
document_type | VARCHAR(50) | Type code (mot, prop, bet, skr, etc.) | Riksdag API | |
document_number | VARCHAR(20) | Sequential number within type | Riksdag API | |
rm | VARCHAR(10) | Riksmรถte (parliamentary year, e.g., 2024/25) | Riksdag API | |
title | TEXT | Document title | Riksdag API | |
subtitle | TEXT | Document subtitle | Riksdag API | |
published_date | DATE | Publication date | Riksdag API | |
status | VARCHAR(50) | Processing status | Riksdag API | |
organ | VARCHAR(10) | Responsible committee | Riksdag API | |
authors | JSON | Array of person_ids (authors) | Riksdag API | |
fulltext | TEXT | Full document text (optional) | Riksdag API | |
attachments | JSON | Array of attachment URLs | Riksdag API | |
related_documents | JSON | Array of related document_ids | Riksdag API |
Indexes:
document_iddocument_type, rm, published_date, organtitle, subtitle, fulltextDocument Types:
| Type Code | Swedish Name | English Name | Count | Description |
|---|---|---|---|---|
| mot | Motion | Motion | 94,633 | MP-initiated proposals |
| prop | Proposition | Government Bill | 5,738 | Government proposals |
| bet | Betรคnkande | Committee Report | 58,231 | Committee decisions |
| skr | Skrivelse | Communication | ~2,000 | Government communications |
| ip | Interpellation | Interpellation | ~5,000 | Questions to ministers |
| fr | Frรฅga | Written Question | ~8,000 | Written questions |
| sou | Statens offentliga utredningar | Government Official Reports | External | Public investigations |
| ds | Departementsserien | Ministry Report Series | External | Ministry reports |
Table: vote_data
Records: 3,529,786
Source: Swedish Riksdag API
Update Frequency: Real-time (after votes)
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
vote_id | VARCHAR(50) | PK | Unique vote identifier | CIA Platform |
ballot_id | VARCHAR(50) | FK | Ballot session identifier | Riksdag API |
person_id | VARCHAR(20) | FK | Voter person_id | Riksdag API |
party | VARCHAR(10) | FK | Party at time of vote | Riksdag API |
vote | VARCHAR(20) | Vote cast (Ja, Nej, Avstรฅr, Frรฅnvarande) | Riksdag API | |
vote_date | DATE | Date of vote | Riksdag API | |
vote_time | TIME | Time of vote | Riksdag API | |
issue | TEXT | Issue being voted on | Riksdag API | |
document_id | VARCHAR(50) | FK | Related document | Riksdag API |
committee | VARCHAR(10) | Responsible committee | Riksdag API | |
is_rebel_vote | BOOLEAN | Vote against party line | CIA Platform | |
is_winning_vote | BOOLEAN | Vote with majority | CIA Platform |
Indexes:
vote_idperson_id, party, ballot_id, document_idvote_date, party, is_rebel_voteVote Classifications:
Metrics Derived:
(winning_votes / total_votes) * 100(rebel_votes / total_votes) * 100((total_votes - absent) / total_ballots) * 100Table: government_body_data
Records: 6,520 (20 governments, 76 roles, 500 role members)
Source: Swedish Government + CIA Platform
Update Frequency: On government changes
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
ministry_id | VARCHAR(50) | PK | Ministry identifier | Government data |
ministry_name | VARCHAR(200) | Ministry name (Swedish) | Government data | |
ministry_name_en | VARCHAR(200) | Ministry name (English) | Translation | |
government_id | VARCHAR(50) | FK | Government identifier | Government data |
start_date | DATE | Ministry start date | Government data | |
end_date | DATE | Ministry end date (NULL if current) | Government data | |
minister_person_id | VARCHAR(20) | FK | Current/last minister | Government data |
party | VARCHAR(10) | FK | Party affiliation | Government data |
portfolio | VARCHAR(200) | Portfolio responsibilities | Government data | |
decision_count | INTEGER | Total decisions made | CIA Platform | |
effectiveness_score | DECIMAL(5,2) | Effectiveness metric (0-100) | CIA Platform | |
risk_level | VARCHAR(20) | Risk classification | CIA Platform |
Indexes:
ministry_idgovernment_id, minister_person_id, partystart_date, end_date, effectiveness_scoreCurrent Swedish Ministries (11):
| Ministry | Swedish Name | Minister | Portfolio |
|---|---|---|---|
| Prime Minister's Office | Statsrรฅdsberedningen | Prime Minister | Overall government coordination |
| Finance | Finansdepartementet | Finance Minister | Budget, taxes, economy |
| Foreign Affairs | Utrikesdepartementet | Foreign Minister | International relations |
| Defence | Fรถrsvarsdepartementet | Defence Minister | Military, security |
| Justice | Justitiedepartementet | Justice Minister | Courts, police, law |
| Interior | Inrikesdepartementet | Interior Minister | Migration, citizenship |
| Health & Social Affairs | Socialdepartementet | Social Affairs Minister | Healthcare, welfare |
| Employment | Arbetsmarknadsdepartementet | Employment Minister | Labour market |
| Education | Utbildningsdepartementet | Education Minister | Schools, universities |
| Environment | Miljรถdepartementet | Environment Minister | Climate, nature |
| Infrastructure | Infrastrukturdepartementet | Infrastructure Minister | Transport, housing |
Table: government_role_data
Records: 76 roles, 500 role members
Description: Cabinet positions and government appointments
| Field Name | Data Type | Key | Description | Source |
|---|---|---|---|---|
role_id | VARCHAR(50) | PK | Role identifier | Government data |
role_name | VARCHAR(200) | Role title (Swedish) | Government data | |
role_name_en | VARCHAR(200) | Role title (English) | Translation | |
role_type | VARCHAR(50) | Type (Minister, State Secretary, etc.) | Government data | |
ministry_id | VARCHAR(50) | FK | Parent ministry | Government data |
person_id | VARCHAR(20) | FK | Current holder | Government data |
start_date | DATE | Role assignment start | Government data | |
end_date | DATE | Role assignment end (NULL if current) | Government data | |
party | VARCHAR(10) | FK | Party affiliation | Government data |
Role Types:
The CIA data layer is organised along two complementary axes. 15 subsystems correspond to the 15 top-level data domains materialised under
cia-data/(anomaly,coalition,committee,distribution,election,election-cycle,ministry,parties,party,percentile,politician,pre-election,risk,seasonal,voting), each backed by one or more CSV extracts and, where applicable, a JSON Schema underschemas/. Those subsystems surface as 19 user-facing analytical products โ 4 intelligence dashboards + 10 Top-10 rankings + 5 advanced analytics โ enumerated below. Both counts are filesystem-verified against the current repository.
Product Name: Riksdag Intelligence Overview
Purpose: Comprehensive snapshot of parliamentary activity
Data Files:
view_riksdagen_politician_sample.csvview_riksdagen_party_summary_sample.csvcia-data/production-stats.jsonKey Fields & Metrics:
Dashboard Integration: Homepage overview section
Update Frequency: Daily (03:00 CET)
Product Name: Party Performance & Effectiveness Analytics
Purpose: Longitudinal party analysis (1990-2026, 37 years)
Data Files:
cia-data/party/view_party_effectiveness_trends_sample.csvcia-data/party/view_party_performance_metrics_sample.csvcia-data/party/distribution_party_effectiveness_trends.csvcia-data/party/distribution_party_momentum.csvKey Fields & Metrics:
| Field | Type | Description |
|---|---|---|
party | VARCHAR(10) | Party abbreviation |
year | INTEGER | Analysis year |
performance_score | DECIMAL(5,2) | Overall performance (0-100) |
win_rate | DECIMAL(5,2) | Vote success rate (%) |
discipline_score | DECIMAL(5,2) | Party unity metric (%) |
document_productivity | INTEGER | Documents produced |
avg_attendance | DECIMAL(5,2) | Attendance rate (%) |
effectiveness_trend | VARCHAR(20) | Trend direction (IMPROVING, DECLINING, STABLE) |
momentum_percentile | DECIMAL(5,2) | Performance percentile (0-100) |
Dashboard Integration: Party Performance Dashboard (index.html)
Visualizations:
Update Frequency: Daily
Product Name: Ministry Performance Scorecards
Purpose: Cabinet-level analysis and ministry effectiveness
Data Files:
cia-data/ministry/distribution_ministry_effectiveness.csvcia-data/ministry/distribution_ministry_decision_impact.csvcia-data/ministry/distribution_ministry_productivity_matrix.csvcia-data/ministry/distribution_ministry_risk_levels.csvKey Fields & Metrics:
| Field | Type | Description |
|---|---|---|
ministry_name | VARCHAR(200) | Ministry name |
minister | VARCHAR(200) | Current minister |
party | VARCHAR(10) | Party affiliation |
decision_count | INTEGER | Decisions made |
effectiveness_score | DECIMAL(5,2) | Effectiveness metric (0-100) |
impact_score | DECIMAL(5,2) | Decision impact (0-100) |
risk_level | VARCHAR(20) | Risk classification |
productivity_matrix | VARCHAR(50) | Productivity classification |
Dashboard Integration: Ministry Dashboard
Visualizations:
Update Frequency: Weekly
Product Name: Historical Patterns & Trend Forecasting
Purpose: Election cycle intelligence (1994-2034, 9 cycles)
Data Files:
cia-data/election-cycle/view_election_cycle_comparative_analysis_sample.csv (1,110 records, 153KB)cia-data/election-cycle/view_election_cycle_decision_intelligence_sample.csv (414 records, 59KB)cia-data/election-cycle/view_election_cycle_predictive_intelligence_sample.csv (41 records, 3.9KB)cia-data/election-cycle/view_election_cycle_temporal_trends_sample.csv (74 records, 8.7KB)Key Fields & Metrics:
| Field | Type | Description |
|---|---|---|
election_cycle_id | VARCHAR(20) | Cycle identifier (e.g., "2022-2026") |
cycle_year | INTEGER | Cycle number |
calendar_year | INTEGER | Specific year |
semester | VARCHAR(20) | Time period (annual, spring, autumn) |
party | VARCHAR(10) | Party abbreviation |
performance_score | DECIMAL(5,2) | Performance metric (0-100) |
decision_effectiveness | VARCHAR(50) | Effectiveness category |
risk_forecast_category | VARCHAR(50) | Risk forecast level |
forecast_confidence | VARCHAR(20) | Confidence level (low, moderate, high) |
Dashboard Integration: Election Cycle Dashboard (src/browser/dashboards/election-cycle.ts)
Visualizations:
Update Frequency: Daily
Product Name: Politician Influence Network Analysis
Purpose: Identify MPs with highest influence scores
Data Files:
cia-data/politician/view_riksdagen_politician_influence_metrics_sample.csvKey Fields:
person_id, first_name, last_name, partyinfluence_score (0-100)network_centrality (0-1)committee_influencecross_party_connectionsRanking Criteria: Influence score (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Weekly
Product Name: Legislative Output Analysis
Purpose: Rank MPs by document production
Data Files:
cia-data/politician/view_riksdagen_politician_sample.csvKey Fields:
person_id, first_name, last_name, partydocuments_last_year (INTEGER)total_documents (INTEGER)document_types (JSON array)Ranking Criteria: Documents produced (last 12 months, descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Voting Pattern Outlier Detection
Purpose: Identify MPs with highest rebellion rates
Data Files:
cia-data/politician/view_politician_behavioral_trends_sample.csvKey Fields:
person_id, first_name, last_name, partyannual_rebel_rate (0-100%)controversial_votes (count)party_discipline_deviationRanking Criteria: Rebel rate (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Attendance Tracking
Purpose: Monitor MP absences
Data Files:
cia-data/politician/view_politician_risk_summary_sample.csvKey Fields:
person_id, first_name, last_name, partyannual_absence_rate (0-100%)absenteeism_violations (count)attendance_trendRanking Criteria: Absence rate (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Cross-Party Voting Analysis
Purpose: Identify MPs who frequently vote against party line
Data Files:
cia-data/voting/distribution_voting_anomaly_classification.csvKey Fields:
person_id, party, rebel_vote_countparty_line_deviation_pctcoalition_alignment_scoreRanking Criteria: Rebel votes (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Cross-Party Collaboration Patterns
Purpose: Identify MPs facilitating coalition work
Data Files:
cia-data/coalition/distribution_coalition_alignment.csvKey Fields:
person_id, coalition_scorecross_party_proposalsbridge_connectionsRanking Criteria: Coalition score (descending)
Dashboard Integration: Coalition Dashboard
Update Frequency: Weekly
Product Name: Emerging Political Figures
Purpose: Identify rapidly advancing politicians
Data Files:
cia-data/politician/view_politician_behavioral_trends_sample.csvKey Fields:
person_id, career_trajectorymomentum_scoremedia_mentions_growthinfluence_accelerationRanking Criteria: Momentum score (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Weekly
Product Name: MPs at Election Risk
Purpose: Predict electoral vulnerability
Data Files:
cia-data/politician/view_politician_risk_summary_sample.csvKey Fields:
person_id, risk_score (0-100)risk_level (LOW, MEDIUM, HIGH, CRITICAL)risk_factors (JSON array)Ranking Criteria: Risk score (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Rule Violation Tracking
Purpose: Monitor transparency and ethics violations
Data Files:
cia-data/politician/view_politician_risk_summary_sample.csvKey Fields:
person_id, total_violationsviolation_types (effectiveness, discipline, productivity, collaboration)latest_violation_dateRanking Criteria: Total violations (descending)
Dashboard Integration: Politician Dashboard
Update Frequency: Daily
Product Name: Public Visibility Index
Purpose: Track media mentions and public visibility
Data Files:
Key Fields:
person_id, media_mentions_countvisibility_score (0-100)sentiment_average (-1 to +1)Ranking Criteria: Media mentions (descending)
Dashboard Integration: Placeholder
Update Frequency: Weekly
Product Name: Committee Influence Mapping
Purpose: Visualize committee assignments and influence
Data Files:
cia-data/committee/view_riksdagen_committee_decisions.csvcia-data/committee/distribution_annual_committee_documents.csvKey Fields & Metrics:
committee_id, committee_nameassigned_members (JSON array)document_count, decision_countproductivity_score (0-100)influence_centrality (0-1)Dashboard Integration: Committee Dashboard
Visualizations:
Update Frequency: Weekly
Product Name: Career Trajectory Tracking
Purpose: Analyze politician career paths and milestones
Data Files:
cia-data/politician/view_riksdagen_politician_experience_summary_sample.csvcia-data/politician/distribution_experience_levels.csvKey Fields & Metrics:
person_id, career_start_date, total_yearsroles_held (JSON array)committee_assignments_historygovernment_positionsexperience_level (JUNIOR, INTERMEDIATE, SENIOR, VETERAN)Dashboard Integration: Politician Dashboard
Visualizations:
Update Frequency: Monthly
Product Name: 50+ Years of Party Evolution
Purpose: Historical party performance (1971-2026)
Data Files:
cia-data/party/view_party_effectiveness_trends_sample.csvcia-data/party/distribution_annual_party_votes.csvcia-data/party/distribution_annual_party_members.csvKey Fields & Metrics:
party, year, decademember_count, vote_countavg_win_rate, avg_disciplineelectoral_success_ratehistorical_trend (RISING, DECLINING, STABLE)Dashboard Integration: Party Performance Dashboard
Visualizations:
Update Frequency: Daily
Product Name: Quarterly Parliamentary Activity Analysis
Purpose: Identify seasonal trends and patterns (2002-2025)
Data Files:
cia-data/seasonal/view_riksdagen_seasonal_activity_patterns_sample.csv (85 records)Key Fields & Metrics:
year, quarter, is_election_year, election_cycletotal_ballots, active_politicians, attendance_ratedocuments_produced, decisions_madeq_baseline_ballots, q_baseline_docs, q_baseline_attendanceballot_z_score, doc_z_score, attendance_z_scorebase_activity_classification (LOW, MODERATE, HIGH, VERY_HIGH)seasonal_pattern_classificationcross_year_quarter_avg_ballots, cross_year_z_scoreqoq_ballot_change_pct, activity_quartile_cycleDashboard Integration: Seasonal Activity Patterns Dashboard
Visualizations:
Update Frequency: Quarterly
Product Name: Statistical Outlier Identification
Purpose: Real-time anomaly detection (2002-2026, 41 quarters)
Data Files:
cia-data/seasonal/view_riksdagen_seasonal_anomaly_detection_sample.csv (41 records)Key Fields & Metrics:
year, quarter, is_election_year, parliamentary_periodtotal_ballots, active_politicians, attendance_rate, documents_producedq_baseline_ballots, q_baseline_docs, q_baseline_attendanceq_stddev_ballots, q_stddev_docs, q_stddev_attendanceballot_z_score, doc_z_score, attendance_z_scoreactivity_classification (NORMAL, UNUSUALLY_LOW, UNUSUALLY_HIGH)anomaly_type (Ballot, Document, Attendance, Mixed)anomaly_direction (UNUSUALLY_HIGH, UNUSUALLY_LOW, NORMAL)max_z_score, anomaly_severity (LOW, MODERATE, HIGH, CRITICAL)quarter_label (Q1_JAN_MAR, Q2_APR_JUN, Q3_JUL_SEP, Q4_OCT_DEC)Anomaly Detection Criteria:
|Z| < 1.5: LOW severity (within normal range)1.5 โค |Z| < 2.0: MODERATE severity2.0 โค |Z| < 2.5: HIGH severity|Z| โฅ 2.5: CRITICAL severityHistorical Findings (41 quarters):
Dashboard Integration: Anomaly Detection Dashboard (src/browser/dashboards/anomaly-detection.ts)
Visualizations:
Update Frequency: Quarterly
erDiagram
POLITICIAN ||--o{ VOTE : casts
POLITICIAN }o--|| PARTY : belongs_to
POLITICIAN }o--o{ COMMITTEE : assigned_to
POLITICIAN ||--o{ DOCUMENT : authors
POLITICIAN }o--o{ GOVERNMENT_ROLE : holds
PARTY ||--o{ POLITICIAN : has_members
PARTY ||--o{ MINISTRY : controls
DOCUMENT ||--o{ VOTE : triggers
DOCUMENT }o--|| COMMITTEE : processed_by
DOCUMENT }o--o{ DOCUMENT : references
COMMITTEE ||--o{ DOCUMENT : produces
COMMITTEE }o--o{ POLITICIAN : includes
MINISTRY ||--o{ GOVERNMENT_ROLE : contains
MINISTRY }o--|| PARTY : led_by
MINISTRY ||--o{ DOCUMENT : issues
GOVERNMENT_ROLE }o--|| POLITICIAN : held_by
GOVERNMENT_ROLE }o--|| MINISTRY : part_of
POLITICIAN {
varchar person_id PK
varchar first_name
varchar last_name
varchar party FK
varchar status
decimal risk_score
varchar risk_level
}
PARTY {
varchar party_id PK
varchar party_name
integer founded_year
varchar riksdag_status
decimal avg_win_rate
}
COMMITTEE {
varchar committee_id PK
varchar committee_name
integer total_documents
decimal productivity_score
}
DOCUMENT {
varchar document_id PK
varchar document_type
date published_date
varchar status
varchar organ FK
}
VOTE {
varchar vote_id PK
varchar ballot_id FK
varchar person_id FK
varchar party FK
varchar vote
date vote_date
boolean is_rebel_vote
}
MINISTRY {
varchar ministry_id PK
varchar ministry_name
varchar minister_person_id FK
varchar party FK
decimal effectiveness_score
varchar risk_level
}
GOVERNMENT_ROLE {
varchar role_id PK
varchar role_name
varchar role_type
varchar ministry_id FK
varchar person_id FK
date start_date
date end_date
}
erDiagram
BALLOT ||--o{ VOTE : contains
BALLOT }o--|| DOCUMENT : relates_to
BALLOT }o--|| COMMITTEE : from
VOTE }o--|| POLITICIAN : cast_by
VOTE }o--|| PARTY : party_vote
VOTE }o--|| BALLOT : in_ballot
BALLOT {
varchar ballot_id PK
date ballot_date
time ballot_time
varchar issue
varchar document_id FK
varchar committee FK
integer total_votes
integer yes_count
integer no_count
integer abstain_count
integer absent_count
}
VOTE {
varchar vote_id PK
varchar ballot_id FK
varchar person_id FK
varchar party FK
varchar vote
boolean is_rebel_vote
boolean is_winning_vote
}
POLITICIAN {
varchar person_id PK
varchar party FK
integer total_votes
decimal annual_rebel_rate
decimal annual_absence_rate
}
PARTY {
varchar party_id PK
decimal avg_win_rate
decimal avg_discipline_score
}
erDiagram
DOCUMENT ||--o{ DOCUMENT_AUTHOR : has
DOCUMENT ||--o{ DOCUMENT_ATTACHMENT : includes
DOCUMENT ||--o{ DOCUMENT_REFERENCE : references
DOCUMENT ||--o{ COMMITTEE_DECISION : leads_to
DOCUMENT }o--|| COMMITTEE : assigned_to
DOCUMENT_AUTHOR }o--|| POLITICIAN : authored_by
DOCUMENT_AUTHOR }o--|| DOCUMENT : for_document
COMMITTEE_DECISION }o--|| DOCUMENT : about
COMMITTEE_DECISION }o--|| COMMITTEE : made_by
DOCUMENT {
varchar document_id PK
varchar document_type
varchar rm
date published_date
varchar status
varchar organ FK
text title
text subtitle
text fulltext
}
DOCUMENT_AUTHOR {
varchar document_id PK_FK
varchar person_id PK_FK
integer author_order
}
DOCUMENT_ATTACHMENT {
varchar attachment_id PK
varchar document_id FK
varchar filename
varchar url
integer size_bytes
}
DOCUMENT_REFERENCE {
varchar source_doc_id PK_FK
varchar target_doc_id PK_FK
varchar reference_type
}
COMMITTEE_DECISION {
varchar decision_id PK
varchar document_id FK
varchar committee_id FK
date decision_date
varchar decision_outcome
text decision_text
}
COMMITTEE {
varchar committee_id PK
varchar committee_name
integer total_documents
}
POLITICIAN {
varchar person_id PK
integer total_documents
}
erDiagram
GOVERNMENT ||--o{ MINISTRY : contains
GOVERNMENT }o--|| PARTY : led_by
MINISTRY ||--o{ GOVERNMENT_ROLE : has_roles
MINISTRY }o--|| POLITICIAN : headed_by
MINISTRY }o--|| PARTY : party_affiliation
GOVERNMENT_ROLE }o--|| POLITICIAN : held_by
GOVERNMENT_ROLE }o--|| MINISTRY : part_of
GOVERNMENT {
varchar government_id PK
varchar government_name
date start_date
date end_date
varchar prime_minister_id FK
varchar leading_party FK
varchar coalition_parties
}
MINISTRY {
varchar ministry_id PK
varchar government_id FK
varchar ministry_name
varchar minister_person_id FK
varchar party FK
integer decision_count
decimal effectiveness_score
varchar risk_level
}
GOVERNMENT_ROLE {
varchar role_id PK
varchar role_name
varchar role_type
varchar ministry_id FK
varchar person_id FK
varchar party FK
date start_date
date end_date
}
POLITICIAN {
varchar person_id PK
varchar party FK
}
PARTY {
varchar party_id PK
varchar party_name
}
erDiagram
POLITICIAN ||--o{ RULE_VIOLATION : has
POLITICIAN ||--|| RISK_ASSESSMENT : assessed_by
PARTY ||--o{ POLITICIAN : contains
PARTY ||--|| PARTY_RISK_METRICS : has_metrics
MINISTRY ||--|| MINISTRY_RISK_METRICS : has_metrics
RULE_VIOLATION {
varchar violation_id PK
varchar person_id FK
date violation_date
varchar violation_type
text violation_description
varchar severity
}
RISK_ASSESSMENT {
varchar person_id PK_FK
decimal risk_score
varchar risk_level
integer total_violations
decimal annual_absence_rate
decimal annual_rebel_rate
date last_updated
text risk_assessment_text
}
PARTY_RISK_METRICS {
varchar party_id PK_FK
integer members_at_risk
decimal avg_party_risk_score
integer total_party_violations
varchar party_risk_level
}
MINISTRY_RISK_METRICS {
varchar ministry_id PK_FK
varchar risk_level
integer risk_violations
decimal risk_score
date last_assessment
}
POLITICIAN {
varchar person_id PK
varchar party FK
decimal risk_score
varchar risk_level
}
PARTY {
varchar party_id PK
}
MINISTRY {
varchar ministry_id PK
}
| Relationship | Cardinality | Description |
|---|---|---|
| Politician โ Party | Many-to-One | Each politician belongs to one party |
| Politician โ Vote | One-to-Many | Each politician casts many votes |
| Politician โ Document | One-to-Many | Each politician authors many documents |
| Politician โ Committee | Many-to-Many | Politicians assigned to multiple committees |
| Politician โ Government Role | Many-to-Many | Politicians can hold multiple roles over time |
| Party โ Politician | One-to-Many | Each party has many members |
| Party โ Ministry | One-to-Many | Each party can control multiple ministries |
| Committee โ Document | One-to-Many | Each committee produces many documents |
| Committee โ Politician | Many-to-Many | Committees have multiple members |
| Document โ Vote | One-to-Many | Each document can trigger multiple votes |
| Document โ Committee | Many-to-One | Each document processed by one committee |
| Document โ Document | Many-to-Many | Documents reference other documents |
| Ministry โ Government Role | One-to-Many | Each ministry has multiple roles |
| Ministry โ Party | Many-to-One | Each ministry led by one party |
URL: https://data.riksdagen.se/
Type: REST API + Open Data Portal
Authentication: None (public data)
Data Coverage: 1971-present (50+ years)
Endpoints:
/personlista/ - MPs and politicians/dokument/ - Parliamentary documents/votering/ - Voting records/utskott/ - Committee information/anforande/ - Chamber speechesUpdate Frequency:
Data Completeness: 98.5% (estimated)
Reliability: 99.9% uptime (government infrastructure)
Integration Method: CIA Platform batch processing + real-time updates
URL: https://val.se/
Type: Open Data Portal
Authentication: None (public data)
Data Coverage: 1911-present (electoral results)
Data Products:
Update Frequency: Post-election (every 4 years + by-elections)
Data Format: CSV, Excel, JSON
Reliability: Official government source
Integration Method: Manual download + CIA Platform import
URL: https://www.esv.se/psidata/
Type: PSI Data Portal (Public Sector Information)
Authentication: None (public data)
Data Coverage: 2000-present (budget data)
Data Products:
Update Frequency: Annual (budget cycle) + quarterly reports
Data Format: CSV, Excel
Reliability: Official government financial data
Integration Method: Manual download + CIA Platform import
URL: https://data.worldbank.org/
Type: REST API + Open Data Portal
Authentication: None (public data)
Data Coverage: 1960-present (country indicators)
Data Products:
Update Frequency: Annual
Data Format: JSON, CSV, XML
Reliability: International organization standard
Integration Method: CIA Platform API client
URL: https://data.imf.org/ (documentation) โข www.imf.org/external/datamapper/api/v1 (Datamapper JSON) โข api.imf.org/external/sdmx/3.0 (SDMX 3.0)
Type: REST (Datamapper JSON v1) + SDMX 3.0
Authentication: None (public data)
Data Classification: Public (same as SCB / World Bank)
Data Coverage: 1980-present (macro); annual + quarterly + monthly depending on dataset; projections to ~2031
Data Products:
Update Frequency:
Data Format: JSON (Datamapper), SDMX 3.0 JSON / XML
Reliability: ~99.5% availability; international-organization standard
Integration Method: Pure-TypeScript client scripts/imf-client.ts (sibling of scripts/world-bank-client.ts and scripts/scb-client.ts) โ not an MCP server (ADR 0001 rationale: npm-SBOM coverage, no Python / uvx / third-party MCP). Invoked by agentic workflows via the bash tool and imported directly by build-time scripts.
Schema/Validation: DatamapperResponse shape in imf-client.ts (numeric-finite check, year parse-guard); SDMX 3.0 schema validation for structural metadata.
Caching: analysis/data/imf/{indicator}/{country}.json + sidecar .meta.json (mcpTool: imf-ts-client, projectionVintage: "WEO-2026-04", fetch timestamp).
Rate-limit handling: ~10 req / 5 s, 3ร exponential back-off (1s โ 2s โ 4s), multi-country batching via Datamapper compare.
Allowlisted egress hosts: data.imf.org, api.imf.org, www.imf.org.
Supporting docs (referenced, not duplicated): analysis/imf/README.md, analysis/imf/indicator-policy-mapping.md, analysis/imf/use-cases.md, docs/adr/0001-adopt-imf-data-alongside-world-bank.md, .github/aw/ECONOMIC_DATA_CONTRACT.md.
IMF cache model (formal):
analysis/data/imf/{indicator}/{country}.json # Datamapper payload
analysis/data/imf/{indicator}/{country}.meta.json # provenance sidecar{indicator}.json payload (subset, normalised by imf-client.ts):
{
"indicator": "NGDP_RPCH",
"country": "SWE",
"values": [
{ "year": 2024, "value": 0.7, "projection": false },
{ "year": 2025, "value": 1.6, "projection": false },
{ "year": 2026, "value": 2.1, "projection": true }
]
}
.meta.json sidecar (always co-written):
{
"provider": "imf",
"mcpTool": "imf-ts-client",
"dataflow": "WEO",
"indicator": "NGDP_RPCH",
"country": "SWE",
"vintage": "WEO-2026-04",
"retrieved_at": "2026-05-06T03:14:22Z",
"sourceUrl": "https://www.imf.org/external/datamapper/api/v1/NGDP_RPCH/SWE",
"transport": "datamapper-v1"
}
SCB cache model (sibling pattern):
analysis/data/scb/{table_id}/{query_hash}.json
analysis/data/scb/{table_id}/{query_hash}.meta.json # provider="scb", dataflow=PxWeb table_id, retrieved_atWorld Bank cache model (sibling pattern):
analysis/data/world-bank/{indicator}/{country}.json
analysis/data/world-bank/{indicator}/{country}.meta.json # provider="worldbank", dataflow="WGI"|"WDI", retrieved_atRiksbank cache model:
analysis/data/riksbank/{series}/{period}.json
analysis/data/riksbank/{series}/{period}.meta.json # provider="riksbank", dataflow="MonetaryPolicy"|"FX", retrieved_atStatskontoret cache model (cross-referenced from ยง"Statskontoret Data Model Extension" below):
analysis/data/statskontoret/{dataset}/{artifact}.json
analysis/data/statskontoret/{dataset}/{artifact}.meta.json # provider="statskontoret", retrieved_atRiR (Riksrevisionen) cache model:
analysis/data/rir/{followup_id}.json
analysis/data/rir/{followup_id}.meta.json # provider="rir", retrieved_atCommon economicProvenance block โ every economic data point that flows into article frontmatter or body MUST carry an economicProvenance block. Schema:
{
"economicProvenance": {
"provider": "imf | scb | worldbank | riksbank | statskontoret | rir",
"dataflow": "string (e.g. WEO, FM, WGI, WDI, PxWeb table_id, MonetaryPolicy)",
"indicator": "string (provider-native indicator code)",
"vintage": "string (e.g. WEO-2026-04, PxWeb-2026Q1, WGI-2025)",
"retrieved_at": "string (ISO 8601 UTC timestamp)"
}
}
The Economic Data Contract enforces vintage discipline: any vintage older than 6 months MUST carry an explicit annotation in the article footnotes. See .github/aw/ECONOMIC_DATA_CONTRACT.md for the full rules and banned-phrase list.
URL: https://www.hack23.com/cia
Type: Java/Spring Boot application (backend data processing)
Authentication: Public read access, admin for updates
Data Coverage: Aggregated data from all sources above
Purpose:
Update Frequency: Daily batch processing (03:00 CET)
Output Format: CSV exports, JSON statistics
Reliability: 99% uptime (self-hosted)
Integration Method: Direct CSV export consumption by Riksdagsmonitor
| Source | Type | Coverage | Frequency | Reliability | Integration |
|---|---|---|---|---|---|
| Riksdag API | REST API | 1971-present | Real-time/Daily | 99.9% | CIA batch + real-time |
| Election Authority | Open Data | 1911-present | Post-election | 99.9% | Manual + CIA import |
| Financial Authority | PSI Portal | 2000-present | Annual/Quarterly | 99.9% | Manual + CIA import |
| World Bank | REST API | 1960-present | Annual | 99.5% | CIA API client |
| IMF Open Data | REST (Datamapper JSON v1) + SDMX 3.0 | 1980-present (macro); projections to ~2031 | WEO Apr/Oct, FM Apr/Oct, IFS/MFS monthly | ~99.5% | Pure-TypeScript client scripts/imf-client.ts (no MCP) |
| CIA Platform | Backend App | Aggregated | Daily (03:00 CET) | 99% | CSV export |
| Metric | Target | Current | Method |
|---|---|---|---|
| Completeness | 95%+ | 98.5% | Field population analysis |
| Accuracy | 99%+ | 99.2% | Cross-source validation |
| Timeliness | <24 hours | <12 hours | Update lag monitoring |
| Consistency | 100% | 99.8% | Schema validation |
| Validity | 100% | 99.9% | Data type checks |
Quality Assurance:
Location: /schemas/cia/ (CIA upstream-mirrored) and /schemas/ (root, repo-owned)
Purpose: Validate CIA platform data exports + repo-owned article-type / PIR / RiR contracts
Standard: JSON Schema Draft 2020-12
Validator: ajv 8.20.0 (invoked from scripts/validate-against-cia-schemas.ts and prebuild chain)
| Schema file | Purpose | Consumed by |
|---|---|---|
schemas/article-types.schema.json | Article-type registry (validates analysis/article-types.json) | scripts/horizon-context.ts, news pipeline |
schemas/pir-status.schema.json | Priority Intelligence Requirement status | PIR roll-forward + horizon-pir-rollforward template |
schemas/rir-followups-schema.json | Riksrevisionen follow-up payload | scripts/rir-followups-client.ts, scripts/fetch-rir-followups.ts |
The public riksdagsmonitor npm package (v0.9.40, "type": "module") exposes typed .d.ts surfaces under four subpaths, all generated by scripts/generate-types-from-cia-schemas.ts from the schemas above:
| Subpath | Contents |
|---|---|
./ | Root barrel |
./shared, ./shared/* | Shared utilities (src/browser/shared/) including typed DashboardGlobals for Chart.js / D3 / PapaParse globals (no any) |
./cia/* | CIA-data typed views generated from schemas/cia/ |
./dashboards/* | Dashboard renderers (src/browser/dashboards/) |
./ui/* | Reusable UI primitives (src/browser/ui/) |
"sideEffects" is restricted to ./dist/lib/shared/register-globals.js and ./src/browser/cia-entry.ts so downstream consumers can tree-shake everything else.
/schemas/cia/)| Schema File | Purpose | Entities Validated |
|---|---|---|
party-performance.schema.json | Party effectiveness metrics | Party performance data |
politician-profile.schema.json | Politician profiles | Politician data |
Schema Example (party-performance.schema.json):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://riksdagsmonitor.com/schemas/cia/party-performance.schema.json",
"title": "Party Performance Schema",
"description": "Validates party effectiveness and performance metrics",
"type": "object",
"properties": {
"party": {
"type": "string",
"enum": ["S", "M", "SD", "C", "V", "MP", "KD", "L"]
},
"year": {
"type": "integer",
"minimum": 1971,
"maximum": 2026
},
"performance_score": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"win_rate": {
"type": "number",
"minimum": 0,
"maximum": 100
}
},
"required": ["party", "year", "performance_score"]
}
Location: /cia-data/
Format: UTF-8 encoded CSV with header row
Delimiter: Comma (,)
Quote Character: Double quote (")
Line Ending: LF (\n)
Header Row Requirements:
Data Type Conventions:
YYYY-MM-DD (ISO 8601)YYYY-MM-DD HH:MM:SS (ISO 8601).), 2 decimal placestrue, false (lowercase)Example (politician risk summary):
person_id,first_name,last_name,party,status,risk_score,risk_level
0665485817222,Daniel,Bรคckstrรถm,C,Tjรคnstgรถrande riksdagsledamot,50.00,HIGH
0836001490919,Ulrika,Heie,C,Tjรคnstgรถrande riksdagsledamot,38.00,MEDIUM
File: /cia-data/production-stats.json
Purpose: Daily statistics from CIA platform
Update: Daily at 03:00 CET via GitHub Actions
Schema Structure:
{
"metadata": {
"source_url": "string (URL)",
"last_updated": "string (ISO 8601 timestamp)",
"extraction_time": "string (ISO 8601 timestamp)",
"generated_at": "string (ISO 8601 timestamp)",
"version": "string (semantic version)"
},
"counts": {
"total_persons": "integer",
"total_votes": "integer",
"total_documents": "integer",
"total_committee_documents": "integer",
"total_rule_violations": "integer",
"total_political_parties": "integer",
"total_governments": "integer",
"total_government_roles": "integer",
"total_government_role_members": "integer"
},
"tables": {
"success": [
{
"name": "string (table name)",
"count": "integer (row count)"
}
],
"empty": ["string (table name)"]
}
}
Validation Rules:
metadata.last_updated must be within 48 hourscounts.* must be non-negative integerstables.success[].count must be positivemetadata.version must follow semantic versioningFile: /cia-data/data-manifest.json
Purpose: Track all CSV files, checksums, and field descriptions
Update: On data file changes
Schema Structure:
{
"version": "1.0.0",
"last_updated": "2026-02-15",
"files": [
{
"path": "politician/view_politician_risk_summary_sample.csv",
"size_bytes": 69755,
"checksum_sha256": "abc123...",
"record_count": 349,
"fields": [
{
"name": "person_id",
"type": "string",
"description": "Unique person identifier",
"required": true,
"example": "0665485817222"
}
]
}
]
}
The CIA-schema lifecycle is owned by four scripts under scripts/, executed in order. All four are pure Node โฅ26 TypeScript (no transpile step, native loader):
flowchart LR
A[scripts/sync-cia-schemas.ts<br/>pulls upstream into schemas/cia/]
B[scripts/validate-against-cia-schemas.ts<br/>ajv 8.20.0 โ runtime + CI]
C[scripts/check-cia-schema-updates.ts<br/>diff vs. last sync, exit 1 on drift]
D[scripts/generate-types-from-cia-schemas.ts<br/>emits .d.ts for ./cia/* subpath]
A --> B
A --> C
B --> D
C --> D
Workflow: .github/workflows/validate-data.yml (if implemented)
Trigger: On push to cia-data/ directory
Steps:
Exit Codes:
0: All validations passed1: Schema validation failed2: Data integrity check failed3: Freshness check failedLocation: Dashboard JavaScript files
Method: Papa Parse CSV validation
Timing: On data load
Validation Checks:
Error Handling:
Versioning Scheme: Semantic Versioning (MAJOR.MINOR.PATCH)
Compatibility:
Schema Evolution Process:
graph TB
subgraph "External Sources"
Riksdag[Riksdag API<br/>data.riksdagen.se]
Election[Election Authority<br/>val.se]
Finance[Financial Authority<br/>esv.se]
WorldBank[World Bank<br/>data.worldbank.org]
IMF[IMF<br/>data.imf.org / api.imf.org<br/>WEO + SDMX 3.0]
end
subgraph "CIA Platform (Backend)"
ETL[ETL Processes<br/>Spring Batch Jobs]
DB[(PostgreSQL<br/>Production Database)]
Analytics[Analytics Engine<br/>Risk Assessment]
Export[CSV Export<br/>Sample Data]
end
subgraph "Riksdagsmonitor (Frontend)"
GitHub[GitHub Repository<br/>cia-data/]
LocalCache[Browser LocalStorage<br/>1-24 hour TTL]
Dashboard[Interactive Dashboards<br/>Chart.js + D3.js]
end
subgraph "Content Delivery"
CloudFront[AWS CloudFront<br/>Primary CDN]
S3[S3 Storage<br/>Multi-region]
GitHubPages[GitHub Pages<br/>DR Hosting]
end
Riksdag -->|REST API| ETL
Election -->|CSV Download| ETL
Finance -->|CSV Download| ETL
WorldBank -->|REST API| ETL
IMF -->|Datamapper JSON + SDMX 3.0<br/>pure-TS client, no MCP| ETL
ETL --> DB
DB --> Analytics
Analytics --> DB
DB --> Export
Export -->|Daily 03:00 CET| GitHub
GitHub -->|Deploy| CloudFront
GitHub -->|Deploy| GitHubPages
CloudFront -->|HTTPS/TLS 1.3| Dashboard
GitHubPages -.->|DR Failover| Dashboard
Dashboard -->|Load Data| LocalCache
LocalCache -->|Cache Hit| Dashboard
LocalCache -->|Cache Miss| GitHub
style Riksdag fill:#ff9800,color:#000000
style ETL fill:#4caf50,color:#000000
style DB fill:#2196f3,color:#ffffff
style Export fill:#9c27b0,color:#ffffff
style GitHub fill:#ff9800,color:#000000
style CloudFront fill:#4caf50,color:#000000
style Dashboard fill:#00bcd4,color:#000000
Workflow: .github/workflows/update-cia-stats.yml
Schedule: Daily at 03:00 CET (02:00 UTC)
Trigger: cron: '0 2 * * *'
Steps:
curl https://raw.githubusercontent.com/Hack23/cia/master/service.data.impl/sample-data/extraction_summary_report.csv
cia-data/production-stats.json)Error Handling:
Workflow: Weekly schema validation check
Trigger: cron: '0 0 * * 0' (Sundays at midnight)
Steps:
schemas/cia/)Change Types:
Location: Browser LocalStorage
Scope: Per-origin (https://riksdagsmonitor.com)
Capacity: ~10MB per origin (browser-dependent)
Cache Key Pattern:
riksdagsmonitor_cache_{data_type}_{language}
Example:
localStorage.setItem('riksdagsmonitor_cache_politician_risk_en', JSON.stringify({
timestamp: Date.now(),
ttl: 3600000, // 1 hour in milliseconds
data: csvData
}));
TTL (Time-To-Live):
Cache Invalidation:
CDN: GitHub Pages built-in CDN
Cache-Control Headers: Set by GitHub Pages
Default TTL: 10 minutes
Cacheable Assets:
Cache Busting:
CDN: AWS CloudFront (primary)
Edge Locations: 600+ globally
Default TTL: 86400 seconds (24 hours)
Cache Behaviors:
Path Pattern TTL Cache-Control
/ 3600s public, max-age=3600
*.html 3600s public, max-age=3600
*.css 86400s public, max-age=86400
*.js 86400s public, max-age=86400
/cia-data/*.csv 3600s public, max-age=3600
/cia-data/*.json 3600s public, max-age=3600
Invalidation:
/* (all files)Implementation: JavaScript function in dashboards
Freshness Criteria:
function isDataFresh(timestamp, ttl) {
const now = Date.now();
const age = now - timestamp;
return age < ttl;
}
const FRESHNESS_TTL = {
realtime: 5 * 60 * 1000, // 5 minutes
daily: 60 * 60 * 1000, // 1 hour
weekly: 24 * 60 * 60 * 1000, // 24 hours
monthly: 7 * 24 * 60 * 60 * 1000 // 7 days
};
Fallback Strategy:
graph LR
A[Collection<br/>CIA Platform] --> B[Validation<br/>Schema Checks]
B --> C[Storage<br/>GitHub + S3]
C --> D[Presentation<br/>Dashboards]
B -->|Invalid Data| E[Error Log]
E -->|Alert| F[Maintainer]
C -->|Cache| G[LocalStorage]
G -->|Serve| D
style A fill:#ff9800,color:#000000
style B fill:#4caf50,color:#000000
style C fill:#2196f3,color:#ffffff
style D fill:#9c27b0,color:#ffffff
style E fill:#f44336,color:#ffffff
Pipeline Stages:
Collection (CIA Platform)
Validation (CIA Platform + GitHub Actions)
Storage (GitHub + AWS)
cia-data/)Presentation (Riksdagsmonitor)
Riksdagsmonitor supports 14 languages with full data model localization:
| Code | Language | Native Name | Script | RTL | Status |
|---|---|---|---|---|---|
| en | English | English | Latin | No | โ Active |
| sv | Swedish | Svenska | Latin | No | โ Active |
| da | Danish | Dansk | Latin | No | โ Active |
| no | Norwegian | Norsk | Latin | No | โ Active |
| fi | Finnish | Suomi | Latin | No | โ Active |
| de | German | Deutsch | Latin | No | โ Active |
| fr | French | Franรงais | Latin | No | โ Active |
| es | Spanish | Espaรฑol | Latin | No | โ Active |
| nl | Dutch | Nederlands | Latin | No | โ Active |
| ar | Arabic | ุงูุนุฑุจูุฉ | Arabic | Yes | โ Active |
| he | Hebrew | ืขืืจืืช | Hebrew | Yes | โ Active |
| ja | Japanese | ๆฅๆฌ่ช | Japanese | No | โ Active |
| ko | Korean | ํ๊ตญ์ด | Hangul | No | โ Active |
| zh | Chinese | ไธญๆ | Chinese | No | โ Active |
Politicians (person_data):
Parties (sweden_political_party):
{
"party_id": "S",
"translations": {
"en": "Social Democrats",
"sv": "Socialdemokraterna",
"de": "Sozialdemokraten",
"fr": "Sociaux-dรฉmocrates",
"es": "Socialdemรณcratas",
"ar": "ุงูุฏูู
ูุฑุงุทููู ุงูุงุฌุชู
ุงุนููู",
"ja": "็คพไผๆฐไธปๅ
",
"zh": "็คพไผๆฐไธปๅ
"
}
}
Committees (committee_document_data):
{
"committee_id": "AU",
"translations": {
"en": "Labour Market Committee",
"sv": "Arbetsmarknadsutskottet",
"de": "Ausschuss fรผr Arbeitsmarkt",
"fr": "Commission du marchรฉ du travail",
"es": "Comisiรณn del Mercado Laboral",
"ar": "ูุฌูุฉ ุณูู ุงูุนู
ู",
"ja": "ๅดๅๅธๅ ดๅงๅกไผ",
"zh": "ๅณๅจๅธๅบๅงๅไผ"
}
}
Document Types:
{
"document_type": "mot",
"translations": {
"en": "Motion (MP-initiated proposal)",
"sv": "Motion",
"de": "Antrag",
"fr": "Motion",
"es": "Mociรณn",
"ar": "ุงูุชุฑุงุญ",
"ja": "ๅ่ญฐ",
"zh": "ๅจ่ฎฎ"
}
}
Dashboard Titles:
<title> tags per languageindex_{lang}.htmlChart Labels:
document.documentElement.langData Classification Values:
{
"risk_level": {
"LOW": {
"en": "Low Risk",
"sv": "Lรฅg risk",
"de": "Geringes Risiko",
"ar": "ู
ุฎุงุทุฑ ู
ูุฎูุถุฉ"
},
"MEDIUM": {
"en": "Medium Risk",
"sv": "Medelhรถg risk",
"de": "Mittleres Risiko",
"ar": "ู
ุฎุงุทุฑ ู
ุชูุณุทุฉ"
},
"HIGH": {
"en": "High Risk",
"sv": "Hรถg risk",
"de": "Hohes Risiko",
"ar": "ู
ุฎุงุทุฑ ุนุงููุฉ"
}
}
}
Affected Languages: Arabic (ar), Hebrew (he)
HTML Structure:
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<title>Riksdagsmonitor - ู
ุฑุงูุจ ุงูุจุฑูู
ุงู ุงูุณููุฏู</title>
</head>
<body>
<!-- Content flows right-to-left -->
</body>
</html>
CSS Adaptations:
[dir="rtl"] .dashboard {
text-align: right;
direction: rtl;
}
[dir="rtl"] .chart-legend {
float: left; /* Reversed from LTR */
}
Data Implications:
Pattern: index_{lang}.html
Files (14 languages):
index.html (English - default)
index_sv.html (Swedish)
index_da.html (Danish)
index_no.html (Norwegian)
index_fi.html (Finnish)
index_de.html (German)
index_fr.html (French)
index_es.html (Spanish)
index_nl.html (Dutch)
index_ar.html (Arabic - RTL)
index_he.html (Hebrew - RTL)
index_ja.html (Japanese)
index_ko.html (Korean)
index_zh.html (Chinese)
Sitemap Files:
sitemap.xml (Master sitemap)
sitemap.html (English - default)
sitemap_sv.html (Swedish)
sitemap_ar.html (Arabic)
...
Purpose: Signal alternate language versions to search engines
Implementation:
<head>
<link rel="alternate" hreflang="en" href="https://riksdagsmonitor.com/index.html" />
<link rel="alternate" hreflang="sv" href="https://riksdagsmonitor.com/index_sv.html" />
<link rel="alternate" hreflang="da" href="https://riksdagsmonitor.com/index_da.html" />
<link rel="alternate" hreflang="no" href="https://riksdagsmonitor.com/index_no.html" />
<link rel="alternate" hreflang="fi" href="https://riksdagsmonitor.com/index_fi.html" />
<link rel="alternate" hreflang="de" href="https://riksdagsmonitor.com/index_de.html" />
<link rel="alternate" hreflang="fr" href="https://riksdagsmonitor.com/index_fr.html" />
<link rel="alternate" hreflang="es" href="https://riksdagsmonitor.com/index_es.html" />
<link rel="alternate" hreflang="nl" href="https://riksdagsmonitor.com/index_nl.html" />
<link rel="alternate" hreflang="ar" href="https://riksdagsmonitor.com/index_ar.html" />
<link rel="alternate" hreflang="he" href="https://riksdagsmonitor.com/index_he.html" />
<link rel="alternate" hreflang="ja" href="https://riksdagsmonitor.com/index_ja.html" />
<link rel="alternate" hreflang="ko" href="https://riksdagsmonitor.com/index_ko.html" />
<link rel="alternate" hreflang="zh" href="https://riksdagsmonitor.com/index_zh.html" />
<link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/index.html" />
</head>
Benefits:
Method: Manual language selection (no auto-detect)
Navigation:
URL Pattern:
https://riksdagsmonitor.com/ โ English (default)
https://riksdagsmonitor.com/index_sv.html โ Swedish
https://riksdagsmonitor.com/index_ar.html โ Arabic
Data Loading:
Strategy: Client-side caching with TTL-based expiration
Implementation:
class DataCache {
constructor(ttl = 3600000) { // 1 hour default
this.ttl = ttl;
}
set(key, data) {
const item = {
data: data,
timestamp: Date.now(),
ttl: this.ttl
};
localStorage.setItem(key, JSON.stringify(item));
}
get(key) {
const item = JSON.parse(localStorage.getItem(key));
if (!item) return null;
const age = Date.now() - item.timestamp;
if (age > item.ttl) {
localStorage.removeItem(key);
return null;
}
return item.data;
}
}
Cache Keys:
riksdagsmonitor_cache_politician_risk_en
riksdagsmonitor_cache_party_performance_sv
riksdagsmonitor_cache_seasonal_patterns_de
riksdagsmonitor_cache_election_cycle_fr
TTL Configuration:
GitHub Pages CDN: Built-in global CDN
Cache-Control Headers: Managed by GitHub
Effective Caching:
Cache-Control: max-age=600 (10 minutes)
Benefits:
Limitations:
Freshness Criteria:
const FRESHNESS_POLICY = {
production_stats: {
ttl: 24 * 60 * 60 * 1000, // 24 hours
acceptable_age: 48 * 60 * 60 * 1000 // 48 hours max
},
politician_risk: {
ttl: 60 * 60 * 1000, // 1 hour
acceptable_age: 24 * 60 * 60 * 1000 // 24 hours max
},
seasonal_patterns: {
ttl: 7 * 24 * 60 * 60 * 1000, // 7 days
acceptable_age: 30 * 24 * 60 * 60 * 1000 // 30 days max
}
};
Stale Data Handling:
Implementation: Load data on-demand per dashboard
Strategy:
// Load only when dashboard becomes visible
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadDashboardData(entry.target.dataset.dashboard);
}
});
});
document.querySelectorAll('.dashboard').forEach(el => {
observer.observe(el);
});
Benefits:
Build System: Vite 8 with ES modules
Split Points:
src/browser/dashboards/election-cycle.ts
src/browser/dashboards/party-dashboard.ts
src/browser/dashboards/seasonal-patterns.ts
src/browser/dashboards/committees-dashboard.ts
src/browser/dashboards/coalition-dashboard.ts
src/browser/dashboards/ministry-dashboard.ts
src/browser/dashboards/anomaly-detection.ts
src/browser/dashboards/risk-dashboard.ts
src/browser/dashboards/pre-election.ts
src/browser/dashboards/politician-dashboard.ts
Loading Strategy:
// Dynamic import per dashboard
if (document.getElementById('election-cycle-dashboard')) {
import('./dashboards/election-cycle.js')
.then(module => module.init())
.catch(err => console.error('Failed to load dashboard', err));
}
Benefits:
| Metric | Target | Current | Dashboard |
|---|---|---|---|
| First Contentful Paint (FCP) | <1.5s | <1s | โ Passing |
| Largest Contentful Paint (LCP) | <2.5s | <2s | โ Passing |
| Time to Interactive (TTI) | <3s | <2s | โ Passing |
| Cumulative Layout Shift (CLS) | <0.1 | <0.05 | โ Passing |
| Total Blocking Time (TBT) | <200ms | <150ms | โ Passing |
Measurement Tools:
File: /budget.json
Resource Size Budgets:
{
"document": "105KB", // HTML pages
"stylesheet": "370KB", // CSS files
"script": "300KB", // JavaScript bundles
"image": "500KB", // Images
"font": "100KB", // Web fonts
"total": "1200KB" // Total page weight
}
Performance Budgets:
{
"first-contentful-paint": "5100ms",
"largest-contentful-paint": "5400ms",
"interactive": "5400ms",
"cumulative-layout-shift": "0.1",
"total-blocking-time": "200ms"
}
Enforcement: GitHub Actions workflow fails on budget violations
graph TB
subgraph "External Data Sources"
Riksdag[Swedish Riksdag API<br/>data.riksdagen.se<br/>2.5M votes, 109K docs]
Election[Election Authority<br/>val.se<br/>Electoral results]
Finance[Financial Authority<br/>esv.se<br/>Budget data]
WorldBank[World Bank<br/>data.worldbank.org<br/>Country indicators]
IMF[IMF<br/>data.imf.org / api.imf.org<br/>WEO + Fiscal Monitor + IFS<br/>macro/fiscal + T+5 projections]
end
subgraph "Riksdagsmonitor System"
System[Data Model<br/>2,494 politicians<br/>40 parties<br/>15 committees]
end
subgraph "CIA Platform (External)"
CIA[CIA Backend<br/>Data aggregation<br/>Risk assessment]
end
subgraph "Users"
Analyst[Political Analysts]
Journalist[Journalists]
Citizen[Citizens]
Researcher[Researchers]
end
Riksdag -->|REST API| CIA
Election -->|CSV Data| CIA
Finance -->|CSV Data| CIA
WorldBank -->|REST API| CIA
IMF -->|Pure-TS client<br/>Datamapper JSON + SDMX 3.0<br/>no MCP| CIA
CIA -->|CSV Exports| System
CIA -->|Daily Statistics| System
System -->|Visualizations| Analyst
System -->|Visualizations| Journalist
System -->|Visualizations| Citizen
System -->|Visualizations| Researcher
style Riksdag fill:#ff9800,color:#000000
style Election fill:#ff9800,color:#000000
style Finance fill:#ff9800,color:#000000
style WorldBank fill:#ff9800,color:#000000
style IMF fill:#00897b,color:#ffffff
style CIA fill:#9c27b0,color:#ffffff
style System fill:#4caf50,color:#000000
style Analyst fill:#2196f3,color:#ffffff
graph TB
subgraph "Data Storage Layer"
GitHub[GitHub Repository<br/>cia-data/<br/>50+ CSV files]
S3[AWS S3<br/>Multi-region<br/>Primary storage]
LocalStorage[Browser LocalStorage<br/>Client-side cache<br/>~10MB capacity]
end
subgraph "Data Processing Layer"
CIA_DB[(CIA Platform<br/>PostgreSQL Database<br/>Production data)]
Export[CSV Export Engine<br/>Sample data generator]
Stats[Statistics Generator<br/>production-stats.json]
end
subgraph "Validation Layer"
Schemas[JSON Schemas<br/>2 schema files]
Validator[Schema Validator<br/>GitHub Actions]
end
subgraph "Presentation Layer"
Dashboards[Interactive Dashboards<br/>Chart.js + D3.js<br/>5 active dashboards]
end
CIA_DB --> Export
CIA_DB --> Stats
Export --> GitHub
Stats --> GitHub
GitHub --> Validator
Schemas --> Validator
Validator -->|Valid| S3
S3 --> Dashboards
GitHub --> Dashboards
Dashboards --> LocalStorage
LocalStorage --> Dashboards
style CIA_DB fill:#2196f3,color:#ffffff
style GitHub fill:#ff9800,color:#000000
style S3 fill:#4caf50,color:#000000
style Dashboards fill:#9c27b0,color:#ffffff
style Validator fill:#f44336,color:#ffffff
This DATA_MODEL.md complements ARCHITECTURE.md:
ARCHITECTURE.md Focus:
DATA_MODEL.md Focus (this document):
Cross-References:
Annex A.8 - Asset Management
| Control | Implementation | Evidence |
|---|---|---|
| A.8.1 | Asset inventory | cia-data/data-manifest.json |
| A.8.2 | Information classification | Section 1 (Public data classification) |
| A.8.3 | Media handling | Git version control, S3 versioning |
Compliance Level: โ FULLY COMPLIANT
PR.DS - Data Security
| Function | Implementation | Location |
|---|---|---|
| PR.DS-1 | Data-at-rest protection | S3 encryption, Git history |
| PR.DS-2 | Data-in-transit protection | HTTPS/TLS 1.3 |
| PR.DS-3 | Asset management | Section 4 (Data Sources) |
| PR.DS-5 | Protection against leakage | No confidential data, all public |
| PR.DS-6 | Integrity checking | JSON Schema validation, checksums |
Compliance Level: โ FULLY COMPLIANT
Control 3 - Data Protection
| Subcontrol | Implementation | Status |
|---|---|---|
| 3.1 | Data inventory | Section 1 (Entity dictionary) |
| 3.2 | Data classification | Section 1 (Public classification) |
| 3.3 | Data retention | Git history, S3 versioning |
| 3.6 | Data encryption | HTTPS/TLS 1.3 |
| 3.12 | Data integrity | JSON Schema validation |
Compliance Level: โ FULLY COMPLIANT
Personal Data Processing:
Data Categories:
Data Subject Rights:
Privacy-by-Design:
Compliance Level: โ FULLY COMPLIANT (Public Interest Processing)
| Control | Implementation | Status |
|---|---|---|
| Access Control | Public data, no restrictions | โ |
| Encryption (Transit) | HTTPS/TLS 1.3 | โ |
| Encryption (Rest) | S3 server-side encryption | โ |
| Integrity | JSON Schema validation, Git history | โ |
| Availability | Multi-region S3, GitHub Pages DR | โ |
| Backup | Git version control, S3 versioning | โ |
| Audit Trail | Git commit history, S3 access logs | โ |
The newsroom's analytic input layer is a typed ArtifactDefinition[] owned by scripts/agentic/artifact-inventory.ts. The analysis-gate (scripts/agentic/analysis-gate.ts, checks 1โ9b, PASS2_MTIME_THRESHOLD_MS = 180_000) admits or rejects an article-day folder before any rendering. Folder convention:
analysis/daily/$ARTICLE_DATE/$SUBFOLDER/
README.md
executive-brief.md
synthesis-summary.md
significance-scoring.md
classification-results.md
swot-analysis.md
risk-assessment.md
threat-analysis.md
stakeholder-perspectives.md
data-download-manifest.md
cross-reference-map.md
scenario-analysis.md
comparative-international.md
devils-advocate.md
intelligence-assessment.md
methodology-reflection.md
election-2026-analysis.md
voter-segmentation.md
coalition-mathematics.md
historical-parallels.md
media-framing-analysis.md
implementation-feasibility.md
forward-indicators.md
documents/{dok_id}-analysis.md # Family E, one per source document (variable count)| # | Filename | requiresMermaid | requiresPass2 | Description |
|---|---|---|---|---|
| 1 | README.md | โ | โ | Folder README with index links |
| 2 | executive-brief.md | โ | โ | BLUF + 3 decisions supported |
| 3 | synthesis-summary.md | โ | โ | Lead-story decision + DIW ranking |
| 4 | significance-scoring.md | โ | โ | DIW scores + sensitivity analysis |
| 5 | classification-results.md | โ | โ | 7-dimension classification |
| 6 | swot-analysis.md | โ | โ | S/W/O/T with evidence + TOWS matrix |
| 7 | risk-assessment.md | โ | โ | Risk matrix + mitigation strategies |
| 8 | threat-analysis.md | โ | โ | STRIDE-style threat assessment |
| 9 | stakeholder-perspectives.md | โ | โ | Stakeholder mapping + positions |
| # | Filename | requiresMermaid | requiresPass2 | Description |
|---|---|---|---|---|
| 1 | data-download-manifest.md | โ | โ | Download manifest with dok_ids |
| 2 | cross-reference-map.md | โ | โ | Cross-reference map |
| # | Filename | requiresMermaid | requiresPass2 | Description |
|---|---|---|---|---|
| 1 | scenario-analysis.md | โ | โ | โฅ3 distinct scenarios |
| 2 | comparative-international.md | โ | โ | Comparator set + rows |
| 3 | devils-advocate.md | โ | โ | โฅ3 competing hypotheses (ACH) |
| 4 | intelligence-assessment.md | โ | โ | โฅ3 Key Judgments with confidence |
| 5 | methodology-reflection.md | โ | โ | ICD 203 audit / improvements |
| # | Filename | requiresMermaid | requiresPass2 | Description |
|---|---|---|---|---|
| 1 | election-2026-analysis.md | โ | โ | Election 2026 analysis |
| 2 | voter-segmentation.md | โ | โ | Voter segmentation analysis |
| 3 | coalition-mathematics.md | โ | โ | Seat-count / vote-breakdown table |
| 4 | historical-parallels.md | โ | โ | Historical parallels analysis |
| 5 | media-framing-analysis.md | โ | โ | Media framing analysis |
| 6 | implementation-feasibility.md | โ | โ | Implementation feasibility |
| 7 | forward-indicators.md | โ | โ | โฅ10 dated forward indicators |
| Filename pattern | requiresMermaid | requiresPass2 | Description |
|---|---|---|---|
documents/{dok_id}-analysis.md | โ (per source) | โ | One file per source document, named after the Riksdag/Regeringen dok_id |
methodology-reflection.md JSON contract (ICD 203 audit)methodology-reflection.md is the only Family-C artifact with both a markdown body and a machine-readable JSON contract block (validated by scripts/validate-methodology-reflection.ts):
{
"icd203": {
"describesQualityOfInformation": "string",
"expressesUncertainties": "string",
"distinguishesUnderlyingFromAssumptions": "string",
"incorporatesAlternatives": "string",
"demonstratesRelevance": "string",
"usesLogicalArgumentation": "string",
"exhibitsConsistency": "string",
"accuratelyDescribesPriorAnalysis": "string"
},
"improvements": [
{ "area": "string", "issue": "string", "fix": "string" }
],
"selfScore": { "icd203": "0..1", "completeness": "0..1" }
}
The eight icd203.* fields correspond 1-to-1 with ICD 203 analytic standards. Missing or empty fields cause analysis-gate check 9b to fail.
Every requiresPass2: true artifact MUST exhibit mtimeMs โฅ birthtimeMs + 180_000 (โฅ 180 s wall-clock between creation and last modification). The threshold lives in scripts/agentic/analysis-gate.ts as PASS2_MTIME_THRESHOLD_MS = 180_000. Operational interpretation: AI-FIRST 2-pass authoring โ Pass 1 drafts the artifact, Pass 2 (โฅ3 minutes later) re-reads and tightens every section. Same-minute writes are a structural failure, not a stylistic preference.
The published news corpus lives under news/ and currently materialises 3,953 .html files (verified find news -type f -name "*.html" | wc -l on 2026-05-06). Each article has 14 language siblings (or fewer if news-translate has not yet completed) plus a canonical article.md upstream of HTML rendering.
news/{ARTICLE_DATE}-{SUBFOLDER}-{LANG}.htmlWhere {LANG} โ en, sv, da, no (= NB), fi, de, es, fr, nl, ar (RTL), he (RTL), ja, ko, zh. EN and SV are produced directly by the agentic newsroom; the remaining 12 are produced out-of-band by the news-translate workflow.
Defaults are emitted by scripts/render-lib/aggregator/frontmatter.ts (language ?? 'en', layout ?? 'article').
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
title | string | โ | โ | Article title (sanitised, โค120 chars) |
language | string (BCP-47-ish, lower-case) | โ | 'en' | One of the 14 supported codes |
layout | string | โ | 'article' | Render-lib layout selector |
date | string (YYYY-MM-DD) | โ | โ | Article date (matches $ARTICLE_DATE) |
subfolder | string | โ | โ | Matches $SUBFOLDER under analysis/daily/$ARTICLE_DATE/ |
articleType | string | โ | โ | One of the registered article-types in analysis/article-types.json |
horizon | string | โ | โ | One of T+72h, T+7d, T+30d, T+90d, T+365d, T+1460d, election |
economicProvenance[] | array of economicProvenance blocks | โ | [] | See ยง4 โ required for any economic data point used |
article.md cleaning contractscripts/render-lib/aggregator/cleaning/ strips before HTML rendering:
| Cleaning step | Module | Purpose |
|---|---|---|
admin-bylines/ | n/a | Removes "Author: agentic-newsroom-bot" admin lines |
deduplication/ | n/a | Collapses duplicate H1s and repeated section headers |
heading-demotion/ | n/a | Demotes unintended H1s in concatenated artifacts to H2 |
link-rewriting/ | n/a | Rewrites relative links to https://github.com/Hack23/riksdagsmonitor/blob/main/โฆ |
pass-two/ | n/a | Strips ## Pass 2 โฆ self-audit sections (analysis-gate keeps them; rendered article does not) |
process-meta/ | n/a | Strips YAML/HTML metadata that should not surface in body |
structural/ | n/a | Final structural sweep (whitespace, ordering) |
scripts/render-lib/aggregator/seo/ produces description.ts and title.ts โ the canonical OpenGraph + JSON-LD NewsArticle headline / description fields used by every rendered article.
The political-intelligence catalog is the single source of truth for which articles, streams, and methodology references render on political-intelligence.html and its 13 language siblings. It is produced by the scripts/political-intelligence/ bounded context.
scripts/political-intelligence/
catalog.ts # Builds the master catalog JSON (articles ร streams ร horizons)
daily-streams.ts # Per-stream per-day groupings (input to grid renderer)
index.ts # Barrel
i18n/
artifact-i18n.ts # 14-language strings for artifact names
methodology-i18n.ts # 14-language strings for methodology names
page-translations.ts # Page-chrome translations
stream-i18n.ts # 14-language stream display names
template-i18n.ts # 14-language template names
render/
daily-day.ts # Per-day card renderer
grid.ts # Stream ร horizon grid renderer
page.ts # Top-level page composer
style.ts # CSS leafinterface PICatalogEntry {
readonly date: string; // YYYY-MM-DD
readonly subfolder: string; // matches $SUBFOLDER under analysis/daily/$DATE/
readonly articleType: string; // registered in analysis/article-types.json
readonly horizon:
| 'T+72h' | 'T+7d' | 'T+30d' | 'T+90d'
| 'T+365d' | 'T+1460d' | 'election';
readonly stream: string; // catalog stream key (resolved via stream-i18n)
readonly languages: readonly string[]; // codes of available rendered HTML siblings
readonly artifactsPresent: readonly string[]; // subset of the 23-artifact inventory
readonly methodologiesUsed: readonly string[]; // subset of the 18-methodology set
readonly templatesUsed: readonly string[]; // subset of the 39-template set
}
daily-streams.ts groups PICatalogEntry[] first by date, then by stream, producing the grid that the renderer uses. Streams currently in production: daily, weekly-review, monthly-review, quarterly-outlook, annual-outlook, election-cycle, mandate-period. Each stream maps deterministically to one or more horizon bands (see ARCHITECTURE.md ยง"Horizon stratification").
All five i18n/*.ts leaves export typed string maps keyed by the 14 supported language codes. The catalog payload is language-agnostic; localisation happens at render time inside scripts/political-intelligence/render/page.ts.
๐ Document Control:
โ
Approved by: James Pether Sรถrling, CEO
๐ค Distribution: Public
๐ท๏ธ Classification:
๐
Effective Date: 2026-05-06
โฐ Next Review: 2027-05-06
๐ฏ Framework Compliance:
Statskontoret adds a public Swedish-administration data domain under the economic/public-administration context layer.
| Entity | Key fields | Storage / source |
|---|---|---|
StatskontoretSourceDefinition | key, title, url, cadence, coverage, primaryUse | Static catalogue in scripts/statskontoret-client.ts; mirrored by analysis/statskontoret/indicators-inventory.json. |
StatskontoretDownloadLink | source, sourcePage, url, resourceType, documentType, fileType, fileName, year, month, status, updatedAt | Derived from Statskontoret HTML pages by extractStatskontoretDownloadLinks. |
StatskontoretWorkbook / StatskontoretSheet | sheet name and row arrays | Parsed locally from XLSX ZIP parts. |
StatskontoretHeadcountRow | year, department, headcount, authorityCount | Derived from Myndighetsfรถrteckning rows. |
analysis/data/statskontoret/{dataset}/{artifact}.json
analysis/data/statskontoret/{dataset}/{artifact}.meta.jsonSidecar metadata includes fetchedAt, mcpTool: statskontoret-ts-client, dataset, and artifact. The provider decision matrix in analysis/statskontoret/indicators-inventory.json maps government-body headcount and central-government budget outturn claims to Statskontoret, while macro/fiscal projections remain IMF-first.
| ๐ Platforms | ๐ฆ Open-Source Projects | ๐ก๏ธ Governance & Standards |
|---|---|---|
| ๐ณ๏ธ Riksdagsmonitor โ Swedish Parliament intelligence ๐ช๐บ EU Parliament Monitor โ European coverage ๐ต๏ธ Citizen Intelligence Agency โ political-data engine ๐ Hack23 AB โ corporate site ๐ฐ Hack23 Blog โ engineering & policy ๐ผ Hack23 on LinkedIn | ๐ณ๏ธ Hack23/riksdagsmonitor ๐ต๏ธ Hack23/cia ๐ช๐บ Hack23/euparliamentmonitor ๐ Hack23/european-parliament-mcp โ Hack23/cia-compliance-manager ๐ฅ Hack23/black-trigram ๐ Hack23/homepage | ๐ก๏ธ Hack23 ISMS-PUBLIC โ public ISMS ๐ Information Security Policy ๐ค AI Policy ๐งช Secure Development Policy ๐ฏ Threat Modeling Policy โ ๏ธ Vulnerability Management ๐ท๏ธ Classification Framework |
๐ณ๏ธ Empower citizens ยท ๐ Strengthen democratic accountability ยท ๐ต๏ธ Illuminate the political process
ยฉ 2008โ2026 Hack23 AB (Org.nr 559534-7807) ยท Maintainer: James Pether Sรถrling, CISSP CISM