Bench 2026-09-11, first fw #50 soak iteration (Studio v0.76, sim at 100 Hz, soak_mode3_closed_loop.yaml with a 200-frame and a 20-frame pattern alternating): 110,641 of 110,643 frame commands OK, 2 rejected — both the first 0x70 of a cl_grating_20f (20-frame) trial, carrying an index computed with the previous trial's modulus (156 and 115 → CE_BAD_PARAM "index out of range", which also flashes the error glyph on the arena).
Cause: the runner's fictracApply op does bridge.setConfig({ frames }) then setApply(true); the bridge (Python) applies the config asynchronously, and the first frame message after setApply was computed with the old frames. It is the one-frame tail of the frame-modulus fix (cd6637e).
Options:
fictracApply waits for the bridge's cfg ack (the [cfg] applied … message the bridge already prints) before setApply(true).
- The bridge client clamps locally:
setConfig({frames}) also sets _clampFrame = i => ((i % frames) + frames) % frames (the heading→index map wraps, so a stale index modulo the new count is the right frame when the old count is a multiple of the new one, and at worst one wrong frame instead of a reject + glyph).
- Both.
Also seen in the same run, for the record: 203 of 110,664 replies (0.18 %) took 50–135 ms (host-observed, incl. queue time), not clustered at step boundaries — unexplained until GET_HEALTH (fw #53) can say whether the controller or the browser paused.
Analyzer table: pixi run python scripts/wedge-scan.py soak-logs/arena-log-20260911-230212-393.jsonl (bench01 log, kept locally).
Bench 2026-09-11, first fw #50 soak iteration (Studio v0.76, sim at 100 Hz,
soak_mode3_closed_loop.yamlwith a 200-frame and a 20-frame pattern alternating): 110,641 of 110,643 frame commands OK, 2 rejected — both the first 0x70 of acl_grating_20f(20-frame) trial, carrying an index computed with the previous trial's modulus (156 and 115 →CE_BAD_PARAM"index out of range", which also flashes the error glyph on the arena).Cause: the runner's
fictracApplyop doesbridge.setConfig({ frames })thensetApply(true); the bridge (Python) applies the config asynchronously, and the first frame message aftersetApplywas computed with the oldframes. It is the one-frame tail of the frame-modulus fix (cd6637e).Options:
fictracApplywaits for the bridge's cfg ack (the[cfg] applied …message the bridge already prints) beforesetApply(true).setConfig({frames})also sets_clampFrame = i => ((i % frames) + frames) % frames(the heading→index map wraps, so a stale index modulo the new count is the right frame when the old count is a multiple of the new one, and at worst one wrong frame instead of a reject + glyph).Also seen in the same run, for the record: 203 of 110,664 replies (0.18 %) took 50–135 ms (host-observed, incl. queue time), not clustered at step boundaries — unexplained until GET_HEALTH (fw #53) can say whether the controller or the browser paused.
Analyzer table:
pixi run python scripts/wedge-scan.py soak-logs/arena-log-20260911-230212-393.jsonl(bench01 log, kept locally).