fix(platform,book): 2026-06-23 book QA triage (#152–#164)#165
Merged
Conversation
The command validator excluded the player entity from all three candidate-finders (getEntitiesByName/BySynonym/ByAdjective) via `entity.id === getPlayer()?.id`, so `examine me`/`myself`/`self`/ `yourself` always failed with "You can't see any such thing." even though the player has a full IdentityTrait with those aliases. Remove the player exclusion (keep the room exclusion) so the player resolves through normal name/alias/adjective matching. The AWARE broad-search (hearing/smelling) path is left untouched. Adds a reproduction test verifying examine me/myself/self/yourself all resolve to the player entity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…155) EventProcessor.processSingleEvent invoked each registered handler through two paths: world.applyEvent() (WorldEventSystem dispatched the eventHandlers Map directly) AND invokeEntityHandlers() (the same handler, wired into the processor's storyHandlers by connectEventProcessor per ADR-086). So every handler registered via world.registerEventHandler fired twice — e.g. region boundary events (region_entered/region_exited) double-executed per crossing. ADR-086 designates the EventProcessor as the single dispatch source and explicitly rejected the "make applyEvent work" alternative for causing exactly this double-processing. Make applyEvent only validate + record history; the EventProcessor's invokeEntityHandlers is now the sole dispatcher. chainEvent handlers were already single-dispatch (applyEvent never invoked them), which matched the field report that Ch.13 chains worked but the Ch.9 region registerEventHandler probe doubled. - WorldEventSystem.applyEvent: no longer invokes eventHandlers. - Updated world-model event-sourcing tests to the new contract (applyEvent records but does not dispatch; register/unregister observed via wiring). - New event-processor reproduction test asserting single dispatch through the real WorldModel<->EventProcessor wiring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#158) Room-contents lists rendered comma-only ("A, B, C here") with no conjunction, even though the lang layer has a list formatter that builds "A, B, and C". Cause: three stdlib emitters of the contents_list message (looking, going auto-look, switching_on) pre-joined item names with ", " into a string, so the {items} placeholder substituted that string verbatim and no list formatter ever ran. Pre-joining also put English list grammar in stdlib, violating the language-layer separation. - stdlib: emit `items` as an array of names (drop the .join), so the lang layer owns the conjunction. - lang-en-us: contents_list (looking + going) and looking.you_see now use the {list:items} formatter token, routing through listFormatter for the locale-appropriate "A, B, and C" output (matches book Ch.19 §19.6). Adds a formatter test rendering the contents_list template from an array. Note: the dead eventMessageFunctions.formatRoomDescription helper (no runtime caller) is left untouched; the runtime path is the message template. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…69/070 amendments Replaces the rejected "degrade visual line to sound" model with per-sense rendering selection: each sense renders only the event descriptions keyed to it, so a blind witness sees the sound description and a deaf witness sees nothing, with no lossy downgrade between sense types. ADR-069 amendment (2026-06-23): adds per-sense rendering selection as the normative mechanism for witnessable event output; supersedes type-matching; adds a normative Contract section pinning the @sharpee/core shared wire-type. ADR-070 amendment (2026-06-23): corrects the stale responsibility table — NPC action execution and npc.* event emission live in stdlib NpcService, not the engine; witnessable movement event is sense-neutral (no sense field on the event shape). Both amendments passed devarch adr-review with the shared wire-type contract pinned. Plan revised to include §3.0 shared wire-type, §4 Behavior Statements, §5 state-mutation test, and npc.moved.witnessed rename. Co-Authored-By: Claude <noreply@anthropic.com>
…announcements (#159) NPC room crossings were silent; now an NPC with `NpcTrait.announcesMovement: true` announces when it crosses the player's room via a `npc.moved.witnessed` event. Implements the per-sense rendering model from plan-159-npc-movement-announce.md: - packages/if-services: add shared wire-types `Rendering`, `PerSenseRenderings`, `SENSE_PRECEDENCE` alongside `Sense` (deviation from plan: placed here where `Sense` lives, not in @sharpee/core; plan doc updated accordingly) - packages/world-model: `NpcTrait.announcesMovement` (default false) + `movementMessages` override map - packages/stdlib/npc-service: thread `playerLocation` through executeActions/executeAction/executeMove/executeMoveTo; new `announceMovement` helper emitting `npc.moved.witnessed` with per-sense renderings map; use `getOppositeDirection` for arrival direction - packages/stdlib/PerceptionService: generic rendering-selection branch in filterEvents (selects renderings[sense] by SENSE_PRECEDENCE) - packages/stdlib/npc-messages: `NPC_HEARD_ARRIVES` / `NPC_HEARD_DEPARTS` - packages/lang-en-us: `npc.heard_arrives` / `npc.heard_departs` templates - packages/stdlib/vitest.config: add @sharpee/if-services → src alias - Tests: 7 new npc-service movement tests (incl. world-state mutation assertion); 7 new perception-service rendering-selection tests; stdlib 1190 passed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On a sparse/replace channel, a `produce` returning `undefined` means "no change this turn" — so the previous room's mood line lingered when the player entered a room with no mood. Emit '' to clear instead (a real value transition the renderer paints as blank, then sparse stays quiet). Also document the undefined (no-change) vs '' (clear) distinction in §24.6. Not a platform defect — the channel system works as designed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#157,#160,#161) - §1.5/§31: sharpee init is an interactive wizard — add -y and document prompts (#152) - §2.3: note the scaffolded stub (@sharpee/sharpee barrel + object literal) vs the book's class form; both satisfy Story (#153) - §17.6: annotate (scope: any) on .where so it compiles under strict tsconfig (#156; cleaner platform overload tracked in #163) - §18.1/§18.3: if.action.taking.success -> if.action.taking.taken (real ID) (#157) - §22.6: correct Try-it — bleating stops on the daemon's own countdown, not feed goats (#160) - §23.3: show the 4 missing awards so the 12 awards sum to 75 and victory is reachable (#161) Documentation-only; no platform code changed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `examined_self` lang template is `{description}`, but the self path
in examining-data never supplied a `description` param: buildExaminingData
returned early for self without setting hasDescription, and the param
assignment in buildExaminingMessageParams was gated behind the
`!eventData.self` guard. Self-examine therefore rendered the literal
`{description}`. Newly exposed by the #154 scope fix, which let
`examine me` reach the report path for the first time.
Description is a universal property of any examinable entity (the player
included), so lift the params.description assignment ahead of the
self-guard and set hasDescription on the self branch. Trait dispatch
(container/supporter/etc.) stays self-exclusive.
Adds a regression test asserting the description param flows into the
examined_self event (verified to fail without the fix).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Republish stdlib carrying the examine-self description fix (#164); 1.1.2 was already published to npm. Sibling packages stay at 1.1.2 — unchanged since that publish. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Zifmia is currently incomplete and not relevant to building stories in
Sharpee. Removes Chapter 32 ("Multi-User with Zifmia"), its book.yaml
entry, and the passing Zifmia mention in the architecture map appendix.
Co-Authored-By: Claude <noreply@anthropic.com>
|
❌ The last analysis has failed. |
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.
Summary
Platform and book-text fixes from the 2026-06-23 book QA triage. Bundles fixes for issues #152–#164.
Platform fixes
examine me/self/yourselffail despite IdentityTrait aliases #154 — player resolvable byIdentityTraitname/aliases (command-validator)Book / docs
sharpee initis an interactive wizard, not the non-interactive one-liner shown #152, Book §2.3: scaffolded stub differs from book's Ch.2 conventions (@sharpee/sharpee + object literal vs @sharpee/engine + class) #153, Book §18.1/§18.3: cites nonexistent message IDif.action.taking.success(real ID isif.action.taking.taken) #157, Book §22.6: claimsfeed goatsstops the bleating, but feed action and bleating daemon key off unrelated state #160, Book §23: defines 12 score IDs (75 pts) but shows awarding code for only 8 (40 pts), so victory is unreachable as written #161)🤖 Generated with Claude Code