Skip to content

The ecCodes gate

The decoder’s acceptance gate is bit-for-bit agreement with ecCodes, ECMWF’s reference implementation. Not close, not within tolerance: identical.

Decoded GRIB values are integers scaled by powers of two and ten, so every value assertion is exact equality — an inexact double is a decoder bug, never a tolerance question. Two deliberate refinements the gate forced:

  • Scale factors use ecCodes’ iterated codes_power, not Math.pow — they differ by an ulp at decimal scale 6.
  • The recorded mean is recomputed with numpy’s pairwise summation, because a naive left-to-right sum differs in the last ulp over millions of doubles.

The golden corpus in test/fixtures/ is twenty real messages harvested from every live feed the forecast engine reads — GFS, HRRR, NAM, HRDPS (continental and West 1 km), RDPS, GDPS, REPS, GEPS, RAQDPS — each paired with an ecCodes-derived (2.48.0) expectation sidecar:

  • a sha256 of the decoded Float64Array (serialized as little-endian float64),
  • exact statistics (count, missing count, min, max, mean),
  • 200 evenly spread sampled values, plus known-missing indexes on bitmapped fields, and
  • ecCodes’ own nearest-gridpoint answer for every catalogued site.

A decoder that reproduces a sidecar is bit-for-bit compatible with ecCodes on that message. The corpus deliberately covers the awkward shapes: a two-submessage NCEP paired-wind message, a sparse bitmap (76 of 1,905,141 points masked), grid-relative ensemble wind for rotation validation, and the GEPS orography field whose values are decametres despite metadata claiming metres.

The fixtures README — grib/test/fixtures/README.md — tells the full story: provenance URLs, the harvest process, and why the corpus cannot be regenerated. In short: ECCC’s Datamart keeps roughly one day of files, so every ECCC source URL expired within ~24 h of harvest; the harvester lived in the retired Python pipeline and is gone; and the site coordinates in the sidecars are a frozen copy of the catalog as it stood at harvest (2026-08-11), part of the golden data rather than a live catalog. The committed bytes are the ground truth; the URLs are provenance, not a reproduction recipe.

One fixture sits deliberately beside the corpus rather than in it: rdps-cape-sfc-jasper, a JasPer-encoded RDPS field that a live smoke surfaced after the corpus froze. It answers to a different oracle (OpenJPEG.js, verified out-of-tree before that codec’s retirement), so the golden suite’s enumeration stays the twenty ecCodes messages and the suites that gate this fixture name it directly. Its role in the JPEG 2000 story is covered in the j2k subset page.

The golden suite lives in the package’s test/ directory alongside the module suites. The JPEG 2000 codec configurations sit behind the same gate — every codec and strategy combination must reproduce the golden answers, full-decode and sampled (test/j2k-configs.test.ts).