The idol comes home: quests, victory, and the authored example - #61
Merged
Conversation
Work items 1-5 of the phase 15 plan: TriggerClause/ObjectiveSpec/QuestSpec in the new crawl/quests.py; the four lifecycle commands with their closed id domain and three rejection codes; the five player-visible quest events; QuestState/ObjectiveState seeded at session construction (activation-less quests active from round 0); the handlers with the beat mapping, the victory transition, and terminal stickiness; and the quests block in persistence with no schema bump. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
Pre-existing defect the widened command fuzz surfaced: GiveItems naming one magic instance id twice raised ValueError from _apply_give, and the DropItems twin half-ran — both breaking the schema-valid-commands-reject- never-throw contract. The shared validation pre-phase now rejects the second naming with exploration.item.not_carried: the whole instance leaves on the first naming, so the second has nothing behind it. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
…hows them Work items 7 and 8: validate_adventure walks quests through the same two bodies triggers use — _validate_trigger's body split into _validate_clause and _validate_consequence, its error lines byte-identical — so the two authoring surfaces cannot drift; quest ids unique across the adventure, every clause and reward reference resolved. PlayerView.quests ships active quests and revealed objectives only, offer and speaker as flat strings, and the leak pins extend to the quest wiring: no clauses, no rewards, no hidden objectives, no inactive quests, no narrative-block field ever a key in the projection. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
…n that wins
Work item 6 and the phase golden: per event, triggers in document order
then quests in document order — activation, reveals, completions, the
completion rule checked the moment a completion the walk itself issued
lands, then CompleteQuest and the rewards in authored order. Clause
matching reuses _matches and condition_holds verbatim; every issued
command carries source="quest:{id}" via the shared _Owner value that
keeps the stamp and the note label from ever drifting apart; suppressed
advancements past the depth bound note instead of issuing, edge gone.
The phase15_quest golden runs the barrow errand to victory with the
spawn reward dropping in the ended session, and replays byte-equal with
no listeners registered.
Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
…ter plays it Work items 9 and 10: LevelSpec.guidance, the per-level ambient steering slot the engine never reads. The example's Jade Idol becomes a bundled GearTemplate placed in the shrine cache by id, so taking it reports the catalog id the authored quest matches; the fetch quest lands as Adventure.quests with pay-on-delivery rewards, and quest.py is deleted — both front ends register the library Interpreter instead, on create and restore alike. The milestone script makes two trips, because the homecoming with the idol ends the adventure on the spot: town business on the first return, the errand on the second, victory closing the transcript. The authored XP retunes 600 -> 1200 to cover the 2,400 gp that left the valuation delta (the mundane idol and the town-paid reward), leaving every member's final XP identical to the old run. The TUI grows a give verb — the sale coin outweighs a marching party, and spreading the purse is the engine's own answer. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
The golden scripts the reworked example, so the run it snapshots is new: two session.xp.adventure_award events instead of one (the two-trip script banks the delve award on the first return and the shrine's 50 gp on the second), extra travel and town turns on the clock, the quest block and victory mode in the final state, and the interpreter's provably empty listener slot where the deleted listener's state used to sit. The post_award checkpoint is now pinned explicitly to the final return and a first_return checkpoint joins it — named captures replacing the old last-town-wins accident. Every member's final XP is byte- identical to the previous golden: the retuned authored award covers exactly what the redesign removed from the valuation delta. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
…the guides Work item 11's remainder. Four sentence-level spec amendments — the journal's display-text rule, the from-start activation consequence, the validation clause rewritten to the executed seam, and the player view's speaker attribution. narrative.py's carrier table rewritten to the shipped mapping: quest blocks speak offer and completion, objective blocks offer and progress, the quest layer journals the display text it showed and leaves the journal field to carriers whose display beat the players never see. The authoring guide gains the quest section and the guidance slot, the commands guide the four lifecycle commands and their closed id domain, the views guide PlayerView.quests and the journal- growth event surface, and the changelog the phase's three entries. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
The TUI walkthrough's fetch-quest transcript is now two byte-exact excerpts of the real seed-21 run, with the split named in prose and the two teachable surprises — the cache spreading the idol to the thief, and the completion beat riding both closing events — taught instead of hidden. _validate_consequence drops the magic parameter nothing read. The views guide's complete example authors a two-objective quest and registers the interpreter, so the quest projection and the no-journal- event pin run under the docs-examples harness and the no-run fragment has its runnable twin. The example README's scripted run uses seed 21, the seed whose transcript does what the paragraph says. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
… twin The quest added to the views guide's runnable example opens the journal with its offer beat, and the revision updated the runnable block's assertion to the last-entry form but left the narrated fragment above it on the old whole-journal equality — the fragment its own page disproves. Mirror the [-1] form, which is also the honest teaching now that a quest opens the journal. Claude-Session: https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7
Owner
Author
|
Closing deliverable filed: mmacy/osr-forge#39 — the overrides schema has no quest surface; quest authoring stays native-project-only until osr-forge grows one against this settled schema. |
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 15 plan (#60): the quest spec, the four lifecycle commands and five player-visible events, engine-owned quest state with construction seeding and persistence, adventure completion into
victory,PlayerView.quests,LevelSpec.guidance, the quest validation walk, the interpreter's quest processing — and the example crawlers author their fetch quest as adventure data, register the libraryInterpreter, and delete the hand-rolled listener.The milestone, twice over
phase15_quest.json) runs the barrow errand as authored data — trigger-then-activation on the threshold crossing, the bundled idol matched by catalog id, a hidden objective revealed by an area entry and completed by a game-issued flag, the concluding completion intovictory, rewards landing after the transition with the authored spawn dropping and noting — and replays byte-equal with no listeners registered,load(save)equal toreplay(seed, commands).--seed 21), pays on delivery, journals every beat, and closes the transcript in[victory]deterministically.Notable decisions
TriggerSpeckeeps its flat wire shape. The clause model (TriggerClause) is quests-only; rehomingwhen/conditionsinside every serialized trigger would be a schema bump bought for symmetry.MarkTriggerFired's open one, cross-referenced both ways: the view must render what the log only references.offer/completion, objective blocksoffer/progress; a quest beat journals its display text verbatim and emits noJournalEntryAddedEvent— the lifecycle event is the beat's event.narrative.py's carrier table and the spec's journal paragraph both say so now._handle_complete_quest), sticky from both terminal modes, rewards issued by the interpreter after the transition so a resume-play reward drops with a note._validate_triggersplit into_validate_clause/_validate_consequence, trigger error strings byte-identical, quests walking the same helpers.giveverb (aftersell allthe seller carries 1,600 coins of weight and the party cannot move — the two-trip script physically requires spreading the purse), and a pre-existing engine defect surfaced by the widened fuzzer is fixed in its own commit (GiveItems/DropItemsnaming one magic instance twice raised out ofexecuteinstead of rejecting).phase5_milestone.jsonis the only pre-existing golden that changed — regenerated for the example's redesign, explained in its commit. NoSCHEMA_VERSIONbump; pre-phase documents and saves load unchanged;docs/adaptations.mduntouched (no SRD text is interpreted this phase). The spec gains exactly the four sentence-level amendments the plan argued.Review provenance
Implemented stage-by-stage with senior review of every diff before commit, then rubber-ducked by a fresh reviewer against the spec, the plan, and AGENTS.md, with active verification (full gate, golden idempotency and regeneration, XP byte-comparison against the old golden, byte-identical trigger validation messages, the single victory entrance, layering/determinism/schema sweeps, greenfield anti-pattern hunt). Round 1: one blocking finding — the TUI walkthrough transcript was invented rather than excerpted; it is now two byte-exact excerpts of the live seed-21 run with the surprising bits taught instead of hidden — plus a dead parameter, a docs fragment without a runnable twin, and a wrong README seed, all fixed. Round 2 verified the fixes, caught one regression (a neighbouring fragment falsified by the new quest opening the journal), fixed and re-verified. Final verdict: SOLID, with the engine code needing no changes across the entire review.
Closing deliverable: the osr-forge no-quest-surface issue is filed and linked in a comment below.
https://claude.ai/code/session_01NQ83sqNnXVeXEd55NK1xR7