feat(dsl,compiler): spec-0026 foundation — horizon library surface, per-area walk_y datum, DW0364/DW0366/DW0367 (dsl 0.9.0) - #260
Open
stellarfeline wants to merge 10 commits into
Open
Conversation
…er-area walk_y datum, DW0364/DW0366/DW0367 (WIP: tests/docs follow) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…er-area walk_y datum, DW0364/DW0366/DW0367 (dsl 0.9.0)
Stage-1 horizon generalizes into the spec-0026 composition: string shorthands
(byte-identical for void/ocean) OR the object form {base, ...params}, all six
bases parsed and param-validated; flatland lands end-to-end (grass superflat
ambient one block under the scene walk plane, plains biome, bare);
valley/cherry-valley/summit/sky are reserved (DW0141) until their surround
slices. Placement moves to the per-area datum walk_ref_y - walk_y (DW0367),
retiring plan::OCEAN_BASE_Y; DW0364 proves every placed piece's standable
cells sit above the flood level empirically, with no waterline_y exemption —
the #149 flooded-interior class is now impossible by construction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 4, 2026
…dation # Conflicts: # crates/compiler/src/lib.rs # crates/compiler/tests/cli.rs # crates/dsl/src/envelope.rs # crates/dsl/src/lib.rs # docs/reference/compiler.md # versions.toml
…am, not by this slice The DW0366 row claimed `summit.vista_radius`'s floor was unenforceable because the spec contradicted itself (floor 192 vs default 176). That was true when the foundation slice reported it and stopped being true on 2026-08-04: the spec-0026 amendment (PR #261, on `main` for 66 commits now) resolved both open params — `vista_radius` measured from the scene bounding box, floor 192, default 208; and `blend_width` 1..=16. Enforcement is deliberately NOT added here. Both params configure surrounds this slice does not emit, and the valley slice (task #155 W-B, PR #259, based on this branch) already carries the checks and the corrected default verbatim. Implementing them twice would put a duplicate in the dependent branch's path for no behaviour gained. The row now says what is true: the ambiguity is resolved, the enforcement is owed, and which slice owes it. No behaviour change: `dsl::validate::horizon_rules` and `horizon_defaults` are byte-identical to this branch's pre-merge state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL
…compiler proves (task #shallows) `DW0364` refuses standable ground at or below the horizon's flood line with no exemption, deliberately: that exemption is what made #149 invisible. Applied to the released `nobodys-cave-island` it fires on 26 cells at world y=62 — the shoreline the two bank-falls batches exist to make. Owner ruling 2026-08-06: the sculpted shoreline stays, and it needs a first-class declaration. The declaration is NOT a suppression switch. `flood` admits the horizon's ambient sea into a declared envelope; the compiler computes which cells the sea actually reaches and materializes them as water, in the model AND in the emitted world. A cell stops being a `DW0364` violation only by ceasing to be ground. Three properties do the safety work, and none of them is "skip the check": - a sealed room under the sea is unreachable by the sea, so declaring `flood` over the #149 fixture is `DW0394`, never green — it only changes which red; - over-declaring costs you your own map (a wider envelope wets more of it, and an envelope that swallows a corridor turns nav red), so it silences nothing; - under-declaring is `DW0395`: water that runs on past the envelope into an undeclared air cell of a placed piece means the shoreline is not where the author said it is. Re-proved after every later batch. `DW0364` keeps its exact rule, tier and domain. A campaign that declares no `flood` emits byte-for-byte what it emitted before (`DW0141` fences the verb below world-edits 0.9.0). Spec (proposal) in `docs/specs/spec-0029-deliberate-shorelines.md`; the proof is `crates/compiler/tests/spec0029_flood.rs` plus the island build, which goes green on exactly this declaration with 25 wetted cells while `DW0364` goes on refusing the one sealed pocket the envelope also covers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL
…ken on an unmerged branch Two workers picked the next free spec number on the same day from `main`, where the highest is 0028. Neither could see the other's branch: `docs/spec-0029-i18n-v2` already holds `spec-0029-i18n-v2-client-selected-language.md`. Text-only rename plus the test-file name; no behaviour change. `spec0030_flood` 6/6 green.
stellarfeline
added a commit
that referenced
this pull request
Aug 7, 2026
…he board is red (task #44) (#322) Every gate in CI built a FIXTURE. Nothing ever built a real campaign, so the product could stop compiling with the whole board green — PR #260 reached 10/10 while stopping the flagship released campaign `nobodys-cave-island` from building at all (26 x DW0364 on standable cells at the ocean line). New required status check `campaign builds (every campaign in the content repo)` builds every campaign the pinned content checkout carries, in every language its world.json declares, on every push. Campaigns are DISCOVERED, never listed, so the next content re-pin gates a new campaign with nobody remembering. A campaign that cannot build today is recorded in .github/campaign-build-exclusions.toml, which INVERTS the assertion instead of removing it: still built, must still fail, and must fail with exactly the recorded codes — an extra code is a new break that was hiding behind the exclusion, and a success is an expired exclusion. Both red. One entry today: hollow-vigil, DW0331 (task #34). Validator-only: no crate, no emission path and no prefab is touched, so player-facing output is byte-identical. Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
stellarfeline
added a commit
that referenced
this pull request
Aug 8, 2026
87a8ade -> e4c58c0f78f2e0e949c625697c3f5b04df125aff Carries content #29 (the flock walks out of the pen), #32 (three actor nameplates the widened l10n inventory now requires) and #33 (untrack the absolute-path symlink). Ordering, established by measurement rather than assumed: this must land BEFORE #317. A sidecar row the engine does not inventory is tolerated (built green against today's main), but an inventory key with no sidecar row is DW0180 and hard — so new-engine-with-old-content reds, and old-engine-with- new-content does not. The pin therefore leads the engine here. Note this is the OPPOSITE of the #260/content#21 ordering, where PrefabMeta's deny_unknown_fields made engine-first the only safe order: the direction is a property of the change, never a rule of the repo.
stellarfeline
added a commit
that referenced
this pull request
Aug 8, 2026
…on (spec-0029) (#317) * feat(compiler): two holes where player-visible text escapes translation (spec-0029) The owner played the island in Chinese and read English. Two independent leaks, both closed here, plus the general form of each so neither class can recur. **Hole 1 — a body's name was not in the inventory.** `dsl::l10n::each_string` inventoried an actor's DROPS but never the actor's own `name`, so every `actors[].name` shipped as a literal. That is one hole with two signatures on the island: the giant is `npc/polyphemus` (translated, correct when he stands still) AND four actor puppets all named `Polyphemus` (untranslated, English the moment a cutscene stages one) — while the eight sheep have no NPC identity at all and were English in every frame. 16 actors, 16 carrying a name, 0 inventoried. Inventorying the field alone would have made it worse: a translator asked for `Polyphemus` five times can answer five ways, and the giant's name would change as he walked into a cutscene — an authored defect rather than an accidental one. So **an entity display name is keyed by its canonical English text, not by its declaration site**: the first site in the traversal (NPCs before actors) owns the key and every later site carrying the identical name emits that same key. The translator is asked once; two bodies a player reads as one character cannot render as two. Scoped to `npc.*.name` + `actor.*.name` — prose stays per-site, and merging `wave.*.mob.*.name` would retire keys live campaigns already translate, which is an owner call, not this PR's. **The general form.** `DW0185` proves a string the inventory KNOWS reaches a component; it is blind to one the inventory never met, which ships English in silence — how this survived twenty playtest rounds. `crates/dsl/tests/ l10n_surface.rs` closes that half: it enumerates every string-valued property of the seven stage schemas (derived from the Rust types, so complete by construction — 78 today) and requires each to be classified Inventoried / Reference / Machine / NotPlayerVisible(<why>), in both directions. A new `String` anywhere in the DSL is red until somebody records whether a player reads it. A test rather than a DW code because the defect is in the compiler: no campaign input can produce it. **Hole 2 — the compiler's own chrome was untranslatable.** Thirteen strings the compiler writes itself had no key and no override. They are now compiler-owned end to end (`dsl::chrome`): reserved `delvewright.ui.…` keys, English canonical, translations shipped with the engine, zero campaign authoring. Eight are product chrome (`New objective: `, `Delve Complete`, `Choose your class`, …) — no author wants to write those, which is why the answer is not an override; five are the diegetic defaults whose authored overrides already exist, are unchanged, and still win. Chrome rides the existing road rather than a parallel one: it enters emission as a translation tag, lowers through `emit::tr`/`snbt_component`, and a site that fails to is `DW0185` like any authored string. Three of the eight were CONCATENATIONS, which freeze English word order into every language. They are now one key with `%s` carried by the component's `with` — `"%s — complete."`, `"New objective: %s"`, `"Waiting for the party — %s / %s"` — vanilla's own primitive for the job. A unit test requires every language's placeholder count to equal the English's. `DW0186` reserves the namespace: a sidecar may not define a chrome key, which would otherwise be written into the language file and replace product chrome. **Language coverage.** `dsl::mclang::CLIENT_LANGS` is the pinned client's own language set — 143 stems DERIVED from Mojang's 1.21.11 asset index, with the digests recorded and `tools/derive-client-langs.py` to re-derive; it replaces the hand-maintained 25-entry table and is a strict superset, so nothing that compiled stops compiling. Chrome tables: 30, covering 47 locales; every other language reads English — absent from its lang file, never faked. Chrome is emitted only into the files a delve already ships, so a French client never gets French chrome around English story. The translations are machine-produced and unreviewed; that is stated in the module header, not glossed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL * feat(compiler,skill): translation provenance, and the naming rule that prevents divergence Three follow-ups on the review of #317. **1. A sidecar row can go stale silently — now it cannot (`DW0187`).** Coverage validation compares key SETS: rewrite an authored line and its translation is present, applied and WRONG, with no key moved and every check green. The text-owned key scheme this PR introduced adds a second, nastier way in — rename ONE body and the key migrates to ANOTHER, so the row that goes stale is not the row the author edited, and `DW0180` points somewhere else entirely. The sidecar now records the English each row was translated FROM (`source`), so the compiler compares instead of a human auditing. It is deliberately the GENERAL fix, not a migration-only guard: any edited line is caught, whatever kind of string it is. `source` is additive — an older sidecar parses unchanged — so `DW0188` counts its unguarded rows on every run and names the deprecation window. An unadopted sidecar is a reported number, never a silence that reads like a pass. `i18n-translate.py` writes `source`, so adoption is a re-run that retranslates nothing. **2. Wave-mob names stay per-site keyed** (owner ruling, 2026-08-06). Live campaigns keep the keys they already translate. **3. The prevention moves to authoring time, where she put it.** Declining the merge leaves the divergence real, so the rule goes where an author can act on it: `SKILL.md` *Writing craft* §D — byte-identical entity names collapse to one name and one translation, wave-mob names do not, and what to do in each direction. Written as a rule applied while naming, for an authoring agent; the key-scheme mechanics stay in `compiler.md`, for a compiler maintainer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL * chore(audit): two baked-string findings are closed by this PR — drop their ledger entries The capability-ownership checker refuses a stale exemption by name: an entry in BAKED_STRINGS whose constant no longer exists is a FAIL, because "a stale exemption hides the next one". This PR moves SEAL_HINT_DEFAULT and BOUNDARY_DEFAULT_MESSAGE behind `dsl::chrome`, where they are inventoried and translatable — so both stop being baked literals, and the guard fired on its first real occasion. Ledger entries dropped; the audit doc's row 23 and its check-B binding count (5 -> 3) follow, and the demonstrated-firing transcript is marked historical for B with a surviving entry named for reproducing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL * chore: re-pin content onto the island v1.1 batch 87a8ade -> e4c58c0f78f2e0e949c625697c3f5b04df125aff Carries content #29 (the flock walks out of the pen), #32 (three actor nameplates the widened l10n inventory now requires) and #33 (untrack the absolute-path symlink). Ordering, established by measurement rather than assumed: this must land BEFORE #317. A sidecar row the engine does not inventory is tolerated (built green against today's main), but an inventory key with no sidecar row is DW0180 and hard — so new-engine-with-old-content reds, and old-engine-with- new-content does not. The pin therefore leads the engine here. Note this is the OPPOSITE of the #260/content#21 ordering, where PrefabMeta's deny_unknown_fields made engine-first the only safe order: the direction is a property of the change, never a rule of the repo. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
versions.toml conflict: main re-pinned content to its own tip (e4c58c0f); this branch pins the walk_y backfill BRANCH. Resolved by re-syncing the content branch onto e4c58c0f and pinning the new sha — the pin stays a branch pin because the change is atomic across two repos and has no valid merge order (deny_unknown_fields on prefab metadata makes content-first impossible; a walk_y-less library makes engine-first impossible).
These cannot merge separately. The foundation's per-area walk_y datum makes DW0364 see the island's banks, and DW0364 fires on 26 standable cells at y=62 — the ocean line — in ALREADY RELEASED content. Owner ruled those banks intended (2026-08-06), and the answer to an intended shoreline is spec-0030's `flood`: the author names an envelope, the compiler works out what the sea reaches inside it and builds that water. DW0364 is untouched; a cell stops being a violation only by ceasing to be ground. So the foundation alone breaks a released campaign, and the flood verb alone has nothing to reason against. One unit. Conflict in edit.rs was a spliced doc comment, and resolving it fixes a real defect on the unmerged branch: `Tide` had been inserted INSIDE `write_cell`'s doc comment, so on `docs/spec-shallows` the first three lines of `struct Tide`'s documentation are about clearing open-gate markings and `fn write_cell` has no documentation at all. `Tide` now keeps only its own doc and write_cell's rejoins write_cell — in main's newer form, which carries the island-round-21 `open=true` paragraph.
…ed pair The pin now names `content/island-tideline`, which CONTAINS the walk_y backfill branch — one content branch carrying both halves this engine needs, because the pair is atomic across two repositories and has no valid merge order in either direction. Capability check C flagged HorizonSpec/ResolvedHorizon as structural twins. Ledgered ACCEPTED, with the reason stated as a re-checkable structural test rather than an assurance: one is every field Option + deny_unknown_fields + serde (what an author may write), the other is every field concrete with no serde (what downstream reads). Sharing the type would delete DW0366 — rejecting an `ocean` that declares `blend_width` is only possible while *absent* and *defaulted* are distinct states. The entry says to generalise the CHECK on that test if a third such pair ever appears, rather than grow a third exemption. Island builds green on this engine, both languages: DW0364 0, DW0394 0, DW0395 0, 0 errors. Before this merge it was 1 error, DW0364, on already released content.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
spec-0026 foundation (task #155 slice W-A): horizon library surface, per-area
walk_ydatum, DW0364/DW0366/DW0367Merge gate: owner playtest batch (engine emission = player-experienceable). Do not merge on green. Machine red→green on the motivating scenario is below and admits this into the batch.
Pairs with content PR stellarfeline/delvewright-campaigns#21 (
worker/spec-0026-walk-y-backfill) —versions.tomlre-pins to that branch's SHA (a63d1a0); re-pin to contentmaintip after the pair merges.What changed (design level)
horizonaccepts the existing strings (byte-identical for"void"/"ocean") OR the object form{base, …params}(spec-0026 §1). All six bases parse with their param schemas;"cherry-valley"desugars exactly to{base:"valley", flora:"cherry", palette:"stone-petal"}(parameter row, not a base — machine-asserted). Fences: the new surface isDW0141below 0.9.0;valley/cherry-valley/summit/skyare additionally reserved at 0.9.0 (DW0141, the npcvendor/bossprecedent) until the W-B/W-C surround slices land — never silently mis-emitted.DW0320generalizes per §5: every non-void base requiresboundary.minecraft:plainsbiome, bare by design;Ambient::Flatlandbranch in the DW0322 boundary model (vacuously safe: ground everywhere, flush). The §3 seam material-dither band + acceptance criterion 4 belong to the surround-generator slices.plan::OCEAN_BASE_Y(deleted): area base y =walk_ref_y − walk_y;walk_yis required prefab metadata for every piece placed in a non-void horizon (DW0367, build/exit 3; pools additionally require entry-role agreement). Islandwalk_y=3→ base 60 — the datum change does not move the island (asserted against the real contentisland-beach-camp).waterline_yexemption — closes the DW0344 gap; DW0344 retained for waterline-declaring shore pieces (sea-mating), message rewritten to name the datum-equation term. Supersedes interim task feat(dsl,compiler): map editor L2 massing verbs — swap/insert/remove/rewire/reseed-piece (spec-0017 PR 3) #149.ratio2..=3,min_drop≥ 100, build-range bounds onplateau_y/float_y) and params foreign to the declared base.compiler::horizon: the one place horizon → physical facts (walk_ref_y, flood_level, generator-settings literals, ambient, slice status).docs/reference/compiler.mdupdated in this PR (rows DW0364/DW0366/DW0367 added; DW0141/DW0320/DW0322/DW0344 rows + the world-output/stage-1 sections updated);tools/check-dw-codes.pygreen (190 codes, all test-covered).Plug-in contract for W-B (valley/cherry surround)
Stated in
crates/compiler/src/horizon.rsmodule docs. A surround generator plugs in with three one-line seams outside its own new module:compiler::valley), consumingdelvewright_dsl::ResolvedHorizon+ the campaign seed, emitting placed prefab tiles like any other piece;horizon::base_implementedtotrue, and delete the DSL-layer reserved-base arm for it indsl::validate::horizon_rules(same PR);horizon::walk_ref_y/generator_settings/nav::Ambientarms with its ambient facts.Everything else (per-area datum, DW0364/DW0367, server-properties plumbing,
check-world-settings.shparity — which asserts derivation, not values, so it is already horizon-agnostic) is base-generic.ResolvedHorizoncarriesratio/rim_height/flora/palettewith pinned defaults;HorizonFlora/HorizonPaletteare typed enums.Machine red→green: the #149 tide-mill scenario
Permanent fixture
spec0026_horizon::flooded_interior_is_dw0364_and_corrected_datum_is_green_and_dry, plus the live demonstration:waterline_y) onhorizon: oceanwalk_y: 3)DW0364— "74 standable cell(s) … at or below the ambient flood level (y=62)"walk_y: 1, what the piece really authors)0 62 0(asserted), walk plane 63 — dryFixture verdicts (acceptance criteria 1/2/3)
{base:"ocean"}object form emits byte-identical to"ocean"(new fixture). Old-engine vs new-engine on the void hello-world:datapack/,server/,critical-path.jsonbyte-identical; onlymanifest.json(content-pin provenance) and the unshippedcreator-datapack/layout.json(version: 0.8.0→0.9.0, the standard consequence of everySUPPORTED_DSL_VERSIONbump) differ — the shipped delve image (Dockerfile.delveCOPY list) carries neither beyond the manifest pin.DW0364,DW0366(5 range + 3 foreign-param cases),DW0367by code; the feat(dsl,compiler): map editor L2 massing verbs — swap/insert/remove/rewire/reseed-piece (spec-0017 PR 3) #149-shaped fixture above is red withDW0364. (DW0365belongs to the sky slice.)island_walk_y_3_keeps_base_60— real contentisland-beach-camp(walk_y: 3) plans at[0, 60, 0], exactly the retired global datum.walk_y: 3→ base 60): old and new engines produce identical diagnostic sets on it (DW0331 ×5 / DW0465 / DW0476 — pre-existing version-adoption debt, red on origin/main too); the datum change alters nothing about it.edit_ocean_breach_strands_the_player_dw0322relied on the mis-datumed placement (walk plane under the sea) that this PR fixes — its breach is now a canonical beach, correctly green. The stranding fixture now uses a genuinely lipped tileset (walk_y: 0, walk plane two over the sea) and still proves DW0322 fires.-D warningsclean;check-dw-codes/check-doc-dupes/check-versions/check-world-settingsgreen.Content pairing & adoption notes
walk_yacross all 36 GitHub-main prefabs (keep 1, cave 2, island 3, hello-room/hero 1–2), verified empirically from the.nbtgeometry (standable-cell histogram + socket-floor probe), and regenerating the keep/cave tilesets from the updated generators reproduces the backfilled files byte-identically. All five generators now emitwalk_y.walk_yadoption when it lands: shore pieces 3, plinth pieces 11 (the tk generator in this PR already derives them from its door list) — same-milestone adoption round per the version-adoption discipline.f5766f7) predated.Ambiguities → reported, not invented
vista_radiusvs its own default: spec saysDW0366onvista_radius < view-distance×16, but summit ships view-distance 12 (§6) → floor 192 > the default 176. Contradiction left unenforced (summit is reserved anyway); needs a ruling in the summit slice.blend_widthrange: none stated; unvalidated (criterion 4's no-material-wall assertion is the real gate, W-B).backdrop/placementparams: deliberately not onHorizonSpecyet — the schema rejects the fields rather than freezing a wire shape before the sky slice picks one (§4 states no wire syntax).cave-shoreauthors an ankle-deep beach (walks flush at its own waterline); under its declaredwalk_y: 2its walk plane lands dry at 63 but its authored pond would sit one block above the world sea. No tracked ocean campaign binds it; documented incave-tileset.md.waterline_y) is untouched.🤖 Generated with Claude Code
Addendum 2026-08-06 — merged
main(66 commits) into this branchThe branch sat while
mainmoved 66 commits; six files conflicted. Resolved bymerge (no rebase, no force-push — PR #259 is based on this branch). Everything
below is either conflict resolution or an adaptation forced by what
mainlanded meanwhile. No player-facing behaviour of this slice changed:
dsl::validate::horizon_rules,horizon_defaults,compiler::horizon,compiler::plan's datum and DW0364/DW0366/DW0367 are byte-identical to370a45b.The two dangerous conflicts
crates/dsl/src/envelope.rs—mainhad independently takendsl 0.9.0.Both sides bumped
SUPPORTED_DSL_VERSIONto0.9.0and both addedis_v09,for different features:
mainfor task #179's declared drops (stage 5), thisbranch for the spec-0026 horizon library (stage 1). Resolved as one version
carrying both surfaces — the established precedent (v0.8 carries spec-0025
and spec-0016 §1), and correct because the fences are per stage: raising
queststo 0.9.0 opens drops and stillDW0141s the horizon object form, andvice versa.
SUPPORTED_DSL_VERSIONSand theordinalarm were identical onboth sides and auto-merged; only the doc contract needed writing, and it now
names both halves and the per-stage consequence.
versions.toml— the content pin.mainhad advanced[content].shato87a8ade(island storybook marker), and contentmainhas since moved to885fd5d. This branch's pin (a63d1a0) was a content-branch commit sitting on4992b4f, four commits behind — reinstating it would have rolled back thestorybook marker, the v1.0.0 engine re-pin and both release fixes. Taking
main's pin was equally impossible: contentmaincarrieswalk_yon zeroof its 36 prefabs, and this engine's DW0367 hard-errors (exit 3) on any piece
placed in a non-void horizon without it.
Resolved by bringing the paired content branch forward instead: content
worker/spec-0026-walk-y-backfill(PR #21) now merges contentmain885fd5d,and the pin is that merge,
5a23d90. The merge result is exactly contentmainplus 36 one-line additions — the same shape as the original backfill,re-derived over
main's regenerated island prefabs (which changed geometry —island-beach-camp21×8×17 → 21×15×44 — and switched to 1-space indent). Theisland values were re-derived, not copied: each regenerated file still declares
waterline_y: 2, and the island convention iswalk_y = waterline_y + 1 = 3.5a23d90is a strict descendant of both87a8adeand885fd5d, so nothing isrolled back. Still a branch sha, still re-pinned to content
mainthe momentcontent #21 merges.
Semantic collisions the conflict markers never flagged
crates/compiler/src/render_plan.rs(new onmain, PR feat(render): first-class panorama emission + Chunky adoption (task #29) #295) matched theold
Horizonenum shape and stopped compiling against this branch'sHorizon::Name/Horizon::Spec. Rewritten ontohorizon::base_of, exhaustiveon
HorizonBase.flatlanddeliberately emits nohorizonkey: therender side's
Horizonis an externally-tagged enum that knows onlyocean,so a
{"kind":"flatland"}invented here would be an unparseable plan ratherthan a better picture. The wire shape belongs to spec-0026 §6's render work,
which lands with the surround slices. Ocean and void are byte-identical.
mainamended spec-0026 itself (PR docs(specs): spec-0026 amendment — vista_radius definition + blend_width range #261, 2026-08-04), resolving the twoambiguities this PR had reported rather than invented —
vista_radiusmeasured from the scene bounding box, floor 192, default 208 (the old 176
sat below its own floor);
blend_width1..=16. The DW0366 doc row's claimthat the spec "contradicts its own default" was therefore false and is
corrected. Enforcement is deliberately not added here: both params
configure surrounds this slice does not emit, and PR feat(dsl,compiler): valley + cherry-valley horizon — surround generator, biome layer, tree layer (spec-0026 W-B, task #155) #259 (based on this
branch) already implements both verbatim. Implementing them twice only put a
duplicate in the dependent branch's path — it was written, then backed out for
exactly that reason, and the row now says who owes the check.
main's(
compiler::pool/DW0498), row 7 + the new 7b are this branch's (walk_ydatum,
DW0364). Thewaterline_ybullet keeps this branch's generalwalk_y − 1statement andmain's concrete island fact, which agree(
walk_y 3 → waterline 2). TheDW0141row ismain's fuller pre-0.8enumeration plus a pre-0.9 clause naming both v0.9 surfaces.
crates/compiler/tests/cli.rsasserteddelvec 0.1.0;mainmadeDELVEC_VERSIONderive fromCARGO_PKG_VERSION(PR fix(compiler): DELVEC_VERSION derives from the crate manifest, not a hand-typed copy #293) and the crate is1.0.0. Took
main's assertion — the branch's literal is stale, not a designdisagreement.
Verification
cargo fmt+clippy -D warningsclean.including
island_walk_y_3_keeps_base_60— the datum survivesmain's islandregen — and the feat(dsl,compiler): map editor L2 massing verbs — swap/insert/remove/rewire/reseed-piece (spec-0017 PR 3) #149 red→green pair.
check-versions/check-world-settings/check-dw-codes(210 codes, alltest-covered, 1 allowlisted) /
check-doc-dupes(68 files) /check-required-contexts(10 ci.yml jobs ↔ 10 required contexts) /check-harness-dsl-version(0.9.0 in the allowlist) /check-skill-version/check-storybook-version(1 campaign, 1 allowlisted) /check-shell-pipe-shortcircuit(15 scripts) /check-compose-isolation(4services) — all green. No job renamed, so
.github/required-status-checks.txtis untouched.
Effect on PR #259
mainalone conflicts with #259 in 8 files. Against this updated branch itconflicts in 3:
crates/compiler/src/main.rs(main's DW0498 advisorychanged
read_structuresfrom&mut planto&plan),docs/reference/tools.md(
maindeletedcheck-worker-override.pyand added five checker rows), anddocs/reference/compiler.md(5 blocks — four are #259's task-#178 wave-countdowncontent vs
main's container-adoption/drops content, plus theDW0141row,which conflicts against
mainregardless). Exactly one block is attributableto this PR: the
DW0366doc row, whose resolution is to take #259's side, since#259 enforces what that row describes.