Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC
82 lines
4.1 KiB
Python
82 lines
4.1 KiB
Python
"""Night 13: close #148 as not-a-bug with the measured chain. ASCII only."""
|
|
import sys
|
|
sys.path.insert(0, r"C:\git\bt411\scratchpad\night7")
|
|
import gitea
|
|
|
|
BODY = """**NOT A BUG -- closing (2026-08-08).** There was nothing to fix here. The bench was lying,
|
|
and this ticket's own premise was wrong twice over.
|
|
|
|
## The answer
|
|
|
|
`Entity::Execute` (`ENTITY.cpp:556`, real engine source [T0]) calls `PerformAndWatch` **only** when
|
|
|
|
```cpp
|
|
application->GetApplicationState() == Application::RunningMission
|
|
|| application->GetApplicationState() == Application::EndingMission
|
|
|| IsPreRunnable()
|
|
```
|
|
|
|
and otherwise merely `WriteSimulationUpdate()`s. `Entity::DefaultFlags` is
|
|
`DynamicFlag|MasterInstance` -- **no `PreRunFlag`**. Only `Player` and `Director` add it in their
|
|
DefaultFlags, and `Mech::Reset` sets it for a reset MASTER ("a reset master must tick"). A
|
|
**replicant mech never gets it.**
|
|
|
|
So a peer mech performs **zero** subsystem ticks until the round actually starts, no matter how
|
|
much correctly-replicated data is arriving for it. Measured on the observer node:
|
|
|
|
```
|
|
235 [perf-first] mech 3:161 master <- own mech, immediately
|
|
402 [torso-rec-rx] <- peer's torso records start arriving
|
|
2754 [perf-first] mech 2:55 REPLICANT <- peer's FIRST performance
|
|
2758 [torso] PushTwist COPY <- its torso ticks 4 lines later
|
|
2761 [ent-exec] state=5 <- RunningMission
|
|
```
|
|
|
|
The peer starts performing exactly at the RunningMission transition. That is the engine doing
|
|
what it says it does.
|
|
|
|
## So the symptom was a BENCH ARTIFACT
|
|
|
|
`BT_AUTOFIRE` starts shooting immediately, during `WaitingForLaunch` -- something no player can do
|
|
in a real match. Those leading salvos measured a peer whose torso, gait and subsystems had never
|
|
run. Every `ZZZZ...XXXX` prefix in this investigation was that, and the first `X` lands within a
|
|
few lines of the state transition.
|
|
|
|
**#141 is unaffected and stays fixed** -- its segment-cache defect was real and mid-match.
|
|
|
|
## Ruled out along the way (all measured, all recorded so nobody repeats them)
|
|
|
|
* **The record cadence is authentic.** My "only 13 records in 5 minutes" premise was wrong. The
|
|
payloads are the sweep EXTREMES with `rate` flipping sign at each one -- the master sends on
|
|
**rate change** and the peer dead-reckons `atUpd + rate * elapsed` between them. 12 records for
|
|
12 direction reversals is correct, not starved.
|
|
* **The `ComputeTargetTwist` clamp.** The copy's limits load correctly (`limL=2.44346
|
|
limR=-2.44346 enab=1`), so `Min/Max` was not pinning `targetTwist` to zero.
|
|
* **The torso's own executable flag.** `Entity::Perform` picks its predicate by instance
|
|
(`IsNonReplicantExecutable` vs `IsReplicantExecutable`, differing on
|
|
`|| lastUpdate >= lastPerformance`), and Mech's tick loop had dropped that branch. Restoring it
|
|
(`f36f013`) is a genuine fidelity fix and is kept -- but it moved this bug by nothing.
|
|
* **The scheduler.** The replicant entity IS offered to the performer with `executable=1` from
|
|
line 171, ~2500 lines before its first `PerformAndWatch`. The gate was inside `Execute`, not in
|
|
who gets offered.
|
|
|
|
## What came out of it
|
|
|
|
* `[perf-first]` -- a one-shot per-mech receipt naming entity ID + instance at a mech's first
|
|
performance. Every other per-frame receipt in mech4 is anonymous, which is exactly why this took
|
|
so long to see in a 2-node log.
|
|
* `[torso-copy]` now prints `limL/limR/enab`; `[launchframe]` prints the shooter's live torso twist.
|
|
* **Gotcha #29** in `context/reconstruction-gotchas.md`: judge a 2-node bench by PREFIX vs
|
|
INTERLEAVED, never by raw percentage; check `[ent-exec] state=` before suspecting replication.
|
|
`missileframe.sh` carries the same warning inline.
|
|
|
|
## Still worth checking separately
|
|
|
|
`#37` (MadCat torso BACKWARDS) and `#70` (torso twist stops after respawn) were flagged here as
|
|
possibly sharing a cause. They do **not** share this one -- it is not a defect. They should be
|
|
re-tested against the #141 segment-cache fix instead, which is a real mid-match change."""
|
|
|
|
gitea.comment(148, BODY)
|
|
gitea.call("/issues/148", method="PATCH", payload={"state": "closed"})
|
|
print("closed #148")
|