magicciv/tooling/claude/dot-claude/instructions/canonical-commands.md
Natalie 6216d97a76 feat(@projects/@magic-civilization): add async smoke test script
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-05 14:12:23 -04:00

4 KiB

Canonical Commands

Load when: running Rust tests, Godot tests, sims, or builds. These must run FROM the EDIT host and execute ON the RUN host via ssh — never run the raw cargo/flatpak/build-gdext.sh commands directly on the EDIT host.

For env var setup (AUTOPLAY_HOST, PROJECT_ROOT_REMOTE, etc.) see two-host-workflow.md.

Intent Canonical command (from EDIT host)
Rust workspace tests ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && cargo test --workspace"
GPU-feature tests ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && cargo test -p mc-turn --features gpu"
Single crate ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && cargo test -p <crate>"
GDExtension build ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && bash build-gdext.sh"
WASM build (web guide) ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && bash build-wasm.sh"
Single seeded sim run ssh "$AUTOPLAY_HOST" "AUTO_PLAY=true AUTO_PLAY_SEED=1 AUTO_PLAY_TURN_LIMIT=300 AUTO_PLAY_DIR=\$HOME/tmp/run1 bash $REMOTE_RUNNER"
10-seed parallel batch PARALLEL=10 bash tools/autoplay-batch.sh 10 300 .local/iter/<stamp> (reads $AUTOPLAY_HOST; p1-45: auto-rebuilds GDExt before launch when running locally — CARGO_TARGET_DIR isolated per run)
GUT unit tests ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/game && flatpak run --filesystem=home org.godotengine.Godot --path . --headless -s addons/gut/gut_cmdln.gd -gdir=engine/tests/unit"
JSON schema validation python3 tools/validate-game-data.py (pure Python, runs on EDIT host)
Lint gdlint src/game/engine/src/ (runs on EDIT host, no toolchain needed)

Pair with ./run wrappers when available — see task-runner.md.

First-run on a fresh apricot scratch dir

Godot needs src/game/.godot/global_script_class_cache.cfg and src/game/.godot/extension_list.cfg to register class_name-declared GDScript classes (e.g. AiTurnBridge) and gdextension libraries (e.g. GdGridState, GdCity). These files are NOT committed and are NOT created by rsync; they're built by Godot on first project import.

If a fresh scratch dir on apricot (~/.cache/mc-src-<stamp>/) shows SCRIPT ERROR: Identifier "GdGridState" not declared in the current scope or Could not find type "AiTurnBridge", run a one-time import to build the cache:

ssh apricot 'cd ~/.cache/mc-src-<stamp> && timeout 60 flatpak run --user --filesystem=home org.godotengine.Godot --path src/game --headless --import 2>&1 | tail -5'

Subsequent runs (autoplay, GUT, batches) will then load extensions and class_name registrations correctly.

Async batch protocol on apricot (p2-64)

When apricot connectivity is intermittent (sleep/wake, sshd channel saturation, network blips), use the launch / status / fetch loop instead of the synchronous scripts/apricot-run.sh smoke … flow. The systemd --user unit on apricot owns the build+batch lifecycle and survives ssh disconnects. Status probes use a single short-timeout ssh and never read file contents — only is-active / ls | wc -l style checks.

STAMP=$(scripts/apricot-run.sh launch smoke 10 300)        # bare stdout = stamp
while STATE=$(scripts/apricot-run.sh status "$STAMP" | jq -r .state); \
      [[ $STATE != complete ]]; do
    [[ $STATE == failed ]] && { echo "batch failed; journalctl --user -u mc-batch-$STAMP" >&2; exit 1; }
    [[ $STATE == unreachable ]] && sleep 30 && continue
    sleep 60
done
LOCAL=$(scripts/apricot-run.sh fetch "$STAMP")              # rsync to .local/iter/<stamp>/

States: running (unit active), complete (completion.marker present), failed (unit inactive + no marker), unreachable (ssh probe timeout — retryable, no work lost).

Submodes currently wired into the launcher: smoke, clan, difficulty. Other modes (gpu-walltime, matchup-grid, huge-map-5clan, ai-quality-baseline*) still run via the synchronous flow and can be added to the launcher case-branch as needed.