Skip to content

Volume Budget Ledger

Phase 9 (Stream E — "the actual filling", docs/plan/phase-9-data-foundation.md) requires an expected raw + processed storage footprint per data pack, recorded before download, so the phase exit criterion can audit Hetzner disk usage against what was planned rather than discovering it after the fact. This file is that ledger.

Convention for the builders of #612–#620 — READ BEFORE EDITING

This table has one pre-stubbed row per wave-5 pack issue already. Nine issues (#612–#620) edit this file concurrently with each other and with any later pack issue. To avoid nine builders colliding on the same appended line:

  • Fill in your issue's existing row in place. Find the row whose Issue column matches your issue number and replace its placeholder cells with real values.
  • Do not append a new row. The row for your issue already exists below.
  • Do not reorder, renumber, or reformat other rows. Touch only your own line(s) — a table-wide reformat (e.g. realigning | columns) turns every other builder's small diff into a conflict.
  • Do not edit the Totals row's formula description — only its numbers, and only if you are genuinely the last pack to land (see "Totals" below). If you're unsure whether you're last, leave the totals row's numbers alone and just update your own row; whoever lands last recomputes it.
  • Every volume figure must trace to something read from the provider's own documentation, or be explicitly labelled an estimate with its basis stated inline. Never fill a cell with an invented number — an honest placeholder (TBD — pending ops download) is correct; a fabricated figure is not. This mirrors the provenance rule issue #621 established after this repo shipped mis-attributed flood curves (ADR-059): every number here must be traceable to a source you actually read.
  • Record the licence as the provider states it, not as assumed or copied from an unrelated document.

Columns

  • Issue / Pack — the GitHub issue and its one-line pack description.
  • Provider — the upstream data provider/publisher, as named in their own documentation.
  • Licence — the provider's own stated licence/reuse terms (SPDX id where one applies, otherwise the provider's own wording). Not assumed, not copied from a sibling pack.
  • Raw volume (est., transient peak GB) — this column measures transient peak local-disk headroom during a pack's download-then-clip step; it is NOT object-storage cost, and the Totals row is not a storage bill. Per ADR-070 the raw zone is a transient staging concept, not an archive: every pack streams its source download to local disk, clips/processes it there, ingests the result into DB rows or the processed zone, then deletes the local copy. Nothing archives the download into the bucket's raw/ prefix, which holds only .keep + catalog.v1.json (~0.03 MB) — see the "Raw-zone reality check" below. The reproducibility artifact is the per-dataset source manifest at hazards/{dataset_id}/source_manifest.json (ADR-066), not a retained raw copy. Recorded before download per the phase exit criterion. Label anything not read from the provider's own published file listing as an estimate, with the basis stated in Notes.
  • Processed volume (est., GB) — expected size of the committed, ingest-pipeline output: the hazards/{dataset_id}/intensity.npz the chord commits (ADR-049) plus, where the pack also produces one, the processed/{org}/{dataset_id}/hazard.tif COG (ADR-029). Exposure packs have no hazard COG; note that in the Notes column instead of leaving the cell blank.
  • Status — planned (budget recorded, not yet downloaded) / downloaded (raw zone populated, manifest written) / ingested (committed through the unified pipeline, catalogued) — update as your pack's ops work (post-merge, out of this builder's reach) progresses. Buildable work in this repo can only ever reach planned, since download/ops steps need the live Hetzner host.
  • Notes — basis for any estimate, caveats, source URL/citation pointer.

Totals

The Totals row sums the numeric raw/processed columns across every row above it that carries a real number (skip rows still at their pending placeholder). It is not kept live by automation — there is no CI job or script that recomputes it. Whoever edits the last remaining pending row in a merge wave should recompute and update the Totals row's numbers in that same PR. Until then the Totals row is understated by construction (it only sums what's filled in so far) — that is expected, not a bug; do not "fix" it by guessing at unfilled rows.

Raw-zone reality check — read this before treating the raw-volume column or the Totals row as a storage bill. Ratified as a deliberate design decision in ADR-070 (2026-08-10), which also amends Phase 9's exit criterion 3 so it no longer demands a raw-zone copy that does not exist for any of the ten packs. Verified live against the Hetzner bucket during the 2026-08-08 ops run (see docs/plan/phase-9-ops-plan.md OPS-5d): the raw/ prefix holds only two objects — .keep and catalog.v1.json, ~0.03 MB total — and the whole bucket was 0.325 GB, against this ledger's own raw-column sum of ≈24.6 GB (see the Totals row below). Re-measured 2026-08-10 after the NetCDF ops run and the trash/ purge: 158 objects / 359.87 MB (0.360 GB) in the bucket, against a raw-column sum of ≈24.87 GB — the same two-orders-of-magnitude gap, for the same reason. The raw/ prefix is still 2 objects / 0.04 MB. That is not a discrepancy to chase down; it is how this pipeline is built to behave. Every pack in this ledger streams its source download to local disk, clips/processes it there, and ingests the result straight into DB rows or the processed-zone artifact (hazards/{id}/intensity.npz) — then deletes the local download. Nothing in the current pipeline archives the raw download into the bucket's raw/ zone. The "Raw volume (est., GB)" column and the Totals row's raw figure therefore measure a transient — peak local-disk headroom needed during a pack's download-then-clip step — not bytes stored in the bucket, and neither should ever be read as a projection of object-storage cost.

Ledger

Issue Pack Provider Licence Raw volume (est., transient peak GB — not stored, see Columns + ADR-070) Processed volume (est., GB) Status Notes
#611 River flood — JRC Copernicus Emergency Management Service / European Commission Joint Research Centre — "River Flood Hazard Maps for Europe and the Mediterranean Basin" v3.1.1 CC-BY-4.0 (data.jrc.ec.europa.eu collection id-0054; recorded verbatim in scripts/historical_catalog_manifest.json → perils.river_flood.source.license/.license_url) ≤ 3.7 (estimate, upper bound — see note a) TBD (see note a) ingested (a) Nine return periods (RP10..RP500). The upstream per-RP full-"European extended domain" GeoTIFF is documented at ~260–330 MB in this repo (scripts/ingest_historical_catalog.py module docstring, verified against the live source 2026-07-27) → ~2.3–3.0 GB for all 9 RPs combined, but that full-domain file is never downloaded whole: scripts.packs.river_flood_jrc.run_ingest_hazards (via fetch_clip) does a rasterio windowed HTTP-range read of only the Greece bbox [19.0, 34.5, 28.5, 42.0]. At the source's native 3 arc-second (~90 m) resolution that bbox is 11 400 × 9 000 px/RP (≈1.03×10⁸ px); an uncompressed single-band float32 clip is ≈0.41 GB/RP × 9 ≈ 3.7 GB — a calculated upper bound, not a measurement, and the figure recorded above. fetch_clip writes with compress="deflate", and flood-depth rasters are mostly nodata/zero outside inundated cells, so the real, compressed footprint actually landing in the raw/staging zone is expected to be meaningfully smaller than this bound; no live download ran in this build to measure it, so no smaller point figure is asserted — that would be a guess, not a measurement. Processed (hazards/{id}/intensity.npz + processed/{org}/{id}/hazard.tif) is the ingest chord's own encoding of the same clipped data and is not sized here for the same reason — TBD pending the first real ops ingest, which needs a live Hetzner host and is out of reach in this build (no live network/DB here). Update 2026-08-10 (ops close-out) — this pack's national baseline had been sitting in prod with no COG at all, and now has one. JRC river flood Greece (national, historical baseline), id 67854ef5-8052-435d-9828-1a1015146654, had been active since 2026-08-07 with its intensity.npz intact but cog_path NULL. It is the same dataset that originally triggered #754 (a classic-TIFF write overflowing 4 GB — 11,400×9,000 × 9 bands ≈ 3.7 GB uncompressed, which is exactly this row's own calculated raw bound arriving as a real failure). Re-dispatching build_dataset_cog from the retained NPZ succeeded in 141.6 s, 9 bands, zero GDAL errors, so #754's fix is now confirmed in production against the very dataset that broke it — not merely against a test fixture. This is the entire reason the bucket's processed/ zone grew 89.77 MB → 158.75 MB on 2026-08-10 (see the Totals note (c)); by difference the COG is ≈68.98 MB, which is a derived figure, not a directly measured object size. The row's processed cell stays TBD because that derivation covers the COG only, not this pack's intensity.npz.
#612 River flood alt — Aqueduct Floods v2 World Resources Institute — "WRI Aqueduct Floods Hazard Maps (version 2)" (scripts/scenario_hazards_manifest.json → perils.river_flood.source.name) CC-BY-4.0 — "All the products, methodologies, and datasets that make up Aqueduct are available for use under the Creative Commons Attribution International 4.0 License", read live from wri.org/aqueduct in this build; matches what the manifest already recorded (.source.license/.license_url) and docs/concepts/eiopa-scenario-mapping.md's verification record (checked against WRI pages + the GEE catalog entry on 2026-07-27) ≤ 0.09 (estimate, upper bound — see note a) TBD (see note a) ingested (a) 7 datasets (2 scenarios × 3 horizons + 1 historical baseline) × 3 return periods (RP10/50/100) = 21 source files, never downloaded whole: scripts.packs.river_flood_aqueduct.run_ingest_hazards (via fetch_clip, shared with the JRC pack) does a rasterio windowed HTTP-range read of only the Greece bbox [19.0, 34.5, 28.5, 42.0]. docs/concepts/eiopa-scenario-mapping.md's verification record documents a real (not calculated) windowed test read of the RCP8.5/2080/RP100 file on 2026-07-27, returning a measured 1140×900 px tile at the source's native 0.008333°/~30 arc-second resolution; the other 20 files share the same bbox and resolution, so the same tile size is assumed uniform across them (not independently re-measured here). An uncompressed single-band float32 clip at that size is 1140×900×4 B ≈ 4.10 MB/file × 21 ≈ 86 MB ≈ 0.09 GB — a calculated upper bound from one measured tile, not a full download. fetch_clip writes with compress="deflate" and flood-depth rasters are mostly nodata outside inundated cells, so the real compressed footprint landing in the raw/staging zone is expected to be smaller than this bound; no live download ran in this build to measure it, so no smaller point figure is asserted. For reference, the full global per-RP GeoTIFFs (never downloaded) were HEAD-verified at ~88–93 MB each (docs/concepts/eiopa-scenario-mapping.md) → ~21×90 MB ≈ 1.9 GB if fetched whole, which this pack avoids entirely via the windowed clip. Processed (hazards/{id}/intensity.npz, no separate COG for this scenario-conditioned pack) is the ingest chord's own encoding of the same clipped data and is not sized here for the same reason as #611 — TBD pending the first real ops ingest, which needs a live Hetzner host and is out of reach in this build (no live network/DB here).
#613 Coastal flood — LISCOAST + Aqueduct coastal World Resources Institute — "WRI Aqueduct Floods Hazard Maps (version 2)", coastal variant (scripts/packs/coastal_flood.py → COASTAL_SOURCE); JRC LISCOAST evaluated but NOT ingested (see note a) CC-BY-4.0 — Aqueduct only (WRI's own statement re-verified live 2026-08-06 against wri.org/aqueduct, unchanged from #612's recorded text) ≤ 0.09 (estimate, upper bound — Aqueduct coastal only, see note a) TBD (see note a) ingested (Aqueduct coastal half only — LISCOAST stays permanently out of scope per ADR-062, see note a) (a) LISCOAST is evaluated but deliberately NOT wired into ingest — the issue's own context line ("LISCOAST format likely NetCDF") does not hold for the real artifact: this build downloaded the JRC LISCOAST "Global Extreme Sea Level projections" archive whole (small enough under the no-multi-GB rule — https://cidportal.jrc.ec.europa.eu/ftp/jrc-opendata/LISCOAST/10012/LATEST/globalESLprojections.zip, 13,351,354 bytes, measured via both a live HTTP HEAD and the actual downloaded+inspected body in this build) and inspected it directly: its own README.txt states "The data are provided in csv files for all combination of parameter, year and RCP", and every one of its 24 CSVs is latitude,longitude,valueMedian,value5th,value95th — irregularly-spaced coastal transect points, not a raster. This platform's hazard-ingest formats (GeoTIFF; NetCDF per #593/ADR-051) both require a regular grid, so neither can ingest scattered points without a new point/vector IngestAdapter (Stream B scope, out of reach of this Stream E pack issue). Recorded as an honest evaluated-source (scripts/packs/coastal_flood.py::LISCOAST_EVALUATED_SOURCE), not silently dropped — mirrors the evaluated_sources shape the scenario manifest already uses for its wildfire/windstorm gaps. Decision final (ADR-062, 2026-08-07): LISCOAST is permanently out of scope for hazard ingest — coastal flood ships computable on Aqueduct coastal alone, so no point→grid ingest path is built; reversible by superseding ADR-062 if a point-published hazard source later becomes load-bearing. Aqueduct coastal (inuncoast_*), by contrast, ingests exactly like the riverine variant (#612): 7 datasets (2 scenarios × 3 horizons + 1 historical baseline) × 3 return periods (RP10/50/100) = 21 source files, every URL HTTP HEAD-verified live in this build (2026-08-06, all 200 image/tiff), never downloaded whole — scripts.packs.coastal_flood.run_ingest_hazards (via fetch_clip, the same helper #611/#612 already share) does a rasterio windowed HTTP-range read of only the Greece bbox [19.0, 34.5, 28.5, 42.0]. That windowed read was actually performed once in this build (not just calculated) against inuncoast_rcp8p5_wtsub_2080_rp0100_0.tif: a real measured 900×1140 px tile at the source's native 0.008333°/~30 arcsec resolution — identical grid to the riverine variant's own measured tile (#612), so the same per-file size is assumed uniform across the other 20 files (not independently re-measured here). An uncompressed single-band float32 clip at that size is 900×1140×4 B ≈ 4.10 MB/file × 21 ≈ 86 MB ≈ 0.09 GB — an upper bound from one measured tile, not a full download; fetch_clip writes with compress="deflate" and coastal-depth rasters are mostly nodata outside inundated cells, so the real compressed footprint is expected to be smaller. Subsidence variant fixed at wtsub (WRI's methodology documents both wtsub/nosub without a stated default — recorded as an [ASSUMPTION] in the pack module, not a missing option: nosub also HEAD-verified 200 in this build). Processed (hazards/{id}/intensity.npz) is not sized here for the same reason as #611/#612 — TBD pending the first real ops ingest on a live Hetzner host, out of reach in this build.
#614 Wildfire FWI — GEFF/ERA5 historical (EWDS) + C3S projections (CDS) — indicator-only, Refs #481: no EAI on FWI, ever ECMWF / Copernicus Emergency Management Service (CEMS), distributed via EWDS — cems-fire-historical-v1 (historical); Copernicus Climate Change Service (C3S) / ECMWF, distributed via CDS — sis-tourism-fire-danger-indicators (projections), both verified live against docs/DATA_SOURCES.html Sec 4.3 and docs/concepts/eiopa-scenario-mapping.md's own prior verification of the projections dataset EWDS historical: CC-BY family (its own landing page states "CC-BY family (Copernicus licence; per-dataset acceptance at download)" — docs/DATA_SOURCES.html Sec 4.3). CDS projections: TBD — see note a; its own landing page carries no licence line at all (unlike its EWDS sibling), so it is not assumed to match 0.0295 (measured 2026-08-10 — supersedes the ≤0.0002 calculated bound, which is kept visible in note a) 0.0000141 (measured 2026-08-10 — EWDS half only; the C3S half has no processed artifact because it is not ingested) partially ingested — EWDS historical ingested in prod 2026-08-10; C3S projections downloaded but NOT ingested (rotated-pole grid, see note a) (a) Neither dataset was downloaded in this build — both are authenticated, queue-based Retrieve-API stores with no anonymous HTTP HEAD path, so no live measurement is possible without a credentialed ECMWF account (matching this issue's own PROVENANCE constraint). Both figures below are calculated upper bounds from the datasets' own stated resolutions (docs/DATA_SOURCES.html Sec 4.3), clipped to the Greece bbox [19.0, 34.5, 28.5, 42.0], uncompressed float32, no compression credit taken (scripts/packs/_wildfire_fwi_common.py::estimate_raw_volume_bytes, unit-tested against synthetic fixtures). EWDS historical (scripts/packs/wildfire_fwi_ewds.py): ~0.25° grid → 38×30 = 1140 cells; this pack requests one reference date per invocation (not the full 1940→present daily series — see the pack's module docstring for why), so 1 slice × 1140 cells × 4 B ≈ 4.6 KB, effectively 0.0000045 GB. C3S projections (scripts/packs/wildfire_fwi_c3s.py): ~0.11° grid → 87×69 = 6003 cells; one retrieval covers all 3 scenarios (RCP2.6/4.5/8.5) — this pack's NetCDFDatasetSpec.supported_years is deliberately left undeclared (derived from the file, not hard-coded, since the exact year cadence to 2098 could not be verified without a live download) so this estimate assumes the platform's existing 3-horizon convention (2030/2050/2080, matching Aqueduct/#612) as a stated planning basis, not a confirmed file layout: 3 scenarios × 3 horizons × 6003 cells × 4 B ≈ 211 KB, effectively 0.0002 GB. Both totals stay well under 1 GB even if the real per-dataset time-step cadence turns out finer than assumed, because the Greece bbox clip is small at either resolution. Processed volume is TBD for the same reason as #611/#612 (no live ops ingest in this build) and because dispatch through the unified pipeline is currently blocked by a real platform gap this build found and filed as #706: resolve_ingest_adapter resolves every registered HazardType — including wildfire — to the GeoTIFF adapter regardless of the staged file's actual format, so a NetCDF FWI ingest cannot complete through the chord until that lands (both packs' run_ingest_hazards fail fast with an actionable error naming the issue rather than dispatching into a chord that would fail deep in the worker; this same gap is independently corroborated by #615's own row/PR below). Both packs are otherwise complete and unit-tested (tests/scripts/test_wildfire_fwi_ewds_pack.py, test_wildfire_fwi_c3s_pack.py, test_wildfire_fwi_common.py): NetCDF spec registration, request construction, and the CDS/EWDS retrieval driver (CdsApiClient/CdsRetrieval, exercised against a scripted httpx.MockTransport, no live credentials). Per-dataset licence acceptance (both stores) and the actual raw-zone download remain ops-only, out of this build's reach (no network/credentials here) — this issue's buildable acceptance checks do not require a completed ops ingest. Update 2026-08-10 (supersedes the 2026-08-08 line this row used to carry, which said "#761 is now CLOSED" — it is not). As of trunk d4b2cc5, no known CODE blocker remains: #706 (PR #717), #761's two worker-side gaps (ADR-064), #782 (PR #794), #791 (PR #798, ADR-067), #793 (PR #800, ADR-068) and #797 (PR #804, ADR-069) are all fixed. [SUPERSEDED 2026-08-10 (late), kept verbatim because this row's own convention is to show what was believed and when — both sentences below are now FALSE: "#761 itself is deliberately still OPEN, repurposed as the end-to-end evidence gate. The assert_netcdf_adapter_wired guard therefore still refuses every dispatch, by design — not for a missing fix, but because no NetCDF ingest has ever been staged, chunked and committed through the chord in any environment." What is true instead: #761 is CLOSED, and PR #825 (42f2a35) deleted layer 2 of assert_netcdf_adapter_wired — the evidence gate — along with its one-shot --first-end-to-end-run escape and the ADAPTER_GAP_ISSUE_URL constant. The guard that survives on trunk performs the plan-time adapter-resolution check only, and refuses nothing that resolves to the right reader. The evidence the gate demanded was produced by the first real end-to-end NetCDF ingest, recorded in the closing update at the end of this row.] Read NETCDF_INGEST_BLOCKERS in scripts/packs/_wildfire_fwi_common.py on trunk before citing a blocker from this row (ADAPTER_GAP_ISSUE_URL no longer exists to read). CDS/EWDS credentials ARE present in the worker (verified live 2026-08-08: CDSAPI_KEY, EWDSAPI_KEY, CDSAPI_URL, EWDSAPI_URL all set) — credentials are not what is blocking this row. Update 2026-08-09 (#802): the first successful retrieval this project ever ran was against the EWDS half of this row — cems-fire-historical-v1, jobID fd5475dd-c034-4ff5-a696-83e8314a3952, 201 → successful in ~24 s → application/netcdf, 28402 bytes measured for a 33×45-cell single-date Greece clip. That supersedes the EWDS estimate above with a measurement (~28 KB compressed vs the ~4.6 KB uncompressed float32 calculation — the delivered file carries CF metadata and a valid_time axis the estimate did not account for). The C3S projections estimate above is now known to be too low: sis-tourism-fire-danger-indicators declares no area request input, so it cannot be clipped server-side and the full European domain is delivered and clipped locally — the ~0.0002 GB Greece-clip figure describes the stored result, not the download. The download total stays TBD: sizing it needs gcm_model/period/time_aggregation/version, whose enums were not captured, so the pack refuses to build a request at all rather than guess. Update 2026-08-10 (#614) — supersedes the "TBD" immediately above, and the C3S half of this row is now MEASURED. All five missing enums were captured, the process's constraints.json was captured with them, and the first C3S retrieval this project has ever run was submitted and downloaded: job 520e1990-6fa4-451d-ba81-2b67450a48aa, 201 → successful, 29 435 326 bytes of application/zip. Request: time_aggregation=seasonal_indicators, product_type=multi_model_mean_case, variable=[seasonal_fire_weather_index], experiment=[rcp2_6,rcp4_5,rcp8_5], period=[2026_2030], version=v2_0, no gcm_model (every multi_model_* constraint block omits it). Note daily_fire_weather_index — what the pack asked for until now — is reachable only with single_model+daily_indicators and can never be combined with a multi-model product type. Download sizing: ~29.4 MB per (3-experiment × one 5-year band) retrieval, so the full 3-horizon pack is ~88 MB — three orders of magnitude above the 0.0002 GB Greece-clip figure, because there is no server-side area and the whole 424×412 European domain arrives. Two new blockers, both measured by opening the file, now stop the ingest regardless of #761: (1) the asset is a ZIP holding one NetCDF per experiment, not the single .nc the dispatch path passes to the worker — and there is no scenario dimension in any member, the scenario is a filename token; (2) the members are on a rotated-pole grid (grid_mapping_name=rotated_latitude_longitude, north pole 39.25 N / −162.0 E) and NetCDF ingest is EPSG:4326-only with no reprojecting read. Worse, before #614 that second one was silent: rlon/rlat are evenly spaced, so the file inspected cleanly as EPSG:4326 with its origin at lon −28.43 / lat 21.89 — the mid Atlantic. #614 added an explicit CF grid_mapping_name guard to core/ingest/netcdf.py that fails it closed, corrected the layout to the measured fwi-mean-jjas(time, rlat, rlon), and made wildfire_fwi_c3s.run_ingest_hazards refuse with UNINGESTABLE_REASON — a refusal the --first-end-to-end-run escape deliberately cannot waive. Unzipping and reprojection are the outstanding work for this row. Update 2026-08-10 (ops run, prod) — the EWDS half of this row is INGESTED, and every figure below is MEASURED on the production host, not calculated. hazard_datasets row wildfire-fwi-historical-greece-20230801, id c83be4f5-5bb1-4bef-82d8-a100061163cc, haz_type=wildfire, status=active, COG present — the first NetCDF ingest this project has ever completed end to end through the unified pipeline, and the evidence that retired the guard's evidence gate (see the SUPERSEDED block above). Raw download measured: 27,990 bytes, delivered as a plain NetCDF (data/wildfire_fwi_ewds/wildfire-fwi-historical-greece-20230801.nc) — not a ZIP, unlike every C3S delivery on this row and on #616. This is a different number from the 28,402 bytes recorded above, and neither supersedes the other: 28,402 B was the 2026-08-09 probe retrieval (#802, jobID fd5475dd-…), 27,990 B is the 2026-08-10 ops retrieval that was actually ingested — two separate submissions on two separate days, both recorded because the ~1.5% delta is real delivery variation, not a correction. Stored footprint measured: hazards/ 0.01 MB + processed/ 0.00 MB ≈ 14,125 bytes total — the figure now in this row's Processed cell. The C3S projections half is still NOT ingested, and exactly one blocker remains. The ZIP-per-experiment problem recorded above is FIXED — PR #822 (ffab274, ADR-071) makes the source layer unpack whatever archive a CDS retrieval actually delivers and dispatch one ingest per member, so the scenario-as-filename-token layout is no longer an obstacle. What still blocks it is the rotated-pole grid: every member declares CF grid_mapping_name=rotated_latitude_longitude (north pole 39.25 N / −162.0 E), and NetCDF ingest is EPSG:4326-only with no reprojecting read — PR #819 (02f0ee3) added the explicit grid_mapping_name guard that fails this closed rather than silently ingesting the mid-Atlantic misplacement described above. Reprojection is therefore the single outstanding item for the C3S half of this row — not the guard, not the ZIP, not the request vocabulary, all three of which are now resolved. Update 2026-09-02 (Cyprus, #1048) — MEASURED 2026-09-02, hazards/ + processed/, method as the storm_europe row. EWDS FWI Cyprus (c6691db1-2ae8-4628-b554-9c5f48fc96ca, wildfire-fwi-historical-cyprus-20230801) active on prod: hazards/ 4,594 B + processed/ 1,980 B = 6,574 B total.
#615 Windstorm — C3S footprints + WISC synthetic Copernicus Climate Change Service (C3S) / ECMWF — Climate Data Store (cds.climate.copernicus.eu); sis-european-wind-storm-reanalysis ("Windstorm tracks and footprints derived from reanalysis over Europe between 1940 to present") + sis-european-wind-storm-synthetic-events ("Synthetic windstorm events for Europe from 1986 to 2011", the WISC set) CC-BY licence (see note a for the WISC caveat) 0.000055 (measured 2026-08-10, C3S historical as actually retrieved — supersedes the ≤0.04 per-footprint calculated bound, kept visible in note b) / ≤ 142.6 (WISC full synthetic set, upper bound — never retrieved, see note b) 0.000125 (measured 2026-08-10, C3S historical half — see note b) ingested (C3S historical half only — WISC synthetic not retrieved for Phase 9, see note b) (a) Both dataset ids and their "CC-BY licence" wording were read live 2026-08-06 from each dataset's own CDS landing page (cds.climate.copernicus.eu/datasets/<id>?tab=overview), not assumed or copied from a sibling pack. The WISC synthetic-events product's own Confluence "Product User Guide" (fetched live 2026-08-06) has a "Licence"/"Terms of Use" row in its overview table that is left blank in the document itself — the CDS landing page is the only live source naming a licence for WISC in this build. Per this issue's own instruction ("WISC ... has its own licence terms distinct from general Copernicus/C3S terms — read them, do not assume CC-BY"), ops must re-confirm the real click-through licence text on the CDS portal when accepting it (the existing ops checklist item "Per-dataset license accepted (portal)" already covers this) before treating CC-BY as final. Update 2026-08-10 — that ops action is MOOT for Phase 9 and should not be carried forward as an open item: WISC is not retrieved at all (see note b's 2026-08-10 update), so no click-through licence is ever accepted for it and there is nothing for ops to re-confirm. The instruction stands only if a future pass decides to retrieve WISC; the C3S historical half that was retrieved carries its own separately-read CC-BY line. (b) CDS has no static file URL to HEAD — every retrieval is an authenticated, queue-based submission (CopernicusCdsSource.download), so unlike JRC/Eurostat/GHSL (#611/#619/#620) there is no anonymous byte count to measure even in principle; both figures below are calculated upper bounds from documented grid dimensions, not measurements. C3S historical footprint: 0.016° grid over the dataset's own documented domain (25W-35E, 30N-70N, from the CDS overview page) = 3750×2500 = 9,375,000 cells; one uncompressed float32 band ≈ 37.5 MB per footprint — the total for "1940 to present" depends entirely on how many storms/years the operator's retrieval request spans (an operator scoping decision made at retrieval time, not fixed by this pack, and this build found no documented total storm count for this specific dataset id to multiply by), so the dataset-wide total is TBD, not calculated, pending that scoping decision. WISC synthetic set: the PUG's own documented domain (25W-40.5E, 34.4N-71.5N) at 4.4 km ≈ 0.0396°/pixel (111 km/degree, a stated approximation — the true per-pixel footprint likely differs slightly by latitude and this was not corrected for) ≈ 1654×937 ≈ 1.55M cells/footprint; one uncompressed float32 band ≈ 6.2 MB × the PUG's own documented count of 22,980 footprints ≈ 142.6 GB if the entire synthetic set were retrieved whole — given the issue's own "no multi-GB downloads" constraint, ops is expected to scope real retrievals far below this (a handful of test events, or an API-side area subset to Greece if the live CDS form supports one — unconfirmed in this build, see scripts/packs/windstorm_c3s_wisc.py's module docstring), so this is a ceiling on the unscoped case, not a plan to actually fetch it. Processed volume (hazards/{id}/intensity.npz) is TBD for the same reason as every other row in this ledger (no live ops ingest ran in this build) and is additionally blocked on a cross-cutting wiring gap this build found but did not fix: worker/ingest/adapters.py::resolve_ingest_adapter resolves ingest format purely from HazardType (every entry typed BaseGeoTIFFIngestor), so STORM_EUROPE's NetCDF footprints cannot reach the unified pipeline's NetCDF reader (core/ingest/netcdf.py, already registered by this pack via register_netcdf_layouts()) until that resolution is wired to route on format, not just haz_type — the same gap the wildfire pack (#614, also CDS/EWDS NetCDF) will hit; see the PR for #615. Update 2026-08-10 (supersedes the 2026-08-08 line, which wrongly said "#761 is now CLOSED"): as of trunk d4b2cc5 no known CODE blocker remains — #706, #761's two worker-side gaps, #782, #791, #793 and #797 are all fixed (see #614's row for the fix table). [SUPERSEDED later the same day, kept verbatim: "#761 stays OPEN as the end-to-end evidence gate, and the assert_netcdf_adapter_wired guard still refuses every dispatch by design, because no NetCDF ingest has ever run end to end." Both halves of that are now FALSE — #761 is CLOSED and PR #825 (42f2a35) deleted the guard's evidence-gate layer, its --first-end-to-end-run escape and the ADAPTER_GAP_ISSUE_URL constant; only the plan-time adapter-resolution check remains, and it refuses nothing that resolves to the right reader. The evidence that satisfied the gate was #614's EWDS ingest — see that row.] Read NETCDF_INGEST_BLOCKERS on trunk, not this row. CDS/EWDS credentials ARE present in the worker (verified live 2026-08-08: CDSAPI_KEY, EWDSAPI_KEY, CDSAPI_URL, EWDSAPI_URL all set) — credentials are not what is blocking this row. Update 2026-08-10 (ops run, prod) — the C3S historical half of this row is INGESTED, and its volumes are now MEASURED rather than calculated. hazard_datasets row windstorm-c3s-footprints-hist, id 3f4f864d-01ab-485c-9f39-23c8856a0452, haz_type=storm_europe, status=active, COG present. One event committed: scenario NULL, year=2007, event_name=1463@2007, no frequency — a year-labelled, frequency-less single-footprint dataset, exactly the shape ADR-068/ADR-069 were written for. Grid 241×161 with 13,174 non-zero cells, 1 band. Raw download measured: the CDS delivery is a ZIP of 54,965 bytes holding one member of 54,713 bytes. That is three orders of magnitude below this row's calculated ≤0.04 GB (37.5 MB) per-footprint upper bound, and the bound is not wrong — it is answering a different question. It sized an unscoped whole-domain (25W–35E, 30N–70N) uncompressed float32 band at 3750×2500 cells; the retrieval ops actually submitted is scoped to a single storm, so what arrives is one small compressed footprint, not the domain-wide grid the bound assumed. The bound is retained above as the ceiling on the unscoped case; the 54,965-byte figure is what a real scoped retrieval costs. Stored footprint measured: hazards/ 0.08 MB + processed/ 0.04 MB = 0.12 MB (124,719 bytes) — the figure now in this row's Processed cell. WISC synthetic is DROPPED for Phase 9, on measured evidence — and the hope this row recorded is now confirmed FALSE. Note b above speculated that the ≤142.6 GB full-set figure could be scoped down "by ... an API-side area subset to Greece if the live CDS form supports one — unconfirmed in this build". It does not support one. The process schema was read live from GET {cds_root}/retrieve/v1/processes/sis-european-wind-storm-synthetic-events and publishes exactly four inputs — variable, version_id, year, month. There is no spatial input, no area, nothing geographic at all. The only scoping levers WISC offers are temporal, so any WISC retrieval fetches whole-domain footprints and cannot be brought under this plan's no-multi-GB rule at retrieval time. This is recorded as a measured negative, not a permanent decision: no ADR was written and none is implied — WISC is simply not pursued for Phase 9 because it cannot be scoped, and a future pass that is willing to fetch whole-domain footprints (or that finds a subsetting path this schema read did not show) is free to revisit it. The C3S historical half alone is what makes this row ingested.
#616 Heatwave — EURO-CORDEX + ERA5-HEAT alt Copernicus Climate Change Service (C3S) — primary: "Heat waves and cold spells in Europe derived from climate projections" (CDS dataset sis-heat-and-cold-spells); alt: "Climate indicators for Europe from 1940 to 2100 derived from reanalysis and climate projections" (CDS dataset sis-ecde-climate-indicators) — see note a CC-BY (both datasets — read live from each dataset's own CDS overview page 2026-08-06, not assumed or copied from a sibling Copernicus product) 0.238 (measured 2026-08-10 — 238,249,300 B of delivered ZIPs; replaces the TBD, see note b) 0.203 (measured 2026-08-10 — 203.33 MB across all three datasets, see note b) ingested (both datasets, all scenarios — with one open caveat, #827, see note b) (a) Both datasets are served through the Copernicus CDS's authenticated, queue-based Retrieve API (src/climate_lama/ingest/sources/copernicus_cds.py, issue #598), not a plain HTTPS URL — unlike #611/#612/#618-#620, there is no file listing an HTTP HEAD can size, and this build holds no CDS credentials to submit a retrieval. scripts/packs/heatwave_packs.py builds the two datasets' CdsRetrievalSpec-shaped registry entries (id/store/dataset/request/title) and round-trips them through the real copernicus_cds.parse_retrieval_specs (unit-tested, not a re-implementation) so they are provably consumable by the production adapter once pasted into the operator-declared DATASET_SOURCE_COPERNICUS_RETRIEVALS registry — that registration is a config concern (per this issue's scope fence), not a code change. The CDS request keys whose values this build could not verify (variable, experiment/period, format — chosen on the dataset's own JS-rendered, login-gated "Download" tab) are left as an explicit _UNRESOLVED_CONFIRM_FROM_CDS_DOWNLOAD_FORM sentinel rather than a guessed value (ADR-059); heatwave_packs.unresolved_fields() reports them so ops cannot silently paste an incomplete request. Update 2026-08-10 — those sentinels are RESOLVED. Both datasets' variable/experiment/period/format values were captured and the retrievals were actually submitted and delivered (see note b), so the unresolved-field discussion above is history rather than an outstanding owner input. [ASSUMPTION — PROMOTED TO A CONFIRMED PICK 2026-08-10, validated by execution rather than by re-reading a page; see note b. The reasoning below is retained in full, because it is still the record of why derived-utci-historical was rejected, and that rejection is what execution confirmed.] "ERA5-HEAT" (this issue's title; docs/plan/phase-9-data-foundation.md's Stream E table row "ERA5/ERA5-HEAT (CDS) — historical truth | 1940→ | CC-BY") is read here as sis-ecde-climate-indicators's own "Heatwave days" indicator (same "days" unit as the EURO-CORDEX primary, ERA5-reanalysis-based 1940→2100 span matching the plan doc), not the literal ERA5-HEAT paper dataset (Di Napoli et al. 2021, CDS id derived-utci-historical), which publishes a different physical quantity (UTCI thermal comfort, °C) — see heatwave_packs.py's module docstring for the full reasoning; ops/product confirmation is no longer outstanding — the 2026-08-10 ops run retrieved and ingested the sis-ecde-climate-indicators pick and it yields heatwave days in days over 1940–2025, the same physical quantity and unit as the EURO-CORDEX primary, which is exactly what the assumption predicted. CMIP6 extreme indices (the plan doc's other alternative, flagged non-standard licence) is not implemented by this pack — the issue title names ERA5-HEAT, and the licence-flag instruction is conditional on CMIP6 being the one picked. (b) No download ran in this build (no CDS credentials, and CDS retrievals cannot be sized by HTTP HEAD the way #611/#612/#618-#620's plain-HTTPS files were) — raw and processed volume are genuinely unknown, not merely estimated, until ops runs a real retrieval; recording TBD rather than a fabricated figure is the correct answer here per this issue's own instruction and ADR-059. Processed volume (hazards/{id}/intensity.npz) is not sized for the same reason. Registering the NetCDF ingest layout (core.ingest.netcdf.register_netcdf_dataset) needs the file's actual variable/dimension names, which exist only inside a downloaded sample — also out of reach here; that registration and the first real ingest through the unified pipeline are this issue's ops-only acceptance checks. Update 2026-08-10 (supersedes the 2026-08-08 line, which wrongly said "#761 is now CLOSED"): as of trunk d4b2cc5 no known CODE blocker remains — #706, #761's two worker-side gaps, #782, #791, #793 and #797 are all fixed (see #614's row for the fix table). [SUPERSEDED later the same day, kept verbatim: "#761 stays OPEN as the end-to-end evidence gate, and the assert_netcdf_adapter_wired guard still refuses every dispatch by design, because no NetCDF ingest has ever run end to end." Both halves are now FALSE — #761 is CLOSED and PR #825 (42f2a35) deleted the guard's evidence-gate layer, its --first-end-to-end-run escape and the ADAPTER_GAP_ISSUE_URL constant; the plan-time adapter-resolution check is all that remains. The satisfying evidence was #614's EWDS ingest.] Read NETCDF_INGEST_BLOCKERS on trunk, not this row. CDS/EWDS credentials ARE present in the worker (verified live 2026-08-08: CDSAPI_KEY, EWDSAPI_KEY, CDSAPI_URL, EWDSAPI_URL all set) — credentials are not what is blocking this row. Update 2026-08-10 (ops run, prod) — this row is INGESTED, both datasets, all scenarios, and every figure here is MEASURED on the production host. This replaces the TBD — pending ops download that stood in both volume cells since the row was authored. Three hazard_datasets rows, all status=active, all with a COG: (i) heatwave-euro-cordex-europe-ssp5-8.5, id 5857653d-4a63-40cc-95ce-3c2c19e54a01 — 100 events over 1986–2085, grid 599×425, 100 bands, stored hazards/ 57.92 MB + processed/ 43.33 MB = 101.25 MB; (ii) heatwave-euro-cordex-europe-ssp2-4.5, id 591da928-cee9-4693-a39d-6a4afbcf0f9f — 100 events over 1986–2085, grid 599×425, 100 bands, stored 57.87 + 42.95 = 100.82 MB; (iii) heatwave-ecde-europe, id 32fcd25e-59ec-4558-8b98-33365203cebd — 86 events over 1940–2025, grid 271×185, 86 bands, stored 0.70 + 0.56 = 1.26 MB. Processed total = 203.33 MB ≈ 0.203 GB. Raw downloads measured, both delivered as ZIPs: EURO-CORDEX returned 203,731,118 bytes holding two members of 101,849,863 bytes each — HWD_EU_health_rcp45_mean_v1.0.nc and HWD_EU_health_rcp85_mean_v1.0.nc (note the upstream filenames say rcp45/rcp85 while this catalog names the datasets ssp2-4.5/ssp5-8.5; the mapping is deliberate and the filenames are the provider's, not a mislabel on our side); ECDE returned 34,518,182 bytes holding one member of 34,512,676 bytes (09_heat_waves_climatological-reanalysis-yearly-grid-1940-2025-v2.0.nc). Raw total = 238,249,300 bytes ≈ 0.238 GB, the figure now in this row's Raw cell and folded into the Totals row's note (c). The two-members-in-one-ZIP delivery is handled by ADR-071/PR #822 — one ingest per member — which is why one retrieval produced two catalogued datasets. Known caveat — do NOT read this row as fully complete. #827 (filed 2026-08-10, OPEN): derive_dataset_axis discards the per-member scenario label at commit time, so both EURO-CORDEX datasets carry their scenario in the dataset name but have scenario IS NULL in the column. Consequence, stated plainly: heatwave cannot yet answer a scenario-labelled matrix cell — the data is ingested and the intensities are correct, but the scenario axis it was retrieved for is not addressable until #827 lands.
#617 Earthquake — ESHM20 hazard maps (EFEHR); ESRM20 vulnerability already seeded by #604, not re-derived here (see note a) EFEHR (European Facilities for Earthquake Hazard and Risk) / Swiss Seismological Service (SED), ETH Zurich — "The 2020 update of the European Seismic Hazard Model (ESHM20)" (Danciu et al. 2021, doi:10.12686/a15) CC-BY-4.0 — confirmed three independent ways, live, in this build 2026-08-06: the EFEHR GitLab efehr/eshm20 repo's own LICENSE file ("This project is licensed under the Creative Commons Attribution 4.0 International License"); the ESHM20 WMS service's own GetCapabilities (<Fees>CC-BY-4</Fees>); and the EFEHR REST API's own openapi.json description ("License: CC BY 4.0"). Not copied from the broader hazard.efehr.org portal page's own generic Dublin-Core tag, which states the differing "CC BY-SA 4.0" for the portal as a whole — per ADR-059 the artefact's own three statements govern, not the sibling/portal-wide notice (see scripts/packs/earthquake_eshm20.py module docstring). ≤0.002 (estimate, upper bound — see note b) ≤0.0002 (estimate, upper bound — see note b) ingested (a) Two real, live findings changed this pack's source from what the issue assumed — see scripts/packs/earthquake_eshm20.py's module docstring for the full trail. First, the EFEHR GitLab eshm20 repo (file tree read live via the GitLab API) holds only LICENSE/README.md/ESHM20_CITATION.cff plus oq_computational/ (OpenQuake input configs) and additional_materials/ (plots) — no precomputed hazard-map rasters; producing one from these inputs needs OpenQuake, out of scope per #605. Second, the EFEHR map-rendering endpoint (WMS and WCS, efehrmaps.ethz.ch/cgi-bin/mapserv?map=/var/www/mapfile/eshm20data.map, layer/coverage seismic-hazard) is render-only: a live GetMap and a live GetCoverage request against it in this build both returned a 3-band uint8 RGB image (values 153–255, confirmed via rasterio), not the underlying PGA floats, despite DescribeCoverage advertising a plausible single-band range — neither WMS nor WCS on this mapfile registers any output format beyond rendering formats (wcs:formatSupported lists only png/gif/jpeg/tiff-as-image, live-read). Using it would have silently ingested rendered pixel colours as PGA values. The pack instead uses the EFEHR Seismic Hazard Services REST API (efehr-services.ethz.ch/api/v1, OpenAPI-documented, linked from hazard.efehr.org/en/web-services/hazard-curve-data/, built under the EU Geo-INQUIRE project): /v1/maps/area returns real numeric PGA values (unit g, live-confirmed via /v1/models/81/imts, matching EarthquakeIngestor.intensity_unit from #604 exactly) on a genuine 0.1° regular grid — live-verified with a real 1×1° test query over the Peloponnese (121 points, values 0.29–0.61 g, a physically plausible range). Model id 81 = "European Seismic hazard Model 2020 (ESHM20)", soil type rock_vs30_800ms-1 (the only one this model publishes at map level, matching Vs30=800 m/s reference rock), aggregation = arithmetic mean — all live-confirmed. The five (probability, timespan) pairs read live from /v1/models/81/poe?imt=PGA give nominal (round(1/probability)) return periods 50/476/976/2500/5000y — within 0–1% of the commonly-cited engineering labels 50/475/975/2475/5000y that core/ingest/earthquake.py's #604 docstring uses (largest gap: 2500 vs 2475, ~1%); this pack dispatches the exact live probability/timespan pair, and treats the nominal year as a cosmetic label only, not a re-derivation. ESRM20 vulnerability/fragility (the other half of this issue) was already fetched, licence-checked (CC-BY-4.0, from the esrm20_vulnerability/esrm20_exposure GitLab repos' own LICENSE files at their pinned release tags) and seeded by #604 — see scripts/packs/derive_esrm20_earthquake_curves.py and scripts/packs/esrm20_2021_pga_vulnerability.json, both read but not re-derived or duplicated here. (b) No live fetch of the full Greece bbox was attempted in this build — not a volume constraint (see below) but a timing one: the real 1×1° (121-point) test query took ~7.8s, i.e. server-side per-point computation dominates response time, not payload size (~47 bytes/point measured: 5688 B / 121 pts). The full Greece bbox (lon 19.0–28.5, lat 34.5–42.0) at the confirmed 0.1° native grid is ≈96×76 = 7296 points per return-period map; extrapolating the measured per-point latency across 5 return periods implies roughly 30–40 minutes of cumulative request time — ops should budget for this, and may want to request sub-tiles in parallel rather than one bbox-wide call per RP. Raw-volume estimate: 7296 pts × 5 RPs × ~47 B/pt (JSON, the wire format actually fetched) ≈ 1.71 MB ≈ 0.0017 GB, rounded up to ≤0.002 GB for margin — a calculated bound from one measured request, matching #611/#612/#613's own methodology, not a guess. Processed-volume estimate: the ingest chord's own single-band float32 GeoTIFF encoding of the same grid, 7296 px × 4 B × 5 RPs ≈ 146 KB ≈ 0.00015 GB before compression, rounded up to ≤0.0002 GB; fetch_map_grid_geotiff's compress="deflate" output (and the chord's own hazards/{id}/intensity.npz) are expected to be smaller still. Both figures are far below any multi-GB concern — no live download of the full grid was needed to establish that.
#618 Exposure — LitPop default asset values ETH Zurich — Institute for Environmental Decisions, Weather and Climate Risks Group (Eberenz, S., Stocker, D., Röösli, T., Bresch, D. N.); dataset archived at the ETH Research Collection, https://doi.org/10.3929/ethz-b-000331316 (DOI resolution verified live in this build — redirects to research-collection.ethz.ch, not a CLIMADA-branded host) CC-BY-4.0 — independently CONFIRMED 2026-08-08 (see note b): the item's own registered DataCite metadata carries rightsList "Creative Commons Attribution 4.0 International", rightsIdentifier cc-by-4.0 on the SPDX scheme, publisher ETH Zurich ≤0.02 (UNVERIFIED estimate — see notes c and d) N/A (see note c) ingested (Path B, --source climada-api — see note d) (b) The companion paper (Eberenz et al., Earth Syst. Sci. Data, 12, 817–833, 2020, https://doi.org/10.5194/essd-12-817-2020) was read directly (PDF): its own license notice (page 1) reads "This work is distributed under the Creative Commons Attribution 4.0 License." Its reference list gives the dataset's own citation: "Eberenz, S., Stocker, D., Röösli, T., and Bresch, D. N.: LitPop: Global Exposure Data for Disaster Risk Assessment, ETH Research Collection, https://doi.org/10.3929/ethz-b-000331316, 2019." Update 2026-08-08 — the licence is now independently confirmed, and this row's earlier access finding was wrong. (i) DataCite (https://api.datacite.org/dois/10.3929/ethz-b-000331316, read live) returns the item's OWN registered metadata: rightsList "Creative Commons Attribution 4.0 International", rightsIdentifier cc-by-4.0, SPDX scheme; publisher ETH Zurich; publicationYear 2019. That record is registered by ETH Zurich as the publisher, so it is the item's own rights field — the "not independently confirmed" hedge this row previously carried is retired, and ops no longer needs to re-check it. (ii) The item page is not a JS-rendered app returning 500: research-collection.ethz.ch returns HTTP 403 "Access Restricted — due to a high volume of automated traffic (scraping), access ... is temporarily restricted from your location / your provider". That is an IP-level anti-scraping control, and this project deliberately does not evade it (ADR-063). (iii) The earlier "deliberately NOT sourced from CLIMADA's own data server" stance is superseded by ADR-063: the CLIMADA Data API is now an opt-in second source (--source climada-api), not the default — see note d. ADR-024 fences CLIMADA's code and packaging, not data fetched over HTTPS. (c) LitPop's published format is a per-country CSV (value, latitude, longitude, region_id) at 30 arcsec (~1 km) resolution (secondary-sourced: CLIMADA docs' LitPop tutorial page; not independently confirmed against the item page). No file was downloaded in this build (no live network access) — the raw-volume figure is a calculated upper bound from Greece's land area (~131,957 km², a verifiable geographic fact) at ~1 km²/cell (≈130,000–190,000 rows including coastal/island cells) times an assumed ≤60 bytes/row (value+lat+lon+region_id as CSV text) ≈ ≤11 MB, rounded up to ≤0.02 GB for margin — a calculation, not a measurement; the real per-country file could be a single combined download rather than land-only, in which case this figure is TBD pending the live ops download. Processed volume is N/A in the object-storage sense the other rows use (hazards/{id}/intensity.npz / processed/.../hazard.tif): exposure packs land as exposure_datasets/exposures DB rows via the existing raster exposure adapter (#594), not a committed storage artifact — see the ledger's own column note for exposure packs. The ≤0.02 GB figure is now flagged UNVERIFIED and possibly far too low: DataCite reports the whole Research Collection release as 16.63 GB across text/plain + text/csv + application/x-tar (the formats field of the same record read in note b). Nothing read so far establishes the per-country share of that 16.63 GB, so the calculated bound above stands only as a bound on the land-area arithmetic, not on the real file. The pack (scripts/packs/litpop_exposure.py) still has no default download URL for this source: ops resolves it from the live handle page in a browser and passes it via --download-url — never a guessed URL. (d) Alternative source, added 2026-08-08 (ADR-063, issue #618). The CLIMADA Data API (https://climada.ethz.ch/data-api/v1/dataset/?data_type=litpop&country_iso3alpha=GRC) is a plain, public, credential-free REST file server publishing the same authors' LitPop as per-country HDF5. It is a different product, recorded as such and catalogued under its own dataset name: 150 arcsec (~4.6 km, screening-grade) versus this row's 30 arcsec, and value epoch 2018 versus 2014. Licence per the API record's own license field: "Attribution 4.0 International (CC-BY-4.0)" — matching DataCite's reading of the RC release. Raw volume is a real measurement, not an estimate: LitPop_150arcsec_GRC.hdf5 (exponents (1,1), fin_mode pc, uuid d9840877-2347-4247-9fc9-ad914cc53fd0) is 1,678,480 bytes = 0.0017 GB, downloaded and verified against its declared md5:06f9bd0a29cfc0d1faa2a9acf3f103f8 byte-exact. Processed volume is N/A for the same reason as the RC path (exposure packs write DB rows, no storage artifact). This alternative is not counted in the Totals row: it is an opt-in second source for the same pack, not an additional pack, and only one of the two lands per ingest. Update, 2026-08-08 ops run (PR #781): ingested via Path B, dataset_id=69e03607-8d99-4870-9560-6f998537f9d3, 7,896 points, total value 1,067,141,118,804 USD(2018) confirmed identical to the source dataset — see docs/plan/phase-9-ops-plan.md OPS-3b for the verification query.
#619 Exposure — GHSL built-up + population European Commission, Joint Research Centre (Global Human Settlement Layer) — GHS-BUILT-S R2023A, GHS-BUILT-V R2023A, GHS-POP R2023A, all epoch 2020, 3 arc-second (~100 m) grid, EPSG:4326 CC-BY-4.0 (see note a — read live from each product's own bundled copyright.txt, not assumed from a sibling GHSL product) 20.13 (measured, not an estimate — see note a) N/A — see note a ingested (a) Licence: each product's own copyright.txt (e.g. .../GHS_BUILT_S_GLOBE_R2023A/GHS_BUILT_S_E2020_GLOBE_R2023A_4326_3ss/V1-0/copyright.txt, fetched live 2026-08-06 for all three products — BUILT-S, BUILT-V, POP) states verbatim: "Any copyright and/or sui generis right on the dataset is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0) licence." Recorded per-artefact rather than copied from the JRC data-catalogue landing pages' more generic "European Commission reuse notice" wording (issue #621/ADR-059's rule). Resolution: GHS-POP R2023A's own JRC catalogue page (data.jrc.ec.europa.eu, verified live 2026-08-06) states the 2023 update ships "at 100m resolution in World Mollweide projection (or 3 arc-seconds in WGS84)" — the native 100 m grid is EPSG:54009; RasterExposureAdapter (#594) requires EPSG:4326 and does not reproject, so scripts/packs/ghsl_exposure.py uses each product's _4326_3ss variant, confirmed live to exist at epoch 2020 for all three products by fetching each product's own JEODPP directory index (see the PR body for the listings read). Raw volume 20.13 GB (3.21 + 4.36 + 12.55 GB) is a real HTTP HEAD measurement, not an estimate: Content-Length read live 2026-08-06 for all three whole-globe zips — BUILT-S 3 208 625 400 B, BUILT-V 4 362 815 348 B, POP 12 554 406 149 B (no body fetched, matching the "no multi-GB download in this build" constraint). These are whole-globe archives: like Eurostat's Census-GRID (#620) and unlike JRC's river-flood GeoTIFFs (#611/#612), GHSL's zip endpoint has no server-side windowed-clip option, so the full per-product archive must land in the raw/staging zone once before scripts/packs/ghsl_exposure.py::clip_and_scale_local clips the Greece bbox [19.0, 34.5, 28.5, 42.0] locally, streamed in row-blocks (never the whole extracted raster in memory) — matching how ingest_historical_catalog.py::fetch_exposure_raster already handles GHSL's existing 30ss/~1km GHS-BUILT-V product. The m3-to-currency fix this issue exists for: GHS-BUILT-S (built-up surface, m2) is converted to EUR using a real, cited factor — Huizinga et al. 2017 (JRC105688, doi:10.2760/16510), sheet "MaxDamage-Residential", column B ("Max Damage Structure, EUR/m2, 2010 price level"), row 77 (Greece): 440.5788419051012 EUR/m2 — the spreadsheet downloaded in this build hashes to the exact sha256 already recorded in scripts/packs/huizinga_2017_europe_damage_functions.json's source.xlsx_sha256 (the same byte-identical file this repo already trusts). GHS-BUILT-V ships alongside it unconverted (value_unit="m3"): no citable EUR/m3 factor, or citable average-building-height factor to derive one from the EUR/m2 figure, could be sourced/verified in this build — GHSL's own methodology derives GHS-BUILT-V as GHS-BUILT-S × GHS-BUILT-H (a per-cell height grid, not a documented single average), so no constant height factor exists to cite either; this is stamped as an explicit [ASSUMPTION] on the dataset's properties, not silently resolved (see the PR body's provenance section for the exact searches run). GHS-POP ships as value_unit="persons" (a headcount, not a currency). Update, 2026-08-08 ops run: all three products ingested (dataset ids 65eb047e/6fe049d3/5e6ed880, BUILT-S/BUILT-V/POP respectively). BUILT-S's first attempt failed on a real defect (#774): its citation inlined the full Huizinga provenance note, overflowing exposure_datasets.citation's VARCHAR(1024) — fixed by pointing at properties.conversion_source instead, which already carries the same text verbatim (JSONB, unbounded). Processed volume is N/A, not blank, for the same reason as #618/#620: exposure ingest (core/exposure_service.ingest_exposure_from_source) writes Exposure/ExposureDataset DB rows only, no hazards/{id}/intensity.npz or processed/{org}/{id}/hazard.tif COG. scripts/packs/ghsl_exposure.py is standalone (own CLI), matching #618/#620's precedent that ingest_historical_catalog.py is a serialised hotspot other concurrent Phase 9 pack issues touch — it does not replace that file's existing GHS-BUILT-V (30ss/~1km) ingest path, which is additive/untouched by this pack.
#620 Exposure — Eurostat Census 2021 grid Eurostat (European Commission), GISCO — "Population and housing census 2021 — population grid" (Census-GRID 2021, V3, published 2026-05-30) UNRESOLVED — see note b 0.566 (measured, not an estimate — see note b) N/A — see note b ingested (b) Provenance/licence check per issue #621's rule (ADR-059): the GISCO population-distribution page (verified live 2026-08-06, https://ec.europa.eu/eurostat/web/gisco/geodata/population-distribution) states, specifically for "Eurostat Census Grid 2021": "EU copyright rules apply, while the licence would be under CC-BY 4.0." Eurostat's general copyright notice (verified live 2026-08-06, https://ec.europa.eu/eurostat/help/copyright-notice), however, separately lists "population grids" among the categories excluded from the default Commission Decision 2011/833/EU CC-BY-4.0-for-any-purpose policy — restricted instead to non-commercial reuse — and the predecessor GEOSTAT 2011/2006 grids carry an explicit no-redistribution/no-commercial-use notice. Which regime governs the 2021 grid's population attribute (TOT_P_2021) was not resolved in this build; the real GISCO-ConditionsOfUse.pdf ships only inside the archive itself, which was not downloaded here (see below). This ambiguity is stamped verbatim onto the ingested dataset's license column by scripts/packs/eurostat_census_grid.py::LICENSE_NOTE so it travels with the data. Raw volume 0.566 GB (566 125 577 bytes) is a real measurement, not an estimate: an HTTP HEAD request against the V3 zip (https://gisco-services.ec.europa.eu/census/2021/Eurostat_Census-GRID_2021_V3.zip, verified live 2026-08-06, Content-Length: 566125577) — no body was fetched, matching the "no multi-GB download in this build" constraint. This is the whole-EU zip; unlike JRC's river-flood files, Eurostat's zip endpoint does not support a server-side windowed clip, so the full archive must land in the raw/staging zone once before the Greece bbox [19.0, 34.5, 28.5, 42.0] clip happens locally (matching how fetch_exposure_raster already handles GHSL's zip in ingest_historical_catalog.py). Every format Eurostat ships this grid in (GeoTIFF, GeoPackage, CSV/Parquet) is natively EPSG:3035 (ETRS89-LAEA) — confirmed on the same page — with no documented EPSG:4326 option, so RasterExposureAdapter (#594, which requires EPSG:4326 and does not reproject) cannot ingest it directly; scripts/packs/eurostat_census_grid.py::reproject_population_to_wgs84 reprojects the extracted raster to EPSG:4326 with rasterio.warp.reproject(resampling=Resampling.sum) first, chosen specifically to conserve the population total under the CRS change (unit-tested against a synthetic fixture — nearest/bilinear would invent or lose people). Processed volume is N/A, not blank: exposure ingest (core/exposure_service.ingest_exposure_from_source) writes Exposure/ExposureDataset DB rows only — there is no hazards/{id}/intensity.npz or processed/{org}/{id}/hazard.tif COG for an exposure pack (per this file's Processed-volume column convention). The zip's exact internal member layout (which .tif holds TOT_P_2021) was not verified by downloading it in this build; select_population_raster_member picks a uniquely-named .tif member by convention and raises rather than guessing if that assumption doesn't hold against the real archive. Update, 2026-08-08 ops run: it didn't hold — the real archive ships one combined 14-band GeoTIFF (band descriptions T/M/F/age groups/..., no per-variable file at all), fixed in #767 (select_population_raster_band matches the band by description, verified against the archive's own read.me: T = Total population, band 1). Ingested 2026-08-08 (dataset id 4ce9317b-c417-4024-9456-4160c954e90f, 52,347 points).
#1038 River flood — JRC (Cyprus, historical) Copernicus Emergency Management Service / European Commission Joint Research Centre — "River flood hazard maps for Europe and the Mediterranean Basin region" v3.1.1 (version read live from the source's own README.txt field G01 and CHANGELOG.txt, which dates v3.1.1 to 2026-03-05) CC-BY-4.0. Licence text verbatim, read from https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/CEMS-EFAS/flood_hazard/copyright.txt on 2026-08-27: "(c) European Union, 1995-2026 … Any copyright and/or sui generis right on the dataset is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0) licence [2]. Reuse is allowed provided appropriate credit is given and any changes are indicated." The same directory's README.txt field A02 adds verbatim: "License information, restrictions on use: no restrictions, free and open Copernicus product". Recorded in scripts/cyprus_historical_catalog_manifest.json → perils.river_flood.source.license / .license_url / .license_text_verbatim. ≤ 0.203 (calculated upper bound — see note a) TBD — no ingest has run (see note a) GAP — measured 2026-08-28 (#1046): zero valid Cyprus cells in all nine RP tiles. HEAD-verified ≠ covered; manifest authored, never ingested and not ingestable (a) This row is the "before" the issue asks for: no byte was downloaded. Nine return periods (RP10…RP500), all nine HTTP-HEAD-verified 200 image/tiff on 2026-08-27 with these exact content-length values: RP10 272,286,610 · RP20 293,735,892 · RP30 298,074,166 · RP40 304,739,764 · RP50 309,424,632 · RP75 318,236,424 · RP100 323,117,744 · RP200 335,098,080 · RP500 349,928,950 — 2,804,642,262 B ≈ 2.80 GB for the full European-domain set, which is a measurement of the remote files, not of anything fetched. Those full-domain files are never downloaded whole: scripts.packs.river_flood_jrc.run_ingest_hazards (via fetch_clip) does a rasterio windowed HTTP-range read of the Cyprus bbox [32.0, 34.4, 34.8, 35.8] only. The raw figure above is that clip's uncompressed upper bound, computed not guessed: the bbox spans 2.8° × 1.4°, which at the source's native 3 arc-second (1/1200°) grid is 3,360 × 1,680 = 5,644,800 px/RP; single-band float32 = 22,579,200 B/RP ≈ 0.0226 GB, × 9 ≈ 203,212,800 B ≈ 0.203 GB. Sanity-check against #611's Greek row: Cyprus's bbox is 3.92 deg² against Greece's 71.25 deg², i.e. 5.5%, and 5.5% of that row's 3.7 GB bound is 0.203 GB — the two bounds are consistent by construction. fetch_clip writes compress="deflate" and flood-depth rasters are mostly nodata outside inundated cells, so the real footprint will be meaningfully smaller; no smaller point figure is asserted because none was measured. Open coverage question, deliberately not resolved here. The JRC Data Catalogue's own description (read live 2026-08-27) says verbatim: "The extent comprises most of the geographical Europe and all the river basins entering the Mediterranean and Black Seas in the Caucasus, Middle East and Northern Africa countries. Flood hazard maps are generated for river basins > 150km2." Cyprus is inside the documented domain — the README.txt field D01 gives it as "European extended domain (-24.54, 67.26; 27.81, 71.13)", which contains the Cyprus bbox — but that > 150 km² basin threshold, on an island of small and largely ephemeral catchments, is what decides whether the Cyprus window carries pixels at all. An HTTP HEAD cannot answer it and this issue permits no raster read, so it is answered by the first real clip in the W2.2a/W2.2b ops run. If that clip returns all-nodata, the honest outcome is to flip the manifest peril to status: "gap" with the measured result — not to widen the bbox. Host-availability note: jeodpp.jrc.ec.europa.eu refused TCP 443 for part of 2026-08-27 (transient, observed identically from two independent networks) and was re-probed successfully the same day; every 200 above comes from the successful probe. RESOLVED 2026-08-28 — the pre-registered criterion above was met. The W2.2a source-coverage probe (issue #1046, reproducible with python scripts/probe_country_source_coverage.py --country CYP --control GRC --only jrc) did the windowed read this note said would settle it. Result: 0 valid cells in the Cyprus window (1680 × 3360 px) in every one of the nine RP tiles, against a Greece control read from the same nine files of 2,097,768 (RP10, 2.045 %) to 2,558,502 (RP500, 2.494 %) valid cells — so the probe is sound and the zero is a real coverage gap, not a broken read. This note pre-registered the response verbatim ("If that clip returns all-nodata, the honest outcome is to flip the manifest peril to status: \"gap\" with the measured result — not to widen the bbox"), which is stronger evidence than an after-the-fact annotation: the criterion was written before the measurement and is now met. The manifest flip itself is the loader-honesty issue filed off #1046; the replacement baseline is the Aqueduct historical row added below. The > 150 km² basin threshold is the stated mechanism — no Cyprus catchment qualifies.
#1038 River flood — Aqueduct (Cyprus, scenario-conditioned) World Resources Institute — "Aqueduct Floods Hazard Maps" version 2 (inunriver_*, GCM NorESM1-M) CC-BY-4.0. Licence text verbatim, read live from https://www.wri.org/aqueduct on 2026-08-27: "All the products, methodologies, and datasets that make up Aqueduct are available for use under the Creative Commons Attribution International 4.0 License." Unchanged from the 2026-08-06 reading recorded in scripts/packs/coastal_flood.py. Recorded in scripts/cyprus_scenario_hazards_manifest.json → perils.river_flood.source.license / .license_url / .license_text_verbatim. ≤ 0.0047 (calculated upper bound — see note b) 0.0000655 (MEASURED 2026-09-02 — hazards/ + processed/, method as the storm_europe row — see note b) ingested; 6 datasets active on prod 2026-08-31 (#1048) (b) Twenty-one files — 2 forcing levels (rcp4p5 / rcp8p5) × 3 horizons (2030 / 2050 / 2080) × 3 return periods (10 / 50 / 100 y), plus a WATCH 1980 historical baseline × the same 3 RPs — mirroring the Greek grid in scripts/scenario_hazards_manifest.json exactly, so the Cyprus matrix answers the same cells. All 21 HTTP-HEAD-verified 200 image/tiff on 2026-08-27, content-length 88,181,962 – 93,233,936 B each, 1,909,537,098 B ≈ 1.91 GB for the full global set — again a measurement of the remote files, not of a download. Aqueduct Floods v2 publishes single world-extent GeoTIFFs, so Cyprus needs no country-specific tile and no separate tile hunt; this is the material difference from the JRC row above, whose product is Europe-and-Mediterranean-scoped with a basin-size threshold. Raw bound, computed the same way as note (a): the Cyprus bbox at Aqueduct's native 0.008333° (30 arc-second) grid is 336 × 168 = 56,448 px/file → float32 225,792 B/file × 21 ≈ 4,741,632 B ≈ 0.0047 GB. Consistent with #612's Greek ≤0.09 GB bound scaled by the same 5.5% bbox-area ratio. What a HEAD cannot show is how many Cyprus pixels carry non-zero depth — measured at W2.2b, not asserted here. Update 2026-09-02 (#1048) — MEASURED, hazards/ + processed/, method as the storm_europe row. 6 datasets active on prod (RCP4.5/8.5 × 2030/2050/2080): hazards/ 36,942 B + processed/ 28,514 B = 65,456 B total across the 6, the figure now in this row's Processed cell.
#1038 Exposure — GHSL built-up volume (Cyprus) European Commission, Joint Research Centre (Global Human Settlement Layer) — "GHS-BUILT-V R2023A", epoch 2020, GHS_BUILT_V_E2020_GLOBE_R2023A_4326_30ss (the GLOBE product — one global grid, so Cyprus needs no country-specific artifact) CC-BY-4.0 — sourced from the product's own copyright.txt (see note h). [CORRECTED 2026-08-28 by #1077; the previous wording of this cell is superseded and must not be re-cited.] That wording claimed "Neither provider page spells out 'CC BY 4.0' in those words" and attributed the CC BY 4.0 statement to "the sibling flood dataset", recording the value "for consistency" with #619's Greek row. That was wrong on the decisive point: GHS-BUILT-V R2023A ships its own copyright.txt, in the very .../GHS_BUILT_V_E2020_GLOBE_R2023A_4326_30ss/V1-0/ directory the archive is downloaded from, and it spells the licence out in full — exactly as #619's row (above) had already recorded for the 3ss products. Captured in both manifests' exposure.source.license_note and exposure.limitations. 0.202 (MEASURED by HTTP HEAD 2026-08-27 — see note c) N/A — exposure packs write DB rows, not a storage artifact (see note c) manifest authored + HEAD-verified; not ingested (c) The archive GHS_BUILT_V_E2020_GLOBE_R2023A_4326_30ss_V1_0.zip HEAD-verified 200 application/zip, content-length 202,045,212 B = 0.202 GB, on 2026-08-27. Unlike the two hazard rows, this figure is a real measurement of the artifact that actually gets fetched: the global zip is downloaded whole and cached once, then its single GeoTIFF member is extracted and the Cyprus bbox windowed-read from the local file — so 0.202 GB is the genuine transient peak, not a bound. Processed volume is N/A in the object-storage sense the hazard rows use: exposure packs land as exposure_datasets / exposures DB rows through the raster→exposure adapter (#594), not as a bucket object — same treatment as #618/#619/#620. grid_aggregation_factor is 2 here, not Greece's 8, and that is arithmetic rather than a copied constant: the Cyprus bbox is 336 × 168 = 56,448 native ~1 km cells, so an 8× aggregation would leave ~880 blocks for an entire country, while 2× yields at most 168 × 84 = 14,112 blocks at a ~2 km effective cell — the same order as the ~16,000 the Greek pack produces from its 1,026,000 native cells at 8×. The real point count is the non-zero-built-up subset of those 14,112 and is measurable only by the ingest; no point figure is asserted. This is the block flagged designated_for_reference_surfaces: true, i.e. the exposure Cyprus reference surfaces (design record D15) will be built from. Extent caveat: this exposure is windowed to the same whole-island bbox as the hazards, which reaches 35.8°N, while the GADM admin-0 boundary fixture for Cyprus tops out near 35.20°N (issue #1039 verified GADM 4.1 publishes no separate XNC admin-0 release — gadm41_XNC_0.json returns HTTP 404). Built-up volume north of ~35.20°N is therefore in the exposure but outside that boundary — any reporting that joins the two must decide explicitly how to treat those points. (h) Licence, corrected and sourced (#1077). https://jeodpp.jrc.ec.europa.eu/ftp/jrc-opendata/GHSL/GHS_BUILT_V_GLOBE_R2023A/GHS_BUILT_V_E2020_GLOBE_R2023A_4326_30ss/V1-0/copyright.txt — fetched live 2026-08-28, HTTP 200, text/plain, 540 bytes — states the following, quoted verbatim except that the source's bracketed footnote markers [1]/[2] (pointing at the Decision and the CC BY 4.0 deed) are elided: "Any copyright and/or sui generis right on the dataset is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0) licence.", under "(c) European Union, 1995-2026" and the Commission Decision of 12 December 2011, and followed by "Reuse is allowed provided appropriate credit is given and any changes are indicated." This is the same per-artefact rule (#621/ADR-059) note (a) of #619's row already applied to the 3ss products. The JRC Data Catalogue landing page (https://data.jrc.ec.europa.eu/dataset/ab2f107a-03cd-47a3-85e5-139d8ec63283, read live the same day) remains weaker — it names only the "European Commission reuse notice" and contains the string "CC BY 4.0" nowhere — so it must not be cited as the licence's source. The CEMS-EFAS river-flood directory carries a byte-identical copyright.txt, which is what the earlier wording had half-seen; the point is that the GHSL product has one of its own, so no inference from a neighbouring dataset was ever needed.
#1038 Coastal flood — Aqueduct (Cyprus) — evaluated, deliberately not carried by the Cyprus scenario manifest World Resources Institute — "Aqueduct Floods Hazard Maps" version 2, coastal variant (inuncoast_*, wtsub / nosub) CC-BY-4.0 — same WRI statement quoted verbatim in the Aqueduct riverine row above, read live 2026-08-27. ≤ 0.0047 for a 21-file matrix (calculated, same arithmetic as note b — see note d) N/A here — owned by scripts/packs/coastal_flood.py, see #613's row (note d) evaluated + HEAD-verified; not carried by this manifest — this is an ownership boundary, not a source gap (d) Read this row before concluding Cyprus has no coastal hazard. The Aqueduct coastal grids exist, are global, cover Cyprus, and five representative URLs HEAD-verified 200 image/tiff on 2026-08-27: inuncoast_rcp4p5_wtsub_2030_rp0100_0.tif 47,109,700 B · inuncoast_rcp4p5_wtsub_2050_rp0100_0.tif 47,597,340 B · inuncoast_rcp8p5_wtsub_2050_rp0100_0.tif 47,749,230 B · inuncoast_rcp8p5_wtsub_2080_rp0100_0.tif 49,318,780 B · inuncoast_historical_nosub_hist_rp0100_0.tif 46,382,660 B (the last confirming the hist year token and nosub variant resolve live, not just the projected ones). They are recorded under perils.coastal_flood in scripts/cyprus_scenario_hazards_manifest.json with status: "gap" and an explicit carried_by pointer, for two stated reasons: ownership — scripts/packs/coastal_flood.py (#613) is a standalone pack that by design registers no coastal_flood block in the scenario manifest and reaches a country by bbox; and schema — scripts.ingest_scenario_hazards._validate_dataset requires every ingested URL to end rp{rp:05d}.tif, while Aqueduct coastal filenames are …rp{rp:04d}_{suffix}.tif, so an ingested coastal entry would fail validation today and making it pass would mean relaxing a shared guard the Greek manifest also relies on — out of scope for a manifest-authoring issue. Cyprus coastal flood therefore runs through the coastal pack exactly as Greece's does, and is covered by the W2.2b ops run. Volume is attributed to #613's row, not double-counted here. Update 2026-09-02 (#1048) — MEASURED, hazards/ + processed/, method as the storm_europe row. 7 Aqueduct coastal Cyprus datasets active on prod 2026-08-31: hazards/ 35,832 B + processed/ 31,821 B = 67,653 B total across the 7 — attributed here per the ownership note above, not double-counted in #613's own (still-TBD, Greek) Processed cell.
#1046 River flood — Aqueduct historical baseline (Cyprus) — the replacement for the JRC row above, which measures zero over Cyprus World Resources Institute — "Aqueduct Floods Hazard Maps" version 2, riverine historical (inunriver_historical_000000000WATCH_1980_rp*.tif, WATCH forcing, 1980) CC-BY-4.0 — the same WRI statement quoted verbatim in the Aqueduct scenario row above, read live 2026-08-27. 0.00068 (measurement-confirmed — see note e) 0.0000109 (MEASURED 2026-09-02 — hazards/ + processed/, method as the storm_europe row — see note e) ingested; active on prod 2026-08-31 (#1048) (e) Volume re-attribution, not a new cost. These three WATCH/1980 RP files are already counted inside the Aqueduct scenario row's 21-file ≤ 0.0047 GB bound (see note (b): "plus a WATCH 1980 historical baseline × the same 3 RPs"). When the baseline is moved into its own dataset with a baseline scenario_label, its bytes move with it — 3 of the 21 files, 3 × 225,792 B ≈ 677,376 B ≈ 0.00068 GB — so this row must not be added to the Totals, which already contain it. Measurement, 2026-08-28 (#1046): inunriver_historical_000000000WATCH_1980_rp00100.tif HEAD 200, 92,162,308 B remote; the Cyprus windowed read (168 × 336 px) returns 368 valid cells, 0.652 % density, max 0.827 m, against a Greece control of 2.377 % on the same file. RP10 behaves the same way. Density go/no-go: at 0.652 % a Cyprus clip is thin, and when this row was written no minimum-valid-cell or nodata-fraction guard existed anywhere on the ingest path (verified across scripts/packs/ and src/climate_lama/core/ingest/), so it would ingest silently. That guard now exists (#1084): core/ingest/coverage.py::enforce_valid_cell_floor runs in the aggregate phase, before the intensity artifact is written and before the dataset row is stamped, and refuses a dataset carrying fewer valid cells than Settings.hazard_ingest_min_valid_cells. That floor defaults to 0 (disabled) so the shared path every live Greek dataset already flowed through is unchanged. Correction, verified 2026-09-01/2026-09-02 (#1048): HAZARD_INGEST_MIN_VALID_CELLS was never set in prod .env.prod, so Settings.hazard_ingest_min_valid_cells stayed at its default 0 (disabled) for the Cyprus run too — #1048 did NOT set an explicit floor. The Cyprus datasets were therefore ingested with the guard disabled, and #1084's measured coverage below (357/362/368 valid cells, 85 on land) is the honest record of how thin they are, not a floor-enforced minimum. Measured volumes, 2026-08-28 (#1084) — re-read of all three baseline RP files over the Cyprus bbox by the same windowed-read mechanism the probe uses, so these are measurements, not estimates: each file's Cyprus window is 168 × 336 px = 56,448 cells, which confirms the 225,792 B/file uncompressed figure (56,448 × 4 B float32) this note previously derived by calculation — hence 3 × 225,792 B = 677,376 B ≈ 0.00068 GB raw, now measurement-confirmed rather than assumed. Valid cells per return period: RP10 357 (0.632 %), RP50 362 (0.641 %), RP100 368 (0.652 %) — reproducing the RP100 figure above exactly — with 357 cells valid at all three and a 368-cell union (the count the ingest guard measures). On-land caveat: only 85 of those 368 cells fall inside the tracked GADM 4.1 Cyprus admin-0 boundary (tests/fixtures/admin_boundaries/gadm41_CYP_0.json.gz); the rest are offshore, so the on-land density is nearer 0.15 % than 0.652 % and a pin must be drawn from the on-land subset — which is how #1084's named Cyprus pin (34.89, 33.61, Larnaca district, recorded on scripts/packs/country_profile.py::CYPRUS.demo_pin) was chosen. Update 2026-09-02 (#1048) — MEASURED, hazards/ + processed/, method as the storm_europe row. Dataset 41040218-fffa-42c9-8240-93fcbc8dba8c active on prod: hazards/ 6,177 B + processed/ 4,761 B = 10,938 B total — the figure now in this row's Processed cell.
#1046 Earthquake — ESHM20 (Cyprus) EFEHR / ETH Zürich — "ESHM20: the 2020 update of the European Seismic Hazard Model", served by the EFEHR Seismic Hazard Services REST API (efehr-services.ethz.ch/api/v1, model id 81), the source scripts/packs/earthquake_eshm20.py actually reads CC-BY-4.0 — as recorded in that pack's EARTHQUAKE_SOURCE block (license / license_url); citation doi:10.12686/a15. 0.0000717 (MEASURED 2026-08-28 — see note f) 0.0000228 (MEASURED 2026-09-02 — hazards/ + processed/, method as the storm_europe row; the pack builds a per-RP GeoTIFF from the API's numeric response and ingests it like any hazard raster — see note f) ingested; active on prod 2026-08-31 (#1048) (f) This row exists because W0.4's acceptance asks for a volume-budget.md row for every Cyprus source, and ESHM20 had none. Measured, not estimated: GET https://efehr-services.ethz.ch/api/v1/maps/area over the Cyprus bbox (modelid=81&imt=PGA&poe=0.0010249&timespan=1&soiltype=rock_vs30_800ms-1&aggregationtype=arithmetic&aggregationlevel=0.5&format=json) returned HTTP 200 in 58–93 s with a 14,337-byte JSON body carrying 287 grid points at 0.1°, PGA 0.138–0.872 g across the bbox and 0.301 g at the point nearest the bbox centroid (33.4 E, 35.1 N). The pack ingests five return periods, so the whole Cyprus retrieval is 5 × 14,337 = 71,685 B ≈ 0.0000717 GB — three orders of magnitude below any raster source in this table, because the payload is numbers rather than pixels. Reproduce with python scripts/probe_country_source_coverage.py --country CYP --only eshm20. Note the long latency: the pack's own 600 s client timeout is load-bearing, not defensive padding. Update 2026-09-02 (#1048) — MEASURED, hazards/ + processed/, method as the storm_europe row. ESHM20 earthquake Cyprus (c8fab9ae-a61c-45be-ab24-75ee5ecad774) active on prod: hazards/ 11,177 B + processed/ 11,633 B = 22,810 B total — the figure now in this row's Processed cell, and distinct from the 71,685 B raw-API figure above (that measures the source JSON payload, not the ingested artifact).
#1046 Exposure — Eurostat Census 2021 grid (Cyprus) Eurostat (European Commission), GISCO — "Population and housing census 2021 — population grid" (Census-GRID 2021, V3), the same whole-EU archive #620's Greek row uses UNRESOLVED — identical to #620's row; the ambiguity is stamped verbatim onto the ingested dataset by scripts/packs/eurostat_census_grid.py::LICENSE_NOTE and travels with the data 0.031 (MEASURED 2026-08-28 — see note g) N/A — exposure packs write DB rows, not a storage artifact (same treatment as #618/#619/#620) probed ok; not ingested for Cyprus (g) Added for the same reason as the ESHM20 row: W0.4 wants a row per Cyprus source and Eurostat had none. The 0.566 GB whole-archive figure in #620's row is the wrong number for a per-country budget — the archive has 9 members and no per-country split, but only one of them is needed: Eurostat_Census-GRID_2021_V3/ESTAT_Census_2021_V3.tiff, 30,762,675 B compressed / 32,327,795 B raw, read out over HTTP ranges through the zip central directory without fetching the 566,125,577 B archive whole (python scripts/probe_country_source_coverage.py --country CYP --only eurostat). That member is EPSG:3035, 14 bands, band 1 = T (total population). Reprojecting the Cyprus bbox into EPSG:3035 and windowing it (227 × 285 cells) yields 2,521 populated cells / 923,554 people — consistent with the real 2021 census of the Republic-controlled area, which is the extent gadm41_CYP_0 also covers. Greece control on the same member: 40,090 cells / 13,831,480 people.
#1028 Earthquake — USGS ShakeMap (event products) — Samos–İzmir M7.0, 2020-10-30 United States Geological Survey (USGS) — ShakeMap event products for event us7000c7y0, served from earthquake.usgs.gov (the FDSN event API for resolution, the product/shakemap/{eventid}/{source}/{updateTime}/download/ prefix for the files), which is what scripts/packs/shakemap_event.py actually reads U.S. public domain, quoted verbatim from the Phase 13 charter §6 verification of 2026-08-26: "USGS-produced data is U.S. public domain"; credit "U.S. Geological Survey". SECOND-HAND, not re-read live — the canonical policy page refused this machine on 2026-09-02; see note (h). 0.0360 (MEASURED 2026-09-02 — see note h) N/A — nothing is ingested into the platform by this issue; the pack's own output is a ≈0.0016 GB uncompressed operator-side GeoTIFF (see note h) planned; atlas grid fetched locally to cut the committed test fixture, no catalog row written (h) Phase 13 W2.1's event-replay pack. Measured, not estimated: the atlas ShakeMap product's own contents listing, read live on 2026-09-02 from GET https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us7000c7y0&format=geojson (HTTP 200), reports download/grid.xml = 22,716,642 B and download/raster.zip = 13,316,924 B — 36,033,566 B ≈ 0.0360 GB staged together at the download step and then deleted (ADR-070), which is what this column measures. Two ShakeMap products exist for this event and the choice is load-bearing: atlas v1 (updateTime 1646891156713, process-timestamp 2022-01-25T12:20:54Z, maxpga 0.386 g) and us v12 (updateTime 1615430727268, process-timestamp 2021-03-11T02:41:32Z, maxpga 0.358 g). The pack pins atlas — the curated archive product — because a replay must be reproducible and the authoritative us stream is revised in place; both ids are recorded in the pack's source_manifest.json so the unchosen one stays visible. Processed side: the pack writes one EPSG:4326 float32 GeoTIFF over the source grid's own 718 × 558 cells = 1,602,576 B ≈ 0.0016 GB uncompressed (<grid_specification lon_min="21.1000" lat_min="33.1000" lon_max="33.0500" lat_max="42.3833" nominal_lon_spacing="0.0167" nlon="718" nlat="558"/>, read from the file's own header), and much less DEFLATE-compressed; the committed Greece-clipped test fixture tests/fixtures/reference_datasets/earthquake_event_pga.tif is a further clip of that — MEASURED after the run: 450 × 445 cells, 658,317 B, all 200,250 cells carrying data. The %g → g conversion is cross-checked against USGS's own published number: the same atlas product's download/info.json states "PGA": {"units": "g", "bias": "0.329", "max_grid": "0.526", "max": "0.386"}, and parsing all 400,644 grid nodes through scripts/packs/shakemap_event.py gives a full-grid maximum of 0.5261 g — USGS's max_grid, in USGS's own declared unit. (max_grid is the whole-grid maximum and max the over-land one; this epicentre is offshore, which is why the 0.386 maxpga quoted above from the event listing is the land figure and not the one to compare against.) Note also that the grid file's own process_timestamp is 2022-01-25T12:22:35 while the product listing's process-timestamp property is 2022-01-25T12:20:54Z; the pack records both. Status stays planned because no hazards/{dataset_id}/intensity.npz exists — the ingest proof needs the dev stack, which no build agent has. Licence provenance is second-hand and labelled so, per ADR-059: the terms above are the charter's 2026-08-26 verification, not a fresh read — https://www.usgs.gov/information-policies-and-instructions/copyrights-and-credits returned HTTP 503 to both curl and httpx from this build machine on 2026-09-02 (that host is bot-protected; earthquake.usgs.gov itself answered 200 throughout). Upgrade this cell to a live, quoted citation on the next ops run.
#1030 Wildfire — NASA FIRMS VIIRS 375 m active fire, brightness temperature (event products) — North Evia fire, 2021-08-03..10 NASA Fire Information for Resource Management System (FIRMS), LANCE / ESDIS — VIIRS S-NPP 375 m active fire, standard processing (VIIRS_SNPP_SP), served from the area API firms.modaps.eosdis.nasa.gov/api/area/csv/[MAP_KEY]/[SOURCE]/[AREA_COORDINATES]/[DAY_RANGE]/[DATE], which is what scripts/packs/firms_bt_event.py reads NO NAMED LICENCE — and the absence is the record. Read live 2026-09-02 (HTTP 200) from https://www.earthdata.nasa.gov/data/tools/firms/faq, question "Are there any restrictions on using data or imagery from FIRMS?", quoted verbatim: "NASA promotes full and open sharing of data and and [sic] we encourage publication of imagery from FIRMS; when doing so for image captions, please cite it as 'NASA FIRMS' and also consider including a direct link to the imagery in FIRMS to allow others to explore the imagery. For acknowledgment in scientific journals, please use: 'We acknowledge the use of imagery from the NASA LANCE FIRMS (https://earthdata.nasa.gov/firms), part of the NASA Earth Science Data and Information System (ESDIS).'" (The doubled "and and" is the source's own; quoted rather than tidied so the citation is verifiably a reading.) NASA states a sharing policy and an acknowledgement request — it names no licence and no SPDX identifier, and none is invented here per ADR-059 and this file's own convention. Credit: "NASA FIRMS". 0.000314 (MEASURED 2026-09-03 — 314,404 B of CSV actually fetched; see note i) 0.0000116 (MEASURED 2026-09-03 — 11,606 B of DEFLATE-compressed GeoTIFF actually written; see note i) pack executed 2026-09-03 (#1149) — two requests, both HTTP 200, six days of raster written to the operator's disk; not ingested (prod registration is #1146) (i) Phase 13 W3.1's wildfire event-replay pack. This row was originally committed BEFORE any download code ran, which was the whole point of it (and of #625's carried check); it is now MEASURED, and the superseded arithmetic is kept below rather than deleted, because a bound that turned out to be 220× the real figure is worth being able to audit. Executed 2026-09-03 (#1149): the owner registered a FIRMS MAP_KEY on 2026-09-02 and the pack ran end to end against the live archive. Raw, measured: two requests — .../VIIRS_SNPP_SP/22.8,38.5,24.1,39.1/5/2021-08-03 returned HTTP 200, 250,765 B, 3,270 data rows, and .../3/2021-08-08 returned HTTP 200, 63,639 B, 822 data rows — 314,404 B ≈ 0.000314 GB and 4,092 rows in total. Rows are staged as CSV, rasterised, and deletable (ADR-070). Processed, measured: six per-day GeoTIFFs (2021-08-05..10) totalling 11,606 B ≈ 0.0000116 GB on the predicted 113 × 67 grid — 1,550 / 2,654 / 2,220 / 1,956 / 1,654 / 1,572 B. Only 6 of the window's 8 days carry data: 2021-08-03 and 2021-08-04 returned zero detections. The superseded bounds, and how far off they were. Raw was bounded at ≤ 0.069 GB: the query window 22.8,38.5,24.1,39.1 is 1.3° × 0.6° = 112.78 km × 66.79 km at 38.8°N, which at the product's nominal 375 m is 301 × 179 = 53,879 pixels per overpass, and the ceiling assumed every pixel was a detection on both daily overpasses for all 8 days — 862,064 rows × ~80 B/row ≈ 68.97 MB. The real fire produced 4,092 rows, 0.47% of that ceiling, which is what the note predicted in prose ("a real fire yields thousands of detections, not hundreds of thousands... expected to be well under 1 MB") and now states as a number. Processed was computed at ≈ 0.00024 GB — 113 × 67 = 7,571 cells × 4 B = 30,284 B/day uncompressed × 8 days = 242,272 B — where the measured figure is 4.8% of it, for the two reasons that note also gave: DEFLATE, and 8 days assumed where 6 had data. The grid geometry itself was predicted exactly. What was verified live on 2026-09-02, before any key existed and still the provenance of every field name here: https://firms.modaps.eosdis.nasa.gov/api/area/ for the endpoint, the SOURCE vocabulary and the limits, and https://www.earthdata.nasa.gov/data/tools/firms/active-fire-data-attributes-modis-viirs for the field names. The run resolved the one thing those pages left ambiguous — the response header is latitude,longitude,bright_ti4,..., so the brightness field is bright_ti4, not the brightness spelling the table promises "in web services" — and contradicted one thing they stated: version reads 2 (Collection 2), not the table's Collection-1 1.0. The committed test fixture tests/fixtures/reference_datasets/firms_evia_2021_viirs_snpp_sp.csv is now 10,923 B of real archive extract (the 2021-08-06 day, every 16th row), replacing the 947 B authored firms_evia_2021_synthetic.csv this row used to cite — and named for the product rather than synthetic so no reader mistakes it for archived NASA data. Three source facts this row depends on, all read live: (1) DAY_RANGE is capped at 1..5 and the response is [DATE] .. [DATE + DAY_RANGE-1], so the 8-day window is two requests (2021-08-03 day_range 5, then 2021-08-08 day_range 3) and a single-request implementation would fetch five days and label them eight; (2) August 2021 is archive, so the pack pins VIIRS_SNPP_SP over VIIRS_SNPP_NRT, whose detections are superseded once standard processing runs — the same reproducibility argument #1028 used to pin the ShakeMap atlas product; (3) the attribute table names the brightness field twice — "Bright_ti4 / Brightness (in web services)" — and this pack calls a web service, so the CSV's spelling could not be settled without a key. Settled 2026-09-03: it is bright_ti4. Both are still accepted, the observed one now leading on evidence rather than on a guess, the one used is recorded, and an unrecognised header raises rather than guessing. The 375 m → ~1 km aggregation is a recorded modelling assumption, not an implementation detail: the seeded Luthi 2021 WF buildings 1km curve is calibrated on ~1 km MODIS aggregates, so detections are aggregated to that scale (per-cell maximum, never a mean, which would dilute a small very hot front) and the assumption is written into every per-day source_manifest.json. Grid cells are ~1 km on both sides because the longitude spacing is cos(latitude)-compensated; a square-in-degrees cell over Evia would have been 1000 m × 779 m, a 22% under-size on one axis. The pack is now executed, but nothing is ingested: no hazards/{dataset_id}/intensity.npz exists, because the ingest proof needs the dev stack, which no build agent has. Registering the six written days on prod is #1146, and only that will make this an ingested row. This row is not in the Totals — the Totals cover #611–#620 and are recomputed on their own note (c).
#1288 Wildfire — NASA FIRMS VIIRS 375 m active fire, near-real-time live feed (firms_nrt adapter, one poll = one AOI window) NASA Fire Information for Resource Management System (FIRMS), LANCE / ESDIS — VIIRS S-NPP 375 m active fire, near-real-time (VIIRS_SNPP_NRT), served from the area API firms.modaps.eosdis.nasa.gov/api/area/csv/[MAP_KEY]/[SOURCE]/[AREA_COORDINATES]/[DAY_RANGE], which is what src/climate_lama/ingest/feeds/firms_nrt.py reads. The optional trailing /[DATE] segment is omitted — that is what asks for the most recent DAY_RANGE days, and DAY_RANGE is pinned to 1 NO NAMED LICENCE — and the absence is the record. Read live 2026-09-02 (HTTP 200) from https://www.earthdata.nasa.gov/data/tools/firms/faq, question "Are there any restrictions on using data or imagery from FIRMS?", quoted verbatim: "NASA promotes full and open sharing of data and and [sic] we encourage publication of imagery from FIRMS; when doing so for image captions, please cite it as 'NASA FIRMS' and also consider including a direct link to the imagery in FIRMS to allow others to explore the imagery. For acknowledgment in scientific journals, please use: 'We acknowledge the use of imagery from the NASA LANCE FIRMS (https://earthdata.nasa.gov/firms), part of the NASA Earth Science Data and Information System (ESDIS).'" (The doubled "and and" is the source's own.) NASA states a sharing policy and an acknowledgement request — it names no licence and no SPDX identifier, and none is invented here per ADR-059. Credit: "NASA FIRMS". Same licence position as the #1030 archive row above, restated rather than cross-referenced because this is a different product (_NRT, not _SP) polled continuously rather than once. ≈ 0.000039 per poll, transient in memory and never written to disk (derived from the #1030 MEASURED figure — see note j) ≈ 0.0000018 per overpass (MEASURED 2026-09-10 — 1,452–1,806 B of DEFLATE-compressed GeoTIFF written; see note j) adapter built and unit-proven offline 2026-09-10 (#1288); no prod poll has run — a live poll needs FIRMS_MAP_KEY plus egress from the worker, which no build agent has; the 24 h poll-health proof is #1300 (j) Phase 15 W1.3's live wildfire feed — the near-real-time sibling of the #1030 archive pack, reading the same core/ingest/firms_points.py grid and writer, so the two produce the same kind of ~1 km per-cell-maximum brightness-temperature surface. This row is committed BEFORE any prod poll, per this file's own convention. Processed, measured: the adapter was run offline against the vendored real archive extract tests/fixtures/reference_datasets/firms_evia_2021_viirs_snpp_sp.csv (142 rows, North Evia, 2021-08-06) over the pack's own 22.8,38.5,24.1,39.1 rectangle. It grouped the rows into 3 overpasses (00:12, 11:34, 23:53 UTC) and wrote 1,806 / 1,452 / 1,608 B — 4,866 B ≈ 0.0000049 GB for a whole day on the predicted 113 × 67 grid, the same geometry #1030 measured. VIIRS S-NPP gives ~2 useful overpasses/day at these latitudes, so ≈2–4 kB/day/watch is the working figure; the fixture's third group is a partial pass. A watch is capped by settings.live_feed_max_snapshots (500), so one feed's lifetime processed ceiling at this grid size is 500 × ~1.8 kB ≈ 0.0009 GB — and a snapshot is a normal hazard_datasets row, so it is subject to the same retention as any other. Raw, derived not measured: one poll is one request whose body is parsed in memory and never staged — the only file this adapter writes is the per-overpass GeoTIFF counted above, so the disk figure for the raw column is effectively 0. The number recorded is the transfer: #1149's real archive pull over the same rectangle returned 314,404 B for 8 days / 4,092 rows, i.e. ≈39.3 kB and ≈512 rows per day at the peak of a major fire, and DAY_RANGE=1 fetches exactly that one day. An AOI with nothing burning returns a header-only body of ~120 B and the adapter releases nothing ([], no file, cursor's last_acq untouched) — the common steady state, not the peak. Transaction budget: the MAP_KEY limit is 5000 transactions per 10-minute interval (read live 2026-09-02 from https://firms.modaps.eosdis.nasa.gov/api/area/), and FirmsNrtFeed.min_cadence_seconds = 300 means one feed spends 2 transactions per 10 minutes, so the key sustains ~2500 concurrent feeds at the cadence floor. At that floor a single burning watch transfers 288 polls/day × ≤~40 kB ≈ 0.0113 GB/day, of which only the ~2–4 kB of new-overpass raster is kept — the rest is the rolling window being re-served and discarded by the cursor's seen set. This row is not in the Totals — the Totals cover #611–#620 and are recomputed on their own note (c).
#1289 Earthquake — USGS ShakeMap PGA ground-motion grids, near-real-time live feed (usgs_shakemap adapter, one poll = one FDSN window over the watch AOI) United States Geological Survey (USGS) — ShakeMap event products, served from earthquake.usgs.gov: the FDSN event web service /fdsnws/event/1/query?format=geojson&minlatitude=…&maxlatitude=…&minlongitude=…&maxlongitude=…&minmagnitude=…&producttype=shakemap&updatedafter=… for discovery, the same path with ?eventid=<id>&format=geojson for one event's products, and /product/shakemap/{eventid}/{source}/{updateTime}/download/grid.xml for the artifact — which is what src/climate_lama/ingest/feeds/usgs_shakemap.py reads. The same host and the same product/…/download/ prefix as the #1028 archive pack; the difference is that discovery is a bbox + magnitude + updatedafter window rather than one pinned event id U.S. public domain (USGS-produced data); credit "U.S. Geological Survey". Not re-spelled here: the adapter and this row both take the wording from core/ingest/shakemap_grid.py's USGS_LICENSE / USGS_CREDIT / USGS_LICENSE_NOTE constants, and every snapshot's provenance carries all three verbatim, so the licence text has exactly one source and cannot drift between the module, the provenance and this table. SECOND-HAND, and labelled so per ADR-059: those constants record the Phase 13 charter's 2026-08-26 verification, not a live re-read — https://www.usgs.gov/information-policies-and-instructions/copyrights-and-credits returned HTTP 503 to this repository's build machine on 2026-09-02 and was not re-attempted on 2026-09-10 (that host is bot-protected; earthquake.usgs.gov itself answered 200 to every request this issue made). Upgrade to a live, quoted citation on the next ops run — the same carried action #1028 records. 0.0227 per released snapshot, transient and then deleted (MEASURED 2026-09-10 — see note k) ≈ 0.0007 per snapshot at a Greece-wide AOI / ≈ 0.0000244 at a single-island AOI (both MEASURED 2026-09-10; ceiling 0.00135 for an unclipped grid — see note k) adapter built and unit-proven offline 2026-09-10 (#1289) — 53 offline tests over recorded USGS responses; no prod poll has run, because a live poll needs egress from the worker, which no build agent has. The 24 h poll-health proof is #1300 (k) Phase 15 W1.4's live earthquake feed — the near-real-time sibling of the #1028 archive pack, reading the same core/ingest/shakemap_grid.py parser, clip and writer, so the two produce the same kind of PGA-in-g surface and pair with the same seeded ESRM20 curves. This row is committed BEFORE any prod poll, per this file's own convention, but its numbers are measurements rather than bounds. Raw, measured: one released snapshot downloads exactly one grid.xml. The atlas product of us7000c7y0 was fetched live on 2026-09-10 (HTTP 200, curl reported 22,716,642 B in 2.78 s), which is the figure in the raw column — 0.0227 GB, streamed to the feed's staging dir in 1 MiB chunks, parsed off disk and deleted inside the same poll (ADR-070; test_the_transient_grid_download_is_not_left_in_the_staging_dir asserts the staging dir holds nothing but the GeoTIFF afterwards). It matches the product's own contents listing to the byte, which is how #1028 recorded it in 2026-09-02 without downloading it. The us product of the same event is 17,498,440 B; a poll that releases n events transfers n such files, and a poll that releases none transfers one ~1.3 kB GeoJSON body — the steady state, not the peak. Processed, measured: the parsed grid was written through write_geotiff at three extents on 2026-09-10 — the unclipped 718 × 558 grid is 1,345,835 B ≈ 0.00135 GB DEFLATE-compressed (against 1,602,576 B uncompressed, the figure #1028 computed), a Greece-wide watch rectangle (21.2, 34.8, 29.7, 41.8) clips to 511 × 420 px = 704,215 B ≈ 0.0007 GB, and a tight single-island watch (26.0, 37.3, 27.6, 38.6) to 97 × 78 px = 24,445 B ≈ 0.0000244 GB. The clip is the watch's own AOI, so the processed figure is set by how big a rectangle an operator watches, not by the event. A watch is capped by settings.live_feed_max_snapshots (500), so one Greece-wide feed's lifetime processed ceiling is 500 × ~0.7 MB ≈ 0.35 GB, and a snapshot is a normal hazard_datasets row subject to the same retention as any other. Request budget: USGS publishes no rate limit for the FDSN event service, so none is invented — UsgsShakeMapFeed leaves min_cadence_seconds at the inherited 60 (unlike FirmsNrtFeed's 300, which comes from a documented 5000-per-10-minutes key limit). One poll over a quiet AOI is exactly one request: the cursor's event_updated gate stops an unchanged event before the per-event query, so 60 s cadence costs 1,440 requests/day and ~1.8 MB/day of GeoJSON per watch with nothing shaking. Four source facts settled live on 2026-09-10, each recorded as a fixture under tests/fixtures/feeds/usgs/ so the tests assert against a response rather than a claim: (1) producttype=shakemap works and does not 404 — the charter's contingency clause is a contingency, and the adapter's fallback triggers on an HTTP 400/404 refusal only; (2) an unrecognised producttype returns HTTP 200 with count: 0, byte-identical to a quiet window, which is why "zero features" must never be read as "the filter is unsupported" (it would double this feed's egress on every quiet tick, forever); (3) updatedafter is accepted and demonstrably excludes — the same query with it moved past the event's own updated (2026-08-11T17:49:27Z) returns count: 0, which is the difference between a parameter that works and one the service merely tolerates; (4) starttime is load-bearing and was missing from the pinned form. The query form this issue pinned — bbox + magnitude + producttype + updatedafter, no starttime — returns count: 0 for the very event it was written to find, and returns it the moment a starttime is supplied: FDSN substitutes its own recent-origin-time default when the parameter is absent, a different axis from updatedafter's update time. The adapter therefore sends starttime = now - 30 days explicitly (ORIGIN_LOOKBACK), which is that observed default written down — today's behaviour unchanged, tomorrow's owned here rather than by a provider setting nothing in the repo names. The charter's [UNVERIFIED] mark on the artifact set for foreign-network events is closed (docs/plan/exploration/07-live-risk.md §6): us7000c7y0 is a Greek event served through the us network and carries two ShakeMap products, both exposing both artifacts — atlas (updateTime 1646891156713, version 1, grid.xml 22,716,642 B, raster.zip 13,316,924 B) and us (updateTime 1615430727268, version 12, grid.xml 17,498,440 B, raster.zip 13,300,776 B). A foreign-network event is not artifact-poor. raster.zip is recorded and never fetched — its band semantics have never been verified in this pipeline and grid.xml is the source of record for PGA; the availability is a Phase 16 input, not a use. Note also that version does not track updateTime: atlas is v1 with the newer update time and us is v12 with the older one, so the adapter selects strictly by params.product_preference and never by version or recency — either heuristic would publish a different product here. This row is not in the Totals — the Totals cover #611–#620 and are recomputed on their own note (c).
Totals — — — ≈ 24.87 (mixed — calculated upper-bound estimates plus 5 real measurements; now includes #616, excludes a separate ≤142.6 GB WISC full-synthetic-set hypothetical from #615; see note c) ≈ 0.203 partial (measured across #614/#615/#616 only — #611/#612/#613/#617 still TBD, exposure packs N/A; see note c) — (c) Recomputed 2026-08-10 after the NetCDF ops run, superseding the ≈24.64 GB figure computed 2026-08-07 on trunk f65cc59. Three cells changed and the change is entirely in what is measured rather than calculated: #614's raw went from the ≤0.0002 GB calculated Greece-clip bound to 0.0295 GB measured (EWDS 27,990 B ingested + C3S 29,435,326 B downloaded-not-ingested), #615's from the ≤0.04 GB per-footprint bound to 0.000055 GB measured (the real retrieval is scoped to one storm, not the whole 25W–35E/30N–70N domain the bound assumed), and #616 from TBD to 0.238 GB measured (238,249,300 B of delivered ZIPs). Both superseded upper bounds stay visible in their own rows — they are not deleted, because they remain the correct ceiling for the unscoped case each was computed for. New sum: #611 ≤3.7 + #612 ≤0.09 + #613 ≤0.09 + #614 0.0295 (measured) + #615 0.000055 (measured) + #616 0.238 (measured) + #617 ≤0.002 + #618 ≤0.02 + #619 20.13 (measured) + #620 0.566 (measured) ≈ 24.87 GB. This total still mixes calculated upper-bound estimates (#611, #612, #613, #617, #618) with real measurements (#614, #615, #616 by download; #619, #620 by HTTP HEAD) — it is not itself a measurement and should not be read as one. #615's own row separately documents a ≤142.6 GB upper bound for fetching WISC's entire 22,980-footprint synthetic set whole; that figure stays deliberately excluded from this headline total — and as of 2026-08-10 it is not merely an un-scoped hypothetical but a not-pursued one: the WISC process schema publishes no spatial input at all, so it cannot be scoped under the no-multi-GB rule (see #615's note b). If it were included anyway, the combined raw-volume exposure would be ≈167.5 GB. The processed column is now partially summable for the first time: #614 0.0000141 + #615 0.000125 + #616 0.203 ≈ 0.203 GB measured, against #611/#612/#613 still TBD — those packs are ingested, so their processed bytes are already sitting in the bucket and are measurable, they have simply never been attributed per-pack — #617 at a ≤0.0002 GB estimate, and #618/#619/#620 N/A (exposure packs write DB rows, not a storage artifact). Treat the 0.203 GB as a floor, not a total. This ≈24.87 GB is NOT a storage bill — see the "Raw-zone reality check" above the Ledger table. The live Hetzner bucket measured 359.87 MB (0.360 GB) across 158 objects on 2026-08-10, after that day's ops run and after trash/ was purged (superseding both the 0.325 GB measured on 2026-08-08 and the 528.30 MB / 185-object intermediate reading taken earlier on 2026-08-10, before the purge; raw/ is still only .keep + catalog.v1.json, 2 objects / 0.04 MB): every pack here streams its source download to local disk, clips/ingests it, then deletes it, so nothing in this column is ever archived to the bucket. Per-zone, final 2026-08-10 reading: hazards/ 55 obj / 200.72 MB, processed/ 47 obj / 158.75 MB, raw/ 2 obj / 0.04 MB, reports/ 7 obj / 0.24 MB, results/ 30 obj / 0.12 MB, staging/ 16 obj / 0.01 MB, tiles/ 1 obj / 0.00 MB, trash/ 0 obj (purged). (Those per-zone figures add to 359.88 MB against a reported total of 359.87 — a 0.01 MB artifact of rounding each zone independently, not a missing object.) Two movements explain the delta from the pre-purge reading: trash/ went 28 obj / 237.40 MB → 0 (the trash/2026-08-08-ops5b/ keys were deleted one by one after confirming all four referenced UUIDs were absent from hazard_datasets, that none was a live ingest_jobs row, and that no dataset had a cog_path under trash/), and processed/ grew 46 obj / 89.77 MB → 47 obj / 158.75 MB because #611's JRC national baseline finally got its COG built (see that row's own update). The bucket is now almost entirely live data: hazards/ + processed/ = 359.47 MB of the 359.87 MB total, of which #616 alone is 203.33 MB.

Phase 12 (Cyprus) rows are deliberately NOT folded into the Totals row above. The Totals row and its note (c) are a Phase 9 accounting over #611–#620, recomputed against that set; the four #1038 rows are a second country whose packs have not run, so every one of their volume cells is either a calculated bound or a HEAD measurement of a remote file rather than bytes that have ever landed. Folding un-ingested bounds into a total that already mixes estimates with measurements would make it less honest, not more. Whoever lands the last Phase 12 pack (W2.2b–d) recomputes a Phase 12 total then, with measured figures — see the Convention section at the top of this file.

The Phase 13 (event replay) rows are not folded into the Totals row either, for the same reason and one more: #1028 and #1030 each budget a single historical event's products rather than a country-wide pack, and nothing either downloads has been ingested — #1028's measured 0.0360 GB is a transient the operator stages, clips and deletes, and #1030's 0.000314 GB raw / 0.0000116 GB processed (MEASURED 2026-09-03, #1149 — this paragraph previously said no FIRMS_MAP_KEY existed and nothing had been fetched, which stopped being true when the owner registered one) are bytes on an operator's disk, not in the bucket. Folding either into a total that already mixes estimates with measurements would make it less honest, not more. Whoever runs the Phase 13 ops ingest — #1146 for wildfire — recomputes a Phase 13 total then, over what actually lands in storage.