You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(engine): give each token battlefield entry its own CR 603.2c occurrence index
Token entries were emitted with `turn_zone_change_index` hardcoded to 0, so
every token entry in a turn aliased onto occurrence #0. The CR 603.2c batched
replay guard dedups on `(definition_ref, turn_zone_change_index)`, so a second
same-turn token batch collided with the first and its batched trigger fire was
swallowed.
Route token births through `restrictions::record_zone_change`, the single
authority that assigns the index and performs the CR 403.3 battlefield-entry
bookkeeping. The three co-located `record_battlefield_entry` calls are deleted
in the same change, since the recorder does it and a second call double-counts.
This exposed a live/replay desync in the CR 733 resolved-commands journal: the
live path now pushes a ledger record for a token birth, but
`apply_resolved_token_creation` did not, so a journaled token birth followed by
a same-turn zone change failed closed with `TurnRecordIndexMismatch`. The
replayer now reconstructs the entry record and records it through the same
authority, which also closes a pre-existing gap where replay skipped the
CR 403.3 bookkeeping entirely. Reconstruction rather than a new command field,
so the serialized journal surface is unchanged.
The same applier also skipped token ability injection. It now dispatches on the
body variant, mirroring the live seam: a Copy body gets `finalize_copied_token`
+ the predefined-only injector (CR 707.2 + CR 702.33a strip cast-only
characteristics off a token copy); a Spec body gets the catalog injector.
Known ceiling, documented at the seam: the live journal point precedes entry
counters, `attach_to`, and injection, so a replayed record can still differ from
live for counter-carrying and Role/Aura token births. Closing those requires
moving the live record point and is out of scope here.
Note: `apply_resolved_token_creation` has no production caller yet — this is
replay fidelity ahead of wiring, exercised by the cr733 suites.
Verification (measured):
cargo test -p engine 21975 passed / 0 failed / 15 ignored
revert-probe: deleting the body dispatch fails 2 tests; replacing it with a
blanket injector fails exactly 1, so both arms are separately load-bearing.
Assisted-by: ClaudeCode:claude-opus-4.8
0 commit comments