diff --git a/CHANGELOG.md b/CHANGELOG.md index efcede4..e7fae7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to `views-frames` are documented here. The format is based o [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/) as governed in `GOVERNANCE.md`. -## [3.0.0] — unreleased +## [3.0.0] — 2026-11-01 **Reconciliation now places every country's fatalities on the grid.** When a country's grid is all zeros in a draw but the country forecast is positive, scaling has nothing to diff --git a/CLAUDE.md b/CLAUDE.md index cc4ae2c..9d22462 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,12 +6,14 @@ at the **root of the platform dependency DAG**, plus two sibling operation packa in the same wheel. numpy only; depends on nothing internal; every other repo depends *toward* it. -> **Status:** **v2.x — the version in this tree**; see +> **Status:** **v3.x — the version in this tree**; see > [PyPI](https://pypi.org/project/views-frames/) for what is published. The v1 API was > frozen from v1.0.0 (ADR-018) -> and **broken once, deliberately, in 2.0.0** (ADR-028): a frame's `index` must now -> actually be a `SpatioTemporalIndex`, and `frame.values` is write-protected. -> `CONFORMANCE_FLOOR` moved `1.0.0` → `2.0.0` — its first move. Everything else is +> and **broken twice, deliberately**: in 2.0.0 (ADR-028) a frame's `index` must +> actually be a `SpatioTemporalIndex`, and `frame.values` is write-protected; in 3.0.0 +> (ADR-030) reconciliation places every country's mass, borrowing a donor draw's pattern +> where a country's grid is empty, and raising when there is no donor. +> `CONFORMANCE_FLOOR` moved `1.0.0` → `2.0.0` → `3.0.0`. Everything else is > additive, and the bar for a further MAJOR stays deliberately high. > Consumers install `views-frames` and validate against the published conformance > suite (`views_frames.conformance`, ADR-016). See `CHANGELOG.md` for the release @@ -79,8 +81,10 @@ across levels (joint sampling). Fail-loud config for the tower family (ADR-019). **`src/views_frames_reconcile/`** — top-down proportional reconciliation of pgm grid forecasts to cm country totals (ADR-023; numpy-only; depends on `views_frames`). -`ReconciliationModule(map_keys, map_vals)` with the geography **injected** (never -fetched); `reconcile` / `reconcile_result` (the latter reports the +`ReconciliationModule(map_keys, map_vals, *, seed=0)` with the geography **injected** +(never fetched); a draw whose grid is all zeros against a positive country borrows a +random donor draw's pattern from the same `(time, country)`, or raises with no donor +(`donor_fill.py`, ADR-030); `reconcile` / `reconcile_result` (the latter reports the `point-broadcast`/`aligned-draws` **mode** — returned, never stamped on the leaf header, D-12). The per-draw method is a documented approximation; the principled joint upgrade is designed and deferred (ADR-024, register C-62). diff --git a/README.md b/README.md index f8d6f61..9e0a86e 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ > containers (`FeatureFrame`, `PredictionFrame`, and their anticipated siblings) > that every other repo depends on and that depends on nothing internal. > -> **Status:** **v2.0.0 — the version in this tree.** For what is actually published, see +> **Status:** **v3.0.0 — the version in this tree.** For what is actually published, see > [PyPI](https://pypi.org/project/views-frames/): between a release commit and its publish > job this number is deliberately ahead, so this banner tracks the source and never claims -> a publication it cannot verify. API frozen at v1.0.0 (ADR-018) and broken once in 2.0.0 -> (ADR-028; the +> a publication it cannot verify. API frozen at v1.0.0 (ADR-018) and broken twice since, in 2.0.0 +> (ADR-028) and 3.0.0 (ADR-030; the > v1.1 surface is > purely additive — the coherent posterior summary, ADR-019; v1.2.0 rebuilt the tower > `outside-in`, C-44; v1.3.0 makes the tower summary distribution-agnostic — no magnitude @@ -25,7 +25,7 @@ > `research/figures/` tower-figure toolkit; v1.10.0 adds the **dense-grid fill** > primitive — `reindex_fill(other, *, fill_value)` on all three frames + > `SpatioTemporalIndex.cartesian` + the published `assert_reindex_fill_law`, ADR-026, -> unblocking pandas-free FAO ingestion; v1.10.1 makes `io.arrow.load` fail loudly on a parquet whose row order breaks the wire contract, #199; v1.10.2 changes no behaviour — it arms the documentation check in CI, turns eleven falsification tests from README-wording checks into behaviour checks, and records ADR-027 declining the construction shortcut; v1.11.0 corrects the published MAP-containment law, which was wrong on tied draws and so failed ~6% of rows on integer count posteriors — register C-88 — and makes the two IO codecs agree on a non-JSON metadata value, C-90; the rest of that release makes the governance documents match the code and adds the CI checks that keep them matching; **v2.0.0 is the first MAJOR** — a falsification audit found that a frame's `index` was never type-checked, so a frame (or any object with an `n_rows`) was accepted silently and the published `assert_summarizer_contract` then certified the result, and it now raises `TypeError`; riding it, `frame.values` becomes read-only (C-66) and `map_estimate` rejects non-finite draws (C-57), and `CONFORMANCE_FLOOR` moves to `2.0.0` — a correct consumer changes its version constraint and re-locks, nothing else, ADR-028). This +> unblocking pandas-free FAO ingestion; v1.10.1 makes `io.arrow.load` fail loudly on a parquet whose row order breaks the wire contract, #199; v1.10.2 changes no behaviour — it arms the documentation check in CI, turns eleven falsification tests from README-wording checks into behaviour checks, and records ADR-027 declining the construction shortcut; v1.11.0 corrects the published MAP-containment law, which was wrong on tied draws and so failed ~6% of rows on integer count posteriors — register C-88 — and makes the two IO codecs agree on a non-JSON metadata value, C-90; the rest of that release makes the governance documents match the code and adds the CI checks that keep them matching; **v2.0.0 is the first MAJOR** — a falsification audit found that a frame's `index` was never type-checked, so a frame (or any object with an `n_rows`) was accepted silently and the published `assert_summarizer_contract` then certified the result, and it now raises `TypeError`; riding it, `frame.values` becomes read-only (C-66) and `map_estimate` rejects non-finite draws (C-57), and `CONFORMANCE_FLOOR` moves to `2.0.0` — a correct consumer changes its version constraint and re-locks, nothing else, ADR-028; **v3.0.0 is the second MAJOR** — reconciliation silently lost a country's fatalities whenever its grid was all zeros in a draw, 2.9–7.3% of the fatality mass on the first production run (#283, register C-99); such a draw now borrows the pattern of a random donor draw from the same month and country, a group with no donor raises, every other draw is bit-identical, and `CONFORMANCE_FLOOR` moves to `3.0.0`, ADR-030). This > README is the design > bible; the contract it specifies is realised in `src/views_frames/` (index, frames, > io, conformance suite) plus the `src/views_frames_summarize/` sibling package diff --git a/pyproject.toml b/pyproject.toml index 44718c7..210147e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "views-frames" -version = "2.0.0" +version = "3.0.0" description = "The VIEWS platform data-contract layer: immutable array+identifier frames (numpy only, root of the dependency DAG)." authors = [ { name = "Simon Polichinel von der Maase", email = "simmaa@prio.org" }, diff --git a/uv.lock b/uv.lock index 89a4605..2715ad6 100644 --- a/uv.lock +++ b/uv.lock @@ -3438,7 +3438,7 @@ wheels = [ [[package]] name = "views-frames" -version = "2.0.0" +version = "3.0.0" source = { editable = "." } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },