Files
gamedev-the-steward/docs/local_quality_gate.md
T
2026-08-12 10:02:45 +02:00

7.0 KiB

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:

    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. 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:

export GODOT_BIN="/Applications/Godot.app/Contents/MacOS/Godot"
$env:GODOT_BIN = "C:\Tools\Godot\Godot_v4.7-stable_win64_console.exe"

Usage

Full project check

./tools/quality.sh
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.

./tools/quality.sh --changed
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\quality.ps1 -Changed

Auto-format (not part of the gate)

./tools/fix_format.sh
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:

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.