Skip to content

test(cliffs): collapse the rule term by term - #18 is in the FIELD, not the placement - #81

Merged
wormeyman merged 1 commit into
mainfrom
cliffs-collapse-rule-field-18
Aug 2, 2026
Merged

test(cliffs): collapse the rule term by term - #18 is in the FIELD, not the placement#81
wormeyman merged 1 commit into
mainfrom
cliffs-collapse-rule-field-18

Conversation

@wormeyman

Copy link
Copy Markdown
Owner

Answers "will messing with the other cliff prototypes help?"

The cliff entity prototype: no. The crossing pass reads only grid_size/grid_offset off it, and the fixture already proves both - all 1569 cliffs land exactly on (cx*4+2, cy*4+2.5), zero off-lattice.

cliff_settings: yes, decisively. It holds every constant the rule uses, all settable on the surface, so a term can be switched off in the game rather than modelled:

lever effect
cliff_smoothing = 0 leaves the RAW elevation
cliff_elevation_interval = 1e6 a single contour at cliff_elevation_0; no band arithmetic
richness = 4 0.5*log2(4) = 1, so cliffiness_basic saturates at 1.5 and its > 0.5 gate is always open

Together the rule reduces to "an edge crosses iff elevation crosses 70" - making the game's own cliffs a direct readout of sign(elevation - 70) at the generator's sample points.

Vulcanus arm game ours matched wrong
smoothing off only 352 432 289 83 = 28.7%
+ single contour 271 349 208 79 = 38.0%
+ gate held open 335 463 265 99 = 37.4%
bands, gate open 431 559 360 105 = 29.2%

The control is what makes this mean something

Nauvis, through the same code and the same lattice, is exact - and not only at the default. cliff_elevation_interval = 80 had never been captured before; the port reproduces it 281/281 in both directions, so the rule tracks the game when a setting moves. It also agrees on the degenerate arm, where a single contour at 50 yields zero cliffs from both (cliffiness_nauvis's cutoff derives from the interval; cliffiness_basic's does not).

So the rule, lattice, code packing, repair sweep and settings plumbing are all now confirmed against the game under a changed setting. What is left is the field.

The informative half is the over-placement, not the error rate: we place 463 where the game places 335, so our 70-contour is ~38% longer. Our elevation is rougher at the 4-tile scale than the one the generator reads.

The open lead: right field, wrong channel

Our field is not wrong against the channel it was checked in - it reproduces the corner-fields fixture to a max of 4.8e-2, and that fixture came from calculate_tile_properties. The question is whether the map generator reads the same values that channel reports.

multisample sits in vulcanus_elevation's chain via vulcanus_basalt_lakes_multisample, and is absent from cliff_elevation_nauvis - the asymmetry the residual needs. Its own docs call it "a separate noise program with a larger grid" whose "sub-grids are copied to the main program" - explicitly grid-dependent. The cliff generator walks a 4-tile lattice; calculate_tile_properties does not. vulcanus-multisample-NOTES.md established multisample(e,dx,dy) == e(x+dx,y+dy) at 150/150 - but measured it through calculate_tile_properties, the same channel as the fixture. A min() of four samples is an erosion operator, so a coarser effective grid would smooth the field exactly the way the over-placement implies.

Not a fixture captured at the wrong site this time - one captured through the wrong channel.

Oracle changes

  • cliffSmoothing generalises to a cliffSettings record keyed by the game's own field names (one call site updated).
  • The Nauvis path gets the same map_gen_settings round-trip - safe because the sampled regions are far from spawn and ungenerated at on_init.
  • parseCliffDumpFull normalises cliffs to an array: table_to_json serialises an empty Lua table as {}, so a legitimately-zero result was reading as undefined. That is a real configuration - raising richness on Nauvis lifts cliffiness_nauvis's cutoff until nothing qualifies.

Does not fix #18. pnpm run verify: 308 files clean, 1298 passed / 3 skipped, preview 12 passed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GRx1CU29RKLsRuUAErEDRB

Answers "will messing with the other cliff prototypes help": the cliff ENTITY
prototype will not - the crossing pass reads only grid_size/grid_offset off it
and the fixture already proves those (all 1569 cliffs land exactly on
(cx*4+2, cy*4+2.5), zero off-lattice). But `cliff_settings` holds every
constant the rule uses, all settable on the surface, so a term can be switched
OFF in the game instead of modelled:

  cliff_smoothing = 0              leaves the RAW elevation
  cliff_elevation_interval = 1e6   a SINGLE contour at cliff_elevation_0
  richness = 4                     0.5*log2(4)=1, so cliffiness_basic
                                   saturates at 1.5 and its >0.5 gate is open

Together the rule reduces to "an edge crosses iff elevation crosses 70", making
the game's cliffs a direct readout of sign(elevation - 70) at the generator's
own sample points.

  Vulcanus arm                game  ours  matched  wrong
  smoothing off only           352   432      289     83 = 28.7%
  + single contour             271   349      208     79 = 38.0%
  + gate held open             335   463      265     99 = 37.4%
  bands, gate open             431   559      360    105 = 29.2%

NAUVIS, through the same code and lattice, is EXACT - and not only at the
default. cliff_elevation_interval = 80 had never been captured before; the port
reproduces it 281/281 in both directions, so the rule tracks the game when a
setting MOVES. It also agrees on the degenerate arm where a single contour at
50 yields zero cliffs from both, because cliffiness_nauvis's cutoff derives
from the interval while cliffiness_basic's does not.

That control is what gives the Vulcanus numbers meaning. The rule, lattice,
code packing, repair sweep and settings plumbing are now all confirmed against
the game under a changed setting. What is left is the field - and the
informative half is the over-placement, not the error rate: we place 463 where
the game places 335, so our 70-contour is ~38% longer. Our elevation is
ROUGHER at the 4-tile scale than the one the generator reads.

The open lead is that our field may be right in the wrong CHANNEL. It
reproduces the corner-fields fixture to 4.8e-2, but that fixture came from
calculate_tile_properties. `multisample` sits in vulcanus_elevation's chain via
vulcanus_basalt_lakes_multisample and is absent from cliff_elevation_nauvis -
the asymmetry the residual needs - and its own docs call it "a separate noise
program with a larger grid" whose "sub-grids are copied to the main program",
i.e. explicitly grid-dependent. The cliff generator walks a 4-tile lattice;
calculate_tile_properties does not. vulcanus-multisample-NOTES established
multisample(e,dx,dy) == e(x+dx,y+dy) at 150/150 - but measured it through
calculate_tile_properties, the same channel as the fixture. A min() of four
samples is an erosion operator, so a coarser effective grid would smooth the
field exactly the way the over-placement implies.

Oracle changes: the `cliffSmoothing` option generalises to a `cliffSettings`
record keyed by the game's own field names (one call site updated); the Nauvis
path gets the same map_gen_settings round-trip, safe because the sampled
regions are far from spawn and ungenerated at on_init; and parseCliffDumpFull
normalises `cliffs` to an array, because table_to_json serialises an EMPTY Lua
table as {} and a legitimately-zero result was reading as undefined.

DOES NOT FIX #18.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GRx1CU29RKLsRuUAErEDRB
@wormeyman
wormeyman merged commit ec78d2e into main Aug 2, 2026
2 checks passed
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.

Vulcanus cliffs: 12.5% of matched cells get the wrong cliff_orientation (residual after the placement-count fixes)

1 participant