Skip to content

Port the #84 stage localisation to Rust (#227) - #359

Merged
wormeyman merged 1 commit into
mainfrom
feat/227-c1-stage-localisation
Aug 30, 2026
Merged

Port the #84 stage localisation to Rust (#227)#359
wormeyman merged 1 commit into
mainfrom
feat/227-c1-stage-localisation

Conversation

@wormeyman

Copy link
Copy Markdown
Collaborator

Ports the #84 stage localisation to Rust so #227 can delete
test/cliffOreActsAtDestroyStage.spec.ts without losing it.

Test-only and additive: no shipped source line changes. The diff is 324
insertions and 2 deletions, and both deletions are import lines in the test file
being widened.

Why this is a prerequisite rather than follow-up work

Verdict 12 on #227 split that spec in two. Its baseline - our raw queue plus the
game's own destruction set reproducing the region exactly - is already graded in
Rust by
the_apply_stage_beats_the_crossing_stage_on_three_counts_and_loses_on_none.
The localisation behind it is not graded anywhere, and a frozen aggregate cannot
stand in for it: removing one cell from a 1,500-cell queue moves a total by one
either way, which says nothing about which neighbour lost an end, and the
neighbour is the whole result.

Verdict 12 recorded the port as conditional on #84 staying open. It is open, so
this lands before the deletion rather than after it.

What it measures

Reproduced exactly from the TypeScript arm:

  • 31 cells the ore arm suppresses
  • of those, exactly 1 has a neighbour that can tell destruction from
    non-generation - the rest have neighbours the game also lacks, neighbours on a
    chunk border, or no facing end
  • treating 1546,1550.5 as never queued contradicts the game at exactly
    1546,1546.5
  • treating any of the other 30 that way costs nothing

The claim is two-sided, which is what makes it a stage localisation rather than
a bare count. Destroyed - the cell in the queue and in the destruction set - is
0 wrong. Never queued - out of both - is 1 wrong, at the neighbour. #122's rule
separates them: destruction runs onDestroy on the connected neighbour
unconditionally, while a cell that was never queued only costs a neighbour its
end when that neighbour sits on a chunk border.

This is an n=1 result and the test says so in its own docs. The third assertion
is what stops the second from reading as a general property.

Planted, not predicted

plant result
shipped apply_cliff_connections: pass no_cascade at both force_destroy sites, so destruction stops taking the neighbour's end RED - the baseline goes from 0 wrong to 8. This grades cliffs::connections and not only itself.
the instrument: drop #122's chunk-border filter from the decidable derivation RED - 5 decidable instead of 1, so the filter is load-bearing rather than decorative

Fixtures

One addition, oracle-vulcanus-cliff-ore-direction.seed123456.json, read through
load_captured_at at 2.1.12 like every other fixture here. The entities fixture
was already loaded by this file.

Gate

pnpm run verify green in 15m0s on Menehune, exit code read out of the log
rather than off the pipe. bash scripts/verify-rust.sh green.

#227 deletes `test/cliffOreActsAtDestroyStage.spec.ts`. Its baseline is already
graded in Rust, but the localisation behind it is not, and nothing in Rust
computes a counterfactual of that shape. A frozen aggregate cannot stand in for
it: removing one cell from a 1,500-cell queue moves a total by one either way,
which says nothing about WHICH neighbour lost an end - and the neighbour is the
whole result.

This is verdict 12's C1, recorded there as conditional on #84 staying open. It
is open, so the port lands before the deletion rather than after it.

Test-only and additive. No shipped source line changes.

The result, reproduced exactly from the TypeScript arm:

- 31 cells the ore arm suppresses
- of those, exactly 1 has a neighbour that can tell destruction from
  non-generation - the rest have neighbours the game also lacks, neighbours on
  a chunk border, or no facing end
- treating `1546,1550.5` as never queued contradicts the game at exactly
  `1546,1546.5`
- treating any of the other 30 that way costs nothing

The claim is two-sided, which is what makes it a stage localisation rather than
a bare count. Destroyed - the cell in the queue and in the destruction set - is
0 wrong. Never queued - out of both - is 1 wrong, at the neighbour. #122's rule
is what separates them: destruction runs `onDestroy` on the connected neighbour
unconditionally, while a cell that was never queued only costs a neighbour its
end when that neighbour is on a chunk border.

Planted rather than predicted:

| plant | result |
| --- | --- |
| shipped `apply_cliff_connections`: pass `no_cascade` at both `force_destroy` sites, so destruction stops taking the neighbour's end | RED - the baseline goes from 0 wrong to 8, so this grades `cliffs::connections` and not only itself |
| the instrument: drop #122's chunk-border filter from the decidable derivation | RED - 5 decidable instead of 1, so the filter is load-bearing rather than decorative |

The one fixture addition is `oracle-vulcanus-cliff-ore-direction.seed123456.json`.
The entities fixture was already loaded by this file.
@wormeyman
wormeyman merged commit a0de0c6 into main Aug 30, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant