Skip to content

Phase 9 implementation — adventure-bundled monsters#26

Merged
mmacy merged 3 commits into
mainfrom
phase-9-impl
Jul 18, 2026
Merged

Phase 9 implementation — adventure-bundled monsters#26
mmacy merged 3 commits into
mainfrom
phase-9-impl

Conversation

@mmacy

@mmacy mmacy commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Implements the phase 9 plan: an Adventure document carries its own MonsterTemplates, and the engine resolves them everywhere it resolves template ids. The milestone holds: a bundled custom template is validated, spawned through every engine path (keyed, command, wandering), fought to XP and treasure, persisted, and replayed — with the consumer call validate_adventure(adventure, load_monsters(), load_equipment()) unchanged.

Notable decisions (all pinned in the plan)

  • The effective catalog builds once in GameSession.__init__, not lazily: load_game restores without re-running validate_adventure, and a doctored save with a colliding bundled id fails at restore with a typed ContentValidationError — never a first-spawn ValueError. An empty bundle returns the @cached base catalog object itself (identity asserted in tests): no copy, no behavior change for adventures that bundle nothing.
  • Four one-line redirects, all draw-neutral: GameSession.spawn, the SpawnMonsters existence check, keyed-encounter resolution, and the listen check now read session.effective_monsters. The wandering spawn path needed no edit — its rows funnel through session.spawn. The 46 golden tests pass with zero golden-file diffs.
  • Validation is total on the failure path: _effective_monsters returns a first-occurrence-wins dedup union plus every skipped colliding id, so a collision reports one line per id through the standard gate with no spurious "unknown monster" echo per keyed reference.
  • Inline wandering-table monster_ids are now validated against the union — closing a pre-existing play-time ValueError surface (changelog Changed bullet).
  • No SCHEMA_VERSION bump, no golden regeneration, no __all__ change; test_public_surface.py passes unedited. Collisions are errors, never overrides; there is no runtime registration surface — the phase 6 boundary stands.

Docs and spec impacts

Spec: the adventure model's bundled-templates clause, the frozen-data note (bundled templates are adventure data, not SRD data), roadmap entry 9. The authoring guide retitles to "Authoring custom classes, spells, and monsters" and gains a bundling section whose example is executed by the docs-example harness. The four-docstring id-domain sweep (GameSession.spawn, KeyedMonster, MonsterEncounterEntry, validate_adventure) names the effective domain. docs/adaptations.md gains no entries — this phase pins engineering seams, not rules readings.

Review provenance

One rubber-duck round by a skeptical senior reviewer with the full reading list (spec, plan, AGENTS.md, the complete diff, the touched code): verdict SOLID, a single non-blocking finding — the default-field test asserted only the dump side of the round-trip — fixed in fc115b7 by validating the dumped document back into Adventure; fix re-verified by the same reviewer, verdict confirmed. No blocking findings in either round.

Full gate on the branch: pytest 1535 passed / 58 skipped, ruff format --check and ruff check clean, pyright 0 errors, mkdocs build --strict clean.

Release 1.2.0 (plan work item 6) follows after merge per the phase 8 checklist.

https://claude.ai/code/session_018e1XMwtEpnzA4zuuPZhzaS

mmacy added 3 commits July 17, 2026 20:21
…ssion's effective catalog

Adventure.monsters carries custom MonsterTemplates; GameSession builds the
base ∪ bundled union once in __init__ (typed ContentValidationError backstop
for doctored saves) and every template-id resolution site — spawn, the
SpawnMonsters existence check, keyed encounters, listen checks — reads it.
validate_adventure keeps its signature and unions internally: collisions
report per id, keyed references and alignment pins resolve the dedup union,
and inline wandering-table monster_ids are now validated up front (closing a
pre-existing play-time ValueError surface).

Claude-Session: https://claude.ai/code/session_018e1XMwtEpnzA4zuuPZhzaS
Spec: the adventure model's bundled-templates clause, the frozen-data note
(bundled templates are adventure data, not SRD data), and roadmap entry 9.
The authoring guide retitles to cover monsters and gains the bundling section
with a runnable example (template helpers, the collision rule, the shipped-
index note). Changelog: the Added bullet and the wandering-table validation
tightening under Changed. docs/adaptations.md gains no entries — this phase
pins engineering seams, not rules readings.

Claude-Session: https://claude.ai/code/session_018e1XMwtEpnzA4zuuPZhzaS
The default-field test now validates the dumped document back into an
Adventure, closing the letter of the plan's round-trip pin.

Claude-Session: https://claude.ai/code/session_018e1XMwtEpnzA4zuuPZhzaS
@mmacy
mmacy merged commit d93d5ed into main Jul 18, 2026
5 checks passed
@mmacy
mmacy deleted the phase-9-impl branch July 18, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant