Skip to content

fix(pursuit): a stealth leg is walked crouched, a death on a pursued step is a measurement, and a build is staged only with every story world passed - #1346

Merged
stellarfeline merged 16 commits into
mainfrom
fix/maze-pursued-leg
Nov 11, 2026
Merged

stellarfeline merged 16 commits into
mainfrom
fix/maze-pursued-leg

Conversation

@stellarfeline

@stellarfeline stellarfeline commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner

The problem

A delve's critical-path bot walked every declared stealth leg standing up.
configureLeg turned the crouch on once, when the leg started, and
mineflayer-pathfinder clears every control state on setMovements, on every
setGoal and on arrival. The leg calls the first two on every hop, so the
crouch was gone before the first step: on the real pathfinder over the real
client physics, the old code walked a two-hop sneak leg standing on 83 of 83
ticks.

Four more defects were found on the same path:

  • A trigger step could never be walked crouched. The compiler always gave it
    sneak: false, and the harness refused the key on a trigger row.
  • Moves a crouched body cannot make had no single owner. Neither the bot nor
    the sculk model had a shared answer for a climb down, a step down or a jump,
    and the sculk model treated a whole sneak leg as silent.
  • On a pursued step, the bot made those moves blind.
  • climbHop's descent could end standing at the top of the ladder, on the
    edge of the floor beside the column. The pathfinder's next hop finished the
    descent only while that hop was walked standing; with the crouch held, the
    walk got stuck there.

Separately, the staging gate read only the critical-path run report and the
written-world record, so a build whose branch runs were red was still
admitted.

The fix

  • The crouch is held on every tick (movement.ts configureLeg). It
    yields only for the leg's exported stand_ups.
  • A trigger performed in front of an objective is walked as that objective
    declares
    (plan::path). It takes the sneak of the first step after it
    that is not a trigger.
  • One answer to "which moves are made standing".
    compiler::waypoints::stand_ups returns the climb downs, the steps to a
    lower route cell outside any climb, and the declared jumps. It is exported
    on a sneak leg as stand_ups and read by the bot. The sculk model hears
    exactly the cells those moves stand in (standing_cells →
    leg_vibrations).
  • A death on a pursued step is a measurement (spec-0132 §5.2 and
    criterion 10, amended, and declared as a loosening of what died
    asserted).
    • Each attempt's record states the attacker, and the run line counts
      deaths: …; closest approach d; x death(s).
    • The bot respawns as a player does, through the sequencer's one recovery,
      respawnInPlace, which retryOnDeath now shares. It then walks the step
      again from the respawn: the leg cursor rewinds, and the leg resumes from
      the proven waypoint nearest the bot.
    • The death-loop bound guards termination, not survival: a step may take
      at most as many deaths as the proven legs it walks have waypoints, and
      the death past that fails the step by name. Whether a life got further
      than the last is never asked.
    • What stays red: pursuer_lost, unread, staged/restored, and a
      death loop.
  • A downward climb takes hold before it slides (climbHop). The old
    descent could end standing at the top, on the edge of the floor beside the
    column.
  • A run that walked its branch and exited non-zero is never a passed row
    in branch-runs.json. A run-level check such as the sculk ear is not a
    report stage, and the gate reads the row.
  • Each darkness the bot receives is printed, with its position, the step,
    the deaths so far and the nearest warden the client sees.
  • A warden's darkness is judged on the server's positions. The sculk
    ear's excuse is read off the pursuit census (SculkEar.onWardenReading):
    the reading before and the one after the darkness, within 20 blocks, with
    no tolerance constant. Where the client and the census disagree, the
    disagreement is printed by name.
  • The ladder scripts that build the delve image (bot-run.sh,
    world-save.sh, reset-when-empty-run.sh) run compose from the engine
    root.
    buildx bake refused the engine's Dockerfile.delve from the
    content tree without an fs.read entitlement.
  • The staging gate requires the branch runs. A build whose
    validation/branch-plan.json names a branch owes --branch-runs, and
    every planned world must have passed on this build: each row carries the
    manifest_sha256 its bot run stamped. playtest-server.sh up takes and
    passes the flag.
  • Gallery.
    • obj/board-the-ferry and obj/cross-the-strait declare stealth, and
      trigger/ferry-tiller in front of the crossing inherits it.
    • Leg 21 exports a step-down and a jump in stand_ups.
    • Each declaration, removed, takes its sneak lines and stand-ups out of
      the emitted path.

Evidence

  • harness:
    • tsc --noEmit is clean; the whole suite passes, 811 of 811. The docs-job checks pass, except check-demo-queue, which needs the content checkout.
    • Red checks on the old code:
      • the one-time crouch: the sneak-leg test fails, standing on 83 of 83
        ticks;
      • the old descent: climb-down.test.ts fails, letting go at
        [5.5, 87.0, 4.8] instead of [5.5, 64.0, 4.8];
      • the old died failure: the death-as-measurement test fails;
      • the sequencer's pursued-death branch removed: both sequencer cases fail;
      • the bound removed: the death-loop case fails;
      • the exit mark removed from branch-runs.sh: the new merge case fails;
      • judging the darkness on the client flag again: both new sculk cases
        fail (client 20.5 / server 19.5 passes; server beyond 20 fails);
      • the cd removed from bot-run.sh: the compose-root test fails.
  • Rust:
    • delvewright-dsl lib: 228 passed.
    • delvec lib, waypoints + sculk: 25 passed.
    • tests/it, native_entrance + teleport_link: 45 passed.
    • The trigger-sneak test fails when built without the derivation.
    • Clippy over all targets with -D warnings: clean.
  • tools/tests: the staging-gate and branch-runs tests pass (157). With
    the gate's call removed, 8 of the 10 new tests fail.
  • check-gallery-coverage.py exits 0.

The warden maze on this branch (unreleased build, no override)

Engine edf9246aa, build manifest 613d5d93…. The whole ladder ran from the
content tree, and it is green. Deaths are the measurement:

Rung Result
PackTest 61 of 61 passed
Critical path passed, 0 deaths
Hatch stand passed
world/0 passed, 3 deaths (one each on steps 6, 8, 9)
world/1 passed, 0 deaths
world/2 passed, 0 deaths
Written world passed
Staging gate (--branch-runs) admitted

On every darkness, the client and the census agreed about the warden in
reach.

  • A sneak leg sprints for the proven sprint jump it makes standing: the crouch leg's sprint lock is lifted per hop for a stand-up hop of a jump declared sprint (the gallery's ferry-deck plank).

🤖 Generated with Claude Code

https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd

stellarfeline and others added 16 commits November 10, 2026 23:25
configureLeg set the crouch once, at the leg's start. mineflayer-pathfinder
clears every control state on setMovements, on every setGoal and on arrival
(resetPath / fullStop -> bot.clearControlStates), and walkLeg calls the
first two on every hop, so the crouch was gone before the body took a step:
a declared stealth leg was walked upright. The crouch is now held on each
physicsTick for the whole leg, after the library's steering and before the
tick's position packet.

A crouched body cannot do three moves a player stands up for: a downward
climb (it holds on the ladder, and will not walk off the brink), a step
down onto a lower floor, and a declared jump (vanilla's edge back-off, which
the client physics reproduces). The hold yields for exactly those hops
(climbHop for a down climb, hopStandsUp for the rest).

Measured on the real pathfinder over the real client physics
(test/sneak-leg.test.ts): with the set-once crouch the body was upright on
83 of 83 ticks of a two-hop sneak leg; with the hold, 0 of the leg's ticks.
Held through a one-block step down, the body stops at the brink; with the
leg's rule it arrives, crouched on every other tick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…ked sneaking

A trigger step's sneak was always false, and the harness refused a `sneak`
key on a trigger row and walked every trigger upright. A trigger the path
performs in front of an objective is walked as part of the walk to it, so it
now takes the `sneak` of the first step after it that is not a trigger (a
spliced link press included); critical-path.json carries `sneak: true` on
such a trigger row, the harness accepts it there and every walk of
fireTrigger takes it.

The warden maze's world/0 walks its 53-block approach to the bridge as a
trigger step in front of the walk to Wren; it was walked upright whatever
the objective after it declared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…ith every world passed

The gate read the critical-path run report and the written-world record
and nothing else, so a build whose branch runs were red was admitted: the
warden maze's world/0 died on its step 9 and the gate minted a token for
that build. A build whose validation/branch-plan.json names a branch now
owes --branch-runs, validation/branch-runs.sh's merged branch-runs.json:
every planned world must have a row that ran and passed on THIS build, and
a declared branch no world realizes is refused. A build with no plan, or a
plan naming no branch, owes none.

The record binds to the build: branch-runs.sh stamps each driven row with
the manifest_sha256 its bot run stamped, and the gate compares it with the
tree's. playtest-server.sh up takes --branch-runs and hands it to the gate;
the skill's hand-over and ladder pages name it.

tools/tests: 157 passed. With the gate's call to the branch-run check
removed, 8 of the 10 new branch tests red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…igger steps, and how the bot holds it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…el hears exactly those moves

A sneak leg's crouch now holds, and the warden maze still lost its bot: the
one loud move left is the tower ladder's descent, which no body makes
crouched, and the bot made it blind. An rcon observer on world/2 read the
bot absent from the warden's anger list for about four minutes of crouched
walking; its first entry (34) came on the standing slide down the ladder,
14.2 blocks from the warden in three axes, 121 at 5.6, and the bot died at
the foot.

spec-0132 §5.2, amended: on a pursued step, before each move a crouched body
cannot make, the bot waits crouched until every live pursuer whose kind hears
stands beyond its reach of the move (least three-axis distance to the
move's segment), on the step's own readings; the wait is bounded by the
largest forget_ticks (the most anger the kind holds over its decay: the
warden's 150 at 1 a second, 3000 ticks), and a spent bound fails the step by
name. The route is otherwise unchanged. Criterion 17 states what it asserts.

One answer to "which moves are made standing": compiler::waypoints::stand_ups
(a climb down, a step to a lower route cell outside any climb, a declared
jump), exported on a sneak leg as `stand_ups` and read by the bot (the
harness's own y-rule is removed); the sculk model hears exactly the cells
those moves stand in (standing_cells -> leg_vibrations). The hearing is
delvewright_dsl::senses, one record, carried on the pursuer's row as
`hearing`; warden-behaviour.md §8 records the reach and the bound.

Tests: dsl senses 1 passed; delvec lib waypoints+sculk 25 passed; it
native_entrance+teleport_link 45 passed; harness tsc clean, waypoints,
critical-path, movement, sneak-leg and the four wait tests pass. With
quietBeforeStanding returning at once, 2 of the 4 wait tests red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
… press in front of it with it

obj/cross-the-strait declares `stealth`, so the exported path carries
`sneak` on it and on trigger/ferry-tiller performed in front of it: the
gallery's element for the sneak marker on an objective step and on a
trigger step (spec-0039). The executor's crouchYielded doc names the
exported stand_ups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
climbHop's descent aligned the body within 0.25 of the column's centre and
then slid "while not on ground"; a body entered from above whose 0.6-wide
hitbox still overlapped the floor beside the column stood on that edge, so
the loop ended at once and the climb "let go" at the top. The pathfinder's
next hop used to finish the descent; with a sneak leg's crouch now held on
that hop, a crouched body holds on the ladder and the walk stuck there for
the hop's whole timeout (the warden maze's world/2, step 7: "let go at
[47.5, 87.0, 48.5]", then stuck at y 86.8). The descent now steps to the
column's centre until the body drops into it, and fails by name if it
never does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…'s stand-ups are emitted

obj/board-the-ferry declares `stealth`; its leg steps down a block and
takes the declared jump, so the waypoints export both hops in `stand_ups`
(step-down [18,69..70,20], jump [16,69,20]->[12,69,20]) and the path carries
`sneak` on it.

Measured on the gallery primary (release build of this branch, prefabs by
tools/ci/gallery-prefabs.py): with both declarations, `sneak` on steps 27,
28 (trigger/ferry-tiller) and 29, and leg 21's two stand-ups; with
board-the-ferry's `stealth` removed, no stand-ups and `sneak` on 28 and 29;
with cross-the-strait's removed (previous commit), the two `sneak` lines on
28 and 29 go. The build's vibration lines are identical either way.
check-gallery-coverage.py exits 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
The wait (spec-0132 §5.2's amendment, criterion 17, quietBeforeStanding and
its forget_ticks bound, and the delvewright_dsl::senses registry and the
pursuer row's `hearing` that only it read) is removed. Measured on the
warden maze, it cannot work: a warden comes to a body that stands still —
three of three waits at the top of the tower spent the bound with the warden
2.5 to 3.3 blocks from the ladder's foot, and two of eight waits at the dais
ended with the bot killed while waiting (warden-behaviour.md §8 keeps the
record). The shared stand_ups answer, the sculk model's agreement with it,
the held crouch, the trigger sneak and the climb's take-hold fix stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…e pursuer row's `hearing`, its parse, and the record

The previous commit removed only crates/dsl/src/senses.rs (a pathspec error
dropped the rest of the staging); this one carries the remainder, so the
tree builds again here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…pawns and walks the step again, and only a death loop is red

Owner ruling, a loosening of what `died` asserted (spec-0132 §5.2 and
criterion 10, amended in their own words): whether a body survives a
vanilla-AI pursuer is the designer's call, and a solo player passes by
dying and retrying. judgePursuedStep no longer fails on `died`; each
attempt's record states the attacker and the run's line counts deaths
(`...; closest approach d; x death(s)`, `deaths` in the report).

The sequencer's one recovery after a death (respawnInPlace: wait out the
respawn, re-arm where the bot stands — what retryOnDeath already did, now
factored and shared) is taken on every death on a pursued step; the
executor then rewinds the leg cursor to where the step began and resumes
its leg from the proven waypoint nearest the respawn
(resumePursuedStep). A life must get further along the step's proven
route than every earlier life on it, measured as the furthest proven
waypoint reached, leg by leg; one that does not is a death loop and fails
the step by name. So a step is walked at most once more than it has proven
waypoints: the bound is the route's own length.

The climb's take-hold fix gains its test (test/climb-down.test.ts: the real
client physics, the tower in miniature; the old descent lets go at
[5.5, 87.0, 4.8], the fixed one at [5.5, 64.0, 4.8]).

Red->green: the old `died` failure put back reds the death-as-measurement
case; the sequencer's pursued-death branch removed reds both sequencer
cases; the progress comparison removed reds the death-loop case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…oute has waypoints; progress is never asked

The bound guards termination, not survival. Asking each life to get further
than the last re-imported the judgement of the pursuer's vanilla will that
the owner ruled out. A pursued step now takes at most as many deaths as the
proven legs it walks have waypoints, whatever each life reached, and the
death past that fails the step by name (death, bound, legs). The executor
notes the legs a step's walks match (noteStepLeg) in place of a per-hop
progress value. spec-0132 §5.2 and criterion 10, playtest-methodology.md and
the skill's ladder page say so.

Red->green: with the bound removed, the death-loop case reds (the fifth
death on a four-waypoint leg is walked again).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
… never a passed row

On the warden maze's world/0 the bot walked its branch to the end and its
report recorded every stage passed, but the run exited non-zero because
the sculk ear failed it (`darkness 1` that no warden in reach explained).
The merge copied the report's `passed: true`, so the staging gate, which
reads that row, admitted the build. The exit code is now the verdict: a
branch whose run wrote a report and still exited non-zero is merged as
not passed, with the exit code in its reason.

The harness also prints each darkness it receives, with where the bot
stood, the step, the deaths so far and the nearest warden the client saw,
so a darkness the ear counts can be read against the deaths and respawns
around it.

Red->green: tools/tests/test_branch_runs_keeps_bot_report.py's new case
(a stub run exits 3 after a passing report) fails without the exit mark,
and passes with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…mpose from the engine root

Compose builds through buildx bake, and bake refuses to read a file
outside the working directory unless it is granted an `fs.read`
entitlement. The skill runs the ladder from the content tree, where the
engine's validation/Dockerfile.delve lies outside the working directory, so
the image build was refused before the hatch stand ran:

    additional privileges requested: pass "--allow=fs.read=../wt-maze-death/validation/Dockerfile.delve"

The same `bot-run.sh --only-hatch-stand` on the same build passed when run
from the engine root. bot-run.sh, world-save.sh and reset-when-empty-run.sh
now cd into the engine root before compose (branch-runs.sh already did).
Every path they hand compose is absolute or resolved against validation/
first; world-save's --seed is made absolute before the cd.

tools/tests/test_ladder_compose_runs_from_engine_root.py: every script that
exports DELVE_DOCKERFILE changes into the engine root before its COMPOSE
line. It found reset-when-empty-run.sh as a third instance, and it fails
with bot-run.sh's cd removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
…the pursuit census, not the client's entity table

The sculk ear excused a darkness when the client saw a warden within 20
blocks. The pulse is applied on the server's positions, and the client's
entity table lags them at the edge of the reach. On the warden maze's
world/0, one darkness of 34 read past 20 on the client and failed the run.
A diagnostic run printed every darkness: the nearest warden the client saw
ran up to 19.0 blocks.

The excuse is now read off the pursuit census, one source: each reading of
a declared warden's actor feeds the ear its server distance to the bot
(SculkEar.onWardenReading, from readPursuers). A darkness is a declared
warden's when the reading before it or the one after has the warden within
20 blocks and no shriek was heard within a second. No tolerance constant.
Where the client and the census disagree about a warden in reach, the run
prints the disagreement by name (`[sculk] darkness at <t>: the client …,
the census …`); the client never decides. spec-0132 §5.7, compiler.md and
playtest-methodology.md say so.

Red->green (test/sculk.test.ts): a darkness the client places at 20.5 and
the census at 19.5 passes; one the census places at 20.5 and 21 fails,
whatever the client saw. Judging on the client flag again reds both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
… standing

A walk declared stealth that crosses a declared sprint jump could not be
walked: `configureLeg` turns `allowSprinting` off for the whole sneak leg, and
mineflayer-pathfinder 2.4.5's parkour move lands at most two cells forward
with sprinting off (`getMoveParkourForward`, `maxD`), so the jump's landing
was no neighbour of its take-off cell and the hop answered `No path to the
goal!`. The compiler already names the jump among the leg's `stand_ups` and
the crouch hold stands the body up for it; the sprint lock was never lifted.

The gallery's ferry walk became stealth on this branch and crosses the broken
plank (`jump/the-broken-plank`, `sprint: true`, a three-wide gap): the gallery
bot stopped at the plank's take-off on `anchor/ferry-deck` waypoint 7/11.

`hopMovements` (harness/src/movement.ts) is the one per-hop setter the leg
calls: the parkour move as before, and sprint on for a plain leg, or for a
sneak leg's hop that is a stand-up of a jump declared `sprint`.

Direction: the defect can only turn a proof red (a stealth leg over a sprint
jump halts); it cannot let anything ship.

Test: test/sneak-leg.test.ts "a sneak leg makes its proven sprint jump
standing, at a sprint, and lands" walks the real pathfinder over the client
physics across a three-wide gap. With the sprint held off on the sneak leg it
reds ("stopped at [9.50, 64.00, 2.50]", the take-off cell); with the fix,
4 of 4 tests in the file pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qiQFhKtTpTbYnn9NZBbSd
@stellarfeline
stellarfeline merged commit 85fc614 into main Nov 11, 2026
39 checks passed
@stellarfeline
stellarfeline deleted the fix/maze-pursued-leg branch November 11, 2026 18:43
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