"Repo-wide version consistency - every version-bearing file moves with VERSION, enforced at bump, gate, and hook"
TASK-IMP-072: Repo-wide version consistency
§1 - Description
- The stamper's coverage MUST be total: tauri.conf.json, src-tauri/Cargo.toml (about-dialog/crate metadata), apps/web/package.json, Android versionName+versionCode, iOS MARKETING_VERSION+CURRENT_PROJECT_VERSION, and the repo mcp/package.json (build.sh's payload stamp becomes a no-op).
- version.yml's bump commit MUST run
stamp --applyand commit every stamped file - a release commit carries the entire codebase to the new version, never just VERSION+CHANGELOG. - payload-gate MUST run
stamp --check --exit-codeso any manual drift is a red build. - The pre-commit hook MUST refuse a staged VERSION change whose artifacts drift, printing the exact one-line fix (
stamp --apply && git add -u). - Store-side invariants MUST hold: versionCode/CURRENT_PROJECT_VERSION derive from the monotonic BUILD_NUMBER (never VERSION), and the Play high-water guard (>10700) stays.
§2 - Why this design
Stamp-at-build kept binaries honest but let the repo lie between releases - a 1.0.0 that greps as 0.1.0 in five files is not "1.0.0 across the whole codebase". Three enforcement points (bump, gate, hook) close every path a stale stamp could survive.
§3 - Contract
node scripts/stamp-release-version.mjs [--apply|--check --exit-code]; exit 10 on drift in check mode. Bump commit file set fixed in version.yml.
§4 - Acceptance criteria
- Coverage total (§1 #1) -
--checkat a fresh VERSION lists exactly the seven files; Cargo + mcp included. - Bump carries all (§1 #2) - version.yml's git add names every stamped file after the apply step.
- Gate red on drift (§1 #3) - the payload-gate step exists; drift exits 10.
- Hook refuses drifting VERSION commits (§1 #4) - staged VERSION + drift = commit rejected with the fix line.
- Monotonic store counters (§1 #5) - versionCode==CURRENT_PROJECT_VERSION==BUILD_NUMBER; high-water guard intact.
§5 - Verification
Live: --check output (7-file drift list at 0.4.0), hook rejection then acceptance around the 1.0.0 commit, gate step grep, version.yml git-add grep. Store counters asserted by the stamper's own output line.
§6 - Implementation skeleton
stampCargo helper + two stampJson targets; three wiring blocks.
§7 - Dependencies
Rides TASK-IMP-071 (bump commits now visible to CI, so the gate actually runs on them).
§8 - Example payloads
VERSION=1.0.0 BUILD_NUMBER=10706 (androidVersionCode + iosBuildNumber) + all release artifacts already match VERSION.
§9 - Open questions
None blocking. apps/console carries no version field (nothing to stamp); services' Cargo.tomls version internal crates, deliberately out of scope (they are not store artifacts).
§10 - Failure modes inventory
- New version-bearing file added later - the gate misses it until listed; the stamper header documents "add here + version.yml git add".
- BUILD_NUMBER reused after a failed upload - Play/ASC reject; bump BUILD_NUMBER, never reuse.
- Hook bypassed with --no-verify - payload-gate catches on push.
- Stamp regex misses a reformatted pbxproj - check mode reports non-match as drift, loudly.
- mcp double-stamp (repo + build.sh) - idempotent by construction.
§11 - Implementation notes
The 1.0.0 release commit itself is the first full-codebase stamp (operator-prepared, hook-verified).
End of TASK-IMP-072.
Audit
TASK-IMP-072 audit
§1 - Verdict summary
Audited for enforcement completeness (bump/gate/hook cover CI-write, CI-read, and operator-write paths) and store-counter safety (BUILD_NUMBER monotonicity + high-water guard untouched). TRACE: #1->AC1, #2->AC2, #3->AC3, #4->AC4, #5->AC5; §5 evidence live in the 1.0.0 leg.
§2 - Findings (resolved during authoring)
ISS-001 hook auto-staging stamped files would mutate commits invisibly - resolved: refuse-with-fix-line instead (§1 #4). ISS-002 services' internal Cargo versions dragged along would churn 20+ crates meaninglessly - resolved: store artifacts only, documented (§9).
§3 - Resolution
Score = 10/10.
Ship record (2026-07-12, batch mode)
Implemented + wired in one leg under the operator's standing verdict; live proof = the 1.0.0 commit.