fix: let an outside write that lands during a discard keep the item

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-15 09:46:12 +02:00
co-authored by Claude Opus 5
parent 47b6934266
commit 1a50765295
2 changed files with 23 additions and 0 deletions
+4
View File
@@ -470,9 +470,13 @@ class Entry<V> {
if (this.origin === 'draft') {
const kept = snapshot(this.value)
const keptRow = this.row
const editsAtStart = this.edits
this.replaceValue(undefined)
this.reconcile()
await this.settleRows([this.key])
// An outside write that arrived while the delete was going is newer than this
// discard: it has already put the item back, and its row is the item.
if (this.edits !== editsAtStart) return { removed: false }
// The row is the item: while its delete has not landed, the item is still there.
if (this.rowRefused(this.key)) {
// The syncer keeps a failed payload for its page-close flush; that delete would
+19
View File
@@ -435,6 +435,25 @@ describe('item store: origins', () => {
expect(rows.writes).toEqual([{ path: 'u/me/r', value: null }])
})
it('keeps a draft-only item an outside write put back while its delete was going', async () => {
const rows = fakeRows()
const draft = { ...deployedRes, description: 'only a draft' }
const { item } = await open(rows, adapter({ draft }))
const gate = deferred()
rows.hold(gate.promise)
const discarded = item.discard()
await settle()
// The chat writes the same item while the delete is in flight.
const fromChat = { ...draft, description: 'written by the chat' }
item.applyExternal(fromChat)
gate.resolve()
expect(await discarded).toEqual({ removed: false })
expect(item.removed).toBe(false)
expect(item.value).toEqual(fromChat)
expect(rows.writes.at(-1)).toEqual({ path: 'u/me/r', value: fromChat })
})
it('keeps a draft-only item whose delete did not land', async () => {
const rows = fakeRows()
const draft = { ...deployedRes, description: 'only a draft' }