From 48a7abde2d40d09d0fb66fa0ee4deb35905a5b43 Mon Sep 17 00:00:00 2001 From: Yash Raj Pandey Date: Fri, 19 Jun 2026 20:34:41 -0400 Subject: [PATCH 1/2] fix(agent-edit-v2): detect live ref drift against persisted base not live fallback findLiveRefDrift compared the live authoritative fragment against a "persisted" base that was itself sourced from the live-fallback canonical read (doc.markdown from getCanonicalReadableDocument). Under live presence those are the same fragment, so the guard compared the live fragment against itself and never detected drift, exactly when it is needed. When an agent edits against a baseRevision (no baseToken) and a concurrent client inserts a block before the agent's referenced block, the positional b-ref resolved to the now-shifted wrong block: replace_block silently clobbered the concurrent human insert and landed on the wrong content, returning 200 success. Source the drift baseline from the real persisted document row (getDocumentBySlug) for baseRevision-only edits, the frame the agent's refs were captured against. When a baseToken is supplied the agent opted into the live authoritative base directly, so that base stays the comparison frame (behavior unchanged). Now returns 409 FRAGMENT_DIVERGENCE and preserves the concurrent edit. --- server/agent-edit-v2.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/agent-edit-v2.ts b/server/agent-edit-v2.ts index 88626cc5..840763b3 100644 --- a/server/agent-edit-v2.ts +++ b/server/agent-edit-v2.ts @@ -867,7 +867,17 @@ export async function applyAgentEditV2( const usingAuthoritativeFallback = authoritativeBase.base.source === 'live_yjs' || authoritativeMarkdown !== stripEphemeralCollabSpans(doc.markdown ?? ''); if (usingAuthoritativeFallback) { - const persistedBase = parseMarkdownWithHtmlFallback(parser, stripEphemeralCollabSpans(doc.markdown ?? '')); + // The b1..bN refs the agent sent were assigned against the base it declared. For a + // baseRevision-only edit that base is the persisted document row at that revision. + // doc.markdown here is the live-fallback canonical read, so using it would compare the + // live authoritative fragment against itself and never detect that a concurrent edit + // shifted block topology under the agent's refs. Use the persisted row as the drift + // baseline. When a baseToken is supplied the agent opted into the live base directly + // (validated above), so that base is already the correct comparison frame. + const driftBaselineMarkdown = baseToken + ? stripEphemeralCollabSpans(doc.markdown ?? '') + : stripEphemeralCollabSpans(getDocumentBySlug(slug)?.markdown ?? doc.markdown ?? ''); + const persistedBase = parseMarkdownWithHtmlFallback(parser, driftBaselineMarkdown); if (!persistedBase.doc) { return { status: 500, From d7dadc8b74f371ade5d3868414641b5ee1ec8e76 Mon Sep 17 00:00:00 2001 From: Yash Raj Pandey Date: Wed, 15 Jul 2026 18:16:47 -0400 Subject: [PATCH 2/2] fix(agent-edit-v2): gate the persisted drift baseline on baseRevision The drift baseline re-read the document row with a second getDocumentBySlug call, several awaits after doc was fetched and revision-validated against baseRevision. That second read was not itself revision-checked, so a concurrent write landing in between returned a newer row than the frame the agent's refs were validated against, and the newer content could be compared as if it were the base - a spurious FRAGMENT_DIVERGENCE on an otherwise valid edit. Only use the re-read row when its revision still matches baseRevision, and fall back to the already-validated doc otherwise. The baseToken path is unchanged. Signed-off-by: Yash Raj Pandey Co-Authored-By: Claude Opus 4.8 (1M context) --- server/agent-edit-v2.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/agent-edit-v2.ts b/server/agent-edit-v2.ts index 840763b3..09c6c5f6 100644 --- a/server/agent-edit-v2.ts +++ b/server/agent-edit-v2.ts @@ -874,9 +874,14 @@ export async function applyAgentEditV2( // shifted block topology under the agent's refs. Use the persisted row as the drift // baseline. When a baseToken is supplied the agent opted into the live base directly // (validated above), so that base is already the correct comparison frame. + const persistedDriftBaseline = baseToken ? null : getDocumentBySlug(slug); const driftBaselineMarkdown = baseToken ? stripEphemeralCollabSpans(doc.markdown ?? '') - : stripEphemeralCollabSpans(getDocumentBySlug(slug)?.markdown ?? doc.markdown ?? ''); + : stripEphemeralCollabSpans( + persistedDriftBaseline?.revision === baseRevision + ? persistedDriftBaseline.markdown + : doc.markdown ?? '', + ); const persistedBase = parseMarkdownWithHtmlFallback(parser, driftBaselineMarkdown); if (!persistedBase.doc) { return {