Skip to content

test(cliffs): the blob is ORE - item 2 of #84 is #24 - #94

Merged
wormeyman merged 1 commit into
mainfrom
cliff-ore-exclusion
Aug 2, 2026
Merged

test(cliffs): the blob is ORE - item 2 of #84 is #24#94
wormeyman merged 1 commit into
mainfrom
cliff-ore-exclusion

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

The handoff into this session named "the blob" the sharpest open lead in #84: a contiguous patch in region [0,0] where the game places no cliff whatever cliff_elevation is routed onto it, on the reasoning that a bounded, field-independent hole cannot be a field error and must be a rule the port does not implement at all.

That reasoning holds. The rule is ore exclusion - the patch is a tungsten-ore field.

The measurement

game port
cliffs whose 4x4 cell contains ore 3 of 1,569 29
of the port's 45 surplus cells - 26 on ore, all at [1500,1500]
the collapsed arms' blob 0 10 of 10 on ore

The blob is the same ten cells in all four collapsed arms - gate forced open and gate real, single contour and real bands. A set invariant to both the band structure and the gate cannot be a field or a cliffiness effect.

Scope note: at real settings the port places nothing in the blob ([0,0] scores 283/283, 2 surplus, 2 missed, neither in it). The blob is only reachable when a sweep forces a contour through the ore field; the ore rule costs accuracy only at [1500,1500].

What it is not - each measured, not read

  • Not lava. 2,597 surface.get_tile samples from the game over x 160..208, y 124..176, 0 lookup misses: the blob's interior is volcanic-cracks-* with no lava at all. The standing "not lava" claim had been made with our resolver - the component it needed to exonerate, and one known to miss lava the game has.
  • Not any other tile. cliff-vulcanus's collision mask, read off a running game: cliff, is_lower_object, is_object, item, meltable, object, player, water_tile. Of the 18 Vulcanus tiles only lava/lava-hot share a layer. VULCANUS_CLIFF_BLOCKING_TILES is now measured, not deduced from tile_collision_masks.lava().
  • Not the cliffiness gate. 0 flips over all 24,960 captured edges, scored as the binary crossesCliff reads (avg(corners) > 0.5) rather than as a value. Two thirds of those corners sit on a clamp, which is what made the old value comparison vacuous - but a clamped corner is not vacuous for a threshold, it is exactly where a small error flips it.
  • Not entity collision - though ruling it out turned up a real unported rule. applyCliffs (0x101623c98) re-tests every accepted cliff through Surface::wouldCollide (0x10160c088), which calls collideWithEntity as well as constCollideWithTile; the port implements only the task-level, tile-only wouldCollide. Ore carries the bare resource layer so it cannot be what that rejects - but big-volcanic-rock, huge-volcanic-rock and crater-cliff do collide, and none of it is ported.

The mechanism of the exclusion is still open: it is not a collision, so it is either an ordering effect in EntityMapGenerationTask (generateCliffs runs before generateEntities, so the direction may be that ore avoids cliffs) or something in resource_autoplace. Settling the direction comes before adding any rejection.

Correction to the issue's headline

37 / 1531 = 2.4% is the arm with no lava rejection. With the rejection renderVulcanusCliffs actually applies it is 33 wrong of 1,525 matched, 45 over-placed, 6 missed. Both arms are now pinned so they cannot be confused again.

No src change - this is evidence, not a fix. pnpm run verify green (1,336 tests).

🤖 Generated with Claude Code

https://claude.ai/code/session_01T4Q2ep3HJSjkyWddMSYj4Y

The handoff named "the blob" the sharpest open lead in #84: a contiguous
patch in region [0,0] where the game places no cliff whatever
cliff_elevation is routed onto it, on the reasoning that a bounded,
field-independent hole cannot be a field error and must be a rule the
port does not implement. That reasoning holds and the rule is ore
exclusion - the patch is a tungsten-ore field.

Measured over the three oracle regions:

  - the game puts a cliff on ore 3 times in 1,569; the port, 29
  - 26 of the port's 45 surplus cells sit on ore, all at [1500,1500]
  - the collapsed arms' blob is 10 cells, ALL on ore, and the SAME ten
    in all four arms - gate open and gate real, single contour and real
    bands - so it cannot be a field or cliffiness effect

Ruled out first, each by measurement rather than reading:

  - not lava: 2,597 surface.get_tile samples from the game over the blob
    (0 lookup misses) are volcanic-cracks-* with no lava at all. The
    standing "not lava" claim had used OUR resolver, the component it
    needed to exonerate.
  - not any other tile: cliff-vulcanus's mask, read off a running game,
    is cliff/is_lower_object/is_object/item/meltable/object/player/
    water_tile, and only lava + lava-hot of the 18 Vulcanus tiles share
    a layer. VULCANUS_CLIFF_BLOCKING_TILES is now measured, not deduced.
  - not the cliffiness gate: 0 flips over all 24,960 captured edges,
    scored as the BINARY crossesCliff reads (avg of the two corners
    > 0.5) rather than as a value. Two thirds of those corners sit on a
    clamp, which made the old value comparison vacuous - but a clamped
    corner is not vacuous for a THRESHOLD, it is where a small error
    flips it.
  - not entity collision, though ruling it out found a real unported
    rule: applyCliffs re-tests every cliff through Surface::wouldCollide
    (0x10160c088), which calls collideWithEntity as well as
    constCollideWithTile. Ore carries only the `resource` layer so it
    cannot be what that rejects - but big/huge-volcanic-rock and
    crater-cliff do collide, and none of it is ported.

The mechanism of the exclusion is still open: it is not a collision, so
it is either an ordering effect in EntityMapGenerationTask or something
in resource_autoplace. Settling the direction comes before adding any
rejection.

Also corrects the issue's headline. "37 of 1531 = 2.4%" is the arm with
NO lava rejection; with the rejection renderVulcanusCliffs actually
applies it is 33 wrong of 1,525 matched, 45 over-placed, 6 missed. Both
arms are pinned so they cannot be confused again.

No src change - this is evidence, not a fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4Q2ep3HJSjkyWddMSYj4Y
@wormeyman
wormeyman merged commit 7a2bff2 into main Aug 2, 2026
2 checks passed
wormeyman added a commit that referenced this pull request Aug 2, 2026
…#84)

#94 ruled out lava, every other tile, the cliffiness gate and entity collision,
then handed the mechanism over open: the cliff/ore correlation fits two stories
demanding opposite fixes, and the note closed "settle the direction, not add a
rejection."

Settled with a lever rather than an argument. `autoplace_controls` is settable
on the surface exactly like `cliff_settings`, so the resources can be switched
off (`size = 0`) and the same regions regenerated - #82's collapse trick pointed
one subsystem over.

| arm | cliff-vulcanus | resources |
| --- | --- | --- |
| `[1500,1500]` resources ON | 885 | 3,933 |
| `[1500,1500]` calcite OFF | 912 | 19 |
| `[1500,1500]` geyser OFF | 889 | 3,914 |
| `[1500,1500]` ALL OFF | 916 | 0 |
| `[0,0]` collapsed, ON | 335 | 945 |
| `[0,0]` collapsed, ALL OFF | **345** | 0 |

**Both arms, not one.** Ore off puts a cliff in all ten blob cells, 0/10 ->
10/10. The converse arm is what makes it a direction: the collapsed settings
force 335 cliffs through the region against the default's 283, straight through
the tungsten field, and the ore does not move - the same 945 entities.

Three properties, each constraining the mechanism: it is ONE-WAY (removing a
resource only ever adds cliffs, in all four paired arms), ADDITIVE (27 calcite +
4 geyser = exactly the 31 of all-off, disjoint), and LOCAL with a geometry that
is a BOX OVERLAP against the resource ENTITY's rectangle - measurable only
because the geyser's collision half-extent is 1.398 against the ores' 0.098,
which is why every point-at-tile-centre geometry scored 20-27 of 31. Scored as
box overlap: 21 of 31 explained, ZERO false alarms in 885, and all six connected
components of the suppressed set contain a directly-overlapped cell (adjacency
is not a free pass - only 8 of 885 kept cliffs touch one).

Worth 31 of the 42 cells the port over-places at `[1500,1500]`: every one of the
31 is a cell the port places and none is a cliff the game kept, so the rule is
pure precision.

Still not a collision, now doubly established. The mask argument stands and the
fixture carries the layers rather than a claim about them. The disassembly says
it more strongly: `computeInternal` (0x101622860) calls `generateCliffs` at +44
and `generateEntities` at +148; `apply` (0x101623b48) calls `applyCliffs` at
+124 and `applyEntities` at +164 - the cliffs are computed AND placed before any
resource exists, which also refutes #94's "maybe ore avoids cliffs" guess.

Harness: `sampleCliffEntitiesFull` gains `autoplaceControls`, `alsoResources`
and `protoNames`, dumping cliffs, resources, prototype collision geometry and
the controls the SURFACE read back from ONE generated surface - so an override
that failed to apply cannot be mistaken for a term that does not matter, and
"the ore moved" and "the cliffs moved" are never compared across two worlds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LT6oy76sLRqoC1QzLocQ1h
wormeyman added a commit that referenced this pull request Aug 2, 2026
…#84) (#99)

#94 ruled out lava, every other tile, the cliffiness gate and entity collision,
then handed the mechanism over open: the cliff/ore correlation fits two stories
demanding opposite fixes, and the note closed "settle the direction, not add a
rejection."

Settled with a lever rather than an argument. `autoplace_controls` is settable
on the surface exactly like `cliff_settings`, so the resources can be switched
off (`size = 0`) and the same regions regenerated - #82's collapse trick pointed
one subsystem over.

| arm | cliff-vulcanus | resources |
| --- | --- | --- |
| `[1500,1500]` resources ON | 885 | 3,933 |
| `[1500,1500]` calcite OFF | 912 | 19 |
| `[1500,1500]` geyser OFF | 889 | 3,914 |
| `[1500,1500]` ALL OFF | 916 | 0 |
| `[0,0]` collapsed, ON | 335 | 945 |
| `[0,0]` collapsed, ALL OFF | **345** | 0 |

**Both arms, not one.** Ore off puts a cliff in all ten blob cells, 0/10 ->
10/10. The converse arm is what makes it a direction: the collapsed settings
force 335 cliffs through the region against the default's 283, straight through
the tungsten field, and the ore does not move - the same 945 entities.

Three properties, each constraining the mechanism: it is ONE-WAY (removing a
resource only ever adds cliffs, in all four paired arms), ADDITIVE (27 calcite +
4 geyser = exactly the 31 of all-off, disjoint), and LOCAL with a geometry that
is a BOX OVERLAP against the resource ENTITY's rectangle - measurable only
because the geyser's collision half-extent is 1.398 against the ores' 0.098,
which is why every point-at-tile-centre geometry scored 20-27 of 31. Scored as
box overlap: 21 of 31 explained, ZERO false alarms in 885, and all six connected
components of the suppressed set contain a directly-overlapped cell (adjacency
is not a free pass - only 8 of 885 kept cliffs touch one).

Worth 31 of the 42 cells the port over-places at `[1500,1500]`: every one of the
31 is a cell the port places and none is a cliff the game kept, so the rule is
pure precision.

Still not a collision, now doubly established. The mask argument stands and the
fixture carries the layers rather than a claim about them. The disassembly says
it more strongly: `computeInternal` (0x101622860) calls `generateCliffs` at +44
and `generateEntities` at +148; `apply` (0x101623b48) calls `applyCliffs` at
+124 and `applyEntities` at +164 - the cliffs are computed AND placed before any
resource exists, which also refutes #94's "maybe ore avoids cliffs" guess.

Harness: `sampleCliffEntitiesFull` gains `autoplaceControls`, `alsoResources`
and `protoNames`, dumping cliffs, resources, prototype collision geometry and
the controls the SURFACE read back from ONE generated surface - so an override
that failed to apply cannot be mistaken for a term that does not matter, and
"the ore moved" and "the cliffs moved" are never compared across two worlds.


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

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