From 915ea21c142d9d8e546aa149e715e10b5a614839 Mon Sep 17 00:00:00 2001 From: Eric J Date: Sun, 30 Aug 2026 12:45:54 -0700 Subject: [PATCH] Rehome the symbols the dead set still owes surviving code (#227) Four groups of symbols live in files phase 7 is about to delete, but surviving code still needs them. This moves them out first, so the deletion can be a deletion rather than a deletion plus a scramble. No behaviour changes and no test coverage is lost. | symbol | left | arrived | | --- | --- | --- | | `ResourceControlLevers` | `resources/resolveResource.ts` | `resources/resourceCatalog.ts` | | `VULCANUS_CLIFF_BLOCKING_TILES` | `preview/renderVulcanusCliffs.ts` | `cliffs/cliffCatalog.ts` | | `LAND_RGBA`, `WATER_RGBA`, `TREE_MAP_COLOR` | `preview/renderElevation.ts`, `preview/renderTrees.ts` | new `preview/palette.ts` | | `PlacedCliffCell` | `cliffs/cliffPlacement.ts` | inlined into `cliffs/cliffConnections.ts` | Measured effect: files outside the dead set that still import from it drop from 14 to 6, and 11 of the 6 remaining edges belong to one file, `preview/elevationRenderRequest.ts`, which the deletion PR has to rewrite anyway. ## Why each target `resourceCatalog.ts` and `cliffCatalog.ts` were chosen because both have zero imports of their own, so neither can form a cycle, and two of the three consumers of `ResourceControlLevers` already imported from `resourceCatalog.ts`. `palette.ts` is new because there was nowhere to put these. The repo keeps per-domain leaf catalogs rather than one palette module, and the obvious home for `TREE_MAP_COLOR` would have been a trees catalog - but every file in `src/noise/trees/` is in the dead set, so that directory disappears. A one-constant `trees/` directory whose name promises tree math that no longer exists is worse than grouping the three render colours together. It also keeps the colour out of the tree field's import graph, which pulls `moisture` and `temperature` behind it. `LAND_RGBA` and `WATER_RGBA` are not game data. They are the two colours this repo picked to paint a sign test on the elevation tree, which is why they have no domain catalog to belong to. `TREE_MAP_COLOR` is game data, from `utility-constants.lua:201`, and its doc comment carries that. These three stay in `src/` rather than moving into `test/` even though the only readers left are two parity specs. They are hand-written oracles for the Rust output, and an oracle that lives in the file it grades is a weaker check. ## `PlacedCliffCell` is a required inline, not a tidy-up `cliffConnections.ts` is kept deliberately: it has no importers at all since #360, and it survives because `crates/fmw-noise/src/cliffs/connections.rs:4` names it as the file the Rust was ported from. `tsconfig.json` includes `src/**/*` by glob rather than by reachability, so a file with zero importers is still fully type-checked. Leave the type-only import of `PlacedCliffCell` pointing at `cliffPlacement.ts` and the dead-set deletion turns `verify:lint` red on the one file it is trying to preserve. Its two doc comments also cited `test/cliffConnections.spec.ts`, which #360 deleted along with the rest of the 23-spec investigation corpus. They now point at the Rust that runs over the same fixture. A file kept as a human-readable reference is not worth much with dead citations in it. ## Two corrections `test/cliffCatalog.spec.ts` re-pins that `VULCANUS_CLIFF_BLOCKING_TILES` is exactly `["lava", "lava-hot"]`. #360 stripped the block that asserted this when it armed `cliffOreDirection.spec.ts`, and nothing replaced it, so the constant survived with its value ungraded. The Rust holds the same pair inlined twice, with no shared definition - worth its own issue. `CLAUDE.md` said `cliffConnections.ts` has "zero `src/` consumers - only 23 investigation specs import it". Those 23 are gone; it now has no consumers of any kind. The sentence justifying the file no longer described the tree. ## What this deliberately does not do Five parity specs still import from the dead set: `wasmNauvisParity` (15 edges), `wasmMultioctaveParity` (2), `wasmPrimitiveParity` (2), `wasmEvalParity` (1) and `wasmVulcanusParity` (1). Every block that would have to be cut from them compares the TypeScript against the Rust, and all of them pass today. They only become impossible when the TypeScript goes, so they are cut in the deletion's own commit rather than a PR early - removing the evidence before taking the step it justifies would be the wrong order. The rehome made five of the ten specs that were deferred for this work need no edit at all, and saved three blocks that were slated for deletion only because the constants they read were assumed to die. ## Verification Full `pnpm run verify`, `VERIFY_RC=0`: - static: all 387 files formatted, 360 files with no warning, lint error or type error, `vue-tsc` clean - vitest: 162 files, 1,595 passed, 3 skipped, 606.83s. The count is up one from #360's 1,594, which is the re-pinned lava assertion running. - preview-service worker: 4 files; `node --test`: 10 tests - Rust: 440 and 35 crate tests, 2 doc-tests, the anti-vacuity check still fails against a deliberately broken port, `engine.wasm` matches its source, and `cargo deny` clean on advisories, bans, licenses and sources Claude-Session: https://claude.ai/code/session_01KLPHLUpGn1cqN46xwhmev8 Co-authored-by: Claude Opus 5 (1M context) --- CLAUDE.md | 9 ++++--- src/model/elevationPreviewCtx.ts | 2 +- src/model/resourceReads.ts | 2 +- src/noise/cliffs/cliffCatalog.ts | 18 ++++++++++++++ src/noise/cliffs/cliffConnections.ts | 26 +++++++++++++++++---- src/noise/preview/elevationRenderRequest.ts | 2 +- src/noise/preview/palette.ts | 19 +++++++++++++++ src/noise/preview/renderElevation.ts | 5 +--- src/noise/preview/renderResources.ts | 8 ++----- src/noise/preview/renderTrees.ts | 3 +-- src/noise/preview/renderVulcanusCliffs.ts | 15 +----------- src/noise/resources/resolveResource.ts | 13 ++++------- src/noise/resources/resourceCatalog.ts | 7 ++++++ test/cliffCatalog.spec.ts | 11 +++++++++ test/cliffOreLeverTileConfound.spec.ts | 2 +- test/multisampleChannelAudit.spec.ts | 2 +- test/wasmElevationRenderParity.spec.ts | 2 +- test/wasmNauvisRenderParity.spec.ts | 2 +- 18 files changed, 99 insertions(+), 49 deletions(-) create mode 100644 src/noise/preview/palette.ts diff --git a/CLAUDE.md b/CLAUDE.md index a68af1d8..239b6a06 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1362,9 +1362,12 @@ Three traps that slice paid for, all transferable: guard, not the correctness gate. **One TypeScript file in a ported directory was ported for a reason that is not -obvious.** `cliffConnections.ts` has **zero `src/` consumers** - only 23 -investigation specs import it - so that #84's cliff investigation can be run -against the engine. +obvious.** `cliffConnections.ts` has **zero consumers of any kind** since #360 deleted the +23 investigation specs that imported it. It is kept as the human-readable +reference `crates/fmw-noise/src/cliffs/connections.rs` cites as its source, so +that #84's cliff investigation can still be run against the engine. The +type-checker still covers it, because `tsconfig.json` includes `src/**/*` by +glob rather than by reachability. #### The three tiers, and what each one cannot see diff --git a/src/model/elevationPreviewCtx.ts b/src/model/elevationPreviewCtx.ts index c99d6353..3a6e3a24 100644 --- a/src/model/elevationPreviewCtx.ts +++ b/src/model/elevationPreviewCtx.ts @@ -3,7 +3,7 @@ import type { Point } from "../noise/distanceFromNearestPoint"; import type { VulcanusResourceControls } from "../noise/eval/ctx"; import { readMapType } from "./mapType"; import { readResourceControls, readVulcanusResourceControls } from "./resourceReads"; -import type { ResourceControlLevers } from "../noise/resources/resolveResource"; +import type { ResourceControlLevers } from "../noise/resources/resourceCatalog"; import type { Preset } from "./types"; import { ENEMY_CONTROL_NAME, type EnemyControls } from "../noise/enemies/enemyCatalog"; import { diff --git a/src/model/resourceReads.ts b/src/model/resourceReads.ts index c8d66d73..3694e9fd 100644 --- a/src/model/resourceReads.ts +++ b/src/model/resourceReads.ts @@ -9,7 +9,7 @@ */ import type { AutoplaceSetting } from "./types"; import type { VulcanusResourceControls, VulcanusResourceLevers } from "../noise/eval/ctx"; -import type { ResourceControlLevers } from "../noise/resources/resolveResource"; +import type { ResourceControlLevers } from "../noise/resources/resourceCatalog"; import { RESOURCE_CATALOG } from "../noise/resources/resourceCatalog"; const DEFAULT_LEVERS: ResourceControlLevers = { frequency: 1, size: 1, richness: 1 }; diff --git a/src/noise/cliffs/cliffCatalog.ts b/src/noise/cliffs/cliffCatalog.ts index e2a85d81..4b779b8d 100644 --- a/src/noise/cliffs/cliffCatalog.ts +++ b/src/noise/cliffs/cliffCatalog.ts @@ -427,3 +427,21 @@ export function cliffCollisionTileBox( bottom: Math.floor(centerY + b), }; } + +/** + * The Vulcanus tiles whose `CollisionMask` shares a layer with the cliff's, so a + * cliff whose collision box touches one is never placed. + * + * `tile_collision_masks.lava()` sets `water_tile = true` and the cliff mask + * holds `water_tile`; no other Vulcanus tile does. Notably + * `volcanic-jagged-ground` - the tile the ore patches paint, which the Lua + * itself labels "CLIFF TILE" - is `tile_collision_masks.ground()`, which the + * cliff mask does not touch, so ore does NOT exclude cliffs. That distinction is + * the whole reason the earlier ore-separation work correctly found no exclusion + * rule while this one exists. + * + * Lives here rather than beside the Vulcanus renderer because that renderer is + * deleted by #227 and this rule is not. The Rust carries the same pair inlined + * at `crates/fmw-noise/src/cliffs/vulcanus_fields.rs:218`. + */ +export const VULCANUS_CLIFF_BLOCKING_TILES: ReadonlySet = new Set(["lava", "lava-hot"]); diff --git a/src/noise/cliffs/cliffConnections.ts b/src/noise/cliffs/cliffConnections.ts index e59f7c15..d735fc4c 100644 --- a/src/noise/cliffs/cliffConnections.ts +++ b/src/noise/cliffs/cliffConnections.ts @@ -120,8 +120,9 @@ * | `oppositeSide` | immediate `0x01000302` | `N<->S`, `E<->W` | * | `destroyEnd` | 4 jump tables under `0x102cfc9db` | `side -> none`, else destroy | * - * `test/cliffConnections.spec.ts` re-derives all four from the names and asserts - * they match, so a transcription slip fails rather than shifts the model. + * `crates/fmw-noise/src/cliffs/connections.rs` re-derives all four from the names + * and asserts they match, so a transcription slip fails rather than shifts the + * model. The TypeScript spec that used to do this went with #227. */ import { @@ -131,7 +132,22 @@ import { CLIFF_GRID_SIZE, CLIFF_ORIENTATION_NAMES, } from "./cliffCatalog"; -import type { PlacedCliffCell } from "./cliffPlacement"; + +/** + * A placed cliff: the cell centre, plus the 8-bit edge-crossing `code` it was + * placed by. The code is carried out rather than discarded because it is the + * only thing that names the cliff's ORIENTATION, and therefore its collision + * box - `cliffOrientationForCode(code)` in `cliffCatalog.ts`. + * + * Inlined from `cliffPlacement.ts`, which #227 deletes. This module is kept as + * the reference `crates/fmw-noise/src/cliffs/connections.rs` cites, so it must + * not import anything that deletion removes. + */ +export interface PlacedCliffCell { + readonly x: number; + readonly y: number; + readonly code: number; +} /** * `CellSide`, in the engine's enum order. Read off `getNeighborPosition` @@ -310,8 +326,8 @@ export interface CliffConnectionOptions { * `<= 0x31`, so during a real generation sweep a cliff pointing into a * not-yet-generated chunk keeps its end, and this model destroys it. It is * therefore an UPPER bound on how much the rule removes - see - * `test/cliffConnections.spec.ts`, which is what measures whether that bound is - * tight. + * `crates/fmw-noise/src/fixtures.rs`, which runs over the same fixture and is + * what measures whether that bound is tight. */ export function applyCliffConnections( cells: readonly PlacedCliffCell[], diff --git a/src/noise/preview/elevationRenderRequest.ts b/src/noise/preview/elevationRenderRequest.ts index 28f6177d..c838dec2 100644 --- a/src/noise/preview/elevationRenderRequest.ts +++ b/src/noise/preview/elevationRenderRequest.ts @@ -6,7 +6,7 @@ import type { EnemyControls } from "../enemies/enemyCatalog"; import type { Planet } from "../../model/planets"; import { PLACEMENT_MARK_RADIUS_PX } from "../placement/placementRoll"; import { NAUVIS_MAX_STARTING_POINTS } from "../wasm/request"; -import type { ResourceControlLevers } from "../resources/resolveResource"; +import type { ResourceControlLevers } from "../resources/resourceCatalog"; import type { RockControls } from "../rocks/rockCatalog"; import { renderCliffs } from "./renderCliffs"; import { renderElevation } from "./renderElevation"; diff --git a/src/noise/preview/palette.ts b/src/noise/preview/palette.ts new file mode 100644 index 00000000..d607616c --- /dev/null +++ b/src/noise/preview/palette.ts @@ -0,0 +1,19 @@ +/** + * Colours the map preview paints with, kept apart from the renderers so they + * outlive them. #227 deletes the TypeScript renderers these were declared in; + * the Rust engine now does the painting and these values are what the surviving + * parity specs grade its output against. + * + * Deliberately an independent copy of the Rust constants rather than a read of + * them - a spec that imported the engine's own numbers would assert nothing. + * The mirrors are `crates/fmw-wasm/src/render.rs:156` and `:159` for the + * elevation pair, and `crates/fmw-noise/src/trees/catalog.rs:69` for the tree + * colour. Rust stores RGB and writes the alpha separately. + */ + +/** RGBA for water (elevation < 0) and land, as [r, g, b, a] byte tuples. */ +export const WATER_RGBA: readonly [number, number, number, number] = [40, 90, 150, 255]; +export const LAND_RGBA: readonly [number, number, number, number] = [70, 120, 60, 255]; + +/** `{0.19, 0.39, 0.19}` in 8-bit - utility-constants.lua:201. */ +export const TREE_MAP_COLOR: readonly [number, number, number] = [48, 99, 48]; diff --git a/src/noise/preview/renderElevation.ts b/src/noise/preview/renderElevation.ts index 87dd7a13..9458edf2 100644 --- a/src/noise/preview/renderElevation.ts +++ b/src/noise/preview/renderElevation.ts @@ -1,10 +1,7 @@ import { makeElevationLakes, type ElevationLakesParams } from "../expressions/elevationLakes"; import { makeElevationNauvis } from "../expressions/elevationNauvis"; import { makeElevationIsland } from "../expressions/elevationIsland"; - -/** RGBA for water (elevation < 0) and land, as [r, g, b, a] byte tuples. */ -export const WATER_RGBA: [number, number, number, number] = [40, 90, 150, 255]; -export const LAND_RGBA: [number, number, number, number] = [70, 120, 60, 255]; +import { LAND_RGBA, WATER_RGBA } from "./palette"; export interface RenderElevationOptions { /** Map seed (= map_seed / seed0). Callers resolve a null "random" seed first. */ diff --git a/src/noise/preview/renderResources.ts b/src/noise/preview/renderResources.ts index a096416c..468f1ae5 100644 --- a/src/noise/preview/renderResources.ts +++ b/src/noise/preview/renderResources.ts @@ -66,13 +66,9 @@ import { makePlacementSet, } from "../placement/placementRoll"; import type { PlacementCollisionBox } from "../placement/placementRoll"; -import { RESOURCE_CATALOG } from "../resources/resourceCatalog"; +import { RESOURCE_CATALOG, type ResourceControlLevers } from "../resources/resourceCatalog"; import { makeResourcePatches } from "../resources/resourcePatches"; -import { - comparePriority, - makeResourceResolver, - type ResourceControlLevers, -} from "../resources/resolveResource"; +import { comparePriority, makeResourceResolver } from "../resources/resolveResource"; import { makeTileResolver } from "../tiles/resolve"; import { paintMark } from "./renderCliffs"; diff --git a/src/noise/preview/renderTrees.ts b/src/noise/preview/renderTrees.ts index c7f5bd9a..2d9b5f0e 100644 --- a/src/noise/preview/renderTrees.ts +++ b/src/noise/preview/renderTrees.ts @@ -41,9 +41,8 @@ */ import { WATER_TILE_COLORS } from "./renderResources"; import { makeTreeDensity, type TreeFieldParams } from "../trees/treeField"; +import { TREE_MAP_COLOR } from "./palette"; -/** `{0.19, 0.39, 0.19}` in 8-bit - utility-constants.lua:201. */ -export const TREE_MAP_COLOR: readonly [number, number, number] = [48, 99, 48]; /** The alpha component of the same constant: fully-forested tiles blend at 40%. */ export const TREE_MAX_ALPHA = 0.4; diff --git a/src/noise/preview/renderVulcanusCliffs.ts b/src/noise/preview/renderVulcanusCliffs.ts index b3b06368..d2197a67 100644 --- a/src/noise/preview/renderVulcanusCliffs.ts +++ b/src/noise/preview/renderVulcanusCliffs.ts @@ -25,6 +25,7 @@ import type { EvalCtxInput } from "../eval/ctx"; import { withCtxDefaults } from "../eval/ctx"; import { makeCliffPlacementFromFields } from "../cliffs/cliffPlacement"; +import { VULCANUS_CLIFF_BLOCKING_TILES } from "../cliffs/cliffCatalog"; import { VULCANUS_CLIFF_ELEVATION_0, VULCANUS_CLIFF_ELEVATION_INTERVAL, @@ -40,20 +41,6 @@ import { makeVulcanusTileResolverFrom, } from "../tiles/vulcanusCatalog"; -/** - * The Vulcanus tiles whose `CollisionMask` shares a layer with the cliff's, so a - * cliff whose collision box touches one is never placed. - * - * `tile_collision_masks.lava()` sets `water_tile = true` and the cliff mask - * holds `water_tile`; no other Vulcanus tile does. Notably - * `volcanic-jagged-ground` - the tile the ore patches paint, which the Lua - * itself labels "CLIFF TILE" - is `tile_collision_masks.ground()`, which the - * cliff mask does not touch, so ore does NOT exclude cliffs. That distinction is - * the whole reason the earlier ore-separation work correctly found no exclusion - * rule while this one exists. - */ -export const VULCANUS_CLIFF_BLOCKING_TILES: ReadonlySet = new Set(["lava", "lava-hot"]); - export interface RenderVulcanusCliffsOptions { readonly seed0: number; /** World tile at the top-left pixel. Default (0, 0). */ diff --git a/src/noise/resources/resolveResource.ts b/src/noise/resources/resolveResource.ts index ff0c1244..dc9a2a1e 100644 --- a/src/noise/resources/resolveResource.ts +++ b/src/noise/resources/resolveResource.ts @@ -22,14 +22,11 @@ */ import type { Point } from "../distanceFromNearestPoint"; import { makeResourcePatches, type ResourcePatches } from "./resourcePatches"; -import { RESOURCE_CATALOG, type ResourceParams } from "./resourceCatalog"; - -/** control::frequency|size|richness levers for one resource. */ -export interface ResourceControlLevers { - readonly frequency: number; - readonly size: number; - readonly richness: number; -} +import { + RESOURCE_CATALOG, + type ResourceControlLevers, + type ResourceParams, +} from "./resourceCatalog"; export interface ResourceResolverCtx { readonly seed0: number; diff --git a/src/noise/resources/resourceCatalog.ts b/src/noise/resources/resourceCatalog.ts index 0d5f7218..c5e6f92b 100644 --- a/src/noise/resources/resourceCatalog.ts +++ b/src/noise/resources/resourceCatalog.ts @@ -59,6 +59,13 @@ export interface ResourceParams { */ export type ResourcePlacement = "threshold" | "roll"; +/** control::frequency|size|richness levers for one resource. */ +export interface ResourceControlLevers { + readonly frequency: number; + readonly size: number; + readonly richness: number; +} + /** map_color (0..1) -> 0..255, rounded, matching the game's preview tint. */ function color255(r: number, g: number, b: number): readonly [number, number, number] { return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; diff --git a/test/cliffCatalog.spec.ts b/test/cliffCatalog.spec.ts index 092d852d..629582b7 100644 --- a/test/cliffCatalog.spec.ts +++ b/test/cliffCatalog.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vite-plus/test"; import { CLIFF_MAP_COLOR, + VULCANUS_CLIFF_BLOCKING_TILES, getModifiedElevationInterval, getModifiedRichness, isCliffPlaced, @@ -46,3 +47,13 @@ describe("cliff orientation predicate", () => { ]); }); }); + +// #360 deleted the block in cliffOreDirection.spec.ts that pinned this literal. +// The set survives and two specs still read it, so the value is re-pinned here. +// The Rust holds the same pair inlined twice, at +// `crates/fmw-noise/src/cliffs/vulcanus_fields.rs:218` and `fixtures.rs`. +describe("VULCANUS_CLIFF_BLOCKING_TILES", () => { + it("is exactly the two lava tiles", () => { + expect([...VULCANUS_CLIFF_BLOCKING_TILES].sort()).toEqual(["lava", "lava-hot"]); + }); +}); diff --git a/test/cliffOreLeverTileConfound.spec.ts b/test/cliffOreLeverTileConfound.spec.ts index 33b18b3d..7c83b980 100644 --- a/test/cliffOreLeverTileConfound.spec.ts +++ b/test/cliffOreLeverTileConfound.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vite-plus/test"; import lever from "./fixtures/oracle-vulcanus-tile-lever.seed123456.json"; -import { VULCANUS_CLIFF_BLOCKING_TILES } from "../src/noise/preview/renderVulcanusCliffs"; +import { VULCANUS_CLIFF_BLOCKING_TILES } from "../src/noise/cliffs/cliffCatalog"; import { makeVulcanusTileResolver } from "../src/noise/tiles/vulcanusCatalog"; import { DEFAULT_VULCANUS_RESOURCE_CONTROLS } from "../src/noise/eval/ctx"; diff --git a/test/multisampleChannelAudit.spec.ts b/test/multisampleChannelAudit.spec.ts index 1b42882b..9e901530 100644 --- a/test/multisampleChannelAudit.spec.ts +++ b/test/multisampleChannelAudit.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vite-plus/test"; import fixture from "./fixtures/oracle-vulcanus-tile-names.seed123456.json"; -import { VULCANUS_CLIFF_BLOCKING_TILES } from "../src/noise/preview/renderVulcanusCliffs"; +import { VULCANUS_CLIFF_BLOCKING_TILES } from "../src/noise/cliffs/cliffCatalog"; import { makeVulcanusStack, makeVulcanusTileResolverFrom, diff --git a/test/wasmElevationRenderParity.spec.ts b/test/wasmElevationRenderParity.spec.ts index 8b8cde72..edd024f2 100644 --- a/test/wasmElevationRenderParity.spec.ts +++ b/test/wasmElevationRenderParity.spec.ts @@ -17,7 +17,7 @@ import { runRenderRequest, type ElevationRenderRequest, } from "../src/noise/preview/elevationRenderRequest"; -import { LAND_RGBA, WATER_RGBA } from "../src/noise/preview/renderElevation"; +import { LAND_RGBA, WATER_RGBA } from "../src/noise/preview/palette"; /** * Tier 3 for the ELEVATION view (#227): the Rust engine's elevation render diff --git a/test/wasmNauvisRenderParity.spec.ts b/test/wasmNauvisRenderParity.spec.ts index d192d037..c7bfc627 100644 --- a/test/wasmNauvisRenderParity.spec.ts +++ b/test/wasmNauvisRenderParity.spec.ts @@ -19,7 +19,7 @@ import { runRenderRequest, type ElevationRenderRequest, } from "../src/noise/preview/elevationRenderRequest"; -import { TREE_MAP_COLOR } from "../src/noise/preview/renderTrees"; +import { TREE_MAP_COLOR } from "../src/noise/preview/palette"; import { planTiles } from "../src/noise/preview/tiling"; /**