createComment: anchor failures give no corrective hint — port editPageText's self-correction affordances (closest-block hint, markdown-strip, multi-block detection) #408

Open
opened 2026-07-07 20:51:31 +03:00 by agent_vscode · 0 comments
Collaborator

Problem

createComment is the top real-error hotspot in agent dialog history: 96 failed invocations across 29 chats (2026-06-17…07-07 DB analysis, see docs/reading-ai-logs.md; one chat shows 10 attempts / 0 successes — blind retry loops). The failure is always anchoring: the agent-supplied selection is not found (or ambiguous) in the document.

Throwing is intentional (live retry — see the comment in apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts:442), but the error text gives the model nothing to correct with, unlike editPageText, whose soft-failure design keeps its error count at 4/79:

Affordance editPageText (packages/mcp/src/lib/json-edit.ts) createComment (packages/mcp/src/client.ts, packages/mcp/src/lib/comment-anchor.ts)
"Closest block text: …" hint on not-found yes (json-edit.ts:367-389) no (client.ts:2552, 2570, 2705 — generic "could not find the selection text")
Markdown-strip fallback (**bold** in the locator) yes (+ soft warning) no (comment-anchor.ts normalizes typography/nbsp/dashes but not markdown)
Cross-block explanation yes ("match crosses a non-text inline node…") no — a selection spanning two blocks is a generic not-found

Fix sketch

  1. Closest-block hint — port the json-edit.ts:367-389 logic (longest token ≥3 chars → first block containing it → quote ≤120 chars) into the three anchor-failure throws in client.ts createComment:
    • pre-check not-found (client.ts:2552-2556)
    • pre-check not-found, non-suggestion branch (client.ts:2570-2574)
    • live-anchor failure after rollback (client.ts:2705-2709)
      The page JSON is already loaded in the pre-check (getPageJson, client.ts:2545) and blockPlainText exists in node-ops.ts — the hint is cheap. Consider extracting the hint builder from json-edit.ts into a shared helper instead of copying.
  2. Markdown-strip fallback in comment-anchor.ts (canAnchorInDoc / countAnchorMatches / applyAnchorInDoc / getAnchoredText): when the raw selection does not match, retry with markdown syntax stripped (same rules as json-edit) and anchor on the raw doc text via the existing normalizeForMatch index map. Report a soft warning like editPageText does. All four functions must stay consistent (count/can/apply/get must agree on what matches — the suggestion-uniqueness gate at client.ts:2551/2677 depends on it).
  3. Multi-block detection: in the pre-check, when the per-block search fails but the selection IS found in the joined-blocks plain text, say explicitly: "the selection spans multiple blocks; anchor on a contiguous fragment within a SINGLE paragraph/block".
  4. Tool description (packages/mcp/src/tool-specs.ts:768, shared spec createComment): add "copy the selection verbatim from getPage/searchInPage output — do not quote from memory" (stale-memory quoting is the root cause of most misses).

Notes

  • Keep the anchoring invariants intact: suggestion anchors must stay strictly unique (0 → not found, ≥2 → ambiguous), and the stored selection must remain the RAW doc substring (client.ts:2528-2537).
  • Unit tests: hint appears on not-found; markdown-stripped selection anchors and warns; multi-block selection produces the explicit message; suggestion uniqueness gate unaffected by the strip fallback.
  • Expected impact: most of the 96 misses become one-retry self-corrections (or first-try successes via the description fix).
## Problem `createComment` is the **top real-error hotspot** in agent dialog history: 96 failed invocations across 29 chats (2026-06-17…07-07 DB analysis, see `docs/reading-ai-logs.md`; one chat shows 10 attempts / 0 successes — blind retry loops). The failure is always anchoring: the agent-supplied `selection` is not found (or ambiguous) in the document. Throwing is intentional (live retry — see the comment in `apps/server/src/core/ai-chat/tools/ai-chat-tools.service.ts:442`), but the error text gives the model **nothing to correct with**, unlike `editPageText`, whose soft-failure design keeps its error count at 4/79: | Affordance | editPageText (`packages/mcp/src/lib/json-edit.ts`) | createComment (`packages/mcp/src/client.ts`, `packages/mcp/src/lib/comment-anchor.ts`) | | --- | --- | --- | | "Closest block text: …" hint on not-found | yes (json-edit.ts:367-389) | **no** (client.ts:2552, 2570, 2705 — generic "could not find the selection text") | | Markdown-strip fallback (`**bold**` in the locator) | yes (+ soft `warning`) | **no** (comment-anchor.ts normalizes typography/nbsp/dashes but not markdown) | | Cross-block explanation | yes ("match crosses a non-text inline node…") | **no** — a selection spanning two blocks is a generic not-found | ## Fix sketch 1. **Closest-block hint** — port the json-edit.ts:367-389 logic (longest token ≥3 chars → first block containing it → quote ≤120 chars) into the three anchor-failure throws in `client.ts createComment`: - pre-check not-found (client.ts:2552-2556) - pre-check not-found, non-suggestion branch (client.ts:2570-2574) - live-anchor failure after rollback (client.ts:2705-2709) The page JSON is already loaded in the pre-check (`getPageJson`, client.ts:2545) and `blockPlainText` exists in `node-ops.ts` — the hint is cheap. Consider extracting the hint builder from json-edit.ts into a shared helper instead of copying. 2. **Markdown-strip fallback** in `comment-anchor.ts` (`canAnchorInDoc` / `countAnchorMatches` / `applyAnchorInDoc` / `getAnchoredText`): when the raw selection does not match, retry with markdown syntax stripped (same rules as json-edit) and anchor on the raw doc text via the existing `normalizeForMatch` index map. Report a soft `warning` like editPageText does. All four functions must stay consistent (count/can/apply/get must agree on what matches — the suggestion-uniqueness gate at client.ts:2551/2677 depends on it). 3. **Multi-block detection**: in the pre-check, when the per-block search fails but the selection IS found in the joined-blocks plain text, say explicitly: "the selection spans multiple blocks; anchor on a contiguous fragment within a SINGLE paragraph/block". 4. **Tool description** (`packages/mcp/src/tool-specs.ts:768`, shared spec `createComment`): add "copy the `selection` verbatim from getPage/searchInPage output — do not quote from memory" (stale-memory quoting is the root cause of most misses). ## Notes - Keep the anchoring invariants intact: suggestion anchors must stay strictly unique (0 → not found, ≥2 → ambiguous), and the stored selection must remain the RAW doc substring (client.ts:2528-2537). - Unit tests: hint appears on not-found; markdown-stripped selection anchors and warns; multi-block selection produces the explicit message; suggestion uniqueness gate unaffected by the strip fallback. - Expected impact: most of the 96 misses become one-retry self-corrections (or first-try successes via the description fix).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#408