Files
code_of_conquest_dnd/api
Phillip Tarrant 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
..
2026-07-09 11:17:54 -05:00
2026-07-09 11:17:54 -05:00

/api — FastAPI proxy

The guarding proxy from charter §4. Not a generic API — it exists to keep the API key, the prompts, and the model routing server-side, and to log every call from day one.

Stack: Python, FastAPI. Models: Ollama (dev/staging) → Replicate (prod), routed per-role server-side.

Role endpoints (charter §4)

POST /dm/narrate      Narrator    — scene/outcome prose        (good model)
POST /dm/adjudicate   Adjudicator — free text → legal action   (small/fast, strict JSON)
POST /dm/improvise    Improviser  — minor sandboxed event       (charter §7 limits)
POST /npc/speak       NPC         — voice one character          (bounded moves, §6)
POST /party/banter    Banter      — companion callbacks          (cacheable, §9)

The client does not know which model serves a role or what the prompt is.

Responsibilities

  • Auth · metering (retrofit later — middleware + Stripe webhook, §4)
  • Prompt ownership — prompts live in prompts/, never in the client
  • Model routing — role → model is config, a deploy not a client patch
  • Logging — log seed and full prompt with every call (§10) for replay/eval

Contracts

Every AI response is untrusted (§2). Parse, validate, be ready to discard. One retry on parse failure, then authored fallback (§12).

See docs/ for endpoint schemas, model routing, and deploy notes.