Phase 9 implementation — adventure-bundled monsters#26
Merged
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the phase 9 plan: an
Adventuredocument carries its ownMonsterTemplates, 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 callvalidate_adventure(adventure, load_monsters(), load_equipment())unchanged.Notable decisions (all pinned in the plan)
GameSession.__init__, not lazily:load_gamerestores without re-runningvalidate_adventure, and a doctored save with a colliding bundled id fails at restore with a typedContentValidationError— never a first-spawnValueError. An empty bundle returns the@cached base catalog object itself (identity asserted in tests): no copy, no behavior change for adventures that bundle nothing.GameSession.spawn, theSpawnMonstersexistence check, keyed-encounter resolution, and the listen check now readsession.effective_monsters. The wandering spawn path needed no edit — its rows funnel throughsession.spawn. The 46 golden tests pass with zero golden-file diffs._effective_monstersreturns 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.monster_idsare now validated against the union — closing a pre-existing play-timeValueErrorsurface (changelog Changed bullet).SCHEMA_VERSIONbump, no golden regeneration, no__all__change;test_public_surface.pypasses 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.mdgains 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:
pytest1535 passed / 58 skipped,ruff format --checkandruff checkclean,pyright0 errors,mkdocs build --strictclean.Release 1.2.0 (plan work item 6) follows after merge per the phase 8 checklist.
https://claude.ai/code/session_018e1XMwtEpnzA4zuuPZhzaS