fix(client): bake the version into the build, so an export can invalidate its cache (T-1241)

current_schema_version() line-scanned res://../project.yaml at runtime. That
resolves to the repo root in a dev run and to nothing in an exported build, so a
shipped game got the "?.?.?" fallback every time. Since that tag is the Atlas
disk cache's ONLY invalidation signal, every exported build stamped and compared
the same sentinel: a canvas cached by one build would be served by every later
build, forever. T-1239 is what that failure looks like once it happens.

loading_screen.gd carried a byte-for-byte copy of the same function, so the
version shown to the player was "?.?.?" in exactly the builds where a version
string is worth showing. Both call sites now share client/scripts/build_version.gd,
which reads application/config/version out of ProjectSettings — a value Godot
bakes into the PCK, identical in the editor and in an export by construction
rather than by luck. No file IO, no fallback branch.

project.yaml stays the source of truth (CLAUDE.md); client/project.godot mirrors
it. A mirror nobody checks would be worse than the bug it replaces -- the old
code failed loudly everywhere, a stale mirror fails silently -- so
tooling/check-client-version compares the two and the pre-push hook runs it
unconditionally. Not gated on "were those files in this push": drift persists on
main once introduced, and gating would let an existing drift ride along.

The test this replaces asserted that current_schema_version() did not return its
fallback, and passed -- in the one environment where the code under test worked.
Three tests now pin the property that actually matters: a real version, sourced
from the baked setting, matching project.yaml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-14 23:35:33 +02:00
co-authored by Claude Opus 5
parent e8d522b482
commit 086d9ed56e
12 changed files with 241 additions and 36 deletions
+20
View File
@@ -253,6 +253,26 @@ to `MIGRATION_SQL` in `import_economics.py`.
See `.claude/rules/asset-pipeline.md` for the full rule set.
## Client version mirror
`project.yaml`'s `version:` is the source of truth, but the client cannot read that
file at runtime — an exported build has no repo root above `res://`. The value is
therefore mirrored into `client/project.godot` as `application/config/version`, which
Godot bakes into the exported PCK, and read through `client/scripts/build_version.gd`.
This is not cosmetic. The Atlas disk cache (D-255) keys its **only** invalidation
signal on that version, so a version the client cannot read means a cache that can
never be invalidated — see T-1241, and T-1239 for what a stale canvas cache actually
costs.
```bash
make check-client-version # exit 1 = the two files disagree
```
The pre-push hook runs this unconditionally (drift persists on `main` once
introduced, so gating it on "were those files touched in this push" would let an
existing drift ride along). **Bump both files together.**
## Pre-commit and Pre-push Hooks
Git hooks are stored in `.config/hooks/` (version-controlled). Activate them with: