#52 the peer STANDING-LOCK: case 0's fallthrough was intercepted
A replicant could not start walking between gait-change records. The port's
body case 4 (the task-#64 lockstep twin) is an INSERTION sitting between case 0
and the advance group; in the binary case 4 is a MEMBER of that group
(FUN_004a5678 @004a5678: case 2,3,4,5,8,... -- no turn block, no speed exit),
so case 0's fallthrough is meant to land on Advance(). The insertion caught it.
On a replicant that is not a race but an identity: case 0 arms walk iff
standSpeed < bodyTargetSpeed, and the inserted block resets iff standSpeed <
bspd -- where bspd IS bodyTargetSpeed for a replicant. Same expression, so arm
and reset fire on the same frame, forever, and a peer parked at Standing with a
live replicated demand never cycles. bodyCycleSpeed stays 0 while position
advances from dead reckoning: the skate.
This is the sequel to e91d447 (#82). Before it the replicant branch read the
dead local mapper cell (0 forever), the exit never fired, and the fallthrough
worked BY ACCIDENT. Fixing the dead cell closed the escape hatch.
Fix: case 0 -> goto advance_body_normally, the leg twin's own idiom, restoring
the binary's structure without touching the #64/#82 turn logic.
BT_NO_BODY_FALLTHRU=1 reverts.
Measured (2-node, scratchpad/night13/skatelock.sh):
legacy 336 consecutive locked seconds, bspd=39.2324 bts=39.2324 every line
fixed 0 locks, every pass
master body-Standing samples 52 -> 21 (it locked too, invisibly at mj=0)
turn-in-place intact: pivoter body state 4 x9 / leg state 4 x8, in lockstep
Diagnostics (both keepers): [skate] now carries bstate= -- the field lines
proved "both channels idle" but never named the state, which was the whole
answer; [bodySM]/[peergait] under BT_BODY_SM_LOG instrument the arm->reset pair
and a moving replicant's body channel.
NOT claimed: that this accounts for the night-13 field episodes. That link is
inference -- locked + translating IS the skate signature by construction, but no
bench caught the two together. bstate= settles it next playtest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
This commit is contained in:
co-authored by
Claude Opus 5
parent
39144813a4
commit
6a96fb6420
@@ -273,6 +273,43 @@ number the peer Standing case walks on). Verified: arena circle replicant 218×s
|
||||
replicant, every `MechControlsMapper` demand cell except those explicitly re-derived
|
||||
(`turnDemand`) is DEAD — any peer-side state machine judging a local mapper read is judging 0.**
|
||||
|
||||
**The #52 SEQUEL: the peer body-channel STANDING-LOCK (root-caused + fixed 2026-08-07) [T2].**
|
||||
Fixing (2) above closed an ACCIDENTAL escape hatch and the skate came back in a new shape. The
|
||||
port's body case 4 is an INSERTION (the task-#64 lockstep twin) sitting between case 0 and the
|
||||
advance group — but in the binary `case 4` is a **member of that advance group**
|
||||
(`FUN_004a5678` @004a5678: `case 2,3,`**`4`**`,5,8,…`, no turn block, no speed exit) [T1], so
|
||||
case 0's fallthrough is supposed to land on `Advance()`. The insertion intercepted it. On a
|
||||
REPLICANT that is fatal and not a race: case 0 arms walk iff `standSpeed < bodyTargetSpeed`, and
|
||||
the inserted block's exit tests `standSpeed < bspd` where `bspd` **IS** `bodyTargetSpeed` on a
|
||||
replicant — the *same expression*. Arm and reset therefore fire on the same frame, every frame,
|
||||
and a peer parked at Standing with a live replicated demand can never start cycling (reverse
|
||||
likewise: both sides test `< ZeroSpeed`). Before e91d447 the replicant branch read the dead mapper
|
||||
cell (0 forever) so the exit never fired and the fallthrough worked by accident. **Fix:** case 0
|
||||
`goto advance_body_normally` — the leg twin's own idiom (`goto advance_normally`, mech2.cpp) —
|
||||
restoring the binary's structure without touching the #64/#82 turn logic. `BT_NO_BODY_FALLTHRU=1`
|
||||
reverts. Measured: legacy 336 consecutive locked seconds with `bspd=39.2324 bts=39.2324` identical
|
||||
on every line; fixed 0 locks across every pass; the MASTER's body-Standing samples also fell 52→21
|
||||
(it was locking too, invisibly — mj=0 writes no joints, and its two tests read *different* cells so
|
||||
it only stalls in the window where they disagree). Turn-in-place re-verified under the fix (pivoter
|
||||
reached body state 4 ×9 / leg state 4 ×8 — armed in lockstep).
|
||||
|
||||
**Why a peer must be able to self-arm walking at all** (the load-bearing bit behind
|
||||
`mech4.cpp` "stand; case 0 walk-begins next tick"): the peer's body state is set directly from
|
||||
`record->legState` only on **type-3 edges** (`ReadUpdateRecord`), and entering Standing emits one
|
||||
while *leaving* it does not. So between gait-change records a replicant is REQUIRED to derive
|
||||
walking itself from the replicated `bodyTargetSpeed`. That is why the lock needs a mech holding a
|
||||
*steady* demand — a mech whose gait keeps changing keeps getting rescued by records, which is why
|
||||
free-walking and wall-jammed benches each reproduce only half the symptom. [T2]
|
||||
|
||||
⚠ **The field symptom link is [T3], not T2.** The Standing-lock is proven and proven removed; that
|
||||
it accounts for the night-13 episodes is inference (a locked peer has `bodyCycleSpeed==0` and never
|
||||
advances its clip, so locked + translating *is* the `[skate]` signature by construction) — but no
|
||||
bench caught the two together. The `[skate]` line now carries `bstate=`, so the next playtest
|
||||
settles it: episodes gone → confirmed; any survivor names its own state. **NB the night-12
|
||||
`skatebench` "reproductions" were a DETECTOR ARTIFACT** — the first detector build tested only
|
||||
`legCycleSpeed==0`, which is normal on a peer (the body channel poses it), so it fired on every
|
||||
healthy movement phase. Old-format lines (`legCycleSpeed=`, no `bodyCyc=`) are not evidence.
|
||||
|
||||
## Controls (`BT_REAL_CONTROLS`, default-on)
|
||||
`MechControlsMapper` (mechmppr.cpp @004afbe0; btl4mppr.cpp mappers) interprets input → `speedDemand`
|
||||
/ `turnDemand`. ⚠ **WndProc NEVER receives WM_KEYUP** (the engine's per-frame reader `GetMessage`s
|
||||
|
||||
Reference in New Issue
Block a user