islaApocalypse-v2/Tools/README.md
beezm 9107b0822b Phase 0: clean project skeleton for the v2 rewrite
Stands up the CODE_REPO the rewrite is written into (D-049, D-058). Godot 4.7.2 /
.NET 8 / Godot.NET.Sdk 4.7.2. Nothing is generated, meshed, or ported — this is the
shell and the two data contracts.

Four layers, each with its boundary stated in a directory README:
  Core/    math + data only, and engine-free — depends on nothing above it
  Server/  authoritative logic                (empty this phase)
  Client/  rendering                          (empty this phase)
  Tools/   the offline generator — may NOT reference Client   (Phase 1 fills it)

Contracts (compiling stubs, no algorithms):
  - Column model (D-053): a 2D grid of columns, each a stack of (material, thickness)
    runs, any material at any depth. Air is the TOP RUN — there is no air-vs-solid
    height branch, and no surface-height accessor exists to reintroduce one. Water is
    not a band; it stays an overlay.
  - Material schemas (D-054): terrain and building as two append-only registries,
    bridged by a recipe seam that is deliberately EMPTY. Identity is a registry key,
    never a serialized ordinal. Mesh style is per-ORIGIN and is not a material field.

Rails, so Phase 1 inherits them rather than rediscovering them:
  - GenerationScale: MapSize is a parameter, everything derives from it, nothing uses
    a raw pixel number. Tightening over the reference — decorrelation offsets are
    declared in map widths, not pixels (chat1/00 §4.2).
  - ToolingPaths: config/blueprint/output paths all env-overridable, resolved in one
    place, so a batch cannot touch the developer's live files.
  - FileSafety: the permanent no-deletion rules as throws rather than sentences.

user:// isolation: project name and use_custom_user_dir both pin the runtime dir to
~/.local/share/islaApocalypse-v2/, away from the old prototype's preserved seeds and
batches. Tools/Scenes/UserDirProbe.tscn confirms it rather than assuming it.
2026-08-19 20:21:12 -04:00

5.8 KiB
Raw Blame History

Tools — the offline generator

Holds: the world generator and its diagnostics. Everything that produces a blueprint, and nothing that consumes one at play time.

Boundary — the tools wall:

⚠⚠ TOOLS MAY NOT REFERENCE Client/. THE DEPENDENCY RUNS ONE WAY, OR THE WALL IS NOT A WALL.

No UI, no player controllers, no shaders, no rendering code. Tools/ may use Core/.

Two reasons, both from Design - Tooling - Offline Generation.md: a lighter shipped client, and — less obviously — not handing players the world-generation logic. Shipping the generator lets it be reverse-engineered into an unfair map preview, with the whole island's layout, every settlement and every route known before anyone sets foot on the beach.

Tools emit data; they never write to a live save. A generator that could touch live server state is a corruption risk for no benefit.

Empty this phase — Phase 1 fills it

The only thing here now is Scenes/UserDirProbe.tscn + Scripts/UserDirProbe.cs, a print-and-quit diagnostic that confirms this project's user:// directory is its own and not the old prototype's. It generates nothing.


The conventions Phase 1's generator inherits

These were earned, not assumed — each one came out of the prototype's terrain arc. → Design - Tooling - Iteration and Batching.md.

1. xvfb-run for unattended generation — NOT --headless

--headless HANGS on a real generation run.

The snapshot capture awaits render frames, and there is no frame loop without a display. Measured, not assumed. A run left on --headless does not fail loudly; it sits there.

xvfb-run -a Godot_v4.7.2-stable_mono_linux.x86_64 --path ~/celerNexus/islaApocalypse-v2 <scene>

A windowed run on the desktop also invites being closed mid-run by whoever is using the machine.

The one exception is a job that awaits no frames — like UserDirProbe, which is why that one documents --headless explicitly:

Godot_v4.7.2-stable_mono_linux.x86_64 --headless \
  --path ~/celerNexus/islaApocalypse-v2 res://Tools/Scenes/UserDirProbe.tscn

If a job awaits a frame, it needs xvfb-run. When unsure, use xvfb-run — it is correct in both cases and costs nothing.

2. Environment overrides — safe BY CODE, not by care

Every path a tool reads or writes resolves through Core/Scripts/ToolingPaths.cs, and each has an environment override, so a batch cannot read over or write to the developer's live files:

Variable Overrides Default
ISLA_CONFIG_PATH the generation config file user://config.json
ISLA_BLUEPRINT_PATH blueprints read/written user://blueprints
ISLA_OUTPUT_DIR generation output (batches live under it) user://output

The point is that it is enforced by CODE, not by care. A rule that depends on an executor remembering it will eventually meet an executor who does not.

There is no second way to obtain these paths. Do not add one.

3. ⚠ File safety — permanent rules

Enforced by Core/Scripts/FileSafety.cs, which throws rather than advises.

  1. No deletion in the runtime root or anywhere under batches/.
  2. Intermediates persist in a scratch/ subfolder that is never cleaned.
  3. The developer's placed files are never touched.
  4. Any deletion is named explicitly in the run report.

These came from a real incident: an executor admitted it had been deleting the developer's staged test blueprint. It was owned and fixed in code. That is why these are rules and not guidance.

4. Batch layout

batches/NN_<name>/<seed>_<variant>/
batches/NN_<name>/INDEX.md
batches/NN_<name>/scratch/          ← persistent; never cleaned

A/B comparisons are browsed by a human, and a flat directory of same-named PNGs is not browsable. The INDEX.md is what makes a batch readable a week later.

Batches are OUTPUT. They live under ISLA_OUTPUT_DIR (i.e. under user://), not in this repo. The batches/ folder here carries the convention, not the data. No batches are run this phase.

5. Iteration levers, for when the generator exists

  • Skip the road pass for all terrain and water iteration. In the prototype this cut a run from ~26 min to ~80 s — a 19× cut, and the difference between iterating on terrain and not iterating on terrain. Blueprints from such a run carry present-but-empty road sections, which is legitimate, not corrupt.
  • Build the oracle before the taste-iteration, not after. Because the classify path was pinned to uncurved height, every shaping iteration had a hard automatic correctness check (biome and water maps md5-identical). Five rounds of taste-iteration were safe because correctness was not being judged by eye. Where a future phase has a subjective gate, ask first what the automatic invariant is.
  • Config-gate every shaping change, with the legacy behaviour surviving on the other side. It keeps changes comparable as an A/B pair, and it means a rejected change costs a flipped default rather than a reverted commit.
  • The lever is variants per batch, not speed per pass. Two Phase B tasks ran ~2 hours each, which looked like the pipeline getting slower. It was not — a single pass stayed at ~2 minutes. The cost was A/B/ablation multiplication. When a batch is genuinely wide, say so up front.

6. Scaling discipline

Nothing uses a raw pixel number. Every distance, radius, threshold and noise frequency comes from Core/Scripts/GenerationScale.cs. Read its header before adding any constant — including the tightening on normalized additive noise offsets, which is a forward-guard for the Phase 1 noise port. → Design - Tooling - Scaling Discipline.md.