Skip to content

Story 1.8: the Observer, part one, map, fog, traps and heaps - #62

Merged
watchthelight merged 3 commits into
mainfrom
story/1-8-the-observer-part-one-map-fog-traps-and-heaps
Sep 6, 2026
Merged

Story 1.8: the Observer, part one, map, fog, traps and heaps#62
watchthelight merged 3 commits into
mainfrom
story/1-8-the-observer-part-one-map-fog-traps-and-heaps

Conversation

@watchthelight

Copy link
Copy Markdown
Owner

Closes #21

Summary

The Observer exists: org.shatterfish.harness.observer.Observer, the one door from game state to the bot, with header() and map(); the other sections arrive with their stories and observe() when all do, so the Observer never emits a section it cannot build.
The map is built from the game's own drawing predicates: terrain reaches its tile through the tile sheet's tables (a secret door carries the wall's visual, a secret trap the floor's), fog is the fog of war's four levels behind its discoverable gate, a trap appears when visible on a cell the fog does not paint opaque, and a heap when seen and not empty, showing its container or its top item, a single for-sale item's price as the heap's title prints it, and a crystal chest's category as its description prints it.
The one thing to look at: Observer.map() and Observer.tile(int), where every read is a field the renderer reads, and MapLeakTest, which searches the serialized Observation for every hidden name.

What changed

  • shatterfish/harness/src/main/java/org/shatterfish/harness/observer/Observer.java: the Input-wait assertion, the visual-to-tile table keyed by the sheet's constants, the fog rule, the trap and heap rules, the header.
  • Tests: FogParityTest (every cell against the fog of war's painted texture at the first wait, blinded, with mind vision, after a scroll of magic mapping read the game's way, and with rock marked visited by hand; two readings of one wait byte-equal), MapLeakTest (a secret door and a hidden frost trap; a revealed disintegration trap on an unknown cell, then mapped, then disarmed; a locked chest, a crystal chest, a plain heap, a single unknown potion for sale, a stack, a hidden heap, a chest, a known potion; an unseen heap, an empty heap, a cell that cannot be discovered), TerrainTableTest (every constant of Terrain maps, every tile but NONE is reached, the secrets share their cover, a terrain in no table fails), ObserverGateTest (the header's fields, the challenges and the boss lock; refusal while the hero acts and under a window), Skeleton (a test-side Observation around the two sections).
  • Docs: ADR-0006 amendment for story 1.8; docs/rules/visibility.md (seven rows name the tests, five rows added); .gitignore (the Shatterfish section ignores shatterfish/*/bin/); HeadlessDriver.heroWaits shared with the gate; HeaderSection's lock cite.

How it was tested

  • ./gradlew build: green, 397 tests across 26 suites, fourteen of them the four observer suites.
  • Mutation battery of twenty on the committed tree, each against the four observer suites (story file, Evidence): all twenty caught, three of them added for the review's fog rule.
  • Fairness review: fairness-reviewer on 530d8cab8: FINDINGS with none blocking, six should-fix findings all taken in 8a7c2b10d (story file, The fairness review): the fog of war paints a wall by the cells its face belongs to, so a room's far wall is opaque while in view, and the Observer now mirrors the painting and emits a visited wall painted opaque at the examine level; FogParityTest reads the painted texture back through the scene in five scenes instead of recomputing the arrays; map() is marked not for play until story 1.9 emits a passive mimic as a chest; the lock's evidence is the LockedFloor buff's icon; the gate shares the driver's predicate and covers the inventory pane; the IDE output under the module is deleted and ignored.
  • Rig numbers: n/a before E3.
  • Screenshots: n/a.

Docs

  • docs/adr/0006-observer-visibility-rules.md: amendment (the Observer's shape and gate, terrain through the sheet's tables, the mine pair, the fog gate, the trap and heap rules, the header, what is left empty).
  • docs/rules/visibility.md: the Test column of seven rows; four rows for the tilemap's visual choice, the mine pair, the trap layer and the heap sprite and title.
  • Story file _bmad-output/implementation-artifacts/1-8-the-observer-part-one-map-fog-traps-and-heaps.md.

Upstream files touched

  • none

The Observer exists, in org.shatterfish.harness.observer, with header() and map(); observe()
arrives when every section does, so the Observer never emits a section it cannot build. Every
call asserts the Input wait: the hero ready with no action and not resting, and no window open.

The map is what the screen draws. Terrain reaches its tile through the tile sheet's own tables,
so a secret door carries the wall's visual and a secret trap the floor's without a rule of
Shatterfish's own; the mine's crystal and boulder, one sprite in every set, are the one pair
mapped by terrain because the cell's name tells them apart. Fog is the fog of war's four levels
behind its discoverable gate. A trap appears when visible on a cell the fog does not paint
opaque, named as the trap names itself, active as the layer colours it. A heap appears when seen
on such a cell and not when empty, showing its container, its top item's title for a plain or
for-sale heap, a single for-sale item's price as the heap's own title prints it, and a crystal
chest's category as its description prints it. The header is built too, the boss lock included.

MapLeakTest builds a secret door, a hidden frost trap, a revealed trap on an unknown cell, a
locked chest around a potion of strength, a crystal chest around a wand, an unknown potion for
sale, a stack, a hidden heap and an empty heap on a seeded first floor, and searches the JSON
and the bytes for every hidden name. TerrainTableTest walks every constant of Terrain.
ObserverGateTest holds the header and the gate. Seven rows of docs/rules/visibility.md name
the tests and four rows are added for what the story read; ADR-0006 is amended.
…test reads the paint back

The fairness review passed on parity and found six things to fix, all taken. The fog of war
paints a wall cell by the cells its face belongs to, so a room's far wall is opaque until the
corridor beyond is seen while the wall is in the hero's field of view; the Observer said in
view. The fog now mirrors the painting, taking the lighter of a wall's two halves as the part
the player sees, and emits a wall painted opaque that is visited or mapped at that level, since
the examine window opens on it and draws its tile. FogParityTest reads the fog of war's texture
back through the scene and holds every cell to it at the first wait, blinded, with mind vision,
after a scroll of magic mapping read the game's way, and with rock marked visited by hand, and
holds two readings of one wait byte-equal; the old test recomputed the formula from the arrays.

The gate uses the driver's own predicate, now HeadlessDriver.heroWaits, and the interface
check that covers the inventory pane, so the driver and the Observer have one definition of an
Input wait. The lock's evidence is the LockedFloor buff's icon, not the stairs and the boss bar.
map() is marked not for play until story 1.9 emits a passive mimic as a chest. The IDE output
under the harness module is deleted and ignored.
… to review

The story file records the twenty-mutation battery against the four observer suites, the
fairness review's six findings and how each was taken, and the limitations handed to stories
1.9, 1.11 and 1.16: the passive mimic that map() cannot yet show, the sections still to come
before observe(), and the two Runs of one seed that cannot be compared until the first floor is
deterministic.
@watchthelight watchthelight added this to the E1 Harness milestone Sep 6, 2026
@watchthelight watchthelight added epic:E1 Harness area:harness Area: harness fairness Touches Observer, ActionExecutor, brain, or information parity labels Sep 6, 2026
@watchthelight
watchthelight merged commit ddc1815 into main Sep 6, 2026
3 checks passed
@watchthelight
watchthelight deleted the story/1-8-the-observer-part-one-map-fog-traps-and-heaps branch September 6, 2026 14:11
@watchthelight watchthelight mentioned this pull request Sep 6, 2026
21 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:harness Area: harness epic:E1 Harness fairness Touches Observer, ActionExecutor, brain, or information parity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E1.8 The Observer, part one: map, fog, traps and heaps

1 participant