Skip to content

test(cliffs): the cascade's 2 false rejections are KNOCK-ONS, not defects (#84) - #147

Merged
wormeyman merged 1 commit into
mainfrom
cliffs-cascade-false-rejections
Aug 4, 2026
Merged

test(cliffs): the cascade's 2 false rejections are KNOCK-ONS, not defects (#84)#147
wormeyman merged 1 commit into
mainfrom
cliffs-cascade-false-rejections

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

#143 priced the destruction cascade as a net +8 shipping gain - 10 fewer missed cells for 2 more false rejections - and deliberately left it untaken with one instruction: look at the 2 new false rejections before the 10 wins, because #134 recorded a gate the port does not model (Cliff::destroyEnd refuses to forceDestroy when entity flag bit 4 of +0x6e is set, leaving the orientation UNCHANGED).

This is that look. No capture - every fact comes from fixtures already committed.

The split that settles it

Every secondary removal - a cell the cascade took that nothing killed directly - classified by whether the game also destroyed the root of its chain:

root kill removals wrong
the game destroyed it too 27 0
the game KEPT it (our false rejection) 2 2

Conditional on a correct root, the cascade's precision is 1.000. Both disagreements descend from a kill that was already wrong, and the two rows account for the entire falseAfter - falseBefore increment.

cell placed = game orientation root root reason root kept by the game
1 (1318, 2618.5) none-to-south (1318, 2622.5) ore yes, north-to-east
2 (3134, 3002.5) north-to-none (3134, 2998.5) lava yes, east-to-south

One ore, one lava, so this is not a single rule's precision problem. Both roots survive in the game carrying the orientation we placed them at, so neither was trimmed either - they were not touched at all.

What it does to #134's gate, and to the adoption decision

The gate is UNSUPPORTED here rather than refuted: there is nothing left in this sample for it to explain. A cascade that force-destroys every single-ended neighbour reproduces the game exactly, 27 times out of 27, whenever it is fed a correct kill.

So the net-8 gain's cost is not intrinsic. Adopting the cascade makes the port worse at nothing - it makes two existing precision defects visible at two extra cells, and fixing either root removes its knock-on for free. That is a materially different decision from the one #143 recorded.

The control that nearly inverted the result

Cell 2's root sits at y = 2998.5, outside its region's y0 = 3000. Tested against the region-filtered game set it reads as "the game destroyed it" - which would have made that cell a genuine cascade defect and halved the finding. The root check therefore runs against the unfiltered dump, which carries cliffs beyond the region and does contain it. Same family as the clamped comparison #139 hit.

Note what the orientations do not prove: both surviving cells are single-ended, so "kept unchanged" is the only alternative to "destroyed" - there is no third state to observe. The unchanged orientation is consistent with the gate without being evidence for it. The root check is what carries the argument, and the spec says so.

Coverage, planted rather than claimed

planted into the cascade this spec
the neighbour loop never runs fails 4
every trim destroys (next = -1) fails 4 - 908 false after, not 14
the isCliffConnected parity guard is dropped PASSES

That last row is a real gap, recorded in the spec rather than left implicit. destroyEnd is already a no-op on a side the orientation lacks, so the guard only bites when a neighbour presents the facing side with the wrong parity, and no cell in these 14 regions does. A green run here is not evidence for the parity rule; test/cliffConnections.spec.ts pins that from the orientation tables.

Where #84 stands now

The open question is unchanged in kind but smaller: the residual is still 31 destruction decisions, the border enrichment still survives both deflations (#134, #143), and the ore recall gap is still the six cells of #142. What has closed is the objection blocking the shipping gain.

Verification

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

🤖 Generated with Claude Code

https://claude.ai/code/session_01HKjzpWJw1HbnigPP9udqN2

…ects (#84)

#143 priced the destruction cascade as a net +8 shipping gain - 10 fewer missed
cells for 2 more false rejections - and left it untaken with an explicit
instruction: look at the 2 new false rejections before the 10 wins, because #134
recorded a gate the port does not model. This is that look. Zero capture.

Splitting every SECONDARY removal - a cell the cascade took that nothing killed
directly - by whether the game also destroyed the ROOT of its chain:

  root the game destroyed too   27 removals, 0 wrong
  root the game KEPT            2 removals, 2 wrong

Conditional on a correct root the cascade's precision is 1.000. Both
disagreements descend from a kill that was already wrong - (1318,2618.5) from an
ORE false rejection, (3134,3002.5) from a LAVA one - so it is not one rule's
problem, and the two account for the entire falseAfter - falseBefore increment.

Both roots survive in the game carrying the orientation we placed them at, so
neither was trimmed either. #134's gate is therefore UNSUPPORTED here rather
than refuted: nothing is left in this sample for it to explain.

Consequence for adoption: the net-8 gain's cost is NOT intrinsic. Adopting the
cascade makes the port worse at nothing; it makes two existing precision defects
visible at two extra cells, and fixing either root removes its knock-on free.

The control that nearly inverted this: cell 2's root sits at y=2998.5, OUTSIDE
its region's y0=3000. Tested against the region-filtered game set it reads as
"the game destroyed it", which would have made that cell a genuine cascade
defect and halved the finding. The root check runs against the UNFILTERED dump,
which does contain it.

Coverage, planted rather than claimed: cascade never fires -> fails 4; every trim
destroys -> fails 4 (908 false after, not 14); dropping the isCliffConnected
parity guard -> PASSES. That last is a real gap - destroyEnd is already a no-op
on a side the orientation lacks, so the guard only bites on a wrong-parity facing
side and no cell in these 14 regions has one. Recorded in the spec so a green run
is not read as covering the parity rule.

Verified: pnpm run verify green - 1562 app (up 4) + 13 worker + 3 container,
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_01HKjzpWJw1HbnigPP9udqN2
@wormeyman
wormeyman merged commit 5f0250d into main Aug 4, 2026
6 checks passed
@wormeyman
wormeyman deleted the cliffs-cascade-false-rejections branch August 4, 2026 20:05
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