Skip to content

DW0452/DW0453: a puppet may only make moves its own body can make - #316

Open
stellarfeline wants to merge 4 commits into
mainfrom
fix/puppet-route-geometry
Open

DW0452/DW0453: a puppet may only make moves its own body can make#316
stellarfeline wants to merge 4 commits into
mainfrom
fix/puppet-route-geometry

Conversation

@stellarfeline

@stellarfeline stellarfeline commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Island round 21, two owner sightings of the flock. Both are move-actor puppets
crossing geometry, both were invisible to every existing proof, and they are
two different root causes on one surface — reported as such rather than
forced into one story.

compiler::clearance proves where a body is. Nothing proved what it did
to get there. This PR adds that proof, and the capability model it has to rest on.

Per-leg route table (binding count: 26 legs, 1672 route cells, 82 rises)

Every walked leg of nobodys-cave-island, its computed A* route intersected
against the assembled voxel model. move-actor legs: 14 (12 sheep + 2
actor/polyphemus-herdsman), matching the campaign's declaration. move-npc
legs: 12. All 26 are Locomotion::Ground; zero climber, zero flier, zero
aquatic
— stated because a proof written for walking bodies would be unbound
over exactly the bodies it understands least.

legs what the route crosses cell verdict
16 (4 npc + 12 actor) closed oak_fence_gate[facing=east,open=false] [18, 73, -63] finding B — reproduced
12 (all actor, sheep) steps onto full-cube mossy_cobblestone course of the fold's north wall, comes down the far side support [7, 63, -10], barrier [8, 63, -10] finding A — reproduced
10 nothing clean

Finding A: reproduced, but not as either of us framed it

It is not a wall block, and nothing passes through anything. The fold's ring
is cobblestone_wall down the east and west sides and at the north corners, and
full-cube mossy_cobblestone (one block high) along the middle of the north and
south edges. A wall block is a 1.5-tall barrier the router may neither pass nor
stand on — standable_fp requires solid ground below and is_occupied
counts tall as impassable, and both rules hold. A full cube is an ordinary
one-block ledge every body in the dims table can hop.

So the enclosure the eye reads as one wall is, to the route planner, impassable
at nine cells and a step at five. The sheep hugs the pen's east face at
[7, 63, -9], rises a block straight upnav::resample's step-up L is a
vertical translation in place, by design, because it is what keeps a body out of
the step block's corner — crosses the north wall's top at [7, 64, -10] and
drops into the meadow at [7, 63, -11]. The pen's real opening at [6, 63, -6]
is never used. Twelve legs do it. From a camera cutting away, an animal walking
up a stone wall.

The move itself is legal: a one-block rise is inside the player-class jump every
body here has. What is wrong is that the line the content drew as an enclosure is
not the enclosure the router sees.

Finding B: reproduced, and worse than reported

[18, 73, -63] shipped oak_fence_gate[facing=east,open=false] in a fence line
that runs east-west. A gate whose facing is on the X axis gets vanilla's
X_SHAPE — thin in X, spanning the cell's full depth in Z — so the leaf stands
edge-on in the doorway. Walking straight through is impossible and offsetting
to x≈18.0 squeezes past the leaf: exactly what the owner described, and it
confirms the orientation is wrong independently of the open/closed question.

Why nothing stopped it: is_occupied deliberately excludes use_gates, because
a closed gate is passable — for the player, who opens it with an
adventure-legal right-click. Scripted walks were routed on the player's rules,
justified in plan_moves' own doc as "the beat's fiction controls the gate".
Nothing proved that fiction, and nothing could have: a scripted walk is a tp
polyline whose puppet performs no interaction at all, and no runtime verb
changes a fence gate's block state
, so a gate that ships open=false is shut
for the whole delve.

DW0451 fired sixteen times and called it advisory on the grounds that a barrier
cell "is a narrow post or panel, so whether the body interpenetrates depends on
sub-block shape the compiler does not carry". That reasoning is about a body at
rest
. It is the wrong question for a body in motion, and this PR does not
change DW0451's severity — it adds the proof that asks the right question.

The general form, closed as two diagnostics

New module compiler::traversal, mirroring the DW0450/DW0451 tier split:
the body physically cannot, vs. the compiler can measure but must not adjudicate.

DW0452 — error. A walked leg's route contains a move the body cannot make.
One bound rule today: the route enters a closed fence-gate cell and the body does
not open gates.

DW0453 — warning. A walked leg goes over a barrier line across a full-cube
course of it: it steps onto a cell whose support is a full cube standing level
with and orthogonally beside a 1.5-tall fence/wall cell, and comes back down
within 4 route steps. A partial floor (slab, dirt_path) beside a fence is never
a course — that is floor detail, not a wall.

Two rules, two questions, two exemption axes

Owner correction (round 21), and it is the structural point: a flying body may
skip the climbing/surmounting checks; the collision check it must still owe.

  • DW0452 is a collision-and-interaction question. The gate leaf spans the
    full cell across one axis, the planned route runs down the cell's centre line,
    and the puppet performs no right-click — and not one of those three facts
    changes because the body has wings or claws. A tp-driven puppet is moved along
    the planned cell route whatever its body is. So the rule binds to every
    body; the only thing that can excuse it is opens_gates, which is why that is
    a per-body field and not a constant. Locomotion does not touch this rule.
  • DW0453 is a locomotion question. "Did this body go over a line it may not
    go through?" is a defect only for a body whose way past a wall is round it.
    Climbers and fliers are exempt — from this rule and nothing else.

The exemption is expressed per rule (exempt_from_gate_rule,
exempt_from_surmount_rule) rather than as an early skip over the whole body. An
earlier draft did the latter and let a flying body walk through a closed gate in
silence. gate_use.cells in the ledger counts route cells for every
non-gate-opening body regardless of class, so the binding count itself shows the
rule is total.

Capabilities come from the entity, and the table is built to fail safe

Spiders really do climb, so the rule cannot be "no body crosses a wall".
Traversal::of_entity derives Locomotion from the entity id under one stated
membership rule, built around an asymmetry: a too-strict classification costs a
false positive the owner dismisses in a minute; a too-loose one costs a body that
is never examined and reports green.

  1. Ground is the default AND the checked class. Every id vanilla data does
    not positively answer lands there — unrecognised ids included. Ambiguity
    resolves to Ground.
  2. A class may carry an exemption only when its membership is vanilla's own
    answer, or a closed cited list whose exemption is advisory-tier.
    Nothing is
    ever exempt from the error tier.
  3. Membership is decided by how a body MOVES, never by its name.

Re-derived on review, every non-Ground entry:

class membership test exempts
Ground default; everything not positively answered below nothing
Climber vanilla's Spider and its subclasses — spider, cave_spider, the only mobs whose onClimbable() is true on horizontal collision DW0453 only
Flier leaves the ground under its own power: 11 species DW0453 only
Aquatic vanilla's own #minecraft:aquatic tag, read from the vendored registry nothing

Two corrections came out of that pass. breeze was listed a flier and is
not
— it "moves around by hovering on the surface and by leaping" and cannot
ascend (wiki); it walks, so it is checked.
#minecraft:fall_damage_immune is the tag that looks like a flight signal and is
not — it holds breeze, chicken, cat, iron_golem, shulker. And the
aquatic hand list was wrong by three
: eleven entries against vanilla's
fourteen, missing turtle, nautilus, zombie_nautilus. It is now read from
the tag, and it exempts nothing, so its membership can never cost a proof. The
vendored entity-tag table moved to registry, beside the other vanilla tables,
so DW0496 and this proof read one copy.

Every hand-listed species is CI-required to exist in the pinned entity registry,
so a typo or a rename at the next MC pin is a red rather than a class that
silently stopped matching.

Deliberately not modelled: per-entity jump reach. Every rise is measured
against the player's apex for every body, because real JUMP_STRENGTH defaults
live in server code rather than any registry the compiler reads.
validation/traversal-gate.json carries that axis as declared-unbound with its
reason
rather than leaving a reader to infer it from silence.

Proposed, NOT implemented — an authored override

New DSL surface needs an owner-approved spec, so this is a proposal only. Shape:
an optional traversal object on a stage-5 actor (and stage-2 NPC), beside
entity{"climbs": true} / {"flies": true} — overriding the
entity-derived default, so a "spider sheep" is a declared creative choice with a
proof behind it. Note opens_gates is deliberately not in that shape: no
body opens a gate, and the fix for a gate is to ship the gate open. The instance
fix here does not need any of it; nothing in this PR blocks on it.

Instance fix (content repo)

Content PR: stellarfeline/delvewright-campaigns#fix/puppet-route-geometry.
Two world-edits batches, no engine widening:

  • batch/fold-ring-one-material — the fold's ring becomes one material on both
    greenfield pieces (the prefab is drawn twice, like batch/fold-clear). The
    south doorway and the south-west corner gap stay air, so the fold still has a
    way in and out, and it is now the only way.
  • batch/pen-gate-open — the pen gate ships open and square to its fence line.
    An open fence gate has no collision at all, so the same route becomes honest
    for puppet and player alike.

One engine fix the instance fix needed

edit::write_cell now honours open=true. Assembled::open_gates — the side set
occupancy_of reads to tell a closed gate from an open one — was populated only
by the prefab palette read, and every edit write unconditionally cleared it. So a
stage-7 edit could write oak_fence_gate[open=true], ship exactly that block in
the world, and still have every proof downstream model the cell as shut: the model
contradicting the bytes it emitted, and the only available fix for DW0452
unauthorable. Its own red→green is the_same_gate_shipped_open_is_silent.

What CI now proves

  • DW0452 fires on a walk whose only crossing is a closed fence gate, names the
    cell and the capability the route assumed, and is silent when the same gate
    ships open.
  • A flier-bodied puppet routed through a closed gate is DW0452 — the
    owner's correction, as a test. It fails under the rejected early-continue
    structure and passes under this one.
  • …and the same flier IS excused the surmount advisory, checked against the same
    fixture that flags a sheep, so the silence is evidence rather than an absent
    code path.
  • An entity the table has never heard of is checked, not skipped — end to
    end, through a real build, for minecraft:mannequin (the body every skinned
    NPC wears) and minecraft:breeze. That safety claim previously lived only in a
    comment.
  • The exemption matrix per rule: no class is exempt from the error tier; climbers
    and fliers only from the advisory tier. A future edit that wires locomotion
    back into DW0452 has to delete an assertion to do it.
  • Every hand-listed species exists in the pinned 1.21.11 entity registry.
  • DW0453 fires on a wall line pierced only by a full-cube course, and is silent
    when the same line has a real opening; barrier_course treats a slab beside a
    fence as floor detail, not a wall.
  • The binding ledger is emitted, states a non-zero count for a walking campaign,
    and names every locomotion class.
  • Every existing test still green (154 test binaries), fmt/clippy -D warnings
    clean, check-dw-codes.py bidirectional (209 codes, all covered).
  • ADR-0006: island builds byte-identical twice.

Machine red→green, and re-running the general form against the current build

before after
island build DW0452 error, exit 3 exit 0
DW0453 (with the gate fixed, ring not yet) 12 legs, all naming [7, 63, -10] silent
DW0451 leg advisories 16, all naming [18, 73, -63] 0
island warnings total 23 6

The 6 that remain are DW0498 (pool repeat) and the Polyphemus DW0359/DW0451
pair the owner has already rejected — untouched, as instructed. Her note that
DW0359's threshold reads as too cautious is recorded here and not acted on.

Re-run against the current build turned up nothing further. Both codes bind
to exactly the two reported instances and nothing else across the island's 26
legs. One honest gap: hollow-vigil, the only other live campaign, is red at
stage 6 on DW0331 (two over-wide dialogue labels) on main already — it never
reaches emission, so the traversal proof is unbound there and cannot be said
to have checked it. That is a finding, not a pass.

Merge gate

Campaign content is player-experienceable, so this does not merge on green —
it goes into the owner's next playtest batch, paired with the content PR. What to
look for: the flock files out of the beach fold through its opening rather than
over the wall, and the mountain pen's gate stands open and square to the fence,
with her own character able to walk straight through it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL

…body can make

Island round 21, two owner sightings of the flock, one surface (`move-actor`)
and two different root causes. `clearance` proves where a body IS; nothing
proved what it DID to get there.

Through (DW0452, error). The mountain pen's gate shipped
`oak_fence_gate[facing=east,open=false]` and sixteen walked legs crossed it,
in a cell the owner herself could not walk through. The occupancy model
excludes use-gates from `is_occupied` because a closed gate IS passable — for
the player, who right-clicks it — and scripted walks were routed on the
player's rules on the stated ground that "the beat's fiction controls the
gate". Nothing proved that fiction, and nothing could: a tp'd puppet performs
no interaction and no runtime verb changes a gate's block state. Capabilities
now come from the entity (`Traversal::of_entity`), so the rule is "this body
cannot", not "no body may" — a spider routed over a wall stays correct.

Over (DW0453, warning). The beach fold's ring is `cobblestone_wall` on two
sides and full-cube `mossy_cobblestone` along the middle of the others, so the
router hopped the low course and twelve legs left the pen over its wall
instead of through its opening. With `resample`'s L-shaped step-up — a
vertical translation in place — that renders as an animal climbing a stone
wall. Advisory: the move is legal, and only the author knows whether a
one-block course is a kerb, a stile or an enclosure.

Also: `edit::write_cell` now honours `open=true`. `Assembled::open_gates` was
fed only by the prefab read and cleared on every edit write, so a stage-7 edit
could ship `oak_fence_gate[open=true]` in the world and have every proof model
it shut — the model contradicting its own emitted bytes, and the one available
fix for DW0452 unauthorable.

`validation/traversal-gate.json` states the binding count per locomotion
class, and declares `jump_reach` unbound on purpose: per-entity JUMP_STRENGTH
is server-code attribute data, so a table of it would be invented precision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL
@stellarfeline

Copy link
Copy Markdown
Owner Author

Planner review: approved on content, HELD for the owner's playtest batch, paired with content #29.

You corrected both of us, and that is the finding

I framed finding A twice and was wrong twice — first as a coverage gap for full blocks, then, after the owner's correction, as a route going over a wall block. It is neither. The fold's ring is mixed: cobblestone_wall on the east and west and at the north corners, full-cube mossy_cobblestone elsewhere. The sheep does not climb and nothing passes through anything. It makes an ordinary one-block hop onto a full cube — a move every body in the dims table can make — and nav::resample's step-up L renders that rise as a vertical translation in place, which from a camera cutting away is an animal walking up a stone wall.

the line the content drew as an enclosure is not the enclosure the router sees

Nine cells impassable, five cells a step. That sentence is the actual defect, and neither the owner's sighting nor my two theories would have produced it. It came from measuring 26 legs against the assembled model instead of reasoning about block classes.

Finding B is worse than reported, and the reason it survived is the important part

oak_fence_gate[facing=east,open=false] in an east-west fence line: the leaf stands edge-on in the doorway, which is why the owner had to offset to squeeze past. The orientation is wrong independently of open/closed — a detail her description contained and I did not extract.

And the reason nothing caught it is the kind of thing worth writing on a wall:

is_occupied deliberately excludes use_gates, because a closed gate is passable — for the player, who opens it with an adventure-legal right-click. Scripted walks were routed on the player's rules, justified in plan_moves' own doc as "the beat's fiction controls the gate". Nothing proved that fiction, and nothing could have.

A tp polyline performs no interaction, and no runtime verb changes a fence gate's block state. So the justification was not merely unproven — it was unprovable, and it sat in a doc comment reading like a design decision.

The engine fix you found on the way

Assembled::open_gates populated only from the prefab palette, with every edit write clearing it — so an edit could write oak_fence_gate[open=true], ship exactly that block, and have every downstream proof model the cell as shut. The model contradicting the bytes it emitted, and the only available fix for DW0452 unauthorable. That is a latent defect nobody was looking for, surfaced because the instance fix needed it. the_same_gate_shipped_open_is_silent is the right name for its gate.

Three judgment calls I want on the record as right

  • Per-entity jump reach deliberately not modelled, because real JUMP_STRENGTH defaults live in server code rather than a registry the compiler reads, and a table of them would be invented precision. Carried in traversal-gate.json as declared-unbound with its reason rather than left for a reader to infer from silence. That is the vacuity discipline applied to something you chose not to model, which is the harder direction.
  • An unrecognised entity id is checked, never exempted. The conservative direction is the only safe default here, and a climber is still held by DW0452 — climbing is not gate-opening.
  • hollow-vigil reported as unbound rather than passing. It is red at stage 6 on main and never reaches emission, so the traversal proof cannot be said to have checked it. Naming that is worth more than the count it would have added.

DW0359's threshold: correctly recorded and not acted on. It stays the owner's call.

What is held, and why

The paired content fix is campaign content, so this is hers to clear. The proposed traversal override ({"climbs": true} / {"flies": true} / {"opens_gates": true}) is new DSL surface and correctly proposed, not built — filed for her ruling. Nothing in this PR blocks on it.

Both go into the batch with #314 and the l10n holes, which is also the v1.1 batch.

stellarfeline and others added 2 commits August 6, 2026 01:08
… may skip it

Owner correction, island round 21: a flying body may skip the
climbing/surmounting checks; the collision check it must still owe.

The exemption was on the wrong axis. `check_traversal` did one early
`continue` over the whole body before BOTH rules, which conflated two
different questions:

- DW0452 is COLLISION-AND-INTERACTION. The gate leaf spans the full cell
  across one axis, the planned route runs down the cell's centre line, and
  the puppet performs no right-click — and not one of those three facts
  changes because the body has wings. A tp-driven puppet is moved along the
  planned cell route whatever its body is. So the rule binds to EVERY body,
  and the only thing that can excuse it is `opens_gates`, which is why that
  is a per-body field and not a constant.
- DW0453 is LOCOMOTION. Going over a line is what a climber does, and a
  flier makes no ground step-up. This is the rule locomotion governs, and
  the only one.

The exemption is now expressed per rule (`exempt_from_gate_rule`,
`exempt_from_surmount_rule`) rather than per body, so a future edit that
wires locomotion back into the error tier has to delete an assertion. The
ledger's `gate_use.cells` counts every non-gate-opening body regardless of
class, so the binding count itself shows the rule is total.

Table, re-derived (planner review). `breeze` was listed a flier and is not:
it hovers on the surface and leaps, and cannot ascend
(minecraft.wiki/w/Breeze) — it walks, so it is checked. `Aquatic` now reads
vanilla's own `#minecraft:aquatic` tag instead of a hand list that was
missing `turtle`, `nautilus` and `zombie_nautilus`; it carries no exemption
at all, so its membership can never cost a proof. `Climber` and `Flier` stay
hand-listed with their tests stated, permitted only because they gate the
advisory tier; `#minecraft:fall_damage_immune` is NOT a flight signal (it
holds `breeze`, `chicken`, `cat`, `iron_golem`, `shulker`). The vendored
entity-tag table moves to `registry`, beside the other vanilla tables.

Red->green: `a_flier_walked_through_a_closed_gate_is_still_dw0452` fails
under the old early-`continue` structure and passes under this one. The
unknown-id fallback — the module's load-bearing safety claim, previously
only a comment — is now pinned end to end: a body the table never heard of
is checked, not skipped. Every hand-listed species is CI-required to exist
in the pinned registry.

Player-facing output byte-identical to the pre-review build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjQ5p1Kv5MrkGPumi7yXWL
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.

1 participant