Skip to content

Fixture tooling for any SPINE tag: role-named cases and a manifest - #3

Merged
pgranger23 merged 1 commit into
mainfrom
fixtures/any-tag
Nov 5, 2026
Merged

pgranger23 merged 1 commit into
mainfrom
fixtures/any-tag

Conversation

@pgranger23

Copy link
Copy Markdown
Collaborator

Third step of following SPINE releases: the fixture tooling can write the golden test files with any SPINE tag, and records which commit wrote each one. This is what a later step needs to check a new SPINE tag automatically: write the files with that tag, compare, and commit nothing when nothing changed.

What changes

  • Two roles for the fixtures.

    • The current set is written by one tag, by default the model's (v1.4.0 today): current_v1, current_v2, current_v1_lite, current_v2_lite, current_v2_fixed_only, current_incomplete.
    • The frozen cases keep the old release that wrote them and are written only with --frozen: v2root (v0.16.3) and v0.11.1_v1 (v0.11.1).
    • The v1.4.0_* files and incomplete are renamed once (git mv). Their .h5 bytes do not change, and each .expected.json changes only its "case" value.
  • make_fixtures.py --tag vX.Y.Z [--sha SHA] [--schema PATH] writes the current set with that tag. The defaults are the committed schema and its tag. --schema is read for lite_dropped, which replaces the hard-coded lite list.

  • tools/fixtures/spine_checkout.py (new, no h5py or numpy) does two things:

    • It resolves a tag with git ls-remote, taking the peeled commit of an annotated tag.
    • It clones each commit once into <workdir>/spine_<sha> and checks HEAD, so a moved tag never reuses old code. Frozen cases are checked out at their recorded commits.
  • tests/data/fixtures/manifest.json (new) records each case's role, tag, commit, layout and file names, plus the run's warnings and substitutions. No test reads it.

    • It was created with --manifest-only, which records the existing files without rewriting them.
    • Later runs merge into it: the frozen entries of --manifest-base (default: the committed manifest, read only) are carried over, and the cases a run writes replace their own entries.
  • Checks.

    • The cross-checks use role names. A missing pair is a failure, except in a partial run (--only or --no-reader-check), which is marked partial in the manifest and on stdout.
    • The lite check now compares each class with the schema's lite_dropped, both ways.
    • New check: each file has the format_version and info@complete it was asked for.
    • Only the writing tag's own HDF5Reader is tried, except for v0.11.1_v1, which its own reader cannot read. A reader that fails counts as a check failure.
  • Enum values follow the writing tag, for the current set only.

    • spine_worker.py write --configure-enums passes the tag's ParticleShape, ParticlePID, NuCurrentType and NuInteractionScheme to the new content.configure().
    • A label the tag lacks is written as UNKNOWN and listed as a substitution. This is what makes v1.2.1 and v1.2.2 writable: they have no GIBUU, NUWRO or NEUT scheme.
    • A stored value that the file's enum does not name is a failure; a label no row stores is a warning.
    • Frozen cases keep the built-in values, so --frozen still reproduces v2root.
  • Exit codes:

    Code Meaning
    0 success, warnings allowed
    1 a check failed
    2 usage error
    3 a worker could not drive SPINE's API (spine_worker.py exits 3 for this)
    4 any other error

    Standard output is one JSON summary line. --artifacts-dir keeps the files a run would otherwise delete: the unshipped cases, the reader output and the worker logs.

  • Tests.

    • test_golden.cpp lists fixtures/*.expected.json instead of a fixed list, and skips cases whose writer.complete is false.
    • A new test case checks the current set's names.
    • test_reader.cpp and test_reader_locking.cpp use the role names.
  • Docs: tools/fixtures/README.md and the EGM.md contracts describe:

    • the roles;
    • the manifest and its merge rule;
    • the options, partial runs and exit codes;
    • the enum rule;
    • when the current set is rewritten.

    Facts measured at v1.4.0 stay literal, and say so.

Checked

  • Same files at v1.4.0. make_fixtures.py --frozen --out <scratch> regenerates all 10 cases with all 36 checks passing. All 8 .expected.json and the manifest come out byte-identical to the committed files. (The .h5 bytes carry timestamps.)

  • Other tags, into scratch directories:

    Run Exit Result
    --tag v1.2.2 0 the 3 scheme substitutions are listed; the frozen entries are kept in its manifest
    --tag v1.2.3 0 no substitutions
    --tag v0.11.1 3 "cannot write format_version 2"
    a schema with a wrong lite_dropped 1
    a tag that does not exist, an unreadable --spine-repo 4
    bad arguments 2
  • The C++ tests on another tag's files. With the v1.2.2 current set swapped in for the committed one, the golden tests pass (59,569 assertions), and so does the whole unit suite.

  • Builds.

    • EL9, LCG_110 (gcc 13, HDF5 1.14.6): every ctest entry passes, and spine_reader_real_files is skipped as designed.
    • ci/sl7-ups.sh (SL7, UPS gcc 12, HDF5 1.12.2): 134 test cases and 108,878 assertions pass.
  • Users of the old names. No CAFMaker branch refers to the renamed files.

The golden fixtures get two roles. The current set (current_v1, current_v2,
current_v1_lite, current_v2_lite, current_v2_fixed_only, current_incomplete)
is written by one SPINE tag, by default the model's; the frozen cases (v2root
by v0.16.3, v0.11.1_v1 by v0.11.1) keep their release and are written only
with --frozen. The v1.4.0_* files and incomplete are renamed once; their .h5
bytes do not change, and each .expected.json changes only its "case" value.

make_fixtures.py:
- --tag, --sha and --schema choose the writing tag, its commit and the schema
  read for lite_dropped (defaults: the committed schema and its tag).
- The new spine_checkout.py resolves a tag with git ls-remote (the peeled
  commit of an annotated tag) and clones each commit once into
  <workdir>/spine_<sha>, checking HEAD, so a moved tag never reuses old code.
  It imports neither h5py nor numpy.
- tests/data/fixtures/manifest.json records each case's role, tag, commit,
  layout and file names, and the run's warnings and substitutions. It was
  created with --manifest-only. Later runs merge: the frozen entries of
  --manifest-base (default the committed manifest) are carried over.
- The cross-checks key on role names; a missing pair is a failure, except in
  a partial run (--only, --no-reader-check), which the manifest and stdout
  mark. The lite check compares, per class, with the schema's lite_dropped,
  both ways. A new check: each file has the asked format_version and
  info@complete.
- SPINE's reader of the writing tag is the only one tried, except for
  v0.11.1_v1, whose own reader cannot read it. A reader that fails is a check
  failure.
- The current set is written with the writing tag's enum values
  (spine_worker.py write --configure-enums, content.configure()); a label the
  tag lacks becomes UNKNOWN and is listed as a substitution. A stored value
  the file's enum does not name is a failure; an unused label is a warning.
- --artifacts-dir keeps the unshipped files, the reader output and the
  worker logs. Standard output is one JSON summary line.
- Exit codes: 0 success, 1 a check failed, 2 usage, 3 a worker could not
  drive SPINE's API (spine_worker.py exits 3 for that), 4 any other error.

test_golden.cpp lists the *.expected.json files instead of a fixed list, and
skips a case whose writer.complete is false; a new test case checks the
current set's names. test_reader.cpp and test_reader_locking.cpp use the
role names. The README and EGM.md contracts describe the roles, the
manifest, the options, the enum rule and when the current set is rewritten.
@pgranger23
pgranger23 merged commit 7e1c003 into main Nov 5, 2026
4 checks passed
@pgranger23
pgranger23 deleted the fixtures/any-tag branch November 5, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant