Files
code_of_conquest_dnd/docs
Phillip Tarrant acc5a7b2a2 fix(npc): a move applies at most once per reply
The tag extractor returns every occurrence of a move tag and the validator is
a pure membership test, so MoveApplier applied duplicates. A model repeating a
tag N times therefore picked an amount in unary — the AI choosing a number,
which is the §2 breach the bounded vocabulary exists to prevent.

The currency fix (8e1238c) closed this for denominations only. Generalizing it
to every move that names a thing covers real items too — three give_item(amulet)
tags are one amulet, not three — and lets the currency special case be deleted
rather than kept alongside a second mechanism. ID_MOVES is reused from
MoveValidator instead of restated.

Also caps adjust_disposition on the reply's NET swing. MAX_DELTA was clamped
per tag, so three +15s moved standing by 45 — precisely the wholesale swing its
own comment says it forbids. Applied in emission order, so a later
become_hostile still floors what came before it.

offer_quest and reveal needed no change: add_quest self-guards on has_quest and
mark_revealed is idempotent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
2026-07-12 19:11:40 -05:00
..
2026-07-09 11:17:54 -05:00

/docs — cross-cutting docs

Anything affecting both client and api, plus planning and roadmap. Side-specific docs live in /api/docs and /client/docs.

Put here:

  • roadmap.md — phases, POC scope, what's next
  • adr/ — Architecture Decision Records
  • Shared contracts — canon log schema, tag syntax, retry policy (§11, §12)
  • Anything spanning the HTTP boundary

The charter itself — CLAUDE.md — stays at the repo root. It is the source of truth; these docs elaborate, they do not override it.