Skip to content

A door-edge trap find doesn't say which door: the search token carries no bearing #67

Description

@mmacy

Surfaced by adversarial review of osr-web's phase-1 authored-layer adoption (mmacy/osr-web#44). Filed engine-first per the standing rule: the renderer needs a fact only the engine knows at emission time, so the engine states it — no downstream reconstruction.

The gap

1.5.0 widened room_traps searches to door edges: _reveal (src/osrlib/crawl/exploration.py) walks the searched cell's door edges and reports an open-trigger trap in the area beyond, guarded so an undiscovered secret door stays blank wall. But the report it emits is the token room_trap:{area_id} on SearchCompletedEvent, whose only other facts are character_id, kind, and found — no position, no bearing. At the moment _reveal appends the token it knows exactly which door edge earned the find; the event does not say.

Why downstream cannot reconstruct it

osr-web's phase 1 tried to name the door at render time by re-deriving the walk from session.dungeon_state.location. Review refuted it three ways, each fundamental rather than a bug in the attempt:

  • Whole-log re-renders fabricate history. The transcript re-renders on page reload, member rename, and save restore, resolving every historical search against wherever the party stands now. Reproduced on the bundled document: a trap found by standing inside its area ("a hidden trap") re-rendered from one cell away as "a trap rigged to the south door" — a bearing the engine never produced, and one _reveal cannot produce for an enter-trigger trap.
  • It leaks hidden geometry unless it re-implements the engine's guards. The walk must skip undiscovered secret doors and non-open triggers — exactly _reveal's guarded logic — or it tells the player a door exists where the projection renders wall. Duplicating that walk downstream is rule re-implementation, which the adoption spec forbids.
  • The event is the contract. Everything else the renderer says resolves off event-carried facts; this would be the one line derived from mutable session state instead.

What downstream needs

The bearing stated at emission, the same shape as every other resolved-at-emission fact (osrlib#65's display names, gate narrative on the command's event). Two candidate forms, this repo's call:

  • the token grows a segment for door-edge finds — room_trap:{area_id}:{direction} — with the bare two-segment form remaining the in-area find, or
  • found stays as-is and the event gains a structured companion field carrying {token, direction} entries.

Either is additive within schema 3 for freshly emitted events; old logs keep formatting since the bare token remains valid.

Downstream in the interim

osr-web renders every room_trap find as "a hidden trap" with no bearing — the spec's door-naming clause is amended to record this decision (render only what the data states) and to point here. No workaround will be built in the interim.

https://claude.ai/code/session_01GSYzXCjpPnVDLTC2rpmhTZ

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions