Skip to content

Releases: views-platform/views-frames

views-frames 2.0.0

Choose a tag to compare

@Polichinel Polichinel released this 18 Aug 12:55

A frame's index must actually be an index.

Until now you could hand a frame anything as its index — a different frame, or a bare object with an n_rows attribute — and it was accepted. The frame was built, it looked fine, and the published conformance suite said it was fine. That now raises TypeError.

If you pass a SpatioTemporalIndex, you will not notice this release. That is what the type hint has always required and what every example does. Change your constraint, re-lock, carry on:

- views-frames = ">=1.10.2,<2"
+ views-frames = ">=2.0.0,<3"

This is the package's first MAJOR and the first move of CONFORMANCE_FLOOR since the v1.0.0 freeze (1.0.02.0.0). Decision, reasoning and full migration: ADR-028.

What actually breaks

If your code… Before Now
passes a SpatioTemporalIndex as index works works, unchanged
passes a frame or other object as index silently constructed TypeError
passes a non-index to reindex/reindex_fill AttributeError on _level TypeError, naming what was expected
mutates frame.values in place silently corrupted buffer-sharing frames ValueError: read-only
calls map_estimate on inf/NaN draws bare IndexError ValueError naming the cause

Only row 4 can plausibly break working code, and ADR-025 already documented that operation as unsupported.

Why it was worth a MAJOR

Every summarizer reads .values and never .index, so a frame built with a non-index returned numerically correct answers — and assert_summarizer_contract certified it. That checker is published under ADR-016 and consumers run it in their own CI, and docs/CICs/Conformance.md names "a checker that cannot detect a violation" as the failure mode it must never have. A false pass is worse than no checker, because it is evidence you are entitled to rely on.

Found by a falsification audit run against the claim that this package was finished.

Also in this release

  • frame.values is write-protected (register C-66) — as a read-only view, so zero-copy and mmap survive and your own array stays writeable.
  • map_estimate rejects non-finite draws (C-57), matching exceedance and expected_shortfall.
  • CONFORMANCE_FLOOR2.0.0. Your CI will assert a new contract version. First move in the package's history.

Adoption issues are open in views-faoapi, views-postprocessing and views-crafdapi.

Full detail in CHANGELOG.md.

views-frames 1.11.0

Choose a tag to compare

@Polichinel Polichinel released this 18 Aug 01:57

The published MAP-containment law was wrong on tied draws, and the governance documents had drifted from the code in ways nothing checked. This release fixes the first, corrects the second, and adds the CI checks that keep both from drifting again.

CONFORMANCE_FLOOR stays 1.0.0, and no public API was added, changed or removed. If you are upgrading from 1.10.2, nothing in your code needs to change.

MINOR rather than PATCH because the conformance suite now asserts a different set of HDI floors than it did in 1.10.2.

The fix that affects consumers

assert_summarizer_contract failed on integer count posteriors (register C-88). The MAP-containment law decided which HDI floors provably contain the tower tip using floor(m·S)+1 — a floor’s index span. The tip is the median of the draws whose value lies inside the floor. Those agree only when draws are distinct: duplicated endpoint values put more draws inside the same bounds, so narrower floors were certified that hold less than half the tip floor, and the law then asserted containment for them.

Measured on zero-inflated Poisson posteriors at S ∈ {32, 64, 128}: 30 of 500 rows failed, every one on the 0.15 floor. After the fix, 0 of 500.

This is published under ADR-016 and consumers run it in their own CI, so the failure landed as another repository going red on correct data — and integer counts are this platform’s primary shape.

If your CI was red on this check with count data, upgrade and it will pass. If it was green, it stays green: the correction narrows what the suite asserts.

Also fixed

The two IO codecs disagreed on a non-JSON metadata value (C-90). io/npz silently stringified it where io/arrow raised — a datetime timestamp reloaded as a string into a field declared int | None. Both now raise, per ADR-008.

New checks

Import contracts, three documentation-completeness assertions, examples/ execution, a cross-version parquet/npz fixture written by v1.8.0 code, and the architecture-tree check.

Governance

ADR-002, ADR-018, GOVERNANCE.md, the physical-architecture standard, README and the CIC set now match the code, with a new FrameMetadata contract. CLAUDE.md gains a maintenance-mode section: this package is finished, and its register’s open entries are a log of accepted conditions rather than a backlog.

Full detail in CHANGELOG.md.

v1.10.2

Choose a tag to compare

@Polichinel Polichinel released this 31 Jul 03:32
a571ed1

No behaviour change. This release publishes work on the checks, the tests and the
documentation. The only change under src/ is a corrected docstring. CONFORMANCE_FLOOR
stays 1.0.0, and no public API was added, changed or removed.

If you are upgrading from 1.10.1, nothing in your code needs to change.

Fixed

  • FeatureFrame.from_2d was documented as a "deprecated shim". It is not deprecated —
    it builds a frame from a 2-D (N, F) array of unsampled features and adds the trailing
    sample axis to give (N, F, 1). Since the sample axis is always explicit (ADR-012),
    that is the ordinary constructor for deterministic features. The method docstring, the
    module docstring, the constructor's ValueError message and the contract file were all
    corrected — the first pass missed the last two, so the same file contradicted itself for
    a while (register C-76).

Changed — checks

  • docs/validate_docs.sh now runs in CI. It checks documentation consistency,
    including that the README's version banner matches pyproject.toml. That banner check
    had been added specifically to stop version drift recurring, but the script was never
    wired into CI — it only ran when someone typed it (register C-74, half closed here; the
    formatting half follows).

Changed — tests

  • Eleven falsification tests now check the code instead of the README's wording. They
    were written before the package existed, when asserting that the design document had
    decided something was the only check available. They had reached the point of failing
    when someone reworded a paragraph and passing when the code broke. Ten were rewritten
    against behaviour; one was retired because test_import_enforcement.py already enforces
    it directly (register C-75).
  • Among them, the check that no legacy priogrid_gid alias exists now inspects the code
    rather than the documentation — a guard against something that was actually attempted.

Changed — documentation

  • New contract document: docs/CICs/Conformance.md. The published conformance suite —
    the checks consumers run in their own CI — had no contract describing what it guarantees,
    while the contract index claimed every shipped surface was covered. It now documents each
    check, what it deliberately does not verify, and the failure mode that matters most: a
    checker must fail when handed a frame that misreports itself (register C-81).

  • ADR-027 records the decision to decline issue #113, which asked for a one-line
    shortcut for building a PredictionFrame. Construction stays two-step. The design that
    had been agreed for it is preserved in the ADR, along with what would justify revisiting
    it (register C-52, C-53, C-54).

  • The reconciliation production-slice check is closed: the comparison tool and the runbook
    requirement for it both shipped some time ago (register C-58).

  • Documentation now cites code by name rather than by line number
    (_validation.py::coerce_values, not _validation.py:64). Line numbers had already
    drifted unnoticed in two entries.

v1.10.1

Choose a tag to compare

@Polichinel Polichinel released this 28 Jul 00:34
d4052c0

[1.10.1] — 2026-07-28

io.arrow.load now validates the wire-contract row order before reshaping (#199 item 1).
Fail-loud hardening of the parquet load path; no API change; CONFORMANCE_FLOOR stays 1.0.0.

Fixed

  • Silent sample-slot corruption on out-of-order parquet input. arrow.save writes the
    row order as the contract (sample = tile(arange(S), N); io/arrow.py) but load
    reconstructed positionally without ever checking it — a reordered, truncated, or
    foreign-rewritten table reshaped plausible floats into the wrong sample slots with no
    error
    . load now validates the layout first and raises ValueError on: a row count
    that is not a positive multiple of the header's n_samples (truncated/filtered table);
    a sample column deviating from the written tile order (row-level reorder); or
    time/unit not constant within a sample block (rows swapped between cells — the case
    the tile check alone cannot see). A whole-cell block reorder (identifiers travel with
    their draws) remains a consistent table and still loads. Implements the check
    views-postprocessing ADR-013 §4.5(b) previously required every consumer to run
    themselves on a separate raw-table read — the leaf now hardens all consumers at once.
    Register C-72. (#199 item 2 — mmap/partitioned arrow reading — remains open.)

v1.10.0

Choose a tag to compare

@Polichinel Polichinel released this 27 Jul 16:44
1049ff9

[1.10.0] — 2026-07-27

The dense-grid fill primitive (ADR-026) — unblocks pandas-free FAO ingestion (#203).
Additive MINOR; CONFORMANCE_FLOOR stays 1.0.0.

Added

  • frame.reindex_fill(other, *, fill_value) on all three sibling frames
    (PredictionFrame/FeatureFrame/TargetFrame, WET per ADR-011): align to other's
    rows with no superset requirement — present rows pass through bit-exact, absent
    rows get the caller's fill_value broadcast across the trailing axes (NaN legal;
    keyword-only and required — no silent default, ADR-009). The result's index is
    other; metadata (and feature_names) preserved. Owns the -1-sentinel scatter once:
    a consumer hand-rolling values[pos] silently picks the last row for absent cells.
    Inherits the C-21 row-uniqueness stance (unique rows assumed in self; duplicate
    target rows allowed and repeat).
  • SpatioTemporalIndex.cartesian(times, units, level): the dense product-index
    constructor — every (time, unit) combination in canonical time-major order, from
    explicit arrays only (deriving them, e.g. "units of the last time step", is
    consumer policy). Fails loud on duplicated input values (a duplicated product input
    manufactures duplicate rows → undefined same-level joins, C-21).
  • assert_reindex_fill_law in the published conformance suite (ADR-016): result
    index equals the target row-for-row; present rows bit-exact; absent rows equal the
    fill (NaN-safe); on a superset frame the fill degenerates to reindex.
  • Consumer note: faoapi's dense_grid.py can now delegate (its last-step-entity rule +
    C-87 dropped-entity check stay consumer-side) and drop its pandas implementation
    (faoapi #242). Densification allocates the full dense buffer — a deliberate, costly
    act at grid scale (documented on both symbols).

v1.9.0

Choose a tag to compare

@Polichinel Polichinel released this 24 Jul 09:26
125905e

[1.9.0] — 2026-07-24

The tower-tip MAP reads the top floor (ADR-019 Amendment 3): tip_mass 0.5 → 0.25.
Behavior change to tower_point/summarize_tower outputs, shipped MINOR per the C-44/C-45
precedent (estimator amendment with ADR evidence); CONFORMANCE_FLOOR stays 1.0.0.

Changed

  • tip_mass default 0.5 → 0.25 (the top-quartile floor). The tower-tip MAP is now the
    median of the top floor of the published tower, matching the design intent the name
    always promised. Evidence (research/map_hdi/tip_mass_study.py, 1000-replicate battery +
    duplicate-capture frontier + the real-cell C-44 gate): the 0.5 shorth carried a structural
    rightward bias that does not shrink with sample count; 0.25 roughly halves it, beats the
    shorth on RMSE at pooled S, reads zero-inflated cells exactly, and passes the real-cell
    zero-stack gate with margin (masses ≤ 0.15 resurrect the C-44 signal loss; 0.20 has zero
    margin). Consumer note: published MAPs shift toward the mode on skewed cells — the intended
    C-32 direction.

Added

  • MAP-containment law in assert_summarizer_contract: every floor holding more than half
    the tip floor's draws (asymptotically mass > tip_mass/2 = 12.5%) provably contains the
    tip — wider floors by nesting, narrower qualifying floors by the sub-window trim argument.
    All published bands (50/90/95/99) qualify; the unguaranteed region shrinks versus the old
    default (was: everything below 0.5).
  • research/map_hdi/tip_mass_study.py — the committed evidence trail for the amendment.
  • research/figures/ — permanent, seeded generators for the PRN06 tower figures (overlay +
    detail, upright-tower rendering), with reports/plots/ as the gitignored output home.

v1.8.1

Choose a tag to compare

@Polichinel Polichinel released this 02 Jul 10:49
58c5c99

[1.8.1] — 2026-07-02

Falsification-audit hardening (four-axis audit 2026-07-02; register C-67/C-68/C-69/C-70).
Bug fixes with an identical contract — the code now honors what the docs already promised.
No public-surface change; CONFORMANCE_FLOOR stays 1.0.0.

Fixed

  • reconcile_proportional conserves exactly for any nonzero draw sum (C-68, the audit's one
    hard finding).
    The torch-port's + 1e-8 denominator epsilon — a float32 no-op for draw sums
    ≳ 0.1 but a silent deflator for tiny nonzero sums (a draw sum of 1e-8 reconciled a country
    total of 100 to 50, with no error signal, violating the Reconcile.md §3 sum-to-country
    guarantee) — is replaced by an explicit all-zero-draw guard: exact division for any nonzero
    sum; all-zero draws stay zero exactly as before. Bit-identical on all realistic data
    (torch-oracle parity unchanged and green).
  • Negative country totals now fail loud (C-68/F8): reconcile_proportional raises
    ValueError instead of silently clamping the output to zero (sum 0 ≠ the requested total).
  • The published conformance suites refuse to run under python -O (C-67): all three
    (views_frames.conformance, summarize, reconcile) now guard their entry points with
    _require_assertions() — under optimized bytecode (which strips the suites' assert
    statements) they raise RuntimeError instead of silently reporting green.
  • Empty-index searchsorted returns all -1 (C-69) — the documented not-found value —
    instead of crashing with an obscure IndexError (the np.clip(pos, 0, -1) corner).

Notes

  • Regression pins for all four fixes: tests/test_falsification_safety_audit_2026_07.py.
  • Reconcile.md §6 documents the two reconcile behaviors; proportional.py's module docstring
    records the deliberate (bit-parity-preserving) deviation from the torch original.
  • Register: C-67/C-68/C-69 registered-and-resolved; C-70 (the audit's docs/tests polish
    bundle) opened and cleared in the same release (below).

Tests

  • C-70 test adds (#195): the share-proportionality law (the method's defining
    forecast-proportion property, previously pinned only by the frozen-oracle fixtures); an mmap
    read-only pin (writeable is False, in-place write raises); the reconcile
    missing-(time, priogrid_gid)-mapping-entry raise.

Documentation

  • C-70 docs refresh (#196): CLAUDE.md rewritten for the released three-package reality;
    README banner → v1.8.0 + chronicle; ADR-013 as-built amendment (feature_names); CIC accuracy
    fixes (§5 artifact names → values.npy, PredictionFrame §6 real dtype behavior, index §6
    NaN-via-dtype, Reconcile §10 pinning files); CICs/ADRs README framing refreshed; and a
    recurrence guardvalidate_docs.sh now checks the README banner's MAJOR.MINOR against
    pyproject.toml.

v1.8.0

Choose a tag to compare

@Polichinel Polichinel released this 28 Jun 01:11
a5ba768

[1.8.0] — 2026-06-28

Native point-country broadcast in views_frames_reconcile (ADR-023 amendment, #143 / Epic #142),
the three showcase notebooks (Epic #166), and a governance/test hardening pass (Epic #179).
All
additive — the frozen leaf and summarize public surface are unchanged, and the hardening work makes
no src/ behaviour change; CONFORMANCE_FLOOR stays 1.0.0.

Added

  • ReconciliationModule.reconcile accepts a point country (cm.sample_count == 1) against a draws
    grid (pgm.sample_count == S): the point is broadcast across the S draws inside the orchestrator
    (np.tile), so callers no longer tile it themselves (the DRY home of pipeline-core's WET
    align_country_to_grid, #143). The aligned-draws path (cm.sample_count == S) is byte-for-byte
    unchanged; any other count still fails loud.
  • ReconciliationModule.reconcile_result(cm, pgm) -> ReconciliationResult (#144) — reconciles and
    reports the mode (POINT_BROADCAST | ALIGNED_DRAWS) + method (proportional) on a returned
    ReconciliationResult. The mode is returned, never stamped on the leaf's generic FrameMetadata
    (ADR-020 / register C-47 — the numpy leaf carries no reconciliation vocabulary). reconcile is
    unchanged (it returns reconcile_result(...).frame). New public names: ReconciliationResult,
    POINT_BROADCAST, ALIGNED_DRAWS, METHOD_PROPORTIONAL.

Notes

  • The broadcast lives entirely in views_frames_reconcile/module.py; the leaf proportional and the
    parity-frozen grouping hot loop are untouched, so the torch-oracle parity is exact (0.000e+00).
  • The aligned-draws mode remains the documented per-draw approximation. ADR-024 (#145) records the
    design direction + deferral for the principled joint upgrade (and corrects proportional.py's
    ambiguous "C-37" reference; register C-62). Design-only — no code.

Documentation

  • Three showcase notebooks (notebooks/01_frames, 02_summaries, 03_reconciliation; Epic #166):
    public-frozen-API-only, synthetic-data teaching notebooks for the frames contract, the posterior
    summaries (with a calibration/coverage + PIT panel), and reconciliation — including a
    bit-identity-≠-method-quality panel and a toy-lattice spatial view (register C-59/C-60/C-61).
  • docs/CICs/Reconcile.md (Epic #179) — the package-level Class Intent Contract for
    views_frames_reconcile (§1–§11): the sum-to-country / zero-preservation / non-negativity /
    de-mutation guarantees, the point/aligned mode contract, the five fail-loud validation guards
    • the per-draw-approximation caveat, and the green/beige/red test alignment. The reconcile package
      was the last non-trivial surface without a CIC (ADR-006); register C-64 resolved.
  • ADR-025 — value-buffer immutability is by convention; only the index is enforced (Epic #179).
    Corrects the "immutable value objects" contract (the three frame CICs §9/§3 + README design
    principle 2) to match the code: the index (time/unit) is setflags(write=False)-enforced; the
    value buffer is immutable by convention (left writeable to preserve zero-copy / mmap — mutating
    .values in place is unsupported). The setflags-enforce on .values would be a MAJOR
    ("tightening an invariant" on a frozen-surface member, GOVERNANCE/ADR-018), so it is recorded as a
    deferred MAJOR-rider, not done now; register C-63 resolved (contract corrected).

Tests

  • Adversarial (red) test hardening (Epic #179), no src/ change, 100% line+branch coverage held:
    • the non-finite (NaN / ±inf) fail-loud guard in exceedance/expected_shortfall is now pinned on
      the blocked (multi-block) path — the bad draw placed in a non-first block via the block_rows
      kwarg with block 0 all-finite (register C-65 resolved);
    • conformance-suite negativesassert_reconcile_contract and assert_summarizer_contract are
      shown to reject a deliberately non-conforming implementation (the leaf's C-51 envelope-negative
      pattern, extended to the sibling packages);
    • reconcile mode-cornersreconcile_result.mode for both-points and pre-tiled-cm inputs (both
      ALIGNED_DRAWS); and ReconciliationResult frozen-ness (FrozenInstanceError).

v1.7.0 — views_frames_reconcile (forecast reconciliation)

Choose a tag to compare

@Polichinel Polichinel released this 26 Jun 05:48
55dda2d

Adds a third sibling package, views_frames_reconcile, to the views-frames mono-wheel (alongside views_frames + views_frames_summarize). CONFORMANCE_FLOOR stays 1.0.0 — additive over the frozen v1 surface.

views_frames_reconcile (ADR-023)

Forecast reconciliation — make grid (pgm) predictions sum, per posterior draw, to their country (cm) totals — as a numpy-only, views_frames-only frame operation (the same kind of thing as views_frames_summarize, ADR-017).

  • ReconciliationModule(map_keys, map_vals).reconcile(cm_frame, pgm_frame) → a new pgm PredictionFrame. The (time, priogrid_gid) → country_id mapping is injected as arrays, never fetched (ADR-014/ADR-023).
  • reconcile_proportional(grid, country) — the per-draw top-down proportional method (zeros preserved, country totals authoritative, non-negative).
  • assert_reconcile_contract(...) — the conformance suite.

How it got here

Faithfully relocated WET from views-postprocessing (where it was mis-homed and stranded) — the ported modules differ from the originals by import lines only. Proven correct by the frozen views-reporting torch-oracle parity tests and a 136-case new-vs-old np.array_equal bit-identity head-to-head.

Notes

  • Charter: frame-reconciliation only; no IO, scoring, plotting, fetched mapping, or foreign views_*. Import-DAG views_frames_reconcile → {views_frames}.
  • WET before DRY: grouping.pycross_level_align fold deferred; the probabilistic upgrade (C-37) is a future sibling module.
  • Consumer repoint (views-models) + views-postprocessing deletion are the cross-repo cutover, gated on this release.
  • Full changelog: CHANGELOG.md.

v1.6.0 — exceedance + worst-case expected_shortfall

Choose a tag to compare

@Polichinel Polichinel released this 24 Jun 23:12
bd1b40f

main/PyPI jump 1.3.0 → 1.6.0 in one release. v1.4.0 and v1.5.0 were development-only milestones; v1.6.0 is the complete superset. CONFORMANCE_FLOOR stays 1.0.0 — every addition is additive over the frozen v1 surface.

Highlights (the 1.4.0 → 1.6.0 arc)

expected_shortfall — the worst-case tail mean (v1.6.0, ADR-022)

expected_shortfall(frame, tails) → (N, …, K): the per-row mean of the worst ⌈t·S⌉ draws (tail mean / CVaR) for each upper-tail fraction t. A coherent, subadditive worst-case risk measure and the companion to exceedance. max is never offered (highest-variance, non-reproducible). Tails are required per-call, in (0, 1] — the consumer's policy. Best-case ships no code (a low quantile + exceedance(frame, [0])).

exceedance — survival probability P(Y > c) (v1.5.0, ADR-021)

exceedance(frame, thresholds) → (N, …, K) + exceedance_reducer(c). Distribution-agnostic counting reducer; the flagship is P(Y > 0) = onset. Strict >; thresholds required per-call; geography-blind compose via aggregate_distributions.

Provenance + published envelope checker (v1.4.0, ADR-020)

FrameMetadata.run_id / data_version; assert_frame_envelope as a published conformance check; NaN-tolerant round-trip.

Fail-loud hardening (pre-release falsification audit)

Both new estimators reject non-finite draws (NaN or ±inf) via an np.isfinite guard — an inf draw (always an upstream bug) can no longer silently contaminate a worst-case or bless an exceedance probability.

Notes

  • Single views-frames wheel ships both views_frames (numpy-only data contract) + views_frames_summarize (sample-axis summarization).
  • Published via PyPI Trusted Publishing (publish_package.yml).
  • Full changelog: CHANGELOG.md.