Lane RB consumed the capture and found the record was wrong: the element is dumped in
memory order and its memory field order is not its wire order. Memory member 1 is wire
member SRsc; six members are unread. RB's first replay regressed two leaves on exactly
that.
The values now ship as rates_memory_order_{u32,f32} with wire: null, and the .tcb emits
the seven '?' tokens RB's own converter emits, so a replayer refuses rather than guesses.
A missing field is honest; a mislabelled one propagates -- and a capture is meant to
outlive whatever adapter happened to read it.
Also records the outcomes against every prediction, including the one the consumer
falsified.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARBgSooAfokKUy6wKUKEyZ
Lane L1 found each AI client's generator takes a fresh per-process word, so the AI is
MT19937 from one word per client and game/ai is a function of (save, seed). A capture
without the seeds records the answer without the input.
- aiseed=log|pin on StrategyApp::RunAI: one detour that reads the fourth stack argument
where the callee reads it, and in pin mode replaces it. Both modes log observed AND
used, so a pinned run says so in its own capture.
- aiorders.words= widens the element window past list 1's 48-byte horizon.
- aiorders.deep= follows the heap: the route vector, the counted vector and the
Population body were ABSENT from every capture so far, not empty.
- tools/turncommands_capture.py (in sots-re) does the typing offline, so a corrected
element record costs a re-parse rather than a VM run.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARBgSooAfokKUy6wKUKEyZ