Skip to content

test(cliffs): the RUNTIME DESTROY PROBE - the cascade reproduces EXACTLY (#84) - #139

Merged
wormeyman merged 2 commits into
mainfrom
cliffs-destroy-probe
Aug 4, 2026
Merged

test(cliffs): the RUNTIME DESTROY PROBE - the cascade reproduces EXACTLY (#84)#139
wormeyman merged 2 commits into
mainfrom
cliffs-destroy-probe

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

#127 asked for a runtime probe that destroys a cliff outside map generation, because the connection rules cannot be scored from map-generation output at any number of regions — the game's output is always connection-consistent, so there is never a dangling end for the rules to act on. #135 read all four of Cliff::onDestroy's cascade gates on the Lua path and showed such a probe is safe. This builds it.

Result

The cascade is confirmed, and the port's destroyEnd model reproduces the game cell for cell and orientation for orientation — zero discrepancies across 16 targets, in both a border and an interior arm. Trims look exactly like the model says: south-to-west → none-to-west, east-to-south → east-to-none.

arm targets removed orientations changed
border, correction ON 8 9 13
border, correction OFF 8 8 0
interior, correction ON 8 10 12
interior, correction OFF 8 8 0

This matters for the residual. #114/#115 identified it as "31 destruction decisions". The destruction cascade is no longer a suspect for those — it is now validated against the game rather than only against the disassembly.

Four things that nearly made this a false result

  • do_cliff_correction DEFAULTS TO FALSE. A probe calling a bare destroy() gets untouched neighbours, and that null reads exactly like "the game does not cascade". Both values are captured; the OFF arms are that near-miss, kept as the control.
  • The comparison was clamped and looked like a defect. The first target set was picked in scan order, so all eight landed on the region's top edge and the port appeared to under-destroy by 7 cliffs. Every mismatch was an edge artifact: a cliff at y = 1498.5 is in the dump only through bounding-box overlap while its own neighbours are outside the dump, so the game cascades through cliffs the comparison cannot see. With 48 tiles of margin the agreement is exact.
  • The counts would have misled. Removals said 8 extra at the border against 1 in the interior, which reads like a border-only cascade; orientations say 13 and 12. A cliff is only removed when a trim leaves it with nothing, so removals measure how many neighbours were single-ended, not where the rule runs.
  • The probe's own instrumentation caught the fourth. The first run FOUND only 4 of 8 targets — find_entities_filtered selects on the per-orientation rotbb bounding box, which is offset from the cell centre and need not contain it. The box is now wider than the largest half-extent with an exact position match, and found is dumped per target so a lookup miss can never read as a destruction.

What this does NOT settle

updateConnections. It is not reachable from Lua at all, so that gate remains unscored. A cheaper route was tried and failed first, and is recorded so it is not retried: #137's chunk-order lever produces arms where a border chunk is applied with its neighbour chunk PROVABLY ungenerated — exactly the gate's input — but on the [1500,1500] west seam all five cliffs carrying a west end have a neighbour that isCliffConnected accepts, so there is still nothing to drop.

Also measured, and the reason there is no unconnected-target control arm: exactly one cliff of the 885 has no connected neighbour at all — itself a restatement of the connection-consistency #127 measured.

Non-vacuity

The exact-match assertion was confirmed by planting a destroyEnd that never force-destroys: both ON arms fail. Target selection is re-derived from the port's real onChunkBorder / isCliffConnected in the spec, so the capture's Node-safe duplicate cannot drift silently.

Verification

pnpm run verify green — 1534 app (up 10) + 13 worker + 3 container tests, 0 warnings, exit 0. Measurement only; shipping accuracy unchanged.

Note: branched off main, so it will conflict with #138 on the notes banner only. Whichever lands first, the other needs Update branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_012VRsPwmSwjnFKVSS6jx9Mo

wormeyman and others added 2 commits August 4, 2026 08:41
…TLY (#84)

#127 asked for a runtime probe that destroys a cliff outside map generation,
because the connection rules cannot be scored from map-generation output at
any number of regions: the game's output is always connection-consistent, so
there is never a dangling end for the rules to act on. #135 read all four of
Cliff::onDestroy's cascade gates on the Lua path and showed such a probe is
safe. This builds it.

RESULT: the cascade is confirmed, and the port's destroyEnd model reproduces
the game CELL FOR CELL AND ORIENTATION FOR ORIENTATION - zero discrepancies
across 16 targets, in both a border and an interior arm. Trims look exactly
like the model says: south-to-west -> none-to-west, east-to-south ->
east-to-none.

  arm                       targets  removed  orientations changed
  border, correction ON        8        9            13
  border, correction OFF       8        8             0
  interior, correction ON      8       10            12
  interior, correction OFF     8        8             0

This matters for the residual: #114/#115 identified it as "31 destruction
decisions", and the destruction cascade is no longer a suspect for those - it
is now validated against the game rather than only against the disassembly.

Three things nearly made this a false result, and all three are recorded:

  do_cliff_correction DEFAULTS TO FALSE. A probe calling a bare destroy()
  gets untouched neighbours, and that null reads exactly like "the game does
  not cascade". Both values are captured; the OFF arms are that near-miss
  kept as the control.

  The comparison was clamped and looked like a defect. The first target set
  was picked in scan order, so all eight landed on the region's top edge and
  the port appeared to under-destroy by 7 cliffs. Every mismatch was an edge
  artifact - a cliff at y = 1498.5 is in the dump only through bounding-box
  overlap while its own neighbours are outside the dump, so the game cascades
  through cliffs the comparison cannot see. With 48 tiles of margin the
  agreement is exact.

  The counts would have misled. Removals said 8 extra at the border against 1
  in the interior, which reads like a border-only cascade; orientations say 13
  and 12. A cliff is only removed when a trim leaves it with nothing, so
  removals measure how many neighbours were single-ended, not where the rule
  runs.

A fourth was caught by the probe's own instrumentation: the first run FOUND
only 4 of 8 targets, because find_entities_filtered selects on the
per-orientation rotbb bounding box, which is offset from the cell centre and
need not contain it. The search box is now wider than the largest half-extent
with an exact position match, and `found` is dumped per target so a lookup
miss can never read as a destruction.

What this does NOT settle: updateConnections. It is not reachable from Lua at
all, so that gate is still unscored. A cheaper route was tried and failed
first and should not be retried - #137's chunk-order lever produces arms where
a border chunk is applied with its neighbour chunk PROVABLY ungenerated, which
is exactly the gate's input, but on the [1500,1500] west seam all five cliffs
carrying a west end have a neighbour that isCliffConnected accepts, so there is
still nothing to drop.

The exact-match assertion was confirmed non-vacuous by planting a destroyEnd
that never force-destroys: both ON arms fail.

Verification: pnpm run verify green - 1534 app (up 10) + 13 worker + 3
container tests, 0 warnings, exit 0. Measurement only; shipping accuracy
unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012VRsPwmSwjnFKVSS6jx9Mo
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012VRsPwmSwjnFKVSS6jx9Mo
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