islaApocalypse-v2/Core/README.md
beezm 35b4818e9e Phase 2a: the faithful redistribution curve, re-measured against v2's own output
Ports the reference's v5 height curve and shelf-detail passes onto Phase 1's shape
and re-calibrates them against this repo's actual pass-1 distribution. This is the
BASELINE the reshape gets judged against, not the reshape.

Core (engine-free, D-060):
- WorldScale — THE vertical yardstick. One metres/raw number (251), replacing the
  prototype's three duplicate M_PER_UNIT constants and ~20 bare literals. The
  chunk-height coupling it had there is recorded as a DEFERRED vault decision, not
  inherited. RawFromMetres divides, matching the reference bit-for-bit.
- HeightCurve — the 7 bands, the frozen corner-fix blends, the per-seed spike
  normalization, the 24-corner monotonicity sweep that throws and refuses.
  Identity at and below sea, which everything downstream rests on.
- CurveKnots / CurveAnchors — input knots (measured percentiles) and output anchors
  (storm ladder) split apart and both made parameters, so the anchors are A/B-able
  without editing source. The reference's shipped knots are kept beside the measured
  ones as the fidelity yardstick.
- TerrainDetailPass — micro-relief skin plus the shelf-edge KNOT warp (which slides
  K3/K4/K5, not height — that is what keeps monotonicity structural). The crater
  exclusion is ported and inert until the carve lands.

Tools:
- Shaping — pass 2a, producing the two height fields. classify is bit-for-bit the
  raw pass-1 field; render is curved and detailed. Aliased when the curve is off,
  as the reference did. Pass1Result is left immutable so the oracle can compare.
- LandHistogram — the calibration engine AND the diagnostic. The reference shipped
  six knot literals and threw the measuring instrument away; this rebuilds it.
- ShapingOracle + CurveBaselineTool — four automatic checks before anything is
  looked at, and the batch that runs them.

Measured, not assumed:
- Knots re-measured over a 6-seed / 12.8M-sample pool. They differ from the
  reference's by at most 5.6 m of world height, against a 44.7 m per-seed spread —
  the pass-1 port is faithful.
- Oracle all pass, including pass 1 bit-identical to Phase 1's own .f32 dump.
- Band shares land on 60/13/10/5/8/3/1 to 0.00 pp.
- Knots hold across map size: the 8K delta (5.8 m) sits inside seed noise.

The finding the histograms deliver: 83% of land ends below 100 m and 96% below
220 m, with the median column at 13 m. That is the share targets doing exactly what
they say, not a bug — and it is the developer's call, which is why nothing here
reshapes it and the palette was deliberately left mis-fitted rather than recalibrated
to disguise it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCWNaDZPfTiAy3meGNGgqt
2026-08-20 01:38:10 -04:00

67 lines
4.3 KiB
Markdown

# Core — math and data only
**Holds:** the column model, the material schemas, the scaling discipline, tooling path
resolution and the file-safety rails. Constants and contracts.
**Boundary: Core depends on nothing above it.** Not on `Server/`, not on `Client/`, not on
`Tools/`. The dependency arrow points one way into this folder and never out of it.
> ### ⚠ Additional boundary, tighter than the layer rule: **Core is engine-free.**
>
> No `using Godot;` anywhere in this folder. Core is plain C# — no `Node`, no `GD.Print`, no
> `ProjectSettings`, no engine types in any signature.
>
> **Two reasons, both load-bearing.** (1) D-049 commits to *"C# for fast iteration, with C++-ready
> seams… port path-by-path when settled and hot"* — the hot paths that get ported first are exactly
> the ones in here, and a type that names `Godot.Vector2` cannot cross that seam. (2) It keeps the
> column model testable and reviewable without standing up an engine.
>
> Where Core genuinely needs something the engine knows — the resolved `user://` directory — the
> engine layer **hands it in** (`ToolingPaths.Configure`), rather than Core reaching for it.
> If you find yourself wanting an engine type here, the type belongs one layer up.
## What is in here
| File | What it is |
|---|---|
| `Scripts/Column.cs` | ★★ **The load-bearing contract** (D-053). A column as run-length bands; `MaterialRun`; `RunOrigin`. Read its header before touching anything that stores world data. |
| `Scripts/ColumnGrid.cs` | The 2D grid of columns. Shape only — chunking and streaming are later phases. |
| `Scripts/MaterialKey.cs` | Material **identity** — a registry key, never an ordinal. |
| `Scripts/TerrainMaterial.cs` | A row in the terrain schema (D-054). |
| `Scripts/BuildingMaterial.cs` | A row in the building schema (D-054). |
| `Scripts/MaterialRegistry.cs` | Both registries, append-only, seed rows only. |
| `Scripts/RecipeRegistry.cs` | The transformation seam — **deliberately empty**. |
| `Scripts/GenerationScale.cs` | ⭐ The scaling discipline. `MapSize`, `ScaleFactor`, normalized offsets, the two frequency conventions. |
| `Scripts/WorldScale.cs` | ⭐ **The vertical yardstick.** The ONE metres↔raw conversion (251 m/unit). No literal `251f` anywhere else. |
| `Scripts/HeightCurve.cs` | ⭐⭐ The height-redistribution curve (v5), 7 bands. **Identity at and below sea.** |
| `Scripts/CurveKnots.cs` | The six INPUT knots — percentiles of the measured land CDF, plus the reference's for comparison. |
| `Scripts/CurveAnchors.cs` | The OUTPUT anchors — the storm-ladder elevations each band lands at. |
| `Scripts/TerrainDetailPass.cs` | Shelf micro-relief + the shelf-edge **knot warp**. Output-height only. |
| `Scripts/ToolingPaths.cs` | Every tooling path, env-overridable, resolved in one place. |
| `Scripts/FileSafety.cs` | The permanent file-safety rules, as throws rather than sentences. |
## The three rules this layer exists to make unbreakable
1. **Air is the top run.** There is no "air vs solid" height branch, anywhere, ever.
`Scripts/Column.cs`.
2. **Properties come from the registry, never from storage.** A run stores an identity.
`Scripts/MaterialRegistry.cs`.
3. **Nothing uses a raw pixel number.** Every distance is a fraction of `MapSize`.
`Scripts/GenerationScale.cs`.
4. **There is one metres-per-raw-unit number.** The prototype scattered `251` across three
duplicate constants and ~20 literals, and the generator never used the derived one at all.
`Scripts/WorldScale.cs`.
## Not here, and not by accident
- **No water.** Water is an overlay over the columns (levels-not-cells), never a band.
- **No biomes.** Biomes are a later *classification* of finished shape, not an input to it (D-049).
- **No algorithms** *beyond the height curve*. Phase 2 added `HeightCurve` and
`TerrainDetailPass` here because they are pure, engine-free, C++-candidate math that defines the
world's elevation profile — a contract, not a tool's dial. Stratigraphy, feature passes, meshing
and run-splitting on dig are still later phases.
- **No erosion, rivers, water bodies, crater carve, coast shelf or offshore islets.** Later chat2
tasks; the curve is deliberately the only pass-2 element present.
`Design - Data - Column Model.md`, `Design - Data - Material Schema.md`,
`Design - Tooling - Scaling Discipline.md`