Multi-agent audit pass surfaced 35 findings across security, correctness, cross-version compatibility, and the merge algorithm itself. This beta closes the 2 CRITICAL and 10 HIGH-severity items. Marked as a beta until the deferred follow-ups land and the mod has more real-world validation.
MoveEntities action is now decoded, every VarInt entityId is remapped through safeRemap, and the new bytes are re-emitted. Previously secondary sources' local ids collided with the primary's global namespace, producing the "frozen mobs / default rotations / missing equipment" symptoms.SET_ENTITY_LINK wire format: read/write int32 instead of VarInt (which mis-decoded any id above 127). Sentinel for "no holder" treated as <= 0 to cover both legacy (-1) and modern (0) encodings — leashes no longer randomly attach to the wrong entity.FlashbackReader.open: every segment path is normalised and confined to the replay folder.OverlapValidator refuses to probe replays whose first segment exceeds 256 MB (OOM guard).copyPrimarySnapshotForTick uses FileChannel.map instead of Files.readAllBytes, avoiding OOM on long replays.HURT_ANIMATION and PLAYER_COMBAT_KILL reclassified EGO → ENTITY so their entity id is remapped through the global namespace.fabric.mod.json java dependency is now templated: 1.21.x jars declare >= 21, the 26.1.x jar declares >= 25. Previously the 26.1 jar advertised >= 21 and crashed at classload on JDK 21 instead of failing cleanly via Fabric.addRenderableWidget reflection on 26.1+ iterates Screen.class.getDeclaredMethods() and binds to the first overload accepting our Button — resilient to method-rename churn.MergeOrchestrator emits multiview.merge_progress.phase.* translation keys and the screen picks Component.translatable vs Component.literal based on the "multiview." prefix.EntityMerger UUID-overwrite race and safeRemap phantom-ID race (H8, H9) — real but carry regression risk; separate focused session.SOUND_ENTITY / LEVEL_EVENT remap (H7) — non-trivial wire format.MergeOrchestrator refactor (still ≥ 1300 lines).Multi-agent audit pass surfaced 35 findings across security, correctness, cross-version compatibility, and the merge algorithm itself. This beta closes the 2 CRITICAL and 10 HIGH-severity items. Marked as a beta until the deferred follow-ups land and the mod has more real-world validation.
MoveEntities action is now decoded, every VarInt entityId is remapped through safeRemap, and the new bytes are re-emitted. Previously secondary sources' local ids collided with the primary's global namespace, producing the "frozen mobs / default rotations / missing equipment" symptoms.SET_ENTITY_LINK wire format: read/write int32 instead of VarInt (which mis-decoded any id above 127). Sentinel for "no holder" treated as <= 0 to cover both legacy (-1) and modern (0) encodings — leashes no longer randomly attach to the wrong entity.FlashbackReader.open: every segment path is normalised and confined to the replay folder.OverlapValidator refuses to probe replays whose first segment exceeds 256 MB (OOM guard).copyPrimarySnapshotForTick uses FileChannel.map instead of Files.readAllBytes, avoiding OOM on long replays.HURT_ANIMATION and PLAYER_COMBAT_KILL reclassified EGO → ENTITY so their entity id is remapped through the global namespace.fabric.mod.json java dependency is now templated: 1.21.x jars declare >= 21, the 26.1.x jar declares >= 25. Previously the 26.1 jar advertised >= 21 and crashed at classload on JDK 21 instead of failing cleanly via Fabric.addRenderableWidget reflection on 26.1+ iterates Screen.class.getDeclaredMethods() and binds to the first overload accepting our Button — resilient to method-rename churn.MergeOrchestrator emits multiview.merge_progress.phase.* translation keys and the screen picks Component.translatable vs Component.literal based on the "multiview." prefix.EntityMerger UUID-overwrite race and safeRemap phantom-ID race (H8, H9) — real but carry regression risk; separate focused session.SOUND_ENTITY / LEVEL_EVENT remap (H7) — non-trivial wire format.MergeOrchestrator refactor (still ≥ 1300 lines).Multi-agent audit pass surfaced 35 findings across security, correctness, cross-version compatibility, and the merge algorithm itself. This beta closes the 2 CRITICAL and 10 HIGH-severity items. Marked as a beta until the deferred follow-ups land and the mod has more real-world validation.
MoveEntities action is now decoded, every VarInt entityId is remapped through safeRemap, and the new bytes are re-emitted. Previously secondary sources' local ids collided with the primary's global namespace, producing the "frozen mobs / default rotations / missing equipment" symptoms.SET_ENTITY_LINK wire format: read/write int32 instead of VarInt (which mis-decoded any id above 127). Sentinel for "no holder" treated as <= 0 to cover both legacy (-1) and modern (0) encodings — leashes no longer randomly attach to the wrong entity.FlashbackReader.open: every segment path is normalised and confined to the replay folder.OverlapValidator refuses to probe replays whose first segment exceeds 256 MB (OOM guard).copyPrimarySnapshotForTick uses FileChannel.map instead of Files.readAllBytes, avoiding OOM on long replays.HURT_ANIMATION and PLAYER_COMBAT_KILL reclassified EGO → ENTITY so their entity id is remapped through the global namespace.fabric.mod.json java dependency is now templated: 1.21.x jars declare >= 21, the 26.1.x jar declares >= 25. Previously the 26.1 jar advertised >= 21 and crashed at classload on JDK 21 instead of failing cleanly via Fabric.addRenderableWidget reflection on 26.1+ iterates Screen.class.getDeclaredMethods() and binds to the first overload accepting our Button — resilient to method-rename churn.MergeOrchestrator emits multiview.merge_progress.phase.* translation keys and the screen picks Component.translatable vs Component.literal based on the "multiview." prefix.EntityMerger UUID-overwrite race and safeRemap phantom-ID race (H8, H9) — real but carry regression risk; separate focused session.SOUND_ENTITY / LEVEL_EVENT remap (H7) — non-trivial wire format.MergeOrchestrator refactor (still ≥ 1300 lines).Hard block on merges that would silently produce broken output.
OverlapValidator — pre-merge guard that probes each selected replay for its ClientboundSetTimePacket anchor, computes its server-gameTime interval ([start, start + totalTicks]), and checks every pair for non-empty intersection. If any pair is disjoint, the Merge button stays disabled and a localised tooltip explains why. Wired into both MergeUi-classic (1.21.x) and MergeUi-modern (26.1+).multiview.button.merge_selected.no_overlap i18n key in en_us.json and fr_fr.json..flashback zip files via FileSystems.newFileSystem(...) instead of expecting a pre-extracted folder — matches the on-disk layout Flashback actually produces.A real user case surfaced the bug: someone ran a merge across two .flashback files recorded 11 days apart. The merge succeeded but produced visually broken output — entities vanished, others stuck with default rotations and no equipment. Root cause: server-side entity IDs are local to each recording client and there is no UUID-based matching for non-player entities, so any merge of non-overlapping POVs guarantees cross-source ID collisions. The fix is defensive: refuse upfront rather than emit silent garbage.
Map<Set<Path>, Result>) so checkbox toggles stay responsive.UNKNOWN (not NO_OVERLAP) when an anchor is missing or the file cannot be read — we never block what we cannot verify.Hard block on merges that would silently produce broken output.
OverlapValidator — pre-merge guard that probes each selected replay for its ClientboundSetTimePacket anchor, computes its server-gameTime interval ([start, start + totalTicks]), and checks every pair for non-empty intersection. If any pair is disjoint, the Merge button stays disabled and a localised tooltip explains why. Wired into both MergeUi-classic (1.21.x) and MergeUi-modern (26.1+).multiview.button.merge_selected.no_overlap i18n key in en_us.json and fr_fr.json..flashback zip files via FileSystems.newFileSystem(...) instead of expecting a pre-extracted folder — matches the on-disk layout Flashback actually produces.A real user case surfaced the bug: someone ran a merge across two .flashback files recorded 11 days apart. The merge succeeded but produced visually broken output — entities vanished, others stuck with default rotations and no equipment. Root cause: server-side entity IDs are local to each recording client and there is no UUID-based matching for non-player entities, so any merge of non-overlapping POVs guarantees cross-source ID collisions. The fix is defensive: refuse upfront rather than emit silent garbage.
Map<Set<Path>, Result>) so checkbox toggles stay responsive.UNKNOWN (not NO_OVERLAP) when an anchor is missing or the file cannot be read — we never block what we cannot verify.
Merges multiple Flashback replays from the same session into a single unified replay — an “omniscient observer” view combining the union of chunks, players, and events seen from each POV.