Problem
Nothing inspects a produced archive. tests/scripts/test_export_public_data.py covers the generation functions against constructed fixtures but does not read the file that gets published. The failure this needs to catch is not an exception but an archive that generates cleanly and is quietly wrong. Examples include: A filter that narrowed too far, a member that wrote zero bytes, a count that dropped 40% between releases.
Proposed behavior
A verification pass that takes an archive and the previous run's result record, and exits non-zero if the archive is unfit to publish.
Structural
- The archive opens and its central directory is intact.
main.json parses.
- Every score set named in
main.json has the members its metadata implies; every member present is named in main.json.
- No zero-byte members.
Parseable
- Every CSV parses and carries the expected header for its namespace set.
- Every NDJSON line is valid JSON.
- A sample of VA-Spec records validates against the schema.
Complete
- The score set count in the archive matches the published, CC0-licensed count from the database at the recorded
asOf.
Consistent with the last release
- Score set count, per-artifact-class row totals, and archive byte size are compared to the previous result record and fail outside a configured tolerance, with an override for a release that intentionally moves them.
Non-leaking
- No non-CC0 score set URN appears anywhere in the archive.
- No user fields beyond ORCID iD and name appear in any member.
Consumable
- Reading the archive back through a consumer-shaped path yields records for a sampled score set.
Output is a report with one row per check, successes included — a failures-only report cannot distinguish "nothing broke" from "nothing ran".
Acceptance criteria
- The verifier runs against an archive file and exits non-zero if any check fails.
- It completes in minutes rather than hours, and issues no per-variant corpus queries.
- An archive with a member truncated to zero bytes fails.
- An archive whose
main.json names a score set with no corresponding files fails, and so does the reverse.
- An archive containing a non-CC0 URN fails.
- An archive whose score set count differs from the previous release beyond tolerance fails, and passes when the override is supplied.
- The report lists every check attempted with its outcome.
- The verifier has its own unit tests, including a deliberately corrupted archive for each failure mode above.
Implementation notes
- The previous run's result record supplies the release-over-release baseline, so the registry doubles as release history.
- Tolerance needs a sensible default and a documented way to raise it for a release that legitimately changes corpus size.
- Leak checks should assert over archive contents rather than re-deriving the query filter, so a filter defect is caught rather than reproduced.
export_sweep keeps its role as a periodic pre-flight against the corpus. It is not this, and it is not the gate.
Problem
Nothing inspects a produced archive.
tests/scripts/test_export_public_data.pycovers the generation functions against constructed fixtures but does not read the file that gets published. The failure this needs to catch is not an exception but an archive that generates cleanly and is quietly wrong. Examples include: A filter that narrowed too far, a member that wrote zero bytes, a count that dropped 40% between releases.Proposed behavior
A verification pass that takes an archive and the previous run's result record, and exits non-zero if the archive is unfit to publish.
Structural
main.jsonparses.main.jsonhas the members its metadata implies; every member present is named inmain.json.Parseable
Complete
asOf.Consistent with the last release
Non-leaking
Consumable
Output is a report with one row per check, successes included — a failures-only report cannot distinguish "nothing broke" from "nothing ran".
Acceptance criteria
main.jsonnames a score set with no corresponding files fails, and so does the reverse.Implementation notes
export_sweepkeeps its role as a periodic pre-flight against the corpus. It is not this, and it is not the gate.