fix(meta): PR #175 review round — all 14 findings addressed

H1 godot-cold-parse exit-code guard (+bonus: import-pass for cold checkouts, found live); H2 pr-watchlist-diff loud registry failure; H3/T1 deny list :* normalization (add-only) + uniform allow syntax; H4/T7 helper-script allows; H5 get_api_key env-only (config.json is tracked — no secret fallback); H6 TEAM.md active/standby split; H7 troblum solo-profiling note; H8 pr-review frontmatter Task->Agent; H9 conventions doc taxonomies fixed vs real tree; T2 ask-gate leash files (settings/hooks) in tracked settings; T3 R-013 cross-reference; T4 governance README index regenerated (pql decisions sync); T5 dudley briefing ACTIVE; T6 pr-process step 7 run-from-main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 22:11:36 +02:00
co-authored by Claude Fable 5
parent c9d9b56933
commit 6c078fbec4
12 changed files with 121 additions and 32 deletions
+1 -1
View File
@@ -107,7 +107,7 @@ Synthesize findings.
## Agent usage notes
### Troblum (Technical Consultant)
- **Always paired with or supporting Tyre** - never works alone on architecture decisions
- **Solo** for performance profiling, benchmarking, and technology stress-tests; **paired with Tyre** for architecture second opinions — never the sole voice on an architecture decision
- Spawned for specific evaluation sidequests, not open-ended discussion
- Blunt, data-driven, will challenge Tyre's assumptions with evidence
+27 -2
View File
@@ -54,8 +54,10 @@
"Bash(godot4:*)",
"Bash(gdformat:*)",
"Bash(tooling/atlas *)",
"Bash(tooling/atlas:*)",
"Bash(tooling/validate-ron:*)",
"Bash(tooling/godot-cold-parse:*)",
"Bash(tooling/pr-watchlist-diff:*)",
"Bash(chmod *)",
"Bash(ls *)",
@@ -80,9 +82,32 @@
],
"deny": [
"Bash(git push --force *)",
"Bash(git push --force:*)",
"Bash(git push --force)",
"Bash(git reset --hard *)",
"Bash(git reset --hard:*)",
"Bash(git reset --hard)",
"Bash(git clean -f *)",
"Bash(rm -rf *)"
"Bash(git clean -f:*)",
"Bash(git clean -f)",
"Bash(rm -rf *)",
"Bash(rm -rf:*)"
],
"ask": [
"Edit(.claude/settings.json)",
"Write(.claude/settings.json)",
"Edit(.claude/settings.local.json)",
"Write(.claude/settings.local.json)",
"Edit(.claude/hooks/**)",
"Write(.claude/hooks/**)",
"Edit(.config/hooks/**)",
"Write(.config/hooks/**)",
"Edit(.worktrees/**/.claude/settings.json)",
"Write(.worktrees/**/.claude/settings.json)",
"Edit(.worktrees/**/.claude/hooks/**)",
"Write(.worktrees/**/.claude/hooks/**)",
"Edit(.worktrees/**/.config/hooks/**)",
"Write(.worktrees/**/.config/hooks/**)"
]
},
"hooks": {
+7 -3
View File
@@ -285,9 +285,13 @@ git diff --stat main...<branch>
Draft title (`<type>(<scope>): <summary>`, max 70 chars) and description.
```bash
# NB: omit --repo — an explicit slug makes tea skip local-repo setup and
# pr create dies with "local repository required". Run from the MAIN checkout;
# tea infers the repo from origin. (.claude/rules/tea-cli.md)
# NB — both halves matter (.claude/rules/tea-cli.md):
# 1. omit --repo: an explicit slug makes tea skip local-repo setup and
# pr create dies with "local repository required";
# 2. run THIS ONE COMMAND from the MAIN checkout, not this worktree —
# tea's go-git can't read a worktree's .git *file*. From the worktree:
# cd "$(git rev-parse --path-format=absolute --git-common-dir)/.."
# for this command, then return here for the remaining steps.
tea pr create \
--login schweitz \
--title "<title>" \
+1 -1
View File
@@ -6,7 +6,7 @@ description: >
/pr-review. Spawns reviewers matched to the branch type (code, copy, visual,
audio) in parallel. Reports approve/reject with inline comments.
user-invocable: true
allowed-tools: Bash, Read, Grep, Glob, Task, Write
allowed-tools: Bash, Read, Grep, Glob, Agent, Write
---
# PR Review Skill
+9 -4
View File
@@ -31,16 +31,21 @@
|-------|------|-------|-------------|
| **SI** | Project Manager & Scrum Master | Sprint planning, ticket management, turning decisions into executable work. Manages `/ticket` skill. | Always (from now) |
## Implementation Team (active)
| Agent | Role | Focus | When active |
|-------|------|-------|-------------|
| **DUDLEY** | Server Developer | Game server, ECS, simulation loop, world state management. | Active — server/ is the main Phase-4 cascade workstream |
| **STIG** | UI Developer | HUD, menus, insert/minimap, diegetic UI per D-013. | Active — client UI work as needed |
| **JUSTINE** | Polish & Deploy | Build pipelines, packaging, performance optimization, release prep. | Active — build/validation tooling |
| **MELLANIE** | Copywriter | In-game text, UI copy, tooltips, flavor text, lore entries. | Active — content batches |
## Standby Team (activate when needed)
| Agent | Role | Focus | When active |
|-------|------|-------|-------------|
| **STIG** | UI Developer | HUD, menus, insert/minimap, diegetic UI per D-013. | UI implementation phase |
| **DUDLEY** | Server Developer | Game server, ECS, simulation loop, world state management. | Server implementation phase |
| **OSCAR** | Networking Developer | Multiplayer networking, client-server protocol, sync. | Networking implementation phase |
| **JUSTINE** | Polish & Deploy | Build pipelines, packaging, performance optimization, release prep. | Pre-release phase |
| **INIGO** | Sound Designer | Soundscape design, ambient layers, diegetic audio cues, audio propagation. | Audio implementation phase |
| **MELLANIE** | Copywriter | In-game text, UI copy, tooltips, flavor text, lore entries. | Content creation phase |
## Agent Briefings
+8 -3
View File
@@ -1,6 +1,6 @@
---
title: "Dudley - Project Briefing"
description: "Backend/engine implementation agent on standby — covers Rust simulation server, ECS model, and bevy_ecs architecture decisions"
description: "Server implementation agent — Rust/bevy_ecs simulation server, ECS model, world-generation cascade; the project's most active workstream"
type: briefing
status: active
agent: Dudley
@@ -8,14 +8,19 @@ updated: 2026-03-13
---
# Dudley - Project Briefing
Last updated: 2026-03-13
Last updated: 2026-07-13
## Current Project State
Check active work: `pql ticket list --status in_progress`
Check your tickets: `pql ticket list --assigned dudley`
## Status
STANDBY. This briefing will be populated when backend/engine implementation begins. Dudley activates when simulation implementation work is assigned.
ACTIVE. The Rust/bevy_ecs simulation server (`server/`) is the project's most
active implementation workstream — the Phase-4 world-generation cascade (D-166,
D-243) runs through it. Dudley is the default implementer for server batches
selected by `/whats-next`; recent work includes the Layer-5 tile fill and the
D-253 region transient model (PR #174). Build/test via the top-level Makefile;
the pre-push gate runs fmt/clippy/full cargo test on every push.
## Key Decisions for Your Domain
Read `decisions/architecture.md` (primary) and `decisions/content.md` (NPC model). Key decisions:
+7 -4
View File
@@ -8,8 +8,9 @@ deleted (CLAUDE-CLEANUP §2 / T-1101).
## d2 diagrams (`/d2-diagram`)
**Output taxonomy:** `.d2` source + `.png`/`.svg` renders under
`docs/diagrams/{category}/{name}.d2` — categories in use: `architecture/`, `ui/`,
`entity/`. Create/update a diagram whenever a D-record is added or modified.
`docs/diagrams/{category}/{name}.d2` — categories in use: `architecture/`,
`data-flow/`, `design/`, `entity/`, `state/`, `ui/`. Create/update a diagram
whenever a D-record is added or modified.
**Agent routing** (who to task with a diagram, by domain):
- **Qatux** — architecture decision records, system-overview + data-flow diagrams.
@@ -19,8 +20,10 @@ deleted (CLAUDE-CLEANUP §2 / T-1101).
## Frame0 wireframes (`/frame0-wireframe`)
**Output taxonomy:** wireframe JSON (source of truth) + exported PNG under
`docs/design/wireframes/{category}/{name}.json` — categories include `insert/`
(neural-insert HUD), `dialogue/`, etc. Palette/style source is
`docs/design/wireframes/{category}/{name}.json` — categories:
`character-creation/`, `dialogue/`, `hud/` (incl. the neural-insert HUD
wireframes `v01-insert-basic.json`, `v10-insert-full.json`), `menus/`,
`monologue/`, `navigator/`, `popups/`. Palette/style source is
`docs/design/visual-grammar-v01.md`.
**Agent routing:** Araminta (art direction / visual consistency) owns wireframe review;
+1
View File
@@ -462,3 +462,4 @@ line in place — keep the Q-record for the audit trail rather than deleting it.
- [R-010: protobuf for client-server serialization](rejected/architecture.md#r-010-protobuf-for-client-server-serialization) — _architecture_
- [R-011: Single currency for Phase 2 economics](rejected/economics.md#r-011-single-currency-for-phase-2-economics) — _economics_
- [R-012: Overheard NPC conversation system (D-078) — scrapped](rejected/perception.md#r-012-overheard-npc-conversation-system-d-078--scrapped) — _perception_
- [R-013: Localization / i18n](rejected/scope.md#r-013-localization--i18n) — _scope_
+1
View File
@@ -4,4 +4,5 @@ Rejected proposals in the **scope** domain, rationale preserved for the audit tr
### R-013: Localization / i18n
- **Rejected:** 2026-07-13
- **Cross-reference:** D-123 (content.md — Generative AI for NPC content), D-138 (content.md — LLM re-voicing pipeline); roster removal in `.claude/agents/README.md` + `TEAM.md`
- **Reason:** Full localization — an i18n framework, translation management, and the volume of template writing the Settled Reach's procedurally-composed text would demand — is prohibitively expensive for a solo developer, and compounds against the Gemma-based naming/text generation: every generated string would need a parallel translation pathway. The game ships English-only. The `tiger` (Translator) agent persona was removed with this decision (see `.claude/agents/README.md` and TEAM.md). Revisit only if project scope and resourcing change fundamentally.
+13 -12
View File
@@ -75,24 +75,25 @@ def get_base_url(key: str, default: str) -> str:
return load_config().get(key, default)
def get_api_key(env_var: str, config_key: str) -> str:
"""Get an API key from the environment or config.json.
def get_api_key(env_var: str, config_key: str = "") -> str:
"""Get an API key from the environment — environment-only, by design.
Checks the ``env_var`` environment variable first, then ``config_key`` in
config.json. Prints a JSON error and exits 1 if neither is set — connector
scripts emit machine-readable JSON on all paths.
``tooling/db/config.json`` is a *tracked* file and holds endpoints only;
it must never carry secrets, so there is deliberately no config.json
fallback here (the old one steered users toward committing paid API keys).
``config_key`` is retained in the signature for caller compatibility but
is ignored. Prints a JSON error and exits 1 if the variable is unset —
connector scripts emit machine-readable JSON on all paths.
"""
key = os.environ.get(env_var)
if key:
return key
try:
with open(CONFIG_PATH) as f:
config = json.load(f)
return config.get(config_key, "")
except Exception:
pass
print(json.dumps({
"ok": False,
"error": f"No {env_var} found in environment or config.json"
"error": (
f"{env_var} not set. Export it in your shell or add it to the "
"machine-local .claude/settings.local.json env block (untracked). "
"Never put keys in tooling/db/config.json — it is tracked."
)
}, indent=2))
sys.exit(1)
+36 -1
View File
@@ -28,15 +28,50 @@ RUN_MENU=false
rm -f "$REPO_ROOT/client/.godot/global_script_class_cache.cfg"
# A truly cold checkout (fresh clone or worktree — .godot/ is gitignored) has
# no resource-import cache, and every imported asset (fonts, ogg) then "fails
# loading" during the parse run: a wall of false positives. Seed the cache
# with an import pass first; source assets are tracked, so this is always
# reconstructible. (Found live: first run in a fresh worktree, 2026-07-13.)
if [ ! -d "$REPO_ROOT/client/.godot/imported" ] || [ -z "$(ls -A "$REPO_ROOT/client/.godot/imported" 2>/dev/null)" ]; then
echo "godot-cold-parse: no import cache — running one-time import pass..." >&2
set +e
IMPORT_OUT=$(godot --headless --path "$REPO_ROOT/client" --import 2>&1)
IMPORT_EXIT=$?
set -e
if [ "$IMPORT_EXIT" -ne 0 ]; then
echo "godot-cold-parse: import pass exited $IMPORT_EXIT" >&2
printf '%s\n' "$IMPORT_OUT" | tail -20 >&2
exit "$IMPORT_EXIT"
fi
fi
FILTER='^(SCRIPT )?ERROR|Parse Error|Export type'
MATCHES=$(godot --headless --path "$REPO_ROOT/client" --quit 2>&1 \
# Capture the godot run separately from the filter pipeline: with the
# trailing `|| true` on the greps, a nonzero exit from godot itself (crash,
# missing binary, corrupted install) would otherwise report "clean". Nothing
# downstream re-reads the raw output now that this is scripted, so fail loud.
set +e
RAW=$(godot --headless --path "$REPO_ROOT/client" --quit 2>&1)
GODOT_EXIT=$?
set -e
if [ "$GODOT_EXIT" -ne 0 ]; then
echo "godot-cold-parse: godot itself exited $GODOT_EXIT — not a parse verdict" >&2
printf '%s\n' "$RAW" | tail -20 >&2
exit "$GODOT_EXIT"
fi
MATCHES=$(printf '%s\n' "$RAW" \
| grep -iE "$FILTER" \
| grep -v "Failed loading resource: res://assets" \
| grep -v "Cannot infer the type" \
| grep -vE '(Messagepack|LocalBridge|ServerProcess|Constants)" not declared' || true)
if [ "$RUN_MENU" = true ]; then
# Deliberately no exit-code check here: `timeout` kills the menu after
# 10s by design (exit 124 is the expected shutdown path); only the
# scraped error lines carry signal for this bounded run.
MENU_MATCHES=$(timeout 10 godot --path "$REPO_ROOT/client" res://scenes/main_menu.tscn 2>&1 \
| grep -iE "$FILTER" || true)
if [ -n "$MENU_MATCHES" ]; then
+10 -1
View File
@@ -17,7 +17,16 @@ set -euo pipefail
BASE="${1:?usage: tooling/pr-watchlist-diff <base> <head>}"
HEAD="${2:?usage: tooling/pr-watchlist-diff <base> <head>}"
mapfile -t GENERATOR_SOURCES < <(python3 tooling/generator_sources.py --list)
# Load the registry via plain assignment (set -e sees its failure), not
# `mapfile < <(...)` — a failed process substitution is invisible to set -e
# and would silently yield an empty watch list, disabling the DB-staleness
# net exactly when the shared registry breaks. Guard the empty case too.
SOURCES_RAW="$(python3 tooling/generator_sources.py --list)"
if [ -z "$SOURCES_RAW" ]; then
echo "pr-watchlist-diff: generator_sources.py --list returned nothing" >&2
exit 1
fi
mapfile -t GENERATOR_SOURCES <<< "$SOURCES_RAW"
git diff --name-only "$BASE...$HEAD" -- \
"${GENERATOR_SOURCES[@]}" \