Skip to content

Latest commit

 

History

History
109 lines (93 loc) · 5.79 KB

File metadata and controls

109 lines (93 loc) · 5.79 KB

Backward-compatibility reference data

This directory holds the on-disk compatibility contract of the SHiP data model. Two independent safety nets are exercised by ctest (part of pixi run test and CI):

  1. Compat read tests (compat_read_<version>): every reference file must be readable with the current library, materialized into the current structs, with all values matching the canonical recipe. Members that did not exist in the writing version must read back default-initialized (ROOT RNTuple automatic schema evolution).
  2. Schema snapshot (schema_snapshot): schema_snapshot.txt is a text dump of the persistent schema (TClass layout of every dictionary class + the RNTuple field tree). CI fails on any schema change — even a backward-compatible one — until the snapshot is deliberately regenerated in the same PR, so every schema change is a conscious, reviewable decision.

Files

  • reference_v<X.Y.Z>.root — frozen forever, never modified or regenerated. Written at release time by scripts/release.sh from exactly the tagged code with the ROOT version pinned in pixi.lock at that moment, so it captures both the schema and the writing ROOT. Exception: the files for v0.1.0–v0.4.0 predate this suite and were backfilled with scripts/backfill_reference_files.sh — they were written by each tag's headers (defining the on-disk schema) but by ROOT 6.40.02, not the historical ROOT versions.
  • reference_head.root — tracks main; asserts "current code reads the current schema". Regenerated in the same PR as any event-model change.
  • reco_fixture_v0.5.0.root — frozen like the release files, see Reconstruction fixture.
  • schema_snapshot.txt — committed schema dump, see above.

Each reference file is an RNTuple named events with 2 entries and top-level fields event_header (v0.4.0+), mcParticles, simHits, simParticles, recParticles, simResult.

Reconstruction fixture

The reference files don't contain TrackFitResult or any detector wrapper, so nothing in them reads those classes back. reco_fixture_v0.5.0.root covers them for the v0.5.0 layout. It holds two RNTuples with 2 entries each: trackfits, with a trackFitResults field, and wrappers, with a ubtHits field (UBTHit stands in for all five wrappers, which share one shape). tests/write_reco_fixture.cpp wrote it against the v0.5.0 headers through scripts/backfill_reference_files.sh. It is frozen like the reference files. compat_read_reco_trackfits_v0.5.0 and compat_read_reco_wrappers_v0.5.0 read one RNTuple each, so a failure in one class cannot hide the result for the other.

Since v0.5.0 every persistent class carries an explicit version, declared in include/SHiP/LinkDef.h as options=version(N) (required for RNTuple I/O customization rules, root-project/root#23146) — bump it together with any layout change; the schema_snapshot test records versions, so forgetting is visible in the diff. Numbering starts at 2, because rootcling already emits 1 for classes without ClassDef and TClass reports that back as -1. Files from v0.1.0–v0.4.0 were written by unversioned classes.

When a compat test fails in your PR

  • schema_snapshot fails, compat_read_* pass: you changed the persistent schema in a backward-compatible way (e.g. added a member). If intentional, run and commit in the same PR:

    pixi run update-schema-snapshot
    pixi run update-reference-head

    This is at least a minor version bump.

  • compat_read_v* fails: your change breaks reading of existing files (e.g. renaming a member silently drops its on-disk values — RNTuple matches members by name). Either make the change compatible (e.g. an I/O customization rule mapping the old name), or accept it as a breaking change: mark the commit !/BREAKING CHANGE (major version bump) and adjust the expectations in tests/test_read_reference.cpp (masking table) — never by editing the frozen files.

  • compat_read_head fails but frozen versions pass: the current schema and reference_head.root are out of sync — run pixi run update-reference-head (plus the snapshot) in this PR.

Value recipe

Expected values are defined in tests/reference_values.hpp and are part of the contract (a future non-C++ reader can check against the same formulas). For members that existed at v0.1.0 they equal the SHiP::test::make* generators in tests/test_utils.hpp; members added later have their own formulas there (e.g. SimHit::geometryNodeId = 900 + 7*i + offset, MCParticle::mothers = {} for i == 0 and {i - 1, (i + 1) % 3} otherwise — its entries are indices into this same 3-element collection, so unlike the other members they carry no offset; the recipe encodes the documented invariant, namely that mothers[0] equals motherId and that an entry without a mother has an empty list rather than a -1 in it — RecParticle::hits filled from makeSimHits(offset + 2)). Per entry e (0-based): field offsets are e for the top-level collections and e + 5 inside simResult; each collection has 3 elements. A reference file written by version V contains values for exactly the members existing in V; newer members read back default-initialized and are masked accordingly in test_read_reference.cpp.

The mother-index invariants the MCParticle recipe encodes are machine-checked rather than merely asserted here: SHiP::mothersAreConsistent (declared beside the struct in include/SHiP/MCParticle.hpp) is exercised against both recipes by the mc_mothers test and against every file this suite reads, so a future recipe change cannot quietly contradict them.