Skip to content

S4 — unfao/wire/sidecar.py + delivery/parity.py: the §5 GAUL sidecar and the gid-set parity invariant #109

Description

@Polichinel

Part of epic #105. Depends on S1. Parallel-eligible with S3/S5.

Problem

§5 pins a 10-column sidecar (priogrid_id first; codes ALWAYS float64; NaN/null rows preserved; ascending rows; column order normative) built from this repo's ADR-011 lookup — no builder exists. §5.2's gid-set parity (sidecar cells == forecast cells) has no invariant.

Work

  • views_postprocessing/unfao/wire/sidecar.py: build_sidecar(lookup: pa.Table, gids) -> pa.Table — pyarrow-only, lookup injected (DIP: production loads data/gaul_lookup.parquet; tests inject synthetic). Restricted to the forecast gid set; a gid absent from the lookup FAILS LOUD (never a dropped row). Reuse unfao/gaul_schema.py column SSOT — do not restate column lists.
  • views_postprocessing/delivery/parity.py: assert_gid_set_parity(forecast_gids, sidecar_gids, *, label) + GidParityError — pandas-free primitives, names the symmetric difference. (Lands under the existing delivery/ no-pandas design-contract enforcement automatically.)

Acceptance criteria

  • Injected synthetic lookup equal to the fixture's rows → output byte-equals fixture_run_0__sidecar.parquet (pyarrow pin as in S3).
  • Property tests vs the real gaul_lookup.parquet: pinned schema incl. float64 codes, ascending priogrid_id, NaN row preserved, column order.
  • Parity raises with named gids on any asymmetry.

Tests: tests/test_wire_sidecar.py, tests/test_parity.py. Oracle: fixture sidecar.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    implementationCode implementation workstoryA single reviewable unit of an epic

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions