fix: keep a caller's draft cell in step when a live item owns the row

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ViTUkt4czrvZdxdWwxqRAQ
This commit is contained in:
Diego Imbert
2026-09-13 06:09:01 +02:00
co-authored by Claude Opus 5
parent c51a932eed
commit 4aa2b0eeba
+19 -2
View File
@@ -372,7 +372,14 @@ export const UserDraft = {
remove(itemKind: UserDraftItemKind, path: string, opts?: UserDraftOptions): void {
const ws = resolveWorkspace(opts)
if (liveItems?.discard(ws, itemKind, path)) return
if (liveItems?.discard(ws, itemKind, path)) {
// The live item owns the row, and its own discard deletes it. Falling through to the
// POST below would race that delete with an unconditional one (see `forgetLocal`), so
// only this caller's mirror is dropped — otherwise its reads keep answering with a
// draft that is gone.
UserDraft.forgetLocal(itemKind, path, opts)
return
}
const mk = mapKey(ws, itemKind, path)
const entry = entries.get(mk)
if (entry) {
@@ -563,10 +570,20 @@ export const UserDraft = {
}
): void {
const ws = resolveWorkspace(opts)
if (liveItems?.discard(ws, itemKind, path)) return
const mk = mapKey(ws, itemKind, path)
const entry = entries.get(mk)
const safeFallback = snapshotDraftValue(fallback)
if (liveItems?.discard(ws, itemKind, path)) {
// No POST, for the reason `remove` gives. The cell still has to reach `fallback`:
// a caller holding one resets it to what it just saved, and its apply-effect would
// otherwise copy the stale draft straight back over the form.
if (entry) {
entry.skipNextSync = true
entry.state.val = safeFallback
}
writtenCache.delete(mk)
return
}
if (entry) {
entry.skipNextSync = true
entry.state.val = safeFallback