diff --git a/frontend/src/lib/itemStore.svelte.ts b/frontend/src/lib/itemStore.svelte.ts index 70119dfc1d..18824714c8 100644 --- a/frontend/src/lib/itemStore.svelte.ts +++ b/frontend/src/lib/itemStore.svelte.ts @@ -359,6 +359,8 @@ class Entry { /** An outside write (the AI chat, another editor): a real divergence, never settling. */ /** `askedAt`: when the write was made, for one parked while a move was heading here. */ applyExternal(value: V, askedAt = nextAsk++): number { + // An ask older than the one that holds changes nothing, value included. + if (askedAt < (this.lastAsk?.at ?? 0)) return this.revision // Before the unchanged-value return: re-writing the same draft is still an ask, and which // ask came last is what outranks a discard still waiting for its turn. this.recordAsk('write', askedAt) diff --git a/frontend/src/lib/itemStore.test.ts b/frontend/src/lib/itemStore.test.ts index 02a0fb4c10..b93ea94f36 100644 --- a/frontend/src/lib/itemStore.test.ts +++ b/frontend/src/lib/itemStore.test.ts @@ -710,6 +710,17 @@ describe('item store: one entry per key', () => { expect(parkedAfterDiscard.moving.value).toEqual(again) expect(parkedAfterDiscard.rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: again }) + // A draft parked for the move, then a newer one written to the editor that opened over it: + // the newer one holds, and the parked one does not come back with the item. + const newerThanParked = { ...b, description: 'written after the parked one' } + const parkedThenWritten = await moveOnto(false, (store, open) => { + store.bridge.seed('w', 'resource', 'u/me/b', { ...b, description: 'parked draft' }) + open() + store.bridge.seed('w', 'resource', 'u/me/b', newerThanParked) + }) + expect(parkedThenWritten.moving.value).toEqual(newerThanParked) + expect(parkedThenWritten.rows.writes.at(-1)).toEqual({ path: 'u/me/b', value: newerThanParked }) + // Deleted last: the delete is what holds, however many drafts preceded it. const deleted = await moveOnto(true, (store) => { store.bridge.seed('w', 'resource', 'u/me/b', { ...b, description: 'first draft' })