Skip to content

test(cliffs): two LEVERS - no entity suppresses a cliff, lava is 166/169 (#84) - #111

Merged
wormeyman merged 1 commit into
mainfrom
cliffs/suppressor-levers
Aug 3, 2026
Merged

test(cliffs): two LEVERS - no entity suppresses a cliff, lava is 166/169 (#84)#111
wormeyman merged 1 commit into
mainfrom
cliffs/suppressor-levers

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

#110 handed over "find a lever that isolates the non-ore suppressor the way autoplace_controls isolated the ore", with the suspect unnamed. This adds two, through map_gen_settings.autoplace_settings - a knob autoplace_controls cannot reach, because a control only touches prototypes that name one, and the rocks, the chimneys and crater-cliff name none.

No placed entity suppresses a Vulcanus cliff

Switching the whole entity category off removes every autoplaced entity in the region - 409 rocks, 115 chimneys, 45 rock explosions and all 8 crater-cliffs - and the cliff set does not move by one cell: same 916 cells, same orientations, bit for bit.

Rocks were previously refuted only statistically, against the port's own rock model (#109). This is the whole class, with the lever's own proof in the same run three ways: autoplace_settings read back off the surface, the 569 entities that vanished, and the crater ring that went with them. The vacuity arm runs the other way too - cliff-vulcanus comes from cliff_settings, so it must survive the lever, and it does.

crater-cliff is worth a line of its own: a real Vulcanus feature the port does not model, and every spec's name === "cliff-vulcanus" filter had been discarding it (the #94 trap). It is not the residual - the whole ring is 47 to 180 tiles from the nearest disputed cell.

Cliffs do not collide with each other

Refuted by the game's own output rather than by a model: 293 pairs of its own cliffs have overlapping collision rectangles.

The lava lever, and the rejection's first precision/recall

Dropping lava/lava-hot from the tile category leaves the elevation the crossings read untouched and takes away the only thing the tile test can reject against.

lava tiles in region, on / off 6709 / 0
game cells, lava on / off 892 / 1058
cells lava suppresses 169
our rejection fires on 171, true 166
precision 0.9708, recall 0.9822

Its errors are the residual, not a scatter. With 1,058 cells to be wrong about, all 8 land inside the 26 the port already disputes: the 3 it misses are 3 of the 10 surplus cells, and the 5 it invents include all 3 of the port's missing ones. They point both ways, which a uniformly-too-small or too-big box cannot produce - the shape is wrong, not the size, so it is left measured and unfixed per #88.

The sharpest statement of the residual there has been

matched wrong surplus missing
[1500,1500], no ore, no lava 1049 9 12 0

Recall 1.0000. The crossing field plus the repair produce a strict superset of the game's cells, so everything left is over-placement, and the two rejections are the only things that can remove one.

What led here

Gap from each cell's collision box to the nearest lava tile, against the matched cells as control:

population n lava within 2 tiles
matched (control) 876 9 = 1.0%
surplus 10 4 = 40%
wrong 13 5 = 38%

A 40x enrichment - kept with two cautions: the effective sample size is 4 clusters, not 23 cells, and one cluster has no lava within 10 tiles. The lever confirms that reservation.

pnpm run verify green (1399 tests).

🤖 Generated with Claude Code

https://claude.ai/code/session_015C8AbtvYMdc7ed3rnAZbhP

…169 (#84)

#110 asked for a lever that isolates the non-ore suppressor the way
`autoplace_controls` isolated the ore, with the suspect unnamed. This adds
two, through `map_gen_settings.autoplace_settings` - a knob
`autoplace_controls` cannot reach, since a control only touches prototypes
that name one and the rocks, chimneys and `crater-cliff` name none.

**No placed entity suppresses a Vulcanus cliff.** Switching the whole
`entity` category off removes 409 rocks, 115 chimneys, 45 rock explosions
and all 8 `crater-cliff`s, and the cliff set does not move by one cell.
Rocks were previously refuted only statistically against our own rock
model (#109); this is the class excluded positively, with the lever's own
proof in the same run three ways.

**Cliffs do not collide with each other**, refuted by the game's own
output rather than a model: 293 pairs of its own cliffs have overlapping
collision rectangles.

**Lava suppresses 169 cells and our rejection gets 166, with 5 false
positives** - precision 0.9708, recall 0.9822, the first real score that
rule has had. Its errors ARE the residual: the 3 it misses are 3 of the 10
surplus cells and the 5 it invents include all 3 of the port's missing
ones. They point both ways, so the box's shape is wrong rather than its
size - left measured and unfixed, per #88.

**With neither ore nor lava, recall is 1.0000** (1049 matched, 9 wrong, 12
surplus, 0 missing of 1058). The port produces a strict superset of the
game's cells, so everything left is over-placement and the question is now
what else the game refuses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015C8AbtvYMdc7ed3rnAZbhP
@wormeyman
wormeyman merged commit 774ceed into main Aug 3, 2026
2 checks passed
@wormeyman
wormeyman deleted the cliffs/suppressor-levers branch August 3, 2026 18:55
wormeyman added a commit that referenced this pull request Aug 3, 2026
…ips (#84) (#112)

`cliffErrorBudget.spec.ts`'s constant named `SHIPPED` did not set
`rejectAtCrossingStage`, which landed in `renderVulcanusCliffs.ts` with #108.
So the file pinned the pre-#108 model - 25 surplus and precision 0.9839 -
while the shipping path was at 22 and 0.9858, and it is the file people read
for "current accuracy".

The port is unchanged; only the measurement was wrong. Corrected figures over
the same three oracle regions:

| | position only | position AND orientation |
| --- | --- | --- |
| recall | 0.9961 (1525/1531) | 0.9824 (1504/1531) |
| precision | 0.9858 (1525/1547) | 0.9722 (1504/1547) |

1504 matched, 21 wrong orientation, 22 surplus, 6 missing.

Also in this file:

- `SHIPPED` now carries a comment saying it must mirror the renderer's call,
  naming this drift as the reason.
- The "precision is the dominant defect" guard goes from `x4` to `x3`, because
  the gap narrowed by #108 removing 3 surplus cells and no missing ones - the
  improvement working, not a weakened test.
- The entity-collision block said item 3 was OPEN and "rocks are the lead".
  #111 closed it with a lever, so the block is retitled and points there; its
  two arms are kept as independent corroboration, and the one statistic in
  them that was measured at 25 surplus is marked as history rather than
  silently re-quoted.

Same treatment for two other stale quotes: the NOTES banner people are told to
read before quoting an accuracy number, and a prose figure in
`cliffPhantomNeighbour.spec.ts` (whose assertions run with rejections off and
do not depend on it).


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

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

#114 reduced the residual to 31 destruction disagreements and handed over one
question: Surface::wouldCollide runs constCollideWithTile against the REAL
surface while the port resolves tiles from our own Vulcanus model, so a
disagreement between the two inside a cliff's box would produce exactly this
two-sided error set. It read as needing a new capture. It needed none.

The tile half is exonerated for all 6 false rejections.
oracle-vulcanus-lava-boundary is a committed 994-position dense capture of
surface.get_tile(x, y).name, taken for a different question back when the
collision box was the defect, and it covers every tile of all six boxes: 70 of
70 covered, ZERO disagreements, both directions. The game read the same lava we
do and placed the cliff anyway. Vacuity arms included, because "0 mismatches" is
also what a comparison that never ran would print.

A second candidate died in factorio-data rather than in a capture:
tiles-vulcanus.lua gives 17 tiles ground() and exactly 2 - lava and lava-hot -
lava(), so VULCANUS_CLIFF_BLOCKING_TILES is provably complete.

The 25 in the other direction do NOT share a cause. By Chebyshev distance from
each box to the nearest tile our own model calls lava, scored against the 1525
cells the port gets right so there is a base rate:

  within 2 tiles   missed 9 (36%)   matched 52 (3.4%)
  4 to 11 tiles    missed 6         matched 436
  none within 12   missed 10        matched 1037

The near group is enriched 10.5x - the signature of a boundary or a box a tile
short. But ten of the 25 have no lava within twelve tiles, so no adjustment to a
lava collision box can reach them; neither can the ore rule (all 25 are
ore=false) nor any entity (#111's lever moved zero cliffs). They also cluster
where the near group does not.

So the handover framing was too narrow: "which cells does wouldCollide reject
that ours does not" is the right question for at most 15 of the 25 and for none
of the 6. Fitting one box to all 31 would be fitting a rule to two causes at
once, which is the failure #88 exists to record.

Refuted on the way, and recorded so nobody re-derives it: cliff-versus-cliff
collision. Attractive because applyCliffs adds each cliff to the surface right
after testing it, and because #111's autoplace_settings lever cannot remove
cliffs - so this is the one case that lever never covered. It dies on the base
rate: 9 of the far 10 overlap another cliff's rotbb box, and so do 1405 of the
1531 cliffs the game KEEPS (91.8%). Independently, the cliff prototype's generic
collision_box is {{-0.99,-0.49},{0.99,0.49}} - "intentionally small" - and cliff
cells sit on a 4-tile grid, so generic boxes cannot overlap at all.

Nothing shipping changes; this is measurement only.


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

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

#130 proposed a mechanism class new to #84 - entity autoplace ROLLS, so removing
calcite shifts the per-chunk RNG stream - and said "nothing here tests it".
This is that test. No capture: every fact is in fixtures already committed, one
of them since #111.

The hypothesis is not refuted. The evidence for it is.

1. **n is ONE crater, not eight.** The eight `crater-cliff` entities are eight
   segments of a single ring - centre (1646.62, 1679.75), radii 4.95 to 7.00,
   against the prototype's own `crater_radius = 7`. FFF #386 describes exactly
   that. Effective sample size 1; #130's table invites reading it as 8.

2. **The spatial reading would have been vacuous.** All eight sit within 0.33
   tiles of a calcite entity - and their chunk holds 805 calcite over 1024
   tiles, 78.6% coverage. Landing on calcite there is expected.

3. **#130's `geyser OFF` control is VACUOUS.** Zero geysers in the ring's chunk;
   all 19 are in (48,48), (48,49), (53,54). The lever works globally - removes
   all 19, moves cliff-vulcanus 885 -> 889 - and cannot touch that chunk's
   stream by construction.

4. **A lever unrelated to calcite also produces craters**, unread in the #111
   fixture: `LAVA TILES OFF only` gives 7 craters with resources still ON, and
   both levers together give 18 against 8 and 7 alone.

5. **And that row is a data fact.** `crater-cliff` overrides the default cliff
   mask with `{item, object, player, water_tile}`, and on Vulcanus only lava and
   lava-hot carry `water_tile`. No RNG needed.

Calcite's own route stays open, with two more closed by reading rather than
assuming: not entity collision (`resource` mask is `{resource}`, disjoint from
every cliff mask including crater-cliff's - #124's argument extended rather than
carried over), and not lava tiles (#128 measured zero blocking tiles moved).

A third fact from the same file closes a route this session had to consider: the
default `cliff` mask carries `not_colliding_with_itself = true`, so cliffs never
collide with same-prototype cliffs. That matters because `applyCliffs` adds each
cliff to the surface before testing the next, and 57 of 400 adjacent orientation
pairs have overlapping boxes.

No new fixtures, no shipping behaviour change.


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

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