Inventory robustness: validation chokepoint + data:ship + pre-commit hook + marcel/player-finishing sources
The other agent shipped broken inventory state last session because the system relied on discipline ("run the tests before committing") instead of enforcement. This commit adds three layers that make broken state structurally
The other agent shipped broken inventory state last session because the system relied on discipline ("run the tests before committing") instead of enforcement. This commit adds three layers that make broken state structurally impossible.
- Generator validation chokepoint (scripts/generate-data-inventory.ts)
Runs BEFORE writing INVENTORY.json. Refuses on any of: - SOURCES path conflicts with IGNORED_DIRS (both lists had overlap) - SOURCES entries without a Done line in data/ROADMAP.md - ROADMAP Done entries for nonexistent sources (orphans) - fetch-*.{ts,mjs} scripts missing @data-source headers - Sources with 0 tracked files (warning by default; --strict makes it an error)
Anyone who runs npm run data:inventory gets all of these checks for free — no one has to remember to run vitest first. The chokepoint refuses to write.
Also: switched from git ls-files data/ to git ls-tree HEAD data/ for the tracked-file set, so regens are deterministic even when invoked from inside a pre-commit hook (git sets GIT_INDEX_FILE to an in-progress temp index, and consecutive regens can otherwise see different staged state).
- npm run data:ship (scripts/data-ship.sh)
Single canonical update path. Atomic pipeline: validate → 9 vitest tests → next build → stage right files → commit → push → verify CLAUDE.md now mandates this as the only correct way to update the inventory. Hand-editing INVENTORY.json or a bare git commit is banned.
- Pre-commit hook (sports-dashboard/.githooks/pre-commit)
Defense in depth. Wired via core.hooksPath = sports-dashboard/.githooks, auto-installed by package.json postinstall → scripts/install-githooks.mjs. Runs the validator + 9 tests on any commit touching inventory-related files. Does NOT re-stage INVENTORY files (doing so inside a commit creates phantom index entries at weird paths). Refuses the commit if validation or tests fail. Bypasses of data:ship still get caught at commit time.
Bonus work through the new system:
- Re-shipped marcel-projections and player-finishing as registered sources
with proper ROADMAP Done entries (the previous session's commit of these had 4 validator violations that the new chokepoint now refuses outright).
- Caught and fixed two IGNORED_DIRS conflicts in my own earlier code
(fbref-cache and derived were both registered AND in IGNORED_DIRS).
- Moved multi-source-xg to ROADMAP "Abandoned / replaced" — its notes say
REJECTED (variance filter A/B test) and it has 0 tracked files, so it shouldn't be a registered source at all.
19 sources tracked. 9/9 inventory CI tests pass. data:ship and the pre-commit hook were both verified green end-to-end in a fresh worktree from origin/main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>