riksdagsmonitor 0.9.11 → 0.9.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/cia/csv-contracts.d.ts +49 -0
- package/dist/lib/cia/csv-contracts.d.ts.map +1 -0
- package/dist/lib/cia/csv-contracts.js +464 -0
- package/dist/lib/cia/csv-contracts.js.map +1 -0
- package/dist/lib/cia/csv-validator.d.ts +46 -0
- package/dist/lib/cia/csv-validator.d.ts.map +1 -0
- package/dist/lib/cia/csv-validator.js +78 -0
- package/dist/lib/cia/csv-validator.js.map +1 -0
- package/dist/lib/dashboards/committees-dashboard.js +4 -4
- package/dist/lib/dashboards/committees-dashboard.js.map +1 -1
- package/dist/lib/dashboards/election-cycle.d.ts.map +1 -1
- package/dist/lib/dashboards/election-cycle.js +40 -14
- package/dist/lib/dashboards/election-cycle.js.map +1 -1
- package/dist/lib/dashboards/party-dashboard.d.ts.map +1 -1
- package/dist/lib/dashboards/party-dashboard.js +5 -1
- package/dist/lib/dashboards/party-dashboard.js.map +1 -1
- package/dist/lib/dashboards/risk-dashboard.js +3 -3
- package/dist/lib/dashboards/risk-dashboard.js.map +1 -1
- package/dist/lib/shared/data-loader.d.ts.map +1 -1
- package/dist/lib/shared/data-loader.js +32 -9
- package/dist/lib/shared/data-loader.js.map +1 -1
- package/package.json +10 -7
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the canonical schema of every CSV file
|
|
3
|
+
* consumed by a Riksdagsmonitor dashboard.
|
|
4
|
+
*
|
|
5
|
+
* Each entry maps an absolute `/cia-data/...` path to:
|
|
6
|
+
* - `requiredColumns`: column names that MUST appear in the header
|
|
7
|
+
* row. Dashboard code is allowed to read ONLY these columns; any
|
|
8
|
+
* legacy fallback column read is a contract violation.
|
|
9
|
+
* - `dashboard`: human-readable dashboard slug the CSV belongs to
|
|
10
|
+
* (used for grouping in test output).
|
|
11
|
+
* - `minRows`: minimum number of data rows expected (defaults to 1).
|
|
12
|
+
*
|
|
13
|
+
* This contract is enforced from three sides:
|
|
14
|
+
* 1. Build-time vitest contract test
|
|
15
|
+
* (`tests/cia-csv-contracts.test.ts`) walks the real `cia-data/`
|
|
16
|
+
* tree and asserts every contract.
|
|
17
|
+
* 2. Runtime validator (`src/browser/cia/csv-validator.ts`) checks
|
|
18
|
+
* fetched rows against this registry and throws a clear,
|
|
19
|
+
* visible Error so missing columns surface as an error banner
|
|
20
|
+
* instead of a silently-empty chart.
|
|
21
|
+
* 3. Cypress contract spec
|
|
22
|
+
* (`cypress/e2e/dashboards-per-chart/csv-contracts.cy.js`)
|
|
23
|
+
* re-runs the same assertions against the served preview /
|
|
24
|
+
* production site, guarding the deploy pipeline.
|
|
25
|
+
*
|
|
26
|
+
* RULE: No legacy column fallbacks. If a CSV producer changes its
|
|
27
|
+
* schema, update this file (and the dashboard code that reads it) in
|
|
28
|
+
* the same commit. Do NOT add `column_a ?? column_b` fallbacks in
|
|
29
|
+
* dashboard rendering code.
|
|
30
|
+
*/
|
|
31
|
+
export interface CsvContract {
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly dashboard: string;
|
|
34
|
+
readonly requiredColumns: readonly string[];
|
|
35
|
+
readonly minRows?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare const CSV_CONTRACTS: readonly CsvContract[];
|
|
38
|
+
/**
|
|
39
|
+
* Look up the contract for a given absolute `/cia-data/...` path.
|
|
40
|
+
* Returns `null` when no contract is registered (e.g. an export
|
|
41
|
+
* that is not yet wired into a dashboard).
|
|
42
|
+
*/
|
|
43
|
+
export declare function getCsvContract(path: string): CsvContract | null;
|
|
44
|
+
/**
|
|
45
|
+
* All contracts grouped by dashboard slug, useful for iterating
|
|
46
|
+
* per-dashboard in tests.
|
|
47
|
+
*/
|
|
48
|
+
export declare function contractsByDashboard(): Record<string, readonly CsvContract[]>;
|
|
49
|
+
//# sourceMappingURL=csv-contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-contracts.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/csv-contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAyb/C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC,CAO7E"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
export const CSV_CONTRACTS = [
|
|
2
|
+
// --------------------------------------------------------------
|
|
3
|
+
// /dashboards/parties.html
|
|
4
|
+
// --------------------------------------------------------------
|
|
5
|
+
{
|
|
6
|
+
path: '/cia-data/party/distribution_party_performance.csv',
|
|
7
|
+
dashboard: 'parties',
|
|
8
|
+
requiredColumns: [
|
|
9
|
+
'party',
|
|
10
|
+
'party_name',
|
|
11
|
+
'active_members',
|
|
12
|
+
'inactive_members',
|
|
13
|
+
'documents_last_year',
|
|
14
|
+
'motions_last_year',
|
|
15
|
+
'propositions_last_year',
|
|
16
|
+
'docs_per_member',
|
|
17
|
+
'performance_level',
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
path: '/cia-data/party/distribution_party_effectiveness_trends.csv',
|
|
22
|
+
dashboard: 'parties',
|
|
23
|
+
requiredColumns: [
|
|
24
|
+
'party',
|
|
25
|
+
'year',
|
|
26
|
+
'quarter',
|
|
27
|
+
'documents_produced',
|
|
28
|
+
'motions_count',
|
|
29
|
+
'active_members',
|
|
30
|
+
'avg_win_rate',
|
|
31
|
+
'effectiveness_assessment',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
path: '/cia-data/party/distribution_party_momentum.csv',
|
|
36
|
+
dashboard: 'parties',
|
|
37
|
+
requiredColumns: [
|
|
38
|
+
'party',
|
|
39
|
+
'year',
|
|
40
|
+
'quarter',
|
|
41
|
+
'period',
|
|
42
|
+
'participation_rate',
|
|
43
|
+
'momentum',
|
|
44
|
+
'trend_direction',
|
|
45
|
+
'stability_classification',
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
path: '/cia-data/party/distribution_coalition_alignment.csv',
|
|
50
|
+
dashboard: 'parties',
|
|
51
|
+
requiredColumns: [
|
|
52
|
+
'party1',
|
|
53
|
+
'party2',
|
|
54
|
+
'shared_votes',
|
|
55
|
+
'aligned_votes',
|
|
56
|
+
'opposed_votes',
|
|
57
|
+
'alignment_rate',
|
|
58
|
+
'coalition_likelihood',
|
|
59
|
+
'bloc_relationship',
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
path: '/cia-data/party/distribution_annual_party_members.csv',
|
|
64
|
+
dashboard: 'parties',
|
|
65
|
+
requiredColumns: ['year', 'party', 'active_members'],
|
|
66
|
+
},
|
|
67
|
+
// --------------------------------------------------------------
|
|
68
|
+
// /dashboards/coalitions.html
|
|
69
|
+
// --------------------------------------------------------------
|
|
70
|
+
{
|
|
71
|
+
path: '/cia-data/parties/distribution_behavioral_patterns_by_party.csv',
|
|
72
|
+
dashboard: 'coalitions',
|
|
73
|
+
requiredColumns: [
|
|
74
|
+
'party',
|
|
75
|
+
'behavioral_assessment',
|
|
76
|
+
'politician_count',
|
|
77
|
+
'avg_absence_rate',
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
path: '/cia-data/parties/distribution_decision_patterns_by_party.csv',
|
|
82
|
+
dashboard: 'coalitions',
|
|
83
|
+
requiredColumns: [
|
|
84
|
+
'party',
|
|
85
|
+
'committee',
|
|
86
|
+
'decision_year',
|
|
87
|
+
'decision_count',
|
|
88
|
+
'total_decisions',
|
|
89
|
+
'avg_approval_rate',
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
path: '/cia-data/anomaly/distribution_anomaly_by_party.csv',
|
|
94
|
+
dashboard: 'coalitions',
|
|
95
|
+
requiredColumns: [
|
|
96
|
+
'party',
|
|
97
|
+
'anomaly_classification',
|
|
98
|
+
'politician_count',
|
|
99
|
+
'avg_rebellions',
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
// --------------------------------------------------------------
|
|
103
|
+
// /dashboards/committees.html
|
|
104
|
+
// --------------------------------------------------------------
|
|
105
|
+
{
|
|
106
|
+
path: '/cia-data/distribution_committee_productivity_matrix.csv',
|
|
107
|
+
dashboard: 'committees',
|
|
108
|
+
requiredColumns: [
|
|
109
|
+
'committee_code',
|
|
110
|
+
'committee_name',
|
|
111
|
+
'year',
|
|
112
|
+
'quarter',
|
|
113
|
+
'total_documents',
|
|
114
|
+
'active_members',
|
|
115
|
+
'productivity_level',
|
|
116
|
+
'productivity_assessment',
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
path: '/cia-data/distribution_annual_committee_documents.csv',
|
|
121
|
+
dashboard: 'committees',
|
|
122
|
+
requiredColumns: ['year', 'committee', 'doc_count'],
|
|
123
|
+
},
|
|
124
|
+
// --------------------------------------------------------------
|
|
125
|
+
// /dashboards/election-cycle.html
|
|
126
|
+
// --------------------------------------------------------------
|
|
127
|
+
{
|
|
128
|
+
path: '/cia-data/election-cycle/view_election_cycle_comparative_analysis_sample.csv',
|
|
129
|
+
dashboard: 'election-cycle',
|
|
130
|
+
requiredColumns: [
|
|
131
|
+
'year',
|
|
132
|
+
'is_election_year',
|
|
133
|
+
'total_ballots',
|
|
134
|
+
'attendance_rate',
|
|
135
|
+
'avg_yes_rate',
|
|
136
|
+
'documents_produced',
|
|
137
|
+
'motions_filed',
|
|
138
|
+
'proposals_filed',
|
|
139
|
+
'nearest_election_year',
|
|
140
|
+
'years_from_election',
|
|
141
|
+
'election_proximity',
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
path: '/cia-data/election-cycle/view_election_cycle_decision_intelligence_sample.csv',
|
|
146
|
+
dashboard: 'election-cycle',
|
|
147
|
+
requiredColumns: [
|
|
148
|
+
'election_cycle_id',
|
|
149
|
+
'cycle_year',
|
|
150
|
+
'calendar_year',
|
|
151
|
+
'semester',
|
|
152
|
+
'party',
|
|
153
|
+
'total_proposals',
|
|
154
|
+
'approved_proposals',
|
|
155
|
+
'rejected_proposals',
|
|
156
|
+
'avg_approval_rate',
|
|
157
|
+
'decision_effectiveness',
|
|
158
|
+
'temporal_approval_rate',
|
|
159
|
+
'ntile_effectiveness',
|
|
160
|
+
'decision_trend',
|
|
161
|
+
'legislative_momentum',
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
path: '/cia-data/election-cycle/view_election_cycle_predictive_intelligence_sample.csv',
|
|
166
|
+
dashboard: 'election-cycle',
|
|
167
|
+
requiredColumns: [
|
|
168
|
+
'election_cycle_id',
|
|
169
|
+
'cycle_year',
|
|
170
|
+
'calendar_year',
|
|
171
|
+
'semester',
|
|
172
|
+
'risk_forecast_category',
|
|
173
|
+
'politicians_at_risk',
|
|
174
|
+
'avg_risk_score_change',
|
|
175
|
+
'ministries_at_risk',
|
|
176
|
+
'forecast_confidence',
|
|
177
|
+
'predictive_alert_level',
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
path: '/cia-data/election-cycle/view_election_cycle_temporal_trends_sample.csv',
|
|
182
|
+
dashboard: 'election-cycle',
|
|
183
|
+
requiredColumns: [
|
|
184
|
+
'election_cycle_id',
|
|
185
|
+
'cycle_year',
|
|
186
|
+
'calendar_year',
|
|
187
|
+
'semester',
|
|
188
|
+
'is_pre_election_semester',
|
|
189
|
+
'avg_attendance_rate',
|
|
190
|
+
'total_ballots',
|
|
191
|
+
'avg_approval_rate',
|
|
192
|
+
'attendance_trend',
|
|
193
|
+
'overall_performance_score',
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
// --------------------------------------------------------------
|
|
197
|
+
// /dashboards/seasonal-patterns.html
|
|
198
|
+
// --------------------------------------------------------------
|
|
199
|
+
{
|
|
200
|
+
path: '/cia-data/seasonal/view_riksdagen_seasonal_activity_patterns_sample.csv',
|
|
201
|
+
dashboard: 'seasonal-patterns',
|
|
202
|
+
requiredColumns: [
|
|
203
|
+
'year',
|
|
204
|
+
'quarter',
|
|
205
|
+
'is_election_year',
|
|
206
|
+
'election_cycle',
|
|
207
|
+
'total_ballots',
|
|
208
|
+
'active_politicians',
|
|
209
|
+
'attendance_rate',
|
|
210
|
+
'documents_produced',
|
|
211
|
+
'ballot_z_score',
|
|
212
|
+
'doc_z_score',
|
|
213
|
+
'attendance_z_score',
|
|
214
|
+
'base_activity_classification',
|
|
215
|
+
'qoq_ballot_change_pct',
|
|
216
|
+
'seasonal_pattern_classification',
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
// --------------------------------------------------------------
|
|
220
|
+
// /dashboards/pre-election.html
|
|
221
|
+
// --------------------------------------------------------------
|
|
222
|
+
{
|
|
223
|
+
path: '/cia-data/pre-election/view_riksdagen_pre_election_quarterly_activity_sample.csv',
|
|
224
|
+
dashboard: 'pre-election',
|
|
225
|
+
requiredColumns: [
|
|
226
|
+
'year',
|
|
227
|
+
'is_election_year',
|
|
228
|
+
'total_ballots',
|
|
229
|
+
'avg_attendance_rate',
|
|
230
|
+
'avg_win_rate',
|
|
231
|
+
'avg_rebel_rate',
|
|
232
|
+
'total_documents',
|
|
233
|
+
'total_proposals',
|
|
234
|
+
'total_motions',
|
|
235
|
+
'total_new_assignments',
|
|
236
|
+
'avg_party_win_rate',
|
|
237
|
+
'avg_party_absence_rate',
|
|
238
|
+
'party_documents_total',
|
|
239
|
+
'baseline_ballots',
|
|
240
|
+
'baseline_documents',
|
|
241
|
+
'baseline_assignments',
|
|
242
|
+
'ballot_deviation_from_baseline',
|
|
243
|
+
'document_deviation_from_baseline',
|
|
244
|
+
'assignment_deviation_from_baseline',
|
|
245
|
+
'ballot_percent_change_from_baseline',
|
|
246
|
+
'document_percent_change_from_baseline',
|
|
247
|
+
'ballot_z_score',
|
|
248
|
+
'document_z_score',
|
|
249
|
+
'q4_activity_classification',
|
|
250
|
+
'yoy_ballot_change_pct',
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
path: '/cia-data/pre-election/view_riksdagen_q4_election_year_comparison_sample.csv',
|
|
255
|
+
dashboard: 'pre-election',
|
|
256
|
+
requiredColumns: [
|
|
257
|
+
'year',
|
|
258
|
+
'is_election_year',
|
|
259
|
+
'total_ballots',
|
|
260
|
+
'attendance_rate',
|
|
261
|
+
'documents_produced',
|
|
262
|
+
'ballot_deviation_from_baseline',
|
|
263
|
+
'doc_deviation_from_baseline',
|
|
264
|
+
'attendance_deviation_from_baseline',
|
|
265
|
+
'ballot_percent_change',
|
|
266
|
+
'doc_percent_change',
|
|
267
|
+
'q4_pattern',
|
|
268
|
+
'activity_classification',
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
// --------------------------------------------------------------
|
|
272
|
+
// /dashboards/anomaly-detection.html
|
|
273
|
+
// --------------------------------------------------------------
|
|
274
|
+
{
|
|
275
|
+
path: '/cia-data/seasonal/view_riksdagen_seasonal_anomaly_detection_sample.csv',
|
|
276
|
+
dashboard: 'anomaly-detection',
|
|
277
|
+
requiredColumns: [
|
|
278
|
+
'year',
|
|
279
|
+
'quarter',
|
|
280
|
+
'is_election_year',
|
|
281
|
+
'total_ballots',
|
|
282
|
+
'active_politicians',
|
|
283
|
+
'attendance_rate',
|
|
284
|
+
'documents_produced',
|
|
285
|
+
'ballot_z_score',
|
|
286
|
+
'doc_z_score',
|
|
287
|
+
'attendance_z_score',
|
|
288
|
+
'activity_classification',
|
|
289
|
+
'anomaly_type',
|
|
290
|
+
'anomaly_direction',
|
|
291
|
+
'max_z_score',
|
|
292
|
+
'anomaly_severity',
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
// --------------------------------------------------------------
|
|
296
|
+
// /dashboards/ministers.html
|
|
297
|
+
// --------------------------------------------------------------
|
|
298
|
+
{
|
|
299
|
+
path: '/cia-data/ministry/distribution_ministry_productivity_matrix.csv',
|
|
300
|
+
dashboard: 'ministers',
|
|
301
|
+
requiredColumns: [
|
|
302
|
+
'ministry_name',
|
|
303
|
+
'year',
|
|
304
|
+
'documents_produced',
|
|
305
|
+
'propositions',
|
|
306
|
+
'government_bills',
|
|
307
|
+
'unique_contributors',
|
|
308
|
+
'performance_assessment',
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
path: '/cia-data/ministry/distribution_ministry_risk_levels.csv',
|
|
313
|
+
dashboard: 'ministers',
|
|
314
|
+
requiredColumns: ['risk_level', 'period_count', 'percentage', 'avg_documents'],
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
path: '/cia-data/ministry/distribution_ministry_decision_impact.csv',
|
|
318
|
+
dashboard: 'ministers',
|
|
319
|
+
requiredColumns: [
|
|
320
|
+
'ministry_code',
|
|
321
|
+
'committee',
|
|
322
|
+
'decision_type',
|
|
323
|
+
'total_proposals',
|
|
324
|
+
'approved_proposals',
|
|
325
|
+
'rejected_proposals',
|
|
326
|
+
'approval_rate',
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
path: '/cia-data/ministry/distribution_ministry_effectiveness.csv',
|
|
331
|
+
dashboard: 'ministers',
|
|
332
|
+
requiredColumns: [
|
|
333
|
+
'ministry_name',
|
|
334
|
+
'year',
|
|
335
|
+
'quarter',
|
|
336
|
+
'documents_produced',
|
|
337
|
+
'government_bills',
|
|
338
|
+
'active_members',
|
|
339
|
+
'effectiveness_assessment',
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
path: '/cia-data/ministry/distribution_ministry_risk_quarterly.csv',
|
|
344
|
+
dashboard: 'ministers',
|
|
345
|
+
requiredColumns: ['year', 'quarter', 'risk_level', 'ministry_count', 'avg_documents'],
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
path: '/cia-data/politician/view_riksdagen_politician_influence_metrics_sample.csv',
|
|
349
|
+
dashboard: 'ministers',
|
|
350
|
+
requiredColumns: [
|
|
351
|
+
'person_id',
|
|
352
|
+
'first_name',
|
|
353
|
+
'last_name',
|
|
354
|
+
'party',
|
|
355
|
+
'network_connections',
|
|
356
|
+
'network_median',
|
|
357
|
+
'influence_classification',
|
|
358
|
+
'broker_classification',
|
|
359
|
+
'influence_assessment',
|
|
360
|
+
],
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
path: '/cia-data/ministry/view_ministry_productivity_matrix_sample.csv',
|
|
364
|
+
dashboard: 'ministers',
|
|
365
|
+
requiredColumns: [
|
|
366
|
+
'org_code',
|
|
367
|
+
'name',
|
|
368
|
+
'year',
|
|
369
|
+
'documents_produced',
|
|
370
|
+
'propositions',
|
|
371
|
+
'government_bills',
|
|
372
|
+
'unique_contributors',
|
|
373
|
+
'avg_documents',
|
|
374
|
+
'productivity_quartile',
|
|
375
|
+
'performance_assessment',
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
path: '/cia-data/ministry/view_ministry_risk_evolution_sample.csv',
|
|
380
|
+
dashboard: 'ministers',
|
|
381
|
+
requiredColumns: [
|
|
382
|
+
'org_code',
|
|
383
|
+
'name',
|
|
384
|
+
'assessment_period',
|
|
385
|
+
'year',
|
|
386
|
+
'quarter',
|
|
387
|
+
'documents_produced',
|
|
388
|
+
'legislative_count',
|
|
389
|
+
'active_members',
|
|
390
|
+
'document_trend',
|
|
391
|
+
'risk_level',
|
|
392
|
+
'risk_assessment',
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
// --------------------------------------------------------------
|
|
396
|
+
// /dashboards/risk.html
|
|
397
|
+
// --------------------------------------------------------------
|
|
398
|
+
{
|
|
399
|
+
path: '/cia-data/politician/view_politician_risk_summary_sample.csv',
|
|
400
|
+
dashboard: 'risk',
|
|
401
|
+
requiredColumns: [
|
|
402
|
+
'person_id',
|
|
403
|
+
'first_name',
|
|
404
|
+
'last_name',
|
|
405
|
+
'party',
|
|
406
|
+
'status',
|
|
407
|
+
'total_violations',
|
|
408
|
+
'risk_score',
|
|
409
|
+
'risk_level',
|
|
410
|
+
'risk_assessment',
|
|
411
|
+
],
|
|
412
|
+
},
|
|
413
|
+
// --------------------------------------------------------------
|
|
414
|
+
// /dashboard/index.html — CIA hub
|
|
415
|
+
// --------------------------------------------------------------
|
|
416
|
+
{
|
|
417
|
+
path: '/cia-data/election/election_forecast.csv',
|
|
418
|
+
dashboard: 'cia-hub',
|
|
419
|
+
requiredColumns: [
|
|
420
|
+
'id',
|
|
421
|
+
'name',
|
|
422
|
+
'currentSeats',
|
|
423
|
+
'predictedSeats',
|
|
424
|
+
'change',
|
|
425
|
+
'voteShare',
|
|
426
|
+
'confidenceMin',
|
|
427
|
+
'confidenceMax',
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
path: '/cia-data/election/coalition_scenarios.csv',
|
|
432
|
+
dashboard: 'cia-hub',
|
|
433
|
+
requiredColumns: [
|
|
434
|
+
'name',
|
|
435
|
+
'probability',
|
|
436
|
+
'composition',
|
|
437
|
+
'totalSeats',
|
|
438
|
+
'majority',
|
|
439
|
+
'riskLevel',
|
|
440
|
+
],
|
|
441
|
+
},
|
|
442
|
+
];
|
|
443
|
+
/**
|
|
444
|
+
* Look up the contract for a given absolute `/cia-data/...` path.
|
|
445
|
+
* Returns `null` when no contract is registered (e.g. an export
|
|
446
|
+
* that is not yet wired into a dashboard).
|
|
447
|
+
*/
|
|
448
|
+
export function getCsvContract(path) {
|
|
449
|
+
return CSV_CONTRACTS.find((c) => c.path === path) ?? null;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* All contracts grouped by dashboard slug, useful for iterating
|
|
453
|
+
* per-dashboard in tests.
|
|
454
|
+
*/
|
|
455
|
+
export function contractsByDashboard() {
|
|
456
|
+
const out = {};
|
|
457
|
+
for (const c of CSV_CONTRACTS) {
|
|
458
|
+
if (!out[c.dashboard])
|
|
459
|
+
out[c.dashboard] = [];
|
|
460
|
+
out[c.dashboard].push(c);
|
|
461
|
+
}
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=csv-contracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-contracts.js","sourceRoot":"","sources":["../../../src/browser/cia/csv-contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime CSV column validator.
|
|
3
|
+
*
|
|
4
|
+
* Used by dashboard data-loaders right after a CSV is parsed.
|
|
5
|
+
* If the parsed rows are missing any of the columns declared in the
|
|
6
|
+
* registered `CsvContract` for a given path, this module throws a
|
|
7
|
+
* clear, structured error. Dashboard error handlers surface the
|
|
8
|
+
* thrown message in their visible error banner, so a CSV schema
|
|
9
|
+
* regression is impossible to ship as a silently-empty chart.
|
|
10
|
+
*
|
|
11
|
+
* Validation rules (intentionally strict — no legacy fallbacks):
|
|
12
|
+
* 1. Header check: every name in `contract.requiredColumns` must
|
|
13
|
+
* appear in the row keys of the first parsed record.
|
|
14
|
+
* 2. Row count: `rows.length >= contract.minRows ?? 1`.
|
|
15
|
+
* 3. No partial rows: a row missing one of the required column
|
|
16
|
+
* keys (i.e. the parser lost a column) fails the check.
|
|
17
|
+
*
|
|
18
|
+
* Use `validateCsvRows()` from any dashboard data loader. Use
|
|
19
|
+
* `validateCsvRowsLenient()` when the CSV is best-effort (e.g. an
|
|
20
|
+
* unreleased export pulled from a remote CDN); it only logs to
|
|
21
|
+
* `console.error` instead of throwing.
|
|
22
|
+
*/
|
|
23
|
+
import { type CsvContract } from './csv-contracts';
|
|
24
|
+
export declare class CsvContractError extends Error {
|
|
25
|
+
readonly path: string;
|
|
26
|
+
readonly missingColumns: readonly string[];
|
|
27
|
+
readonly availableColumns: readonly string[];
|
|
28
|
+
readonly rowCount: number;
|
|
29
|
+
constructor(path: string, missingColumns: readonly string[], availableColumns: readonly string[], rowCount: number);
|
|
30
|
+
}
|
|
31
|
+
type CsvRowLike = Readonly<Record<string, unknown>>;
|
|
32
|
+
/**
|
|
33
|
+
* Inspect parsed rows against the registered contract for `path`.
|
|
34
|
+
* Returns the input unchanged on success. Throws `CsvContractError`
|
|
35
|
+
* on any violation. If no contract is registered for `path`,
|
|
36
|
+
* validation is skipped (returns input).
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateCsvRows<T extends CsvRowLike>(path: string, rows: readonly T[], overrideContract?: CsvContract): readonly T[];
|
|
39
|
+
/**
|
|
40
|
+
* Same checks, but logs to `console.error` instead of throwing.
|
|
41
|
+
* Returns `true` when the contract is satisfied (or no contract is
|
|
42
|
+
* registered), `false` otherwise.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateCsvRowsLenient<T extends CsvRowLike>(path: string, rows: readonly T[]): boolean;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=csv-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-validator.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/csv-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,iBAAiB,CAAC;AAEnE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAExB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,gBAAgB,EAAE,SAAS,MAAM,EAAE,EACnC,QAAQ,EAAE,MAAM;CAanB;AAED,KAAK,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,UAAU,EAClD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,gBAAgB,CAAC,EAAE,WAAW,GAC7B,SAAS,CAAC,EAAE,CAqBd;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,UAAU,EACzD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,CAAC,EAAE,GACjB,OAAO,CAWT"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime CSV column validator.
|
|
3
|
+
*
|
|
4
|
+
* Used by dashboard data-loaders right after a CSV is parsed.
|
|
5
|
+
* If the parsed rows are missing any of the columns declared in the
|
|
6
|
+
* registered `CsvContract` for a given path, this module throws a
|
|
7
|
+
* clear, structured error. Dashboard error handlers surface the
|
|
8
|
+
* thrown message in their visible error banner, so a CSV schema
|
|
9
|
+
* regression is impossible to ship as a silently-empty chart.
|
|
10
|
+
*
|
|
11
|
+
* Validation rules (intentionally strict — no legacy fallbacks):
|
|
12
|
+
* 1. Header check: every name in `contract.requiredColumns` must
|
|
13
|
+
* appear in the row keys of the first parsed record.
|
|
14
|
+
* 2. Row count: `rows.length >= contract.minRows ?? 1`.
|
|
15
|
+
* 3. No partial rows: a row missing one of the required column
|
|
16
|
+
* keys (i.e. the parser lost a column) fails the check.
|
|
17
|
+
*
|
|
18
|
+
* Use `validateCsvRows()` from any dashboard data loader. Use
|
|
19
|
+
* `validateCsvRowsLenient()` when the CSV is best-effort (e.g. an
|
|
20
|
+
* unreleased export pulled from a remote CDN); it only logs to
|
|
21
|
+
* `console.error` instead of throwing.
|
|
22
|
+
*/
|
|
23
|
+
import { getCsvContract } from './csv-contracts';
|
|
24
|
+
export class CsvContractError extends Error {
|
|
25
|
+
path;
|
|
26
|
+
missingColumns;
|
|
27
|
+
availableColumns;
|
|
28
|
+
rowCount;
|
|
29
|
+
constructor(path, missingColumns, availableColumns, rowCount) {
|
|
30
|
+
super(`CSV ${path} fails its registered contract — missing columns: [${missingColumns.join(', ')}]; received ${rowCount} row(s); header: [${availableColumns.join(', ')}]`);
|
|
31
|
+
this.name = 'CsvContractError';
|
|
32
|
+
this.path = path;
|
|
33
|
+
this.missingColumns = missingColumns;
|
|
34
|
+
this.availableColumns = availableColumns;
|
|
35
|
+
this.rowCount = rowCount;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Inspect parsed rows against the registered contract for `path`.
|
|
40
|
+
* Returns the input unchanged on success. Throws `CsvContractError`
|
|
41
|
+
* on any violation. If no contract is registered for `path`,
|
|
42
|
+
* validation is skipped (returns input).
|
|
43
|
+
*/
|
|
44
|
+
export function validateCsvRows(path, rows, overrideContract) {
|
|
45
|
+
const contract = overrideContract ?? getCsvContract(path);
|
|
46
|
+
if (!contract)
|
|
47
|
+
return rows;
|
|
48
|
+
const minRows = contract.minRows ?? 1;
|
|
49
|
+
if (rows.length < minRows) {
|
|
50
|
+
throw new CsvContractError(path, contract.requiredColumns, rows[0] ? Object.keys(rows[0]) : [], rows.length);
|
|
51
|
+
}
|
|
52
|
+
const headerKeys = Object.keys(rows[0]);
|
|
53
|
+
const headerSet = new Set(headerKeys);
|
|
54
|
+
const missing = contract.requiredColumns.filter((c) => !headerSet.has(c));
|
|
55
|
+
if (missing.length > 0) {
|
|
56
|
+
throw new CsvContractError(path, missing, headerKeys, rows.length);
|
|
57
|
+
}
|
|
58
|
+
return rows;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Same checks, but logs to `console.error` instead of throwing.
|
|
62
|
+
* Returns `true` when the contract is satisfied (or no contract is
|
|
63
|
+
* registered), `false` otherwise.
|
|
64
|
+
*/
|
|
65
|
+
export function validateCsvRowsLenient(path, rows) {
|
|
66
|
+
try {
|
|
67
|
+
validateCsvRows(path, rows);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err instanceof CsvContractError) {
|
|
72
|
+
console.error('[csv-validator]', err.message);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=csv-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-validator.js","sourceRoot":"","sources":["../../../src/browser/cia/csv-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAoB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEnE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAS;IACb,cAAc,CAAoB;IAClC,gBAAgB,CAAoB;IACpC,QAAQ,CAAS;IAC1B,YACE,IAAY,EACZ,cAAiC,EACjC,gBAAmC,EACnC,QAAgB;QAEhB,KAAK,CACH,OAAO,IAAI,sDACT,cAAc,CAAC,IAAI,CAAC,IAAI,CAC1B,eAAe,QAAQ,qBAAqB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAID;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,IAAkB,EAClB,gBAA8B;IAE9B,MAAM,QAAQ,GAAG,gBAAgB,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QAC1B,MAAM,IAAI,gBAAgB,CACxB,IAAI,EACJ,QAAQ,CAAC,eAAe,EACxB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EACnC,IAAI,CAAC,MAAM,CACZ,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,IAAkB;IAElB,IAAI,CAAC;QACH,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|