Files
BT411/scratchpad/night13/close52.py
T
Joe DiPrimaandClaude Opus 5 43d30ca7e4 #140 receipts: name the corruption case in a FIELD log
Two ungated one-liners, because no bench here reached the failing path and
the next playtest is a better instrument than more automation:

  [glasswin] destroy entry #N windows=M   -- N=2,M=0 is the double-destroy
  [glasswin] saved ... (live=L remembered=R) -- live=0 IS the corruption case
                                                (pre-cache that wrote a file
                                                holding only the plasma line)

Also lands the benches that did NOT reproduce it, with their failure modes
recorded in the headers so the next attempt does not repeat them:
layoutsave.sh (round trip -- passes on the fixed build), layoutteardown.sh
(graceful WM_CLOSE; still never reaches the dtor chain), layoutround.sh (MP
round boundary; the relay never started the mission inside the window).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
2026-08-07 01:23:33 -05:00

91 lines
4.8 KiB
Python

"""Night 13: report the #52 root cause on the tracker. ASCII only."""
import sys
sys.path.insert(0, r"C:\git\bt411\scratchpad\night7")
import gitea
BODY = """**ROOT CAUSE FOUND AND FIXED (2026-08-07, commit `6a96fb6`)** -- but read the
"what is NOT proven" section before treating this as closed.
## The defect
A replicant cannot start walking between gait-change records.
The port's body `case 4` (the task-#64 lockstep twin, mech2.cpp) is an INSERTION sitting between
`case 0` and the advance group. In the binary it is a MEMBER of that group -- `FUN_004a5678`
@004a5678 reads `case 2,3,`**`4`**`,5,8,...` with no turn block and no speed exit [T1] -- so case
0's fallthrough is meant to land on `Advance()`. The insertion intercepted it.
On a replicant that is not a race, it is an identity:
* case 0 arms walk iff `standSpeed < bodyTargetSpeed`
* the inserted block resets iff `standSpeed < bspd`, and `bspd` **IS** `bodyTargetSpeed` on a replicant
Same expression. Arm and reset fire on the same frame, every frame. A peer parked at Standing with a
live replicated demand never cycles: `bodyCycleSpeed` stays 0 while position advances from dead
reckoning. That is the skate. (Reverse is dead the same way -- both sides test `< ZeroSpeed`.)
## Why it appeared when it did
This is the sequel to `e91d447` (#82). Before that commit the replicant branch read the LOCAL
mapper's `speedDemand` -- a dead cell on a peer, 0 forever -- so the exit never fired and the
fallthrough worked BY ACCIDENT. Fixing the dead cell (correctly) closed the accidental escape
hatch, and the trn-lock skate came back as a Standing-lock skate.
## Why masters were unaffected
Two reasons, either sufficient: their two tests read DIFFERENT cells (`bodyTargetSpeed` held at
last-sent by the gait mirror, vs the live mapper `speedDemand`), so they only stall in the window
where those disagree; and the master's body channel runs `mj=0` and writes no joints, so its stall
is invisible -- the leg channel, whose case 0 falls through correctly, drives pose and travel.
## The load-bearing detail
`mech4.cpp`'s "stand; case 0 walk-begins next tick" is not an aside. A peer's body state is set from
`record->legState` only on **type-3 edges**, and ENTERING Standing emits one while LEAVING it does
not. Between gait-change records a replicant is REQUIRED to derive walking itself from the
replicated demand. The insertion removed that ability.
This also explains the shape of the field data: the lock needs a mech holding a STEADY demand, so a
mech whose gait keeps changing is continually rescued by records. Night 13's four episodes all carry
`bodyTargetSpeed` 39-48 held across 100-400 frames, and each ended when that mech next changed gait.
## 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 | fixed |
|---|---|---|
| STANDING-LOCK seconds | **336 consecutive**, `bspd=39.2324 bts=39.2324` identical every line | **0**, every pass |
| master body-Standing samples | 52 | 21 |
| turn-in-place | -- | body state 4 x9 / leg state 4 x8, armed in lockstep |
## What is NOT proven [T3]
That this accounts for the night-13 episodes. The lock is proven and proven removed; the link to the
field symptom 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. Four rigs failed to reproduce the symptom end-to-end.
The `[skate]` line now carries `bstate=`, which is the diagnostic tonight's logs lacked. Next
playtest settles it: episodes gone -> confirmed; any survivor names its own state.
**Correction for the record:** the night-12 `skatebench` "reproductions" (6 episodes, `sk_run.out`)
were a DETECTOR ARTIFACT, not this bug. 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. It was corrected the same day to require both channels idle. Old-format lines
(`legCycleSpeed=`, no `bodyCyc=`) are not evidence of anything.
Related: #130 (Vulture skating) is very likely the same defect -- re-test it against this build
before spending separate effort."""
gitea.comment(52, BODY)
gitea.comment(130,
"Cross-ref: #52's root cause was found and fixed 2026-08-07 (`6a96fb6`) -- a replicant could not "
"start walking between gait-change records, so a peer parked at Standing with a live replicated "
"demand kept its position advancing with a dead animation channel. That is the same shape as the "
"skating reported here. **Re-test this against a build newer than `6a96fb6` before investigating "
"separately.** Full write-up in #52.")