#!/usr/bin/env python3 """Fail if client/project.godot's baked version has drifted from project.yaml. project.yaml is the version source of truth (CLAUDE.md). The client cannot read it at runtime — an exported build has no repo root — so the value is mirrored into `application/config/version` in client/project.godot, which Godot bakes into the PCK (T-1241). A mirror nobody checks is worse than the bug it replaced: the old code failed LOUDLY in an export ("?.?.?" everywhere, no cache invalidation ever), whereas a stale mirror fails SILENTLY — the Atlas disk cache would keep serving canvases under a version that stopped matching the build. That is precisely the T-1239 failure, which cost eight days of a map drawn from a canvas whose generating code no longer existed. Hence this check, wired into the pre-push hook. Exit: 0 = in sync, 1 = drifted or unreadable. """ import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent PROJECT_YAML = ROOT / "project.yaml" PROJECT_GODOT = ROOT / "client" / "project.godot" # Anchored to line start so the commentary above `version:` (which mentions # earlier versions by number) can never be mistaken for the field itself. YAML_VERSION = re.compile(r"^version:\s*(\S+)\s*$", re.MULTILINE) GODOT_VERSION = re.compile(r'^config/version\s*=\s*"([^"]*)"\s*$', re.MULTILINE) def read(path: Path, pattern: re.Pattern, label: str) -> str | None: if not path.exists(): print(f"check-client-version: {path} not found", file=sys.stderr) return None match = pattern.search(path.read_text(encoding="utf-8")) if not match: print(f"check-client-version: no {label} in {path}", file=sys.stderr) return None return match.group(1) def main() -> int: yaml_version = read(PROJECT_YAML, YAML_VERSION, "`version:` line") godot_version = read(PROJECT_GODOT, GODOT_VERSION, "`config/version=` line") if yaml_version is None or godot_version is None: return 1 if yaml_version != godot_version: print( "check-client-version: version drift\n" f" project.yaml {yaml_version}\n" f" client/project.godot {godot_version}\n" "\n" "project.yaml is the source of truth. Set config/version in\n" "client/project.godot's [application] section to match it.\n" "\n" "This matters beyond cosmetics: the Atlas disk cache keys its\n" "invalidation on this version, so a stale mirror makes a shipped\n" "build serve canvases generated by code it no longer runs (T-1239).", file=sys.stderr, ) return 1 print(f"check-client-version: OK — {yaml_version}") return 0 if __name__ == "__main__": sys.exit(main())