Collector: polisen-events (adopted — WAVE 2, batch 6)
The Polisen incident-notice daemon. Fetches the Swedish Police public events API (https://polisen.se/api/events — a top-level JSON array, no auth, no personal data) and lands each event as a row. Adopted to the daemon architecture (../collectors-daemon-design.md, §11) as a warehouse-sink (Iceberg) daemon. Implementor: src/iceberg_daemons.rs (PolisenDaemon, parse_polisen), behind --features daemon. Rides the existing generic REST/JSON record mapper rest::parse_records driven by the RestCollector::polisen() preset's field map (records at the document root — the empty pointer).
Config trait (Settings ▸ Collectors ▸ polisen-events)
enabled: bool
url: String // events API (default https://polisen.se/api/events; optionally ?locationname=&type=)
region: String // advisory — encode as ?locationname= in the URL
table: String // Iceberg table (default polisen_events)
State machine (State trait)
Offline → Downloading(fetch %) → Indexing(parse JSON) → Online // event rows landed
→ Failed{reason} // empty-is-RED / fetch/parse error
The State Facet renders sink=iceberg, phase, table, rows_written, last_run_unix, error. Green in the infra matrix only when ≥1 event row is landed.
Storage — Iceberg (warehouse-sink)
Rows land through CollectorCtx.warehouse (WarehouseSink) into polisen_events (columns: id, datetime, name, type, summary, url, location_name, gps). No S3 bucket.
Acquisition — the fetch seam (GET)
The events array is fetched through CollectorCtx.fetch GET (korp = the shared rustls HTTP core; tests = a canned Fetcher::from_map fixture, no live gov API). Fetch + parse run off the async reactor via spawn_blocking.
empty-is-RED
An enabled collector that parses to 0 events is a loud Failed{reason:"…(empty-is-RED)"} (red in the matrix), never a silent green.
Tests (src/iceberg_daemons.rs + tests/collector_daemons_register.rs)
polisen_daemon_reaches_online_and_sinks_events— the synthetic Polisen array (2 incidents) drives fetch→parse→append→Online, 2 rows inpolisen_events, facettable=polisen_events.batch6_empty_sources_are_red_not_silently_green— an empty[]array ⇒Failed/red.batch6_daemons_go_red_then_green_in_the_register— absent → RED (never-run) → GREEN (Online) as read back out-of-process through aRegisterReader.
Credential note
Open API, no key — fully exercised live and offline. (Measured standalone: serve reached ONLINE and landed 500 rows to polisen_events with no korp server, its phase readable via korp-collectors status from a separate process.)