5 Commits

Author SHA1 Message Date
8f3aa75fa9 chore(warnings): silence the four pre-existing script warnings the creation screen surfaced
Not errors and not regressions — Godot printed them on every script reload
and they predate M4-b. Cleared so a real warning is not lost in the noise:

- Redundant `const ContentDB`/`const NewGame` preloads that shadowed their
  own `class_name` globals (character_creation.gd, creation_draft.gd) — the
  class is already global, so the const bought nothing.
- Two `log` locals shadowing the built-in `log()` — renamed to `out`
  (canon_log.from_dict) and `canon` (NewGame.construct); the "log" dict KEY
  is the public contract and is unchanged.
- currency.format's copper->denomination division is integer BY DESIGN (the
  remainder is carried, not lost) — annotated `@warning_ignore` to say so.

319 client tests green; headless parse reports none of the four sites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:09:29 -05:00
a668cf98eb refactor(contract)!: class_id -> calling_id, and the log gains race_id
class_id is the rulebook's word; the world has callings — that was the whole §17
reconcile. The contract the Narrator reads should say what the world says. There
are no saves (M9) and no deployed clients, so this is as cheap as it will ever be
and strictly more expensive every milestone after.

race_id reaches the log because the AI must be able to describe the player:
api/app/prompts.py rendered 'a sellsword' and now renders 'a beastfolk cutpurse'.
It humanizes the id (the model must never read 'hedge_mage') and picks the right
article ('an elf', not 'a elf').

LogPlayer's hardcoded CLASSES const is deleted — the roster is Callings.IDS. A
parity test reads the JSON Schema from the client and asserts its enum equals the
code, so the two sides of the HTTP boundary cannot drift.

The deserter allowed three callings that no longer exist. He now allows all seven;
a thematic gate is a content decision for the Greywater authoring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 20:27:56 -05:00
3b71fcdcc0 feat(client): CanonLog.add_quest/has_quest for offer_quest 2026-07-10 12:36:37 -05:00
4166370f9d feat(client): CanonLog container + maintenance mutators (cap 5, dedup, stack)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 14:19:55 -05:00
a682022f17 feat(client): id helper + leaf canon-log entities with owned invariants
Also configure GUT to not treat push_error() as a test failure
(client/.gutconfig.json: failure_error_types = [engine, gut]).
The brief's LogPlayer/Quest setters intentionally push_error() on
rejected input; GUT's default failure_error_types includes
push_error, which would fail test_player_rejects_unknown_class and
test_quest_status_enum despite their assertions passing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 14:12:16 -05:00