From 724e8b183f5016b5b6b6f26c98d6a618897cc822 Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Tue, 3 Nov 2026 19:53:32 +0100 Subject: [PATCH] Add tracked AI skills for Blender assets and release QA --- .agents/.gdignore | 0 .../gig-line-blender-asset-contract/SKILL.md | 210 +++++++++++++++ .../references/asset-contract.md | 139 ++++++++++ .../references/verification.md | 123 +++++++++ .agents/skills/gig-line-release-qa/SKILL.md | 254 ++++++++++++++++++ .../references/qa-gates.md | 171 ++++++++++++ .../references/release-runbook.md | 171 ++++++++++++ .gitignore | 14 +- AGENTS.md | 13 + MEMORY.md | 4 + README.md | 2 + TODO.md | 11 + tools/README.md | 37 +-- 13 files changed, 1124 insertions(+), 25 deletions(-) create mode 100644 .agents/.gdignore create mode 100644 .agents/skills/gig-line-blender-asset-contract/SKILL.md create mode 100644 .agents/skills/gig-line-blender-asset-contract/references/asset-contract.md create mode 100644 .agents/skills/gig-line-blender-asset-contract/references/verification.md create mode 100644 .agents/skills/gig-line-release-qa/SKILL.md create mode 100644 .agents/skills/gig-line-release-qa/references/qa-gates.md create mode 100644 .agents/skills/gig-line-release-qa/references/release-runbook.md diff --git a/.agents/.gdignore b/.agents/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/.agents/skills/gig-line-blender-asset-contract/SKILL.md b/.agents/skills/gig-line-blender-asset-contract/SKILL.md new file mode 100644 index 0000000..e52d64c --- /dev/null +++ b/.agents/skills/gig-line-blender-asset-contract/SKILL.md @@ -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 + +flatpak run org.blender.Blender --background \ + --python "$PWD/tools/bake_ao.py" -- --only +``` + +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. diff --git a/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md b/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md new file mode 100644 index 0000000..0ddc269 --- /dev/null +++ b/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md @@ -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 + `_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 ` 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 `_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. diff --git a/.agents/skills/gig-line-blender-asset-contract/references/verification.md b/.agents/skills/gig-line-blender-asset-contract/references/verification.md new file mode 100644 index 0000000..562feb2 --- /dev/null +++ b/.agents/skills/gig-line-blender-asset-contract/references/verification.md @@ -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 --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-.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. diff --git a/.agents/skills/gig-line-release-qa/SKILL.md b/.agents/skills/gig-line-release-qa/SKILL.md new file mode 100644 index 0000000..6e81314 --- /dev/null +++ b/.agents/skills/gig-line-release-qa/SKILL.md @@ -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" +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//after +python3 tools/scene_concepts.py realism --run docs/screens/realism/ \ + --judge --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-** +PUBLISH_DRY_RUN=1 ./tools/publish_release.sh +sha256sum -c build/SHA256SUMS-.txt +``` + +Check package contents: + +```bash +unzip -l build/gig-line-web-.zip | head +unzip -l build/gig-line-desktop-hq-.zip | head +unzip -p build/gig-line-desktop-hq-.zip override.cfg +``` + +Check the runnable Linux and HQ packages: + +```bash +./build/gig-line-linux-.x86_64 --headless --quit-after 60 +unzip -q build/gig-line-desktop-hq-.zip -d /tmp/gig-line-hq +/tmp/gig-line-hq/gig-line-linux-.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 " +git tag -a "v" -m "Gig Line " +git push origin main "v" +``` + +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 +``` + +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. diff --git a/.agents/skills/gig-line-release-qa/references/qa-gates.md b/.agents/skills/gig-line-release-qa/references/qa-gates.md new file mode 100644 index 0000000..840312a --- /dev/null +++ b/.agents/skills/gig-line-release-qa/references/qa-gates.md @@ -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//after +python3 tools/scene_concepts.py realism --run docs/screens/realism/ \ + --judge --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 +sha256sum -c build/SHA256SUMS-.txt +unzip -l build/gig-line-web-.zip +unzip -l build/gig-line-desktop-hq-.zip +unzip -p build/gig-line-desktop-hq-.zip override.cfg +./build/gig-line-linux-.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: +``` diff --git a/.agents/skills/gig-line-release-qa/references/release-runbook.md b/.agents/skills/gig-line-release-qa/references/release-runbook.md new file mode 100644 index 0000000..125907c --- /dev/null +++ b/.agents/skills/gig-line-release-qa/references/release-runbook.md @@ -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-.x86_64 +build/gig-line-windows-.exe +build/gig-line-macos-.zip +build/gig-line-web-.zip +build/gig-line-desktop-hq-.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 +sha256sum -c build/SHA256SUMS-.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-.zip | head -20 +unzip -l build/gig-line-desktop-hq-.zip | head -20 +unzip -p build/gig-line-desktop-hq-.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-.x86_64 --headless --quit-after 60 +unzip -q build/gig-line-desktop-hq-.zip -d /tmp/gig-line-hq +/tmp/gig-line-hq/gig-line-linux-.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" -m "Gig Line " +git push origin main "v" +``` + +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 +``` + +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. diff --git a/.gitignore b/.gitignore index 23a2c79..2fad8bc 100644 --- a/.gitignore +++ b/.gitignore @@ -59,9 +59,19 @@ assets/models/generated/npc_base_*_normal.png # Local AppImage extraction squashfs-root/ -# Local agent skills (installed per machine from the Blender Skills Pack; not part of -# the game, tests or release artifacts, and never shipped) +# Local agent skills. The third-party Blender pack is installed per machine and +# stays ignored; the two project-authored skills are tracked so the workflow can +# be shared and reviewed. .agents/ +!.agents/ +.agents/* +!.agents/.gdignore +!.agents/skills/ +.agents/skills/* +!.agents/skills/gig-line-blender-asset-contract/ +!.agents/skills/gig-line-blender-asset-contract/** +!.agents/skills/gig-line-release-qa/ +!.agents/skills/gig-line-release-qa/** # Blender asset library: per-asset Cycles renders are local review output (the # committed review artefacts are docs/blender_previews/sheet_*.jpg), and Godot # extracts the GLB-embedded textures next to the models on import. diff --git a/AGENTS.md b/AGENTS.md index 69044ef..8e49c92 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,19 @@ forces one. Use them when a task touches `tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/bake_ao.py`, `assets/models/blender/**`, or Blender-authored venue/prop geometry. +### Project-authored skills (tracked) + +Two project skills are committed under `.agents/skills/` and are guidance for +any agent, not only Pi: + +- `gig-line-blender-asset-contract` — the NPC/gear/prop contract, build order, + headless Blender commands, failure playbook and verification gates. +- `gig-line-release-qa` — the test/smoke matrix, visual judges, clean-worktree + build, checksum/tag/publish sequence and release records. + +They are not runtime dependencies and do not move tool implementations into +`.agents/`. The third-party `blender-skills` pack stays local/gitignored. + ### Routing Start with `blender-director` for anything multi-discipline, then load only the diff --git a/MEMORY.md b/MEMORY.md index 984f3d7..e95b63f 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -10,6 +10,10 @@ canonical implemented-features list in `docs/development-status.md`. the licence gate. Downloads live in `tmp/research/` (gitignored): DDG image search, street-view frames, neighbouring buildings — never committed, never shipped. Promotion into `docs/screens/refs/` always passes the sidecar licence + privacy gate and `CREDITS.md`. +- **Project agent skills (2026-11-03):** two tracked skills live in `.agents/skills/`: + `gig-line-blender-asset-contract` and `gig-line-release-qa`. They are guidance only, + add no runtime dependency and are referenced from `tools/README.md`. The third-party + `blender-skills` pack remains gitignored. - **TV Studio shares the Hollywood location (owner):** the Late Night TV Studio is the same El Capitan Entertainment Centre block at 6840 Hollywood Blvd (which houses *Jimmy Kimmel Live!*), restaged for a late-night arrival. `VENUE_SPECS["tv_studio"]` is a 30.0 m variant of the 29.6 m diff --git a/README.md b/README.md index 164fcb7..0b22edd 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,8 @@ Full setup, every run/test/smoke command, and the controls table are in - [`docs/tutorial.md`](docs/tutorial.md) — First-shift tutorial beats and rules. - [`docs/asset-tooling.md`](docs/asset-tooling.md) — Asset pipelines, model tools, and screenshot gates. - [`tools/README.md`](tools/README.md) — Tool inventory, categories, test commands and AI-skill evaluation. +- [`.agents/skills/gig-line-blender-asset-contract`](.agents/skills/gig-line-blender-asset-contract/SKILL.md) — tracked AI skill for Blender/NPC/gear asset work. +- [`.agents/skills/gig-line-release-qa`](.agents/skills/gig-line-release-qa/SKILL.md) — tracked AI skill for release and visual-QA work. - [`docs/getting-started.md`](docs/getting-started.md) — Setup, run/test commands, and controls. - [`docs/development-status.md`](docs/development-status.md) — Implemented features and what's next. - [`docs/accessibility.md`](docs/accessibility.md) — Accessibility features, known gaps and statement. diff --git a/TODO.md b/TODO.md index 4310149..1769b8e 100644 --- a/TODO.md +++ b/TODO.md @@ -618,6 +618,17 @@ three-up boards; `tools/refboard.py` + reference-anchored generation (`--referen - [ ] Prefer `tools/scene_concepts.py promote` (or a manual move into `game_ready/v2/` plus a `PICKS` entry) so new picks follow the same path as `limestone_ashlar` and `dark_stucco`. +### Agent skill upkeep + +- [x] Add the tracked project skills `gig-line-blender-asset-contract` and + `gig-line-release-qa` under `.agents/skills/`, with references for the + asset contract/verification and release/QA runbooks. +- [x] Keep the third-party `blender-skills` pack local/gitignored while allowing + project-authored skills to be committed; reference the skills from + `tools/README.md`, `AGENTS.md` and `MEMORY.md`. +- [ ] Revisit the skills after the next Blender or release work changes the + contract, commands or gates; stale skills are worse than no skill. + ### Blender skills upkeep - [ ] Re-check the installed Blender pack (`version.json`) when updating it and record the version diff --git a/tools/README.md b/tools/README.md index 675def4..3c35cf6 100644 --- a/tools/README.md +++ b/tools/README.md @@ -129,34 +129,25 @@ All Python tooling tests live in [`tests/`](tests/). They use the repository's `requirements-tools.txt` (Pillow) and do not start Godot or Blender. See [`tests/README.md`](tests/README.md) for the exact discovery command. -## Which tools could become AI skills? +## Project AI skills -A skill is a **procedure and decision guide**, not a script wrapper. The useful -split is project-specific judgement that an AI repeatedly needs, not a second -copy of every command. +Two project-authored skills now live under +[`../.agents/skills/`](../.agents/skills/) and are tracked in the repository: -### Recommended: elevate as a project skill +- [`gig-line-blender-asset-contract`](../.agents/skills/gig-line-blender-asset-contract/SKILL.md) — contract, command order, failure playbook and verification for Blender/NPC/gear/prop work. +- [`gig-line-release-qa`](../.agents/skills/gig-line-release-qa/SKILL.md) — test/smoke matrix, visual gates, clean build, checksums, tag/publish and release records. -1. **`gig-line-blender-asset-contract` (high value).** - Bundle the ordering and contract around `blender_assets.py`, - `npc_pipeline.py`, `bake_ao.py`, `npc_proportions.py` and - `npc_baseline.py`: the 13-bone `npc_base` contract, tint slots, 8,000/8,000 - character cap, gear attach space, AO/UV rules, audit → fit → measure → - baseline sequence, and the “inspect the diff before committing” rule. - This is the workflow most likely to be repeated by an AI and most likely to - be damaged by improvising. +The third-party `blender-skills` pack remains local/gitignored. These project +skills are guidance only; they do not move scripts into `.agents`, add runtime +dependencies or replace the tools above. -2. **`gig-line-release-and-visual-qa` (high value).** - Capture the sequence `check_docs.py` → `check_screenshots.sh` → - `screen_designs.py compare/judge` → clean-worktree `build_releases.sh` → - `PUBLISH_DRY_RUN` → checksum/upload checks. Include the optional nature of - the vision judge, the clean-worktree trap and the release rollback rules. +### Remaining skill candidate -3. **`gig-line-reference-provenance` (medium value).** - Guide `refboard.py` vs `refcollect.py`: committed Wikimedia-sourced boards - with sidecars versus local-only `tmp/research/` downloads, and the rule that - generated concepts never override photo evidence. This is more of a policy - skill than a command skill. +- **`gig-line-reference-provenance` (medium value).** Guide `refboard.py` vs + `refcollect.py`: committed Wikimedia-sourced boards with sidecars versus + local-only `tmp/research/` downloads, and the rule that generated concepts + never override photo evidence. This is more of a policy skill than a command + skill. ### Keep as scripts