4494856a440645aba384593efed8c1c209c0e91b
The Luck sweep's non-empty-label assertions could not fail: _bind_bay and
_bind_callings always wrap prose in BBCode italics ("[i]%s[/i]"), and
_origin_prose() always emits the literal connective " Now you carry a %s's
work — " even when every authored fragment/blurb is blank. So
"[i][/i]".strip_edges().is_empty() reads false regardless of what ContentDB
served — the 28-combination sweep was proving the wrapper is non-empty, not
that §7's own guard against a blank ContentDB actually holds. Replaced the
emptiness checks with assertions that the DM panel and detail panel render
the WORLD's own fragment/blurb strings, and that those strings are
themselves non-blank, for every race x calling combination.
The M3-a collapse guard (`assert_gt(s.size.x, 0.0, ...)`) also could not
fail: the .tscn root is authored at exactly 1920x1080, matching the
project's viewport size, so the assertion passed on the authored offsets
alone with _fit_to_viewport() and its size_changed connection deleted
entirely. Replaced it with an actual resize proof: setting
Window.content_scale_size (the property this project's canvas_items stretch
mode actually keys Control.get_viewport_rect() off of — get_viewport().size
does not move it headless) to a non-1920x1080 value and asserting the root
followed, then restoring it.
Also covers three previously-unasserted binder behaviours: a race-granted
skill chip going inert (and a chip going inert once the pool's picks are
spent), the bonus-skill row's visibility gate per race, the ability card's
primary-stat Tag/theme_type_variation, and _on_enter_pressed's early-out on
an illegal draft.
Every new/changed guard was proven red against the bug it names (blanked a
calling's blurb; hardcoded a placeholder origin string; deleted
_fit_to_viewport's wiring; dropped the chip.disabled line; forced the bonus
row visible) and reverted. Suite: 298 -> 302, all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
coc-rpg
AI-driven single-player, party-based fantasy RPG. Godot 4 client, FastAPI proxy, AI as Dungeon Master.
Read CLAUDE.md first — project charter and working agreement. It is the source of truth. If code disagrees with it, the charter wins until the charter is changed.
The one rule
Code owns state. AI owns text. (charter §2)
Repo layout
/client Godot 4.7 game client (GDScript) — ALL game state, ALL game rules
/docs Client-specific docs (scenes, input, combat wiring)
/api FastAPI proxy — auth, metering, prompt routing, logging (charter §4)
/docs API-specific docs (endpoints, model routing, deploy)
/prompts Role prompts — source code, versioned, reviewed (charter §5, §16)
/content Authored game data — quests, NPC knowledge lists, fallback text
/quests Story skeletons and quest definitions
/npcs Per-NPC knowledge lists (charter §6 — "the whole design")
/fallback Authored degraded-DM text for every AI surface (charter §13)
/docs Cross-cutting docs — roadmap, ADRs, planning affecting both sides
/adr Architecture Decision Records
The three processes (charter §4)
client (GDScript) ──HTTP──▶ api (FastAPI) ──▶ Replicate / Ollama
The client holds no API key, ever. It knows one base URL and a set of role endpoints. It sends game state, receives text.
Description
Languages
Text
100%