Spec clause: W3C Web Annotation Data Model — Text Quote Selector. The selector is defined by exact, prefix, and suffix; prefix/suffix exist specifically to disambiguate among multiple occurrences of exact in the document.
Expected behavior: Hypothesis's own blog states the design intent directly: "Hypothesis already deals with minor changes to a document thanks to our fuzzy anchoring algorithm... But sometimes documents change a lot. If an annotation is anchored to a sentence in a paragraph and the whole paragraph is deleted, then even the smartest algorithm isn't going to help — the original text is no longer present and that annotation will fail to anchor. When annotations fail to anchor, we call them orphans." (web.hypothes.is/blog/showing-orphaned-annotations) This case should have produced an orphan. It didn't — it produced a confident, wrong match.
Minimal witness:
<!-- captured against -->
<div>
<p id="alpha">Team Alpha reported that the new deployment reduced latency by twelve percent across all regions.</p>
<p id="beta">Team Beta reported that the new deployment reduced latency by twelve percent across all regions.</p>
</div>
<!-- selector captured on Alpha's sentence: -->
{ "exact": "reduced latency by twelve percent across all regions",
"prefix": "eported that the new deployment ",
"suffix": ".Team Beta reported that the new" }
<!-- page later edited to: -->
<div>
<p id="alpha">Team Alpha reported that the new deployment reduced latency by twenty percent across all regions after further optimization.</p>
<p id="beta">Team Beta reported that the new deployment reduced latency by twelve percent across all regions.</p>
</div>
Expected vs. actual: Per Hypothesis's own stated design, this should orphan — the original text no longer exists at its captured location. Actual: toRange() returns a confident, non-null match — silently re-anchored inside <p id="beta">, a different paragraph with different authorship, based on a decoy occurrence. No signal is surfaced that the match moved.
Mechanism: the captured prefix ("eported that the new deployment ") is identical in both paragraphs — the disambiguating token (Alpha vs Beta) sits outside the fixed 32-character context window, so the fuzzy search can't distinguish them once the original location's exact text is gone.
Affected-implementation matrix:
| Strategy |
Result on this case |
| DOM-path (XPath+offset) |
Fails at the correct location — wrong content, doesn't move elements |
| Text-position (global offset) |
Same — wrong content, correctly contained |
web-highlighter (tag+index+offset) |
Same — wrong content, correctly contained |
dom-anchor-text-quote (fuzzy text-quote) |
Confidently anchors in a different element entirely |
Related work, checked before filing:
Oracle citation: TextQuoteSelector's own spec text (disambiguation is the stated purpose of prefix/suffix) plus Hypothesis's own orphans-design blog post (large changes should orphan, not silently reattach).
Spec clause: W3C Web Annotation Data Model — Text Quote Selector. The selector is defined by
exact,prefix, andsuffix; prefix/suffix exist specifically to disambiguate among multiple occurrences ofexactin the document.Expected behavior: Hypothesis's own blog states the design intent directly: "Hypothesis already deals with minor changes to a document thanks to our fuzzy anchoring algorithm... But sometimes documents change a lot. If an annotation is anchored to a sentence in a paragraph and the whole paragraph is deleted, then even the smartest algorithm isn't going to help — the original text is no longer present and that annotation will fail to anchor. When annotations fail to anchor, we call them orphans." (web.hypothes.is/blog/showing-orphaned-annotations) This case should have produced an orphan. It didn't — it produced a confident, wrong match.
Minimal witness:
Expected vs. actual: Per Hypothesis's own stated design, this should orphan — the original text no longer exists at its captured location. Actual:
toRange()returns a confident, non-null match — silently re-anchored inside<p id="beta">, a different paragraph with different authorship, based on a decoy occurrence. No signal is surfaced that the match moved.Mechanism: the captured prefix (
"eported that the new deployment ") is identical in both paragraphs — the disambiguating token (Alpha vs Beta) sits outside the fixed 32-character context window, so the fuzzy search can't distinguish them once the original location's exact text is gone.Affected-implementation matrix:
web-highlighter(tag+index+offset)dom-anchor-text-quote(fuzzy text-quote)Related work, checked before filing:
product-backlog— closed, resolved via Change anchored range representation to fix overlapping highlight issues #2720. Its example is a pre-existing duplicate at capture time plus a PDF cross-page-boundary case — different from this report, where the text is unique at capture and only becomes ambiguous after a later edit.Rangesilently invalidated when painting a different annotation's highlight mutates the DOM), fixed by moving to just-in-time resolution. No changes todom-anchor-text-quoteor the fuzzy-matching algorithm. This report is about the matching algorithm's disambiguation logic when the page author edits the source text — a different layer and cause, no file overlap with Change anchored range representation to fix overlapping highlight issues #2720.Oracle citation:
TextQuoteSelector's own spec text (disambiguation is the stated purpose of prefix/suffix) plus Hypothesis's own orphans-design blog post (large changes should orphan, not silently reattach).