docs/solutions/logic-errors/2026-04-09-slate-history-withnewbatch-must-split-at-the-commit-writer.md
slate-history claimed HistoryEditor.withNewBatch(...),
HistoryEditor.withoutMerging(...), and editor.writeHistory(...), but the
live v2 source only had withMerging(...) and withoutSaving(...).
That left two real problems:
writeHistory(...) was cosmeticThe v2 history package moved from legacy per-op wrapping to snapshot-based commit subscribers.
That architecture shift was fine, but the helper recovery stopped halfway:
history.undos and
history.redosSo the old helper names were missing, and the one instance seam serious callers actually need never ran.
Restore the helper surface in the shape the current engine can honestly support:
SPLITTING_ONCEHistoryEditor.withNewBatch(...)HistoryEditor.withoutMerging(...)editor.writeHistory(stack, batch)Then apply the split-once rule at the commit-subscriber writer, not before it.
In with-history.ts, the correct flow is:
save and merge for the committed snapshotSPLITTING_ONCE is set, force merge = false for that commit onlySPLITTING_ONCEeditor.writeHistory(...)withNewBatch(...) scope merge normallywithNewBatch(...) is not “never merge inside this callback”.
It is:
On a snapshot/commit model, that decision only makes sense at the place where a commit is actually written to history.
Anything earlier is guessing.
Routing all push-style writes through editor.writeHistory(...) also makes the
public instance seam real again, so downstream packages can intercept undo/redo
batch writes without forking the history plugin.
writeHistory(...) unless commit-time writes actually route
through it.withNewBatch(...) splits once, then merges the rest of the scopewithoutMerging(...) forces a fresh batchwriteHistory(...) is the real stack-write seam