feat(backend): Word edit-protocol contract - unique originals, occurrence-all, whole-item deletion rules
WHY THIS MATTERS
The client refuses any <original> that matches more than one place in the
document (safety: applying one block to every identical clause would
silently broaden the edit). But the prompt never told the model that -
worse, it demanded the SHORTEST possible passage, actively steering models
into ambiguous quotes that the client then skipped while the streamed
prose claimed success. The other half of the bug: "replace all X with Y"
was inexpressible, so it always dead-ended.
WHAT THE CONTRACT NOW SAYS
- <original> must identify exactly ONE place: when the target text also
appears elsewhere, extend the quote with surrounding words from its own
paragraph until it is document-unique. The old "shortest passage" rule
becomes "shortest passage that is still unique" - the two rules used to
conflict.
- Escape hatch: if no unique passage fits the 200-character budget (the
budget exists because Word's search API rejects long strings - the
documented cap is 255, enforced inconsistently per host), ASK the user
which occurrence they mean instead of guessing.
- Occurrence-targeted requests ("the second one", "the one in the closing
paragraph") must quote context FROM that occurrence and name the
location in <reason> - the reason line renders on the card, giving the
user free visible disambiguation before they accept.
- Replace-all: ONE block with the exact repeated text plus
<occurrence>all</occurrence>, never context-extended, never any other
value. The client applies it to every occurrence.
- Citations get the same uniqueness rule: the click-to-locate control
silently jumped to the FIRST occurrence of a repeated quote, which may
not be the cited one.
- Whole-item deletions must quote the paragraph's ENTIRE text (the client
escalates to removing the paragraph mark so Word renumbers the list) and
never "renumber" by editing list numbers, which are renderer annotations
rather than document text.
DEPLOY-ORDER NOTE (why this commit is last)
The prompt starts EMITTING <occurrence> only here, after the parser
commits: an older cached add-in that receives an unknown tag never seals
the block, leaving a permanently "Incomplete" card. In production the
add-in must ship before the backend prompt does. The commit order in this
branch mirrors that constraint on purpose.
The documentContext test pins the prompt's marker-annotation guidance so
the renderer contract (leading # marks, list markers, table pipes are
annotations, NOT document characters) cannot drift silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A5yxFV2YCFmR61KLyB33yi
| Repository | open-legal-products/mike |
|---|---|
| Author | Amal <mamalanand3@gmail.com> |
| Authored | |
| Committed | |
| Parents | 3c651a6b |
| Stats | 2 files changed , +12 , -3 |
| Part of | Make Word edit approval reliable across hosts |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-0f54e7fb.md
from inside the repo you want the change in.