Skip to content

test(cliffs): four of the ten ore remainders are the onDestroy CASCADE (#84) - #125

Merged
wormeyman merged 1 commit into
mainfrom
test/ore-remainder-is-the-ondestroy-cascade
Aug 4, 2026
Merged

test(cliffs): four of the ten ore remainders are the onDestroy CASCADE (#84)#125
wormeyman merged 1 commit into
mainfrom
test/ore-remainder-is-the-ondestroy-cascade

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

vulcanusOreRejection.ts records box overlap as explaining 21 of the 31 cells the ore suppresses, the other ten as "run remainders", and the cascade half of that question as REFUTED.

That refutation is about a different cascade. It tested #108's crossing-stage mechanism - a rejection zeroes the cell's edge registers, a neighbour's code changes, re-test to a fixpoint - and its conclusion ("rejected cells do not turn neighbours rejectable") still stands.

The applyCliffs cascade is a different thing: Cliff::onDestroy takes the facing end of every connected neighbour, and a neighbour left with no end at all is destroyed outright. It was read out of the binary in #113, after #110 ran, and nothing had re-run the remainder question against it.

Replayed entirely on the game's own data

Nothing of the port's field, ore model or geyser roll appears in this measurement:

  • start from the game's ALL resources OFF cliff set - 892 cells with the game's own orientations
  • destroy the cells whose base collision box overlaps one of the game's own resource entity positions, at the prototype half-extents the fixture itself carries
  • compare against the game's resources ON set - 861 cells
arm matched wrong surplus
control - destroy the lever's own 31 861 0 0
direct overlap only, no cascade 856 5 10
direct overlap + onDestroy cascade 859 2 6
  • Direct overlap fires on 21 cells and every one is in the lever's 31 - precision 1.000, re-derived with no data of ours.
  • The cascade closes 4 of the 10 remainders and 3 of the 5 orientation errors.
  • Recall 21/31 = 0.677 → 25/31 = 0.806, with no new parameter and no wider box.
  • missing is 0 in both arms, so no cell the game kept is ever removed. That is what separates a mechanism from a bigger rectangle - a box wide enough to reach those four would also reach cells the game kept, and test(cliffs): the ore rule is NOT entity collision, and it acts at the destroy stage (#84) #124 established the box is not the engine's collision test to begin with.

The control is load-bearing, and so is one flag

The control says the ore-off world minus those 31 cells is the ore-on world, orientations included. Without it none of the other rows mean anything.

Getting it exact needs noUpdateConnections: true: the game's dumped set is POST-pipeline, so running updateConnections over it again double-applies the pass and trims ends that legitimately survived. Forget it and the control scores wrong = 13 - which reads like a defect in the cascade model and is an artifact of the harness. Any future experiment that starts from a dumped set rather than from our own queue has the same hazard, so it is written down.

The six that remain

1546,1550.5  1546,1554.5  1606,1590.5  1606,1594.5  1622,1614.5  1626,1614.5

Two are the pair #123 attributed to the geyser, and 1546,1550.5 is the one cell in this entire residual whose destruction the game's own orientations directly witness (#124's n=1). So the best-evidenced destruction in the whole investigation is still unexplained by any rule.

What this does NOT change

Nothing shipping. The renderer rejects at the crossing stage and does not run applyCliffConnections at all - see ## The queue has a CONSUMER for why that is deliberate. This is a statement about the RULE and about which of its remainders now have a mechanism. The stale "cascade REFUTED" line in vulcanusOreRejection.ts is corrected in place rather than left to mislead.

Verification

pnpm run verify green - 1465 app (up 4) + 13 worker + 3 container tests, 0 warnings, exit 0.

🤖 Generated with Claude Code

https://claude.ai/code/session_015jeznBmWiZywUc7cBw9xFU

#84)

`vulcanusOreRejection.ts` records box overlap as explaining 21 of the 31 cells
the ore suppresses, the other ten as "run remainders", and the cascade half of
that question as REFUTED.

That refutation is about a DIFFERENT cascade. It tested #108's crossing-stage
mechanism - a rejection zeroes the cell's edge registers, a neighbour's code
changes, re-test to a fixpoint - and its conclusion ("rejected cells do not turn
neighbours rejectable") still stands. The `applyCliffs` cascade is
`Cliff::onDestroy` taking the facing end of every connected neighbour and
destroying a neighbour left with no end at all. It was read out of the binary in
#113, AFTER #110 ran, and nothing had re-run the remainder question against it.

Replayed entirely on the game's own data - its ore-off cliff set (892 with the
game's orientations), its resource entity positions, the prototype boxes the
fixture itself carries - so none of the port's field, ore model or geyser roll
appears in the measurement:

| arm                                  | matched | wrong | surplus |
| ---                                  | ---     | ---   | ---     |
| control - destroy the lever's own 31 | 861     | 0     | 0       |
| direct overlap only, no cascade      | 856     | 5     | 10      |
| direct overlap + onDestroy CASCADE   | 859     | 2     | 6       |

- Direct overlap fires on 21 and every one is in the lever's 31 - precision
  1.000 re-derived with no data of ours.
- The cascade closes 4 of the 10 remainders and 3 of the 5 orientation errors.
  Recall 21/31 = 0.677 -> 25/31 = 0.806, no new parameter, no wider box.
- `missing` is 0 in both arms, so no cell the game kept is ever removed. That is
  what separates a mechanism from a bigger rectangle - and #124 established the
  box is not the engine's collision test to begin with.

The control validates the harness, and getting it exact needs
`noUpdateConnections: true`: the game's dumped set is POST-pipeline, so running
`updateConnections` over it again double-applies the pass and scores wrong=13,
which reads like a defect in the cascade model and is an artifact of the
harness. Any experiment starting from a dumped set has the same hazard.

Six remain: 1546,1550.5 1546,1554.5 1606,1590.5 1606,1594.5 1622,1614.5
1626,1614.5. Two are the geyser pair, and the first is the one cell in this
whole residual whose destruction the game's own orientations directly witness
(#124's n=1) - so the best-evidenced destruction is still unexplained.

Measurement only - the renderer rejects at the crossing stage and does not run
`applyCliffConnections` at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jeznBmWiZywUc7cBw9xFU
@wormeyman
wormeyman merged commit 961a6fb into main Aug 4, 2026
6 checks passed
@wormeyman
wormeyman deleted the test/ore-remainder-is-the-ondestroy-cascade branch August 4, 2026 00:49
wormeyman added a commit that referenced this pull request Aug 4, 2026
…count is 14 (#84) (#126)

Everything the last three PRs established about the ore rule was measured on
[1500,1500], because that is the only region
`oracle-vulcanus-cliff-ore-direction` re-runs with the resources off. A rule
characterised on one region and never tested on another is fitted until proven
otherwise, so the lever was captured for the two regions the entities fixture
covers and it never did.

| region        | resources        | ON  | OFF | suppressed |
| ---           | ---              | --- | --- | ---        |
| [0,0]         | 945 tungsten-ore | 283 | 283 | 0          |
| [-1200,800]   | 1047 coal        | 387 | 387 | 0          |

- PRECISION 1.000 SURVIVES. Our predicate fires on zero cells in both regions,
  so 1992 resource entities across two fresh regions produce no false positive.
  This is the arm that would have caught a rule fitted to [1500,1500].
- THE UNEXPLAINED POPULATION IS 14, NOT 11. #123 could only park `106,26.5`,
  `90,38.5` and `-1050,1022.5` as undetermined because the lever's region did
  not cover them. It does now, and the ore suppresses nothing there.
- Re-confirms #110's attribution - 27 calcite, 4 geyser, 0 tungsten and coal -
  at far larger scale than the arm that produced it.

The non-vacuity check is in the fixture rather than argued: "0 suppressed" is
also what a lever that never reached the generator prints, and the OFF arms read
back 0 resources against 945 and 1047.

What this does NOT establish: neither region contains calcite or a geyser, the
only two controls that suppress anything. So this is a PRECISION test, not a
recall test - the rule's positive evidence is still one region, and #125's
cascade result is still measured on [1500,1500] alone. Breaking the rule would
need a region with calcite in it, and the oracle set has none.

New fixture is deliberately separate from `oracle-vulcanus-cliff-ore-direction`
so regenerating it cannot rewrite ground truth four merged PRs depend on.
PROVENANCE entry added.


Claude-Session: https://claude.ai/code/session_015jeznBmWiZywUc7cBw9xFU

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
wormeyman added a commit that referenced this pull request Aug 4, 2026
…for cliffs (#84) (#128)

Every ore result in #84 uses one instrument: switch a resource off through
`map_gen_settings.autoplace_controls` and see which cliffs come back, treated
throughout as removing entities and nothing else. It does more, and the game's
data files say so:

  vulcanus_calcite_size   = slider_rescale(control:calcite:size, 2)
  vulcanus_calcite_region = ... vulcanus_calcite_size ..., control:calcite:frequency ...
  volcanic_jagged_ground_range = 5 * min(10, max(vulcanus_calcite_region + 0.2, ...))

That last one is a TILE range, so `calcite size = 0` changes which tile the
argmax picks - a live route from the lever to `Surface::wouldCollide`'s tile
half, exactly the kind #124 was left looking for after closing the entity half.

Measured against the GAME, three arms over [1500,1500] on a uniform stride-2
grid of 16384 points:

| arm               | tiles changed | blocking gained | blocking lost |
| ---               | ---           | ---             | ---           |
| calcite OFF       | 841 (5.1%)    | 0               | 0             |
| ALL resources OFF | 1066          | 0               | 0             |

Every change is ground-to-ground - jagged-ground losing the argmax to folds,
folds-warm, soil-dark, soil-light, folds-flat. Nothing crosses the
lava/lava-hot boundary, so `constCollideWithTile` cannot see any of it and
EVERY ORE RESULT IN #84 STANDS. But the instrument was mischaracterised, and
anyone using `autoplace_controls` for a new question needs to know it moves
tiles.

Non-vacuity: 1682 of the 16384 sampled tiles ARE blocking, so there was a
boundary to cross, and each arm records the controls the SURFACE read back.

Our port reproduces it - 3335 of 65536 changed, 0 blocking, a rate of 5.09%
against the game's 5.13%. That corroborates the port on a lever nobody had
pointed at it, and is what lets its "no blocking flip anywhere" cover the 75%
of tiles the grid skipped. Control: tungsten OFF moves zero tiles here, because
there is no tungsten in this region.

WHERE THIS LEAVES THE MECHANISM - a three-way contradiction, recorded rather
than smoothed over. Both halves of `Surface::wouldCollide` are now closed
against the ore (entity by #124, tile here), yet #124 also found the ore acting
at the destroy stage, where `wouldCollide` is the only thing that destroys. All
three cannot be right. Ranked by corroboration, the destroy-stage result is
weakest at n=1 - and its one cell, `1546,1550.5`, is also one of the six #125's
cascade does not explain, so it has been anomalous twice.

Harness: `sampleTileNames` gains an `autoplaceControls` override and a
`sampleTileNamesFull` sibling returning the controls the surface read back.
New fixture + PROVENANCE entry; capture takes ~7s.


Claude-Session: https://claude.ai/code/session_015jeznBmWiZywUc7cBw9xFU

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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