Add tracked AI skills for Blender assets and release QA
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped

This commit is contained in:
zwitschi committed 2026-11-03 19:53:32 +01:00
1 parent e4e1566e55
commit 724e8b183f
13 files changed
+1124 -25

No files matched your search

View File
Whitespace-only changes.
@@ -0,0 +1,210 @@
---
name: gig-line-blender-asset-contract
description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the 13-bone npc_base contract, five tint slots, triangle/vertex budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing.
compatibility: Gig Line repository checkout. Godot 4.7.2 on PATH; Blender 5.2 LTS via the org.blender.Blender flatpak for build/bake/render. Audit, fit, inspect and proportion checks are stdlib-only.
metadata:
project: Gig Line
domain: 3d-assets
version: "1.0.0"
triggers: Blender, NPC, character, gear, prop, npc_base, GLB, AO, texel, asset rebuild, fit, audit
---
# Gig Line Blender Asset Contract
Use this skill for any change that touches:
- `assets/models/blender/**`
- `assets/models/generated/npc_base.glb`
- `assets/textures/npc/**`
- `tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/bake_ao.py`,
`tools/npc_proportions.py` or `tools/npc_baseline.py`
- Blender-authored venue/prop geometry
The project contract and measured gates override any generic Blender advice.
There is **no Blender MCP** in this project. Blender runs headless through the
flatpak CLI; the `blender-skills` pack is optional, local guidance only, and
gitignored.
## Read first
From the repository root, read the relevant sources rather than relying on this
skill alone:
1. `AGENTS.md` — required workflow and verification.
2. `TODO.md` and `MEMORY.md` — current track, claimed tasks, known gotchas.
3. `docs/blender-assets.md` — library contract and command reference.
4. `docs/asset-tooling.md` — exact rebuild/bake/capture commands.
5. `docs/npc-visual-review.md` and `docs/3d-model-review.md` — accepted limits,
scorecards and known blockers.
6. `docs/known-limitations.md` — limits that must not be silently “fixed” into
contract changes.
The contract lives in code and docs, not in this skill. If they disagree, stop
and resolve the source of truth before editing assets.
## Non-negotiable contract
| Area | Rule |
| --- | --- |
| Mesh root | `npc_base` mesh node, skinned under `Rig`; preserve the limb node names. |
| Bones | 13 contract bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck` (parent/helper bones must not change the contract). |
| Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`. |
| Orientation | Front is Blender −Y / Godot +Z; feet grounded near y = 0; metres. |
| Library budget | **8,000 triangles / 8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). |
| Frozen fallback | `npc_base` keeps **6,000 tris / 4,000 verts**. Do not silently raise or lower it. |
| Gear budget | **1,500 triangles** per gear piece; authored in attach-point space. |
| Prop budget | **4,000 triangles** per prop. |
| Gear attach | Use the catalogued attach points; verify with `fit`. Runtime `GEAR_OFFSETS` (lanyard forward, firefighter helmet up) and `HAND_ITEM_FORWARD` are intentional, not asset-contract changes. |
| Textures | 256² albedo/normal/ORM maps. Cloth and pants use `NPC_FABRIC_UV_SCALE = (4,4,1)` and **skip** baked per-character AO; skin/hair/gear keep baked AO. |
| CI | Offline and skill-free. Committed GLBs/AO/maps must make CI pass without Blender or MCP. |
| Licensing | No new asset source without ADR-0015: CC0, or CC-BY with attribution in `CREDITS.md`; record provenance. |
Do not change the renderer, engine baseline, runtime dependency graph or the
`npc_base` contract as part of an asset pass.
## Workflow
### 1. Preflight and claim
```bash
git status --short
git log --oneline -5
godot --version
flatpak run org.blender.Blender --version | head -3
```
Inspect the current asset and the relevant docs. Claim the TODO item with `[-]`
before starting. Work on one asset family per commit.
### 2. Establish a baseline
Run the checks that do not need Blender first:
```bash
python3 tools/blender_assets.py audit
python3 tools/blender_assets.py fit
python3 tools/blender_assets.py texels
python3 tools/npc_proportions.py report
python3 tools/npc_pipeline.py audit
```
For a specific incoming or existing GLB:
```bash
flatpak run org.blender.Blender --background \
--python "$PWD/tools/blender_assets.py" -- \
inspect --file "$PWD/path/to/asset.glb" --category npc_gear --json
```
Record the before measurements (tris/verts, head/shoulder/hip/leg/arm/foot,
fabric texel density, gear clearance). Do not “improve” an asset without a
measurable target.
### 3. Optional Blender-skill routing
If the local `blender-skills` pack is installed, load `blender-director`, then
only the specialists the task needs:
- character mesh/face/hands: `character-artist`, `retopology`
- rig/weights/pose: `rigging`
- UVs/texel density: `uv-workflow`
- maps/materials: `texture-workflow`, `materials`, `lookdev`
- gear/props: `prop-artist`, `hard-surface`
- budget/LOD/collision: `asset-optimization`, `lod-pipeline`, `collision-proxy`
- final review: `qa-review`
Translate any MCP instruction into a change to `tools/*.py` or a headless CLI
run. Never add an MCP dependency to the build, CI or runtime.
### 4. Build or bake
Characters, gear and library props:
```bash
flatpak run org.blender.Blender --background \
--python "$PWD/tools/blender_assets.py" -- build --only <name>
flatpak run org.blender.Blender --background \
--python "$PWD/tools/bake_ao.py" -- --only <name>
```
NPC base and its material maps:
```bash
python3 tools/npc_pipeline.py prepare # only when fabric tiles change
flatpak run org.blender.Blender --background \
--python "$PWD/tools/npc_pipeline.py" -- build
python3 tools/npc_pipeline.py audit
```
Do not overwrite a review image or a promoted texture pick. Use a new `-vN`
path and document the promotion.
### 5. Import and capture
```bash
godot --headless --path . --import
godot --headless --path . --script res://src/test/test_runner.gd
# neutral baseline: 8 variants x 6 views, raw frames stay in tmp/
godot --path . --script res://src/test/capture_npc_baseline.gd \
-- --out=res://tmp/npc-baseline
# final-context: 96 frames across both venues and day/night
godot --path . --script res://src/test/capture_npc_review.gd \
-- --out=res://tmp/npc-review
```
Compare before/after with `tools/npc_baseline.py compare`; do not replace the
committed baseline sheet until a fix actually lands. See
`references/verification.md` for the full gate matrix.
### 6. Verify and hand off
At minimum:
- `blender_assets.py audit` and `fit` exit 0.
- `npc_proportions.py` passes the stylized guide.
- `npc_pipeline.py audit` passes if the base/textures changed.
- texel density is inside the authored/fabric bands.
- No character exceeds 8,000/8,000; gear/prop caps hold.
- 24-NPC budget and Web/Compatibility path remain green.
- Contract tests, headless suite, capture gates and docs check pass.
- The diff contains only the intended assets, tools, tests and docs.
State in the handoff: files changed, measurements before/after, skills used,
gates run, and any accepted limit.
## Failure playbook
- **`Class "..." hides a global script class`** — a stray `.gd` backup is in the
project. Delete `tmp/*.gd` backups, `rm -rf .godot`, re-import; never keep
`class_name` copies in `tmp/`.
- **Blender cannot see the path** — the flatpak cwd is `/app/blender`; use
absolute paths (`"$PWD/..."`).
- **Empty or stale captures** — close modals/pause, check the capture script's
settle frames, and remove stale output directories before re-running.
- **Pose harness mismatch** — the current `capture_npc_pose.gd` is blocked per
`docs/3d-model-review.md`; do not use its frames as pose evidence until the
recipe is fixed.
- **Asset test fails after import** — re-run audit/fit first, then import; if the
manifest or AO path changed, rebuild the affected asset rather than editing
the manifest by hand.
- **Uncertain about a visual change** — produce a labelled before/after sheet and
ask for review; do not hide a regression behind a budget claim.
## Bundled references
- [`references/asset-contract.md`](references/asset-contract.md) — full contract,
inventory, file locations and provenance rules.
- [`references/verification.md`](references/verification.md) — command matrix,
capture gates, expected results and acceptance criteria.
## Do not
- Add an MCP server, Blender dependency or API call to the build/runtime.
- Change the bone/tint/contract to make a generic asset fit.
- Rewrite committed baselines or overwrite existing images.
- Commit `.blend` sources, raw captures or generated AI inputs.
- Treat an asset audit as a substitute for visual review at portrait and crowd
distance.
@@ -0,0 +1,139 @@
# Asset Contract Reference
This is a working summary. The authoritative sources remain
`docs/blender-assets.md`, `docs/asset-tooling.md`, ADR-0013, the tests in
`src/test/tests/` and the constants in `tools/blender_assets.py` /
`tools/npc_pipeline.py`.
## Library inventory
- **Character variants (8):** `npc_casual`, `npc_jacket`, `npc_coat`,
`npc_vest`, `npc_dress`, `npc_hoodie`, `npc_firefighter`, `npc_guard`.
- **Frozen fallback:** `npc_base` / `assets/models/generated/npc_base.glb`.
- **Gear:** 18 attach-space pieces covering head, back, chest and hand items.
- **Library props:** 20 Blender-authored props plus 6 generated props.
- **Venues:** procedural venues in `src/game/world_builder.gd`; Blender venue
geometry follows the same budgets and collision/provenance rules.
## Skeleton and geometry
The contract skeleton has 13 bones:
```text
Head, Spine, Neck,
HipL, HipR,
KneeL, KneeR,
ShoulderL, ShoulderR,
ElbowL, ElbowR,
HandL, HandR
```
Requirements:
- `npc_base` mesh node exists and is skinned under `Rig`.
- Limb node names stay stable for `NpcAvatar` and tests.
- Front is Blender −Y / Godot +Z.
- Feet are grounded at approximately y = 0; no floating origin.
- Units are metres; character height is approximately 1.8 m.
- No zero-area/duplicate degenerate faces in the exported mesh.
- Every character has UVs in [0,1] unless a planned UDIM/atlas change is
explicitly accepted.
## Material slots
Exactly these five tint slots:
```text
skin, cloth, pants, accessory, hair
```
- Neutral albedo is authored in Blender; runtime tinting is authoritative.
- Slot names are contract values; do not rename or add a sixth slot casually.
- The procedural fallback (`NpcAvatar._build_body`) must keep working when the
GLB is missing.
## Budgets
| Asset | Limit |
| --- | --- |
| Library character | 8,000 triangles / 8,000 glTF vertices |
| `npc_base` fallback | 6,000 triangles / 4,000 vertices |
| Gear piece | 1,500 triangles |
| Prop | 4,000 triangles |
| Library prop/venue total | must stay inside the venue tests and library budget |
`CHAR_MAX_TRIS`, `CHAR_MAX_VERTS`, `GEAR_MAX_TRIS`, `PROP_MAX_TRIS` and related
constants live in `tools/blender_assets.py`. The budget is per character, not an
average. Measure after every mesh change. Do not lower the cap to make a diff
pass.
## Gear and hand items
- Gear is authored in the attach-point space documented by `GEAR` /
`GEAR_ATTACH` / `ATTACH_BLENDER`.
- `blender_assets.py fit` measures gear boxes against the character's head band,
clothing radius and back clearance.
- Runtime offsets are intentional:
- `NpcAvatar.GEAR_OFFSETS = {"lanyard": Vector3(0,0,0.04),
"firefighter_helmet": Vector3(0,0.03,0)}`
- `NpcAvatar.HAND_ITEM_FORWARD = Vector3(0,0,0.04)`
- An offset is **not** an authored-asset change; do not bake it into the GLB
without a separate contract decision.
- Open-palm grip (no finger-curl rig) is the accepted stylized limit.
## Textures and AO
- NPC maps are 256² albedo + normal + packed ORM.
- `TEX_SIZE = 256` in `tools/npc_pipeline.py`.
- Fabric UV scale is `Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`.
- Cloth/pants skip the per-character baked AO; skin/hair/gear keep it. This
avoids the large blotchy magnification that appeared at 256².
- Gear/props may have their own AO maps; `tools/bake_ao.py` writes
`<name>_ao.png` next to the GLB and Godot wires it into the AO channel.
- Never overwrite an existing committed image; use a new `-vN` candidate and
promote only after review.
- Run `python3 tools/asset_pipeline.py audit <path>` and the relevant
`npc_pipeline.py audit` before committing map changes.
## File map
| Path | Role |
| --- | --- |
| `tools/blender_assets.py` | Catalogue, builders, audit/fit/inspect/texels/sheet. |
| `tools/npc_pipeline.py` | `npc_base` builder, texture preparation and audit. |
| `tools/bake_ao.py` | Blender AO bake into `<name>_ao.png`. |
| `tools/npc_proportions.py` | Exported-GLB proportion audit (no Blender). |
| `tools/npc_baseline.py` | Contact sheets/comparisons (no Blender). |
| `assets/models/blender/manifest.json` | Generated asset manifest. |
| `assets/models/blender/**/*.glb` | Committed library assets. |
| `assets/models/generated/npc_base.glb` | Frozen NPC fallback. |
| `assets/textures/npc/*_{albedo,normal,orm}.png` | Committed NPC maps. |
| `src/test/capture_npc_baseline.gd` | 48-frame neutral baseline. |
| `src/test/capture_npc_review.gd` | 96-frame final-context review. |
## Provenance and source rules
- Procedural Blender assets are project-owned.
- External/CC assets need ADR-0015 clearance: CC0 preferred, CC-BY only with
attribution in `CREDITS.md`; no service assets with redistribution limits.
- Editable `.blend` files under `assets/models/blender_src/` are gitignored;
only exported `.glb`, AO maps, manifests and committed preview sheets ship.
- AI-generated source images are development inputs, not shipped assets. Keep
raw generations under gitignored paths until picked, checked and credited.
- Do not copy a downloaded/Street View/AI reference into a committed asset
without the licence and provenance review.
## Verification invariants
The asset pass is not complete unless:
1. `python3 tools/blender_assets.py audit` exits 0.
2. `python3 tools/blender_assets.py fit` exits 0 and the report is reviewed.
3. `python3 tools/npc_proportions.py report` passes the stylized guide.
4. `python3 tools/npc_pipeline.py audit` passes when the base/textures changed.
5. The 48-frame baseline and 96-frame final-context review are captured, with no
blank frames.
6. The 24-NPC budget smoke is inside its frame budget.
7. The full Godot suite and Python tooling tests pass.
8. No runtime contract, renderer or dependency changed except the rebuilt
assets and their generated metadata.
@@ -0,0 +1,123 @@
# Verification Matrix
Run from the repository root. Stop and fix the first failure before continuing.
## Environment
```bash
godot --version
flatpak run org.blender.Blender --version | head -3
git status --short
```
Expected: Godot 4.7.2; Blender 5.2 LTS flatpak; clean or intentionally scoped
working tree. Blender's flatpak cwd is `/app/blender`; all paths passed to
Blender must be absolute.
## Asset checks
| Check | Command | Expected |
| --- | --- | --- |
| Contract audit | `python3 tools/blender_assets.py audit` | exit 0, no `BAD` assets |
| Gear fit | `python3 tools/blender_assets.py fit` | exit 0; review head band/clothing/back clearances |
| Texture/texel density | `python3 tools/blender_assets.py texels` | authored 40–400 px/m; fabric ≥250 px/m |
| NPC base | `python3 tools/npc_pipeline.py audit` | exit 0, contract bones/slots/maps |
| Proportions | `python3 tools/npc_proportions.py report` | all eight inside the stylized guide |
| Single incoming GLB | `flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets.py" -- inspect --file "$PWD/path.glb" --category <cat> --json` | contract result and measurements |
| Prop audit | `python3 tools/model_pipeline.py audit` | exit 0 when generated props changed |
| Texture audit | `python3 tools/asset_pipeline.py audit assets/textures/ai/game_ready` | exit 0 when textures changed |
## Build/bake
```bash
# one library asset
flatpak run org.blender.Blender --background \
--python "$PWD/tools/blender_assets.py" -- build --only npc_guard
# bake AO for the same asset
flatpak run org.blender.Blender --background \
--python "$PWD/tools/bake_ao.py" -- --only npc_guard
# NPC base material maps/base
python3 tools/npc_pipeline.py prepare
flatpak run org.blender.Blender --background \
--python "$PWD/tools/npc_pipeline.py" -- build
python3 tools/npc_pipeline.py audit
```
Only run `prepare` when AI fabric inputs changed. Do not run a full library
rebuild just to hide a small diff; build the affected asset and its AO map.
## Import and tests
```bash
godot --headless --path . --import
godot --headless --path . --script res://src/test/test_runner.gd
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
python3 tools/check_docs.py
```
Expected: Godot suite passes; Python tooling suite passes; docs check OK. The
project uses its own headless runner, not GUT.
## Capture gates
```bash
# neutral studio baseline: 48 frames (8 characters x 6 views)
godot --path . --script res://src/test/capture_npc_baseline.gd \
-- --out=res://tmp/npc-baseline-after
# final-context: 96 frames (8 models x 3 distances x 2 venues x day/night)
godot --path . --script res://src/test/capture_npc_review.gd \
-- --out=res://tmp/npc-review-after
# optional hand close-up: 8 frames
godot --path . --script res://src/test/capture_npc_baseline.gd \
-- --out=res://tmp/npc-hands --view=hand
```
Raw frames stay under `tmp/` and are never committed. Compare with:
```bash
python3 tools/npc_baseline.py compare \
--before tmp/npc-baseline --after tmp/npc-baseline-after \
--out docs/blender_previews/sheet_npc_baseline_compare-<topic>.jpg
```
Do not replace the committed baseline sheet until the change is accepted.
## Budget/performance
```bash
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
```
Expected report: 24 avatars / 168 meshes / 131,616 triangles (current baseline)
inside the 50 ms budget. Record the actual frame time; do not copy an old number
without measuring.
## Visual review criteria
For each changed variant, inspect at least:
- 2 m portrait: eyes, mouth, ears, neck/shoulder, hair/headgear clearance.
- 4.2 m conversation: hands, gear contact, clothing silhouette.
- 8 m crowd: readable silhouette and LOD/impostor swap.
- Day and night/LATE final-context frames.
- Front, three-quarter and profile for a shape change.
Accepted stylized limits are in `docs/npc-visual-review.md` and
`docs/known-limitations.md`. Do not turn an accepted limit into an unreviewed
contract change.
## Final diff review
```bash
git diff --check
git status --short
git diff --stat
```
Check that only intended `.glb`, AO/maps, manifest, tests and docs changed. If a
`.blend`, raw capture, generated AI input or temporary sheet is staged, stop and
remove it. Commit one coherent asset family per commit.
+254
View File
@@ -0,0 +1,254 @@
---
name: gig-line-release-qa
description: Use when preparing, validating, tagging or publishing a Gig Line release or release candidate, or when running the full screenshot, screen-design and realism QA gates. Covers version/changelog discipline, smoke and tooling matrices, clean-worktree builds, checksums, Web/HQ verification, publish rollback and post-release records. Do not use for ordinary asset edits or feature work.
compatibility: Gig Line repository checkout with Godot 4.7.2 on PATH and Python 3 + Pillow. Release export needs installed Godot export templates; publishing needs Gitea credentials and is intentionally CI/tag-driven.
metadata:
project: Gig Line
domain: release-qa
version: "1.0.0"
triggers: release, tag, version bump, changelog, build releases, publish, screenshots, screen design, realism judge, release candidate, deployment
---
# Gig Line Release and Visual QA
Use this skill for version bumps, release candidates, tags, artifact builds,
publishing, and the full visual/QA gate. For a Blender/asset rebuild, use
`gig-line-blender-asset-contract` first.
## Read first
1. `AGENTS.md` — release procedure and verification rules.
2. `TODO.md` — current milestone, blockers and release exit criteria.
3. `docs/RELEASING.md` — build/publish commands, artifact list, macOS policy.
4. `docs/smoke-checklist.md` — manual QA matrix.
5. `docs/development-status.md`, `CHANGELOG.md`, `README.md` — current claims.
6. `MEMORY.md` — release gotchas, especially the clean-worktree rule.
A release is not just a tag. It includes a version bump, changelog, clean build,
artifact/checksum verification, CI publication, and post-release records.
## Hard rules
- **Do not tag while the TODO still lists unresolved release blockers.** Check
external playtest, legal/AI provenance, signing and target-hardware items.
- **Never reuse a tag.** If a published version needs a fix, bump the patch and
create a new tag.
- **Build from a clean checkout or detached worktree.** A normal working tree can
pack ignored `tmp/` and `build/` content into exports, inflating a ~160 MB
package to 1.6–3.1 GB.
- A tag push triggers CI checks/build/publish. Do not upload manually unless CI is
unavailable and you have followed the same preflight.
- Do not commit generated realism runs, raw captures, API keys, or build artifacts.
- The vision judge is an optional development aid with external API cost, never a
hard CI gate.
- Keep `project.godot`, changelog, tag and release asset version equal.
## Release workflow
### 1. Scope and version
Choose the semantic increment from `AGENTS.md`:
- MAJOR: incompatible/removed behavior, save/config contract or core-pillar
replacement.
- MINOR: new user-facing feature/venue.
- PATCH: fixes and polish.
Update:
1. `project.godot` `config/version`.
2. `CHANGELOG.md` with a dated entry.
3. `README.md`, `PLAN.md`, `docs/architecture.md`,
`docs/development-status.md`, `TODO.md`/`DONE.md` and `MEMORY.md` as needed.
For a release candidate, use a prerelease version only if the project policy
allows it and never present it as the final release.
### 2. Preflight
```bash
git status --short
git log --oneline -5
git tag -l "v<version>"
rg -n 'config/version' project.godot
```
Expected: only intended release changes; tag does not exist; version matches the
changelog and planned artifacts.
### 3. Automated checks
```bash
godot --headless --path . --script res://src/test/test_runner.gd
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
python3 tools/check_docs.py
python3 tools/blender_assets.py audit
python3 tools/blender_assets.py fit
python3 tools/npc_proportions.py report
python3 tools/npc_pipeline.py audit
```
Then run the smoke matrix, using isolated user-data directories for
tutorial/campaign:
```bash
for s in smoke_audio smoke_crowd smoke_emergency smoke_npc_budget \
smoke_plan_verbs smoke_scenario_content smoke_session_shell \
smoke_timeline smoke_ui_flows; do
godot --headless --path . --script res://src/test/$s.gd || exit 1
done
XDG_DATA_HOME=/tmp/gig-line-campaign godot --path . --fixed-fps 60 \
--script res://src/test/smoke_campaign.gd
XDG_DATA_HOME=/tmp/gig-line-tutorial godot --path . --fixed-fps 60 \
--script res://src/test/smoke_tutorial.gd -- --tutorial
godot --path . --script res://src/test/smoke_movement.gd
godot --path . --script res://src/test/smoke_props.gd
godot --path . --script res://src/test/smoke_focus_radial.gd
```
Use a fresh `$XDG_DATA_HOME` for campaign/tutorial and check the exit code, not
just the log.
### 4. Visual and judge gates
```bash
./tools/check_screenshots.sh
python3 tools/screen_designs.py compare
python3 tools/screen_designs.py judge --model auto # optional, record model/verdicts
```
For realism/venue work:
```bash
godot --path . --script res://src/test/capture_realism.gd \
-- --out=res://docs/screens/realism/<run>/after
python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> \
--judge --model <pinned-model>
```
Requirements:
- Gallery: 21 good / 0 bad; screen judge has no unexplained `diff`.
- Realism runs stay under `docs/screens/realism/` (gitignored); only decisions and
committed sheets/docs are tracked.
- Record judge model, run count/attempts, spend if exposed, and verdicts.
- Review every `review` verdict; turn layout regressions into fixes or documented
known limitations.
### 5. Clean build
Commit the release preparation first, then build the committed tree in a clean
worktree:
```bash
git worktree add --detach /tmp/gig-line-release HEAD
cd /tmp/gig-line-release
./tools/build_releases.sh
```
Verify artifact names/sizes and checksums:
```bash
ls -lh build/gig-line-*<version>*
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
sha256sum -c build/SHA256SUMS-<version>.txt
```
Check package contents:
```bash
unzip -l build/gig-line-web-<version>.zip | head
unzip -l build/gig-line-desktop-hq-<version>.zip | head
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
```
Check the runnable Linux and HQ packages:
```bash
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
unzip -q build/gig-line-desktop-hq-<version>.zip -d /tmp/gig-line-hq
/tmp/gig-line-hq/gig-line-linux-<version>.x86_64 --headless --quit-after 60
```
Check Web static serving with a local HTTP server and `curl` for `index.html`,
`index.wasm`, `index.pck` and the player docs. Windows/macOS/AppImage/installer
checks require the target matrix; if unavailable, record that explicitly.
Remove the worktree after verification:
```bash
git worktree remove --force /tmp/gig-line-release
```
### 6. Tag and publish
Only after every gate is green:
```bash
git add -A
git commit -m "Release <version> <topic>"
git tag -a "v<version>" -m "Gig Line <version>"
git push origin main "v<version>"
```
CI builds and publishes on the tag. Verify:
- Tag commit equals the release commit.
- CI checks/build job succeeded.
- Release page has the expected 7 assets (Linux, Windows, macOS, NSIS setup,
AppImage, Web, Desktop HQ).
- Asset names and download links point at the released version.
`tools/publish_release.sh` preflights artifact size/free space, writes SHA-256
checksums, rolls back newly uploaded assets/release on failure, and supports
opt-in retention:
```bash
RETAIN_RELEASES=7 ./tools/publish_release.sh <version>
```
The default `RETAIN_RELEASES=0` never prunes.
### 7. Post-release record
Update `README.md`, `docs/development-status.md`, `MEMORY.md`, `CHANGELOG.md`,
`TODO.md`/`DONE.md` and the release page with the built/CI result. Commit the
release record and push. Record any skipped check and the reason; never leave a
tag with unreported missing verification.
## Known gotchas
- **Dirty build inflation:** always use the clean worktree above.
- **`Class ... hides a global script class`:** remove stray `.gd` backups in
`tmp/`, delete `.godot`, re-import.
- **Screenshot staging:** `capture_ui_states.gd` needs its settle frames and
staged state; do not capture a paused frame or a stale modal.
- **Judge keys:** OpenRouter calls need `.env`/`OPENROUTER_API_KEY`; never commit
the key or generated review folders.
- **Tag builds publish automatically:** do not run a second manual publish that
duplicates assets; use the existing release if re-running.
- **macOS is unsigned unless policy changes:** record quarantine instructions and
do not claim notarization.
- **Release blockers are real:** external playtest, legal/storefront approval,
AI-provider rights and target-hardware checks cannot be replaced by green unit
tests.
## Bundled references
- [`references/release-runbook.md`](references/release-runbook.md) — version,
build, tag, CI, publish and rollback sequence.
- [`references/qa-gates.md`](references/qa-gates.md) — full command matrix,
expected results and evidence to record.
## Completion checklist
- [ ] Version/changelog/docs/tag match.
- [ ] No unresolved release blockers for a final tag.
- [ ] Godot, Python, smokes, asset and docs gates pass.
- [ ] Gallery and optional judges reviewed with evidence.
- [ ] Clean worktree build and checksums verified.
- [ ] Linux/HQ/Web checks recorded; unavailable platforms noted.
- [ ] Tag pushed; CI/publish succeeded; seven assets verified.
- [ ] Release record and durable docs committed.
@@ -0,0 +1,171 @@
# QA Gate Matrix
Run from the repository root. Capture the exit code and the useful report line,
not only the final “OK”.
## 1. Source and docs
```bash
git status --short
git log --oneline -5
python3 tools/check_docs.py
git diff --check
```
Expected: intended files only; `check_docs: OK`; no whitespace errors.
## 2. Automated suites
```bash
godot --headless --path . --script res://src/test/test_runner.gd
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
```
Expected: the current Godot suite passes (historically 272+ tests) and the
Python tooling suite passes (currently 160 tests). Do not edit expected counts
without inspecting the suite.
## 3. Asset gates
```bash
python3 tools/blender_assets.py audit
python3 tools/blender_assets.py fit
python3 tools/blender_assets.py texels
python3 tools/npc_pipeline.py audit
python3 tools/npc_proportions.py report
```
Expected: exit 0, no `BAD` assets, all eight characters inside the stylized
proportion guide, no budget/contract regression.
Optional texture/model audits when those assets changed:
```bash
python3 tools/asset_pipeline.py audit assets/textures/ai/game_ready
python3 tools/model_pipeline.py audit
```
## 4. Smoke matrix
Headless:
```bash
for s in smoke_audio smoke_crowd smoke_emergency smoke_npc_budget \
smoke_plan_verbs smoke_scenario_content smoke_session_shell \
smoke_timeline smoke_ui_flows; do
echo "== $s"
godot --headless --path . --script res://src/test/$s.gd || exit 1
done
```
Isolated data:
```bash
rm -rf /tmp/gig-line-release-campaign /tmp/gig-line-release-tutorial
XDG_DATA_HOME=/tmp/gig-line-release-campaign godot --path . --fixed-fps 60 \
--script res://src/test/smoke_campaign.gd
XDG_DATA_HOME=/tmp/gig-line-release-tutorial godot --path . --fixed-fps 60 \
--script res://src/test/smoke_tutorial.gd -- --tutorial
```
Windowed input/UI:
```bash
godot --path . --script res://src/test/smoke_movement.gd
godot --path . --script res://src/test/smoke_props.gd
godot --path . --script res://src/test/smoke_focus_radial.gd
```
Expected: 14 smokes green. `smoke_npc_budget` should print the current mesh,
triangle and frame-time evidence; the 50 ms budget is a safety ceiling.
## 5. Screenshot and design gates
```bash
./tools/check_screenshots.sh
python3 tools/screen_designs.py compare
```
Expected: 21 good / 0 bad; no unexplained compare output. The judge is optional:
```bash
python3 tools/screen_designs.py judge --model auto
```
Record model, confidence/verdict summary, `diff` count and any manual review.
`docs/screen-design-report.md` is the durable record.
## 6. Realism judge (when visual assets/lighting changed)
```bash
godot --path . --script res://src/test/capture_realism.gd \
-- --out=res://docs/screens/realism/<run>/after
python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> \
--judge --model <pinned-model>
```
Expected: a complete set of required stage captures, no stale pauses/modals, and
a report under the gitignored run directory. Record:
- pinned model/fallbacks
- shots attempted/completed
- spend if the tool exposes it
- mean score and Pillow gap
- every `review` verdict and disposition
Do not commit the run. Commit only the decision/report summary and any durable
comparison sheet explicitly intended for review.
## 7. Package checks
Use the clean worktree from `release-runbook.md`.
```bash
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
sha256sum -c build/SHA256SUMS-<version>.txt
unzip -l build/gig-line-web-<version>.zip
unzip -l build/gig-line-desktop-hq-<version>.zip
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
```
Expected:
- names match the version;
- Linux/Windows/macOS/Web/HQ present locally;
- Web contains HTML/wasm/pck and docs;
- HQ contains `override.cfg`, executables and docs;
- Linux/HQ start without a script error.
Windows installer/AppImage and macOS launch require CI or the target matrix. If
not available, mark them as unverified rather than passing them by analogy.
## 8. Release verification
After the tag push:
- CI checks job succeeded;
- CI build job succeeded;
- release page has seven assets;
- each artifact name includes the released version;
- the tag points at the release commit;
- README/changelog/status and release notes agree.
## Evidence summary template
```text
Release: vX.Y.Z (commit)
Godot: pass (N/N)
Python tooling: pass (N/N)
Smokes: 14/14
Assets: audit/fit/proportions/npc audit pass
Budget: 24 NPCs, N meshes, N triangles, N ms
Gallery: 21 good / 0 bad
Screen judge: N/N match, N review, N diff
Realism: model, attempts, mean, gap, review dispositions
Build: clean worktree, artifact sizes/checksums
Launch: Linux/HQ/Web checks; unverified platforms
CI/release: run id, seven assets
Skipped checks + reason:
Known limitations:
```
@@ -0,0 +1,171 @@
# Release Runbook
Authoritative source: `AGENTS.md` (Release Procedure), `docs/RELEASING.md`.
This runbook is the operational checklist; if it conflicts with those, they win.
## 0. Decide the release
Determine whether this is a major, minor, patch, or release-candidate checkpoint.
Do not assign a version to an unversioned development track until its scope is
accepted into a release.
Check the current release constraints in `TODO.md`:
- external playtest evidence
- legal/AI-provider/storefront review
- macOS signing/notarization policy
- target hardware matrix
- any manual QA gaps
If a final release would ship with unresolved blockers, prepare an RC or stop;
do not create a final tag.
## 1. Prepare the version
Files to update:
| File | Change |
| --- | --- |
| `project.godot` | `config/version="X.Y.Z"` |
| `CHANGELOG.md` | dated `## [X.Y.Z] — YYYY-MM-DD` entry |
| `README.md` | latest/current version and summary |
| `PLAN.md` / `docs/architecture.md` | current version reference |
| `docs/development-status.md` | shipped capability/release result |
| `TODO.md` / `DONE.md` | close/move milestone when complete |
| `MEMORY.md` | release state and gotchas |
Then commit the preparation before building.
## 2. Run gates
Use `qa-gates.md` as the command matrix. The minimum release gate is:
- Godot suite
- Python tooling tests
- documentation gate
- asset audits/fit/proportions
- 24-NPC budget
- 14 smoke scripts
- screenshot compare
- optional screen/realism judge with recorded model/attempts
- clean build and artifact checks
Any skipped check must be written into `MEMORY.md` or `TODO.md` with a reason.
## 3. Build in a clean worktree
Why: Godot can pack ignored `tmp/` captures and `build/` outputs into the export.
A dirty build can produce 1.6–3.1 GB artifacts instead of ~160–240 MB.
```bash
git worktree add --detach /tmp/gig-line-release HEAD
cd /tmp/gig-line-release
./tools/build_releases.sh
```
Expected local artifacts:
```text
build/gig-line-linux-<version>.x86_64
build/gig-line-windows-<version>.exe
build/gig-line-macos-<version>.zip
build/gig-line-web-<version>.zip
build/gig-line-desktop-hq-<version>.zip
```
CI additionally produces the NSIS setup and AppImage, for seven release assets.
## 4. Preflight and checksum
```bash
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
sha256sum -c build/SHA256SUMS-<version>.txt
```
`publish_release.sh` checks non-empty artifacts and local free space before any
API call. It writes checksums under `build/` and does not upload them by default.
Inspect packages:
```bash
unzip -l build/gig-line-web-<version>.zip | head -20
unzip -l build/gig-line-desktop-hq-<version>.zip | head -20
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
```
Web must contain `index.html`, `index.wasm`, `index.pck`, and player docs.
Desktop HQ must contain the Linux/Windows executables, `override.cfg`,
`README.txt`, `CREDITS.md`, `PRIVACY.md`, `accessibility.md` and
`known-limitations.md`.
## 5. Runtime launch smoke
```bash
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
unzip -q build/gig-line-desktop-hq-<version>.zip -d /tmp/gig-line-hq
/tmp/gig-line-hq/gig-line-linux-<version>.x86_64 --headless --quit-after 60
```
For Web, serve `build/web` and check HTTP 200 for `index.html`, `index.wasm`,
`index.pck` and docs. Do not claim browser interaction from a curl check.
Remove the temporary worktree after checks:
```bash
git worktree remove --force /tmp/gig-line-release
```
## 6. Tag and CI
From the real repository, on the release commit:
```bash
git tag -a "v<version>" -m "Gig Line <version>"
git push origin main "v<version>"
```
The tag triggers `.gitea/workflows/build.yml`: checks, export, installer,
AppImage, release publish. Verify the run and assets:
- check job success
- build job success
- seven assets present
- tag/version/artifact names equal
- download links respond
Do not reuse a published tag. If a fix is needed, bump patch and repeat.
## 7. Manual publish fallback
Only if CI cannot publish:
```bash
RETAIN_RELEASES=7 ./tools/publish_release.sh <version>
```
The script reuses or creates the release, uploads present artifacts, verifies the
asset count, and rolls back newly uploaded assets/new release on failure. The
default retention is `0` (no deletion). Never delete older releases implicitly.
## 8. Post-release record
Commit a release record that includes:
- tag and commit
- CI run/result
- seven assets
- checksums or size evidence
- skipped checks
- known limitations
- release URL
Update `DONE.md`/`TODO.md` and `MEMORY.md`; keep the changelog and README
consistent. Push the record commit.
## Versioning pitfalls
- A `vX.Y.Z` tag is immutable in practice; do not move/replace it.
- A release candidate is not a final release. Do not label it as such in the
README or release page if blockers remain.
- `config/version` must match the tag and artifact filenames.
- The clean-worktree build is a release requirement, not an optimization.