# Local Quality Gate A single command to detect broken GDScript, formatting issues, lint problems, parser errors, and LLM-generated garbage before committing. ## Requirements - **Python 3** with the pinned `gdtoolkit` (gdscript-toolkit). The recommended setup uses `uv` and a project-local environment. These commands are the same in macOS shells and Windows PowerShell: ```bash uv venv .venv uv pip install -r requirements-dev.txt ``` - **Godot 4.7.x** binary on `PATH`, or set the `GODOT_BIN` environment variable. The gate rejects other engine series before importing or testing. - **GUT 9.7.1** is vendored under `addons/gut` for Godot 4.7. No separate package-manager install is needed. - **Terrain3D 1.0.2** is vendored with macOS and Windows x86-64 debug and release binaries. No separate native build is needed on either development platform. The vendored addon comes from the official [`bitwes/Gut` v9.7.1 release](https://github.com/bitwes/Gut/releases/tag/v9.7.1). The downloaded release archive SHA-256 is `14969aa46adc84aa08cdd21b9f6d1a64addd92ae60b36f02d0521ed305aa4086`. Terrain3D carries one intentional local Godot 4.7 compatibility patch in `addons/terrain_3d/src/double_slider.gd`: its editor display-scale lookups use the 4.7 `interface/editor/appearance/*` setting paths. Preserve or re-evaluate that patch when upgrading the vendored addon; without it, the first isolated import fails before a class cache exists. The quality and format scripts discover `.venv` automatically; activating it is optional. Missing `gdformat` or `gdlint` is a gate failure rather than a silent skip. ### Finding Godot The macOS gate checks project metadata, `godot`/`godot4` on `PATH`, and the standard `/Applications/Godot.app` location. The Windows gate checks project metadata, `PATH`, common Program Files and Local AppData locations, and a standard Scoop install. It prefers Godot's console executable when available. For a downloaded or custom install, set the executable explicitly: ```bash export GODOT_BIN="/Applications/Godot.app/Contents/MacOS/Godot" ``` ```powershell $env:GODOT_BIN = "C:\Tools\Godot\Godot_v4.7-stable_win64_console.exe" ``` ## Usage ### Full project check ```bash ./tools/quality.sh ``` ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 ``` ### Fast changed-files mode Only runs `gdformat` / `gdlint` on tracked changes and new untracked `.gd` files. The Godot dependency check and all project scenarios still run. ```bash ./tools/quality.sh --changed ``` ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 -Changed ``` ### Auto-format (not part of the gate) ```bash ./tools/fix_format.sh ``` ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\fix_format.ps1 ``` Both gates and both formatter entry points operate on the same game-owned roots: `player`, `simulation`, `tests`, `tools`, and `world`. Third-party addons and demos remain outside automatic formatting. ### Add-on policy Add an editor or runtime add-on only for a current gameplay or diagnostic consumer. Pin its exact release, retain its license and source provenance, and avoid auto-updates. Native add-ons must vendor macOS and Windows x86-64 debug and release payloads; add those paths to the `platform-assets` manifest in both quality scripts so either development platform detects an incomplete package. ## What it checks | Check | Tool | What it detects | |---|---|---| | **platform-assets** | File manifest | Missing Terrain3D macOS or Windows native payloads | | **godot-import** | Godot 4.7 headless importer | Missing or stale global `class_name` cache on fresh clones | | **gdformat** | Game-owned GDScript roots | Formatting without rewriting addons or demos | | **gdlint** | Game-owned GDScript roots | Lint violations such as unused arguments and naming | | **godot-check** | Headless definitions scenario | Parser errors and missing dependencies | | **scenarios** | Every `tests/*_test.gd` script | Simulation, persistence, navigation, and presentation regressions | | **gut** | Vendored GUT 9.7.1 CLI | Focused unit regressions under `tests/unit/` | ## Output If everything passes: ``` QUALITY RESULT: PASS Godot: 4.7.stable.official.5b4e0cb0f platform-assets PASS godot-import PASS gdformat PASS gdlint PASS godot-check PASS scenarios PASS gut PASS Full logs: logs/quality/latest/ ``` On failure, only relevant errors and fix suggestions are shown: ``` QUALITY RESULT: FAIL Godot: 4.7.stable.official.5b4e0cb0f platform-assets PASS godot-import PASS gdformat FAIL gdlint FAIL godot-check PASS scenarios PASS gut PASS res://simulation/SimNPC.gd:42 Unused argument 'delta' res://simulation/task_manager.gd:88 Line too long (120 > 100) NEXT FIX: 1. Fix unused-argument in SimNPC.gd 2. Run gdformat to auto-format files Full logs: logs/quality/latest/ ``` Full logs are always written to `logs/quality/latest/` and never dumped to the terminal. ## Environment variables | Variable | Description | |---|---| | `GODOT_BIN` | Path to the Godot 4.7.x executable (auto-detected if unset) | ## CI setup To add this to CI, provide a Godot 4.7.x executable, install the dependencies, and run: ```bash python -m pip install -r requirements-dev.txt ./tools/quality.sh ``` The script exits non-zero on any failure, including a wrong Godot series or missing pinned formatter/linter, so it will fail the CI step. Both gates isolate Godot's cross-platform user-data paths under `logs/quality/godot_profile`. Before running scenarios it imports project and GUT global classes whenever GDScript changes, so fresh, renamed, and deleted `class_name` scripts cannot leave the ignored cache stale. Godot/GUT script parse or load markers are failures because headless Godot can report those errors while returning a zero process exit code. Every Godot subprocess has a portable watchdog on stock macOS as well as Linux/Windows, and nonzero `gdformat`/`gdlint` exits fail the gate even when their output is not a familiar diagnostic string. Import receives a 60-second timeout on both shell and PowerShell; the focused checks retain their 30-second timeout. Scenario logs are also classified after successful process exits. Unexpected `ERROR:`, `SCRIPT ERROR:`, and `WARNING:` headers fail the gate and name their originating scenario. The only narrow platform/vendor exceptions are the isolated-profile macOS certificate-store condition, Terrain3D 1.0.2's Godot 4.7 interpolation deprecation, and the dummy renderer's exact one-`DummyShader` RID exit report. Different warning text, leak counts, or RID types remain failures; the full unfiltered output stays in `logs/quality/latest/scenarios.log`. The scenario stage also runs the presentation-quality contract once with `--rendering-method gl_compatibility`. This catches unsupported feature toggles and profile-selection regressions; because the gate is headless, it is not a substitute for a rendered OpenGL frame-time capture on representative hardware.