Skip to content

fix(CommandPalette): weigh the grapheme-snap ceiling against the value - #388

Merged
IgorShevchik merged 2 commits into
mainfrom
fix/grapheme-ceiling-anchored-to-value
Aug 13, 2026
Merged

fix(CommandPalette): weigh the grapheme-snap ceiling against the value#388
IgorShevchik merged 2 commits into
mainfrom
fix/grapheme-ceiling-anchored-to-value

Conversation

@IgorShevchik

@IgorShevchik IgorShevchik commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Linked issue

Closes #387.

Type of change

  • Documentation (updates to the documentation or readme)
  • Bug fix (a non-breaking change that fixes an issue)
  • Enhancement (improving an existing functionality)
  • New feature (a non-breaking change that adds functionality)
  • Chore (updates to the build process or auxiliary tools and libraries)
  • Breaking change (fix or feature that would cause existing functionality to change)

Description

GRAPHEME_SNAP_MAX_LENGTH is documented, and was tested, as a bound on the field text. It was not measured against it. truncateHTMLFromStart built its snapper from content — the value after escaping and after mark insertion — so the ceiling was reached early, by an amount nothing in the constant hints at. Escaping has no fixed overhead: & expands to five characters, " to six.

const FLAG = '\u{1F1FA}\u{1F1F8}'   // 🇺🇸

'a'.repeat(8140) + FLAG.repeat(10) + 'match'     // value.length 8185 — under the ceiling
'&'.repeat(1600) + FLAG.repeat(50) + 'match'     // value.length 1805 — 22% of the ceiling

Both degraded, and both rendered 🇸🇺 with an orphaned regional indicator where the author wrote 🇺🇸 — a different country, with nothing to signal the loss. That is the defect #364 describes and #371 exists to prevent, reappearing above a threshold no reader could predict from the constant.

Fix

createClusterSnapper takes the length to weigh separately from the string to segment, named fieldTextLength for what it is. The parameter is required, not defaulted to value.length: a default is precisely what would let the next derived-string caller inherit this bug in silence.

Cost

Segmenting a string the ceiling would have excluded is affordable — but not because the call is cheap in isolation. On a long run of regional indicators it is not, since containing() walks the run. It is that Array.from(html) above it already paid the larger price on the same string, unconditionally, on both sides of this fix.

Measured end to end, this branch against the old behaviour on identical input:

input old new delta
plain, value.length 8185 86 µs → 🇸🇺 98 µs → 🇺🇸 +11 µs
escape-heavy, value.length 1505 172 µs → 🇺🇸 167 µs → 🇺🇸 −6 µs

Within noise in both directions. An independent A/B through vitest bench (400+ samples, ~2% RME) reached the same conclusion: 1.1879 ms vs 1.1843 ms on the all-quotes worst case at the ceiling.

test/bench/search.bench.ts gains under the ceiling, escaped six-fold, which reaches the ceiling by escaping rather than by length, so the claim rests on a durable measurement rather than a throwaway script — the convention that file's own header sets.

An earlier revision of this description carried a cost table that was wrong by three orders of magnitude. The benchmark behind it built the Segments view once and reused it across iterations, while the real code builds a fresh view per truncation. Recording that here because the number was quoted in the commit message and the source comment too, and the comment now explains the trap instead of restating a figure.

Tests

The two ceiling tests moved off value.length + MARKUP onto value.length. That makes snaps clusters exactly at the ceiling the plain-text repro in its own right — a value of exactly the advertised length previously degraded, verified against main.

measures the ceiling against the value, not its escaped copy covers the unbounded half. It was missing because no fixture in degraded paths contained an escapable character, so only the fixed 13-character single-mark overhead was ever exercised.

Mutation-checked: reverting the segmenter gate to the derived string, passing content.length at the call site, moving GRAPHEME_SNAP_MAX_LENGTH by ±1, and ignoring the new parameter are each caught by a named test.

732 tests green (test/utils/, test/components/); eslint and vue-tsc --noEmit clean. test/utils/search.spec.ts run 38 consecutive times on a quiet tree, all green — two reviewers reported intermittent failures in these tests, which reproduced only while a concurrent mutation-testing pass had the file modified, and whose failure signature matches that mutation exactly.

Documentation

.sync/PORTING.md's guard entry said the threshold "is crossed 13 characters earlier than a reading of value.length suggests". That described the defect rather than the design, so it is corrected here rather than deferred to the documentation follow-up — a porter reading the old sentence could have restored the bug deliberately.

Provenance

The defect was found by an independent review pass over #371 — five reviewers reading the merged code, rather than the authoring session re-reading itself. #371's own description argued its three self-review rounds were not converging; this is what that looked like in practice. The wrong cost figure, the parameter name, the missing default, and the deferred documentation fix were all caught by a second such pass over this branch.

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@IgorShevchik
IgorShevchik force-pushed the fix/grapheme-ceiling-anchored-to-value branch from 7d53463 to 16cea6d Compare August 13, 2026 12:26
`GRAPHEME_SNAP_MAX_LENGTH` is documented, and was tested, as a bound on the
field text. It was not measured against it: `truncateHTMLFromStart` built its
snapper from `content` — the value after escaping and after `<mark>` insertion —
so the ceiling was reached early, by an amount nothing in the constant hints at.
Escaping has no fixed overhead: `&` expands to five characters, `"` to six.

    'a'.repeat(8140) + FLAG.repeat(10) + 'match'     // value.length 8185
    '&'.repeat(1600) + FLAG.repeat(50) + 'match'     // value.length 1805

Both degraded, and both rendered `🇸🇺` with an orphaned regional indicator where
the author wrote `🇺🇸` — a different country, silently. That is the defect #364
describes and #371 exists to prevent, reappearing above a threshold no reader
could predict.

`createClusterSnapper` now takes the length to weigh separately from the string
to segment, named `fieldTextLength` for what it is. The parameter is required
rather than defaulted: a default is what would let the next derived-string
caller inherit this bug without noticing.

Segmenting a string the ceiling would have excluded is affordable, but not
because the call is cheap in isolation — on a long run of regional indicators it
is not. It is that `Array.from(html)` already paid the larger price on the same
string, unconditionally, on both sides of this fix. End to end the difference is
tens of microseconds either way, within noise. `test/bench/search.bench.ts`
gains a case that reaches the ceiling by escaping rather than by length, so the
claim has a durable measurement behind it rather than a throwaway script.

The two ceiling tests moved off `value.length + MARKUP` onto `value.length`,
which makes `snaps clusters exactly at the ceiling` the plain-text repro — a
value of exactly the advertised length previously degraded. The new case covers
the unbounded half: every fixture in `degraded paths` was free of escapable
characters, so the expansion never reached the ceiling arithmetic.

`.sync/PORTING.md`'s guard entry said the threshold "is crossed 13 characters
earlier than a reading of `value.length` suggests". That described the defect,
not the design, and is corrected here rather than left for the documentation
follow-up — a porter reading it could otherwise restore the bug on purpose.

Closes #387.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
@IgorShevchik
IgorShevchik force-pushed the fix/grapheme-ceiling-anchored-to-value branch from 16cea6d to 8f851dd Compare August 13, 2026 12:39
@IgorShevchik
IgorShevchik merged commit c909bc7 into main Aug 13, 2026
1 check passed
@IgorShevchik
IgorShevchik deleted the fix/grapheme-ceiling-anchored-to-value branch August 13, 2026 13:08
IgorShevchik pushed a commit that referenced this pull request Aug 13, 2026
…hecked

All three were mine, and all three were checkable — which is how they were
caught.

**"218 tests" was 220.** The figure came from an early planning note and was
carried into the commit message and the PR body without being re-measured
against the final `origin/main` content. Counted: 110 per project, two projects.

**"Every other multi-code-point fixture here already uses escapes" was false.**
The Devanagari pair is written as literal glyphs, and the ZWJ family's joiners
are literal U+200D bytes sitting between escaped emoji — only the flag and the
skin-tone modifier were fully escaped.

Rather than restate the claim more narrowly, the ZWJ joiners are now escaped
too, for a reason the original comment did not name: they are invisible in an
editor, so one could be deleted without anyone seeing. That is a different
hazard from NFC collapse and it applies to that fixture specifically. The
Devanagari pair keeps its glyphs — it is visible, and `normalize('NFC')`
round-trips it unchanged, so neither hazard applies. The comment now says which
reason applies where instead of claiming a consistency that was not there.

The escaped joiners are byte-identical to the literals they replace.

**"752 tests green" had no stated scope**, and none of the obvious readings
reproduce it — not the repository, not `test/utils/` plus `test/components/`,
not the two files this branch changes. It counted `test/utils/` plus
`CommandPalette.spec.ts`, which is a scope nobody could infer. The PR body now
names the command. The same convention was used on #388's "732" and was equally
unverifiable there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik pushed a commit that referenced this pull request Aug 15, 2026
…nput

`sanitizeSnippet` preserved real `<mark>` tags by swapping them for
`\0markO\0`/`\0markC\0`, escaping everything, then swapping back. NUL is an
ordinary character a snippet can carry, so what decided whether markup was
emitted was a string the input could supply.

A whole sentinel forged a tag outright:

    sanitizeSnippet('before \0markO\0 after')
    // → 'before <mark> after'      — one <mark> out, none in

    sanitizeSnippet('\0markC\0\0markO\0')
    // → '</mark><mark>'            — a close ahead of its opener

Worse, and easier: **six** of the seven bytes, immediately before a *real* tag,
were enough. The placeholder this function inserted for that tag completed the
prefix, and the restore step then found a sentinel spanning the two:

    sanitizeSnippet('a\0markO<mark>hit</mark>b')
    // → 'a<mark>markO\0hit</mark>b'

The genuine highlight moved, and with text on both sides it landed on text it
was never meant to mark. No crafted sequence — one stray fragment ahead of any
highlight. The first description of this defect, in #391 and in this branch's
first revision, said the input had to carry the sentinel itself. That understated
both the trigger and the consequence; an independent fuzzing pass found the
prefix case.

The function's own doc says the preserved tag is hardcoded *"on purpose: taking
it as a parameter would let a caller pass any tag through to the `v-html` that
renders the result."* The intent was right; the mechanism did not hold it.

Not XSS, and the bound is worth stating because it is what keeps this a content
bug: `escapeHTML` ran before the swap back, so content inside a forged region
stayed escaped, and the emitted tag came from a fixed literal rather than from a
capture group — no attribute could land inside it. Forgeable surface: the two
strings, nothing else. The consequence is spoofed emphasis, relocated highlights
and unbalanced markup reaching `v-html`, in snippets that come from whatever
backend the host application passes to `<ContentSearch>`
(`useContentSearch.ts:141,144`).

Splitting on the real tags removes the guess, and with it the collision. Both
implementations were run over ~2.1M generated inputs by an independent pass:
every divergence traces to this family, and the new one never emitted a tag
other than the two literals nor leaked an unescaped character. The regex has no
quantifiers, and growth is linear to 61MB.

Five tests added, each mutation-checked: dropping the regex capture, dropping the
closing-tag half of the condition, and escaping the tags themselves are all
caught; restoring the old implementation fails exactly the four forgery cases.
One pins the *bound* rather than the bug — a forged tag could never carry an
attribute — so a future rewrite cannot widen that silently.

Pre-existing since `557a5178`, the original port, and untouched by #365, #371
and #388. The function came from upstream unchanged, so `nuxt/ui` very likely
carries it too.

Closes #391.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik pushed a commit that referenced this pull request Aug 15, 2026
…nput

`sanitizeSnippet` preserved real `<mark>` tags by swapping them for
`\0markO\0`/`\0markC\0`, escaping everything, then swapping back. NUL is an
ordinary character a snippet can carry, so what decided whether markup was
emitted was a string the input could supply.

A whole sentinel forged a tag outright:

    sanitizeSnippet('before \0markO\0 after')
    // → 'before <mark> after'      — one <mark> out, none in

    sanitizeSnippet('\0markC\0\0markO\0')
    // → '</mark><mark>'            — a close ahead of its opener

Worse, and easier: **six** of the seven bytes, immediately before a *real* tag,
were enough. The placeholder this function inserted for that tag completed the
prefix, and the restore step then found a sentinel spanning the two:

    sanitizeSnippet('a\0markO<mark>hit</mark>b')
    // → 'a<mark>markO\0hit</mark>b'

The genuine highlight moved, and with text on both sides it landed on text it
was never meant to mark. No crafted sequence — one stray fragment ahead of any
highlight. The first description of this defect, in #391 and in this branch's
first revision, said the input had to carry the sentinel itself. That understated
both the trigger and the consequence; an independent fuzzing pass found the
prefix case.

The function's own doc says the preserved tag is hardcoded *"on purpose: taking
it as a parameter would let a caller pass any tag through to the `v-html` that
renders the result."* The intent was right; the mechanism did not hold it.

Not XSS, and the bound is worth stating because it is what keeps this a content
bug: `escapeHTML` ran before the swap back, so content inside a forged region
stayed escaped, and the emitted tag came from a fixed literal rather than from a
capture group — no attribute could land inside it. Forgeable surface: the two
strings, nothing else. The consequence is spoofed emphasis, relocated highlights
and unbalanced markup reaching `v-html`, in snippets that come from whatever
backend the host application passes to `<ContentSearch>`
(`useContentSearch.ts:141,144`).

Splitting on the real tags removes the guess, and with it the collision. Both
implementations were run over ~2.1M generated inputs by an independent pass:
every divergence traces to this family, and the new one never emitted a tag
other than the two literals nor leaked an unescaped character. The regex has no
quantifiers, and growth is linear to 61MB.

Five tests added, each mutation-checked: dropping the regex capture, dropping the
closing-tag half of the condition, and escaping the tags themselves are all
caught; restoring the old implementation fails exactly the four forgery cases.
One pins the *bound* rather than the bug — a forged tag could never carry an
attribute — so a future rewrite cannot widen that silently.

Pre-existing since `557a5178`, the original port, and untouched by #365, #371
and #388. The function came from upstream unchanged, so `nuxt/ui` very likely
carries it too.

Closes #391.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik added a commit that referenced this pull request Aug 15, 2026
…nput (#405)

`sanitizeSnippet` preserved real `<mark>` tags by swapping them for
`\0markO\0`/`\0markC\0`, escaping, then swapping back. NUL is an ordinary
character a snippet can carry, so what decided whether markup was emitted was a
string the input could supply.

A whole sentinel forged a tag outright. Worse and easier: six of its seven bytes
immediately before a real tag were enough, because the placeholder inserted for
that tag completed the prefix — so `a\0markO<mark>hit</mark>b` came back as
`a<mark>markO\0hit</mark>b`, the genuine highlight landing on text it was never
meant to mark. No crafted sequence, one stray fragment ahead of any highlight.

Not XSS: escaping ran before the swap back, so content inside a forged region
stayed escaped, and the emitted tag came from a fixed literal rather than a
capture group — no attribute could land inside it. Forgeable surface was the two
strings and nothing else. The consequence is spoofed emphasis, relocated
highlights and unbalanced markup reaching `v-html`, in snippets that come from
whatever backend the host application passes to `<ContentSearch>`.

Splitting on the real tags removes the guess, and with it the collision.
Independently fuzzed at ~2.1M inputs against both the old implementation and a
reference scanner using neither `split` nor `replaceAll`: no bypass, no
unescaped character, no tag other than the two literals. The regex has no
quantifiers; growth is linear to 61MB and costs 2.15µs against the old 2.09µs at
realistic snippet size.

Five tests added, each mutation-checked by running it: dropping the regex
capture, dropping either half of the condition, escaping the tags themselves and
returning the input untouched are all caught, and restoring the old
implementation fails exactly the forgery cases.

Pre-existing since `557a5178`, the original port; untouched by #365, #371 and
#388.

Closes #391.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik pushed a commit that referenced this pull request Aug 15, 2026
…erage

Each was falsifiable, which is how each was caught. The pattern is the finding:
a prose claim about test coverage cannot fail when it stops being true.

**"Every constant and every branch above was verified by removing it and
watching a named test fail."** #390 found six surviving mutations, three of them
constants this bullet covers. Restated as intent, with the procedure spelled out
rather than implied — delete, run `pnpm test`, confirm a named test goes red,
revert — and with the other three survivors named, since a paragraph rebuilding
trust in coverage should not leave half its own evidence unaccounted for.

**"The unpaired-surrogate strings are the only input that can catch a surrogate
range constant being widened."** True only where the probe sits one code point
outside the bound it pins. Two of the four sat `0x100` away and caught nothing.

**"A pickaxe returns exactly one commit."** It counts occurrences of the string,
not authorship, so `54b93e33`'s jsDoc line joined the list and any future comment
naming the parameter will too. Restating the number would only defer the
problem; the claim now attributes rather than counts, in all three places it
appeared.

Two smaller corrections: the `8 of 66` figure appears nowhere in the repository
and cannot be re-derived, and `createClusterSnapper` gained a second parameter in
#388.

Adds one §2 invariant — **`sanitizeSnippet` splits on the tag**. Upstream's
placeholder round-trip is what this file was ported from, and it lets a snippet
forge `<mark>` out of its own input: six of the sentinel's seven bytes ahead of a
real tag suffice, because the placeholder inserted for that tag completes the
prefix, moving a genuine highlight onto text it was never meant to mark (#391,
fixed in #405). Carries the sibling rule from the function's jsDoc too — the tag
is hardcoded so a caller cannot pass any tag through to `v-html` — since a port
that generalises the signature breaks the other half of the same guarantee.

Two things found while writing it, both worth more than the corrections:

`getGraphemeSegmenter()`'s module-level memo is a second cache, distinct from the
per-value `segments` view, and was documented nowhere. Collapsing either into
per-call construction costs a search box every keystroke and fails no test — the
module-level one has no coverage at all. Now named.

The four sub-bullets restated numbers that also live in the code comments, and
one such figure has already rotted in one of its two homes. They now point at
the code rather than copying it, which is why this correction pass removes 17
lines as well as adding.

No `src/` change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik pushed a commit that referenced this pull request Aug 15, 2026
…erage

Each was falsifiable, which is how each was caught. The pattern is the finding:
a prose claim about test coverage cannot fail when it stops being true.

**"Every constant and every branch above was verified by removing it and
watching a named test fail."** #390 found six surviving mutations, three of them
constants this bullet covers. Restated as intent, with the procedure spelled out
rather than implied — delete, run `pnpm test`, confirm a named test goes red,
revert — and with the other three survivors named, since a paragraph rebuilding
trust in coverage should not leave half its own evidence unaccounted for.

**"The unpaired-surrogate strings are the only input that can catch a surrogate
range constant being widened."** True only where the probe sits one code point
outside the bound it pins. Two of the four sat `0x100` away and caught nothing.

**"A pickaxe returns exactly one commit."** It counts occurrences of the string,
not authorship, so `54b93e33`'s jsDoc line joined the list and any future comment
naming the parameter will too. Restating the number would only defer the
problem; the claim now attributes rather than counts, in all three places it
appeared.

Two smaller corrections: the `8 of 66` figure appears nowhere in the repository
and cannot be re-derived, and `createClusterSnapper` gained a second parameter in
#388.

Adds one §2 invariant — **`sanitizeSnippet` splits on the tag**. Upstream's
placeholder round-trip is what this file was ported from, and it lets a snippet
forge `<mark>` out of its own input: six of the sentinel's seven bytes ahead of a
real tag suffice, because the placeholder inserted for that tag completes the
prefix, moving a genuine highlight onto text it was never meant to mark (#391,
fixed in #405). Carries the sibling rule from the function's jsDoc too — the tag
is hardcoded so a caller cannot pass any tag through to `v-html` — since a port
that generalises the signature breaks the other half of the same guarantee.

Two things found while writing it, both worth more than the corrections:

`getGraphemeSegmenter()`'s module-level memo is a second cache, distinct from the
per-value `segments` view, and was documented nowhere. Collapsing either into
per-call construction costs a search box every keystroke and fails no test — the
module-level one has no coverage at all. Now named.

The four sub-bullets restated numbers that also live in the code comments, and
one such figure has already rotted in one of its two homes. They now point at
the code rather than copying it, which is why this correction pass removes 17
lines as well as adding.

No `src/` change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik pushed a commit that referenced this pull request Aug 15, 2026
Each was falsifiable, which is how each was caught. The pattern is the finding:
a prose claim about test coverage cannot fail when it stops being true.

**"Every constant and every branch above was verified by removing it and
watching a named test fail."** #390 found six surviving mutations, three of them
constants this bullet covers. Restated as intent, with the procedure spelled out
rather than implied — delete, run `pnpm test`, confirm a named test goes red,
revert — and with the other three survivors named, since a paragraph rebuilding
trust in coverage should not leave half its own evidence unaccounted for.

**"The unpaired-surrogate strings are the only input that can catch a surrogate
range constant being widened."** True only where the probe sits one code point
outside the bound it pins. Two of the four sat `0x100` away and caught nothing.

**"A pickaxe returns exactly one commit."** It counts occurrences of the string,
not authorship, so `54b93e33`'s jsDoc line joined the list and any future comment
naming the parameter will too. Restating the number would only defer the
problem; the claim now attributes rather than counts, in all three places it
appeared.

**"Only 16 of ~3200 commits carry an `Upstream:` trailer."** 52 do. Checked two
ways — `git log --grep` and a pass over every commit body — and against the tree
as it stood when the sentence was written, where it was already 52 of 3179. It
was never right, and it is load-bearing: it is the stated reason the trailer
convention cannot support an inference about provenance. That conclusion still
holds at 52 of 3200; the number does not. Corrected in all three places.

Two smaller ones: the `8 of 66` figure appears nowhere in the repository and
cannot be re-derived, and `createClusterSnapper` gained a second parameter in
#388.

The guard list omitted `describe('truncation from the start')`, which pins the
surrogate safety of `truncateHTMLFromStart` — a function this same bullet names.

Adds one §2 invariant — **`sanitizeSnippet` splits on the tag**. Upstream's
placeholder round-trip is what this file was ported from, and it lets a snippet
forge `<mark>` out of its own input: six of the sentinel's seven bytes ahead of a
real tag suffice, because the placeholder inserted for that tag completes the
prefix, moving a genuine highlight onto text it was never meant to mark (#391,
fixed in #405).

Two things found while writing it, both worth more than the corrections:

`getGraphemeSegmenter()`'s module-level memo is a second cache, distinct from the
per-value `segments` view, and was documented nowhere. Collapsing either into
per-call construction costs a search box every keystroke and fails no test — the
module-level one has no coverage at all. Now named.

The four sub-bullets restated numbers that also live in the code comments, and
one such figure has already rotted in one of its two homes. They now point at
the code rather than copying it, which is why this pass removes 31 lines as well
as adding.

No `src/` change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
IgorShevchik added a commit that referenced this pull request Aug 15, 2026
…age (#409)

Each was falsifiable, which is how each was caught. The pattern is the finding:
a prose claim about test coverage cannot fail when it stops being true.

**"Every constant and every branch above was verified by removing it and
watching a named test fail."** #390 found six surviving mutations, three of them
constants this bullet covers. Restated as intent, with the procedure spelled out
rather than implied, and the other three survivors named — two of which are
pinned by `describe('key selection')`, credited so the trail does not end
nowhere.

**"The unpaired-surrogate strings are the only input that can catch a surrogate
range constant being widened."** True only where the probe sits one code point
outside the bound it pins. Two of the four sat 0x100 away and caught nothing.

**"A pickaxe returns exactly one commit."** It counts occurrences of the string,
not authorship, so `54b93e33`'s jsDoc line joined the list and any future comment
naming the parameter will too. The claim now attributes rather than counts.

**"Only 16 of ~3200 commits carry an `Upstream:` trailer."** 52 do, and 52 of
3179 did when the sentence was written — it was wrong on arrival, not stale. It
is load-bearing: it is the stated reason the trailer cannot support a provenance
inference. The conclusion survives the correction; the number does not.

Also: the unreproducible `8 of 66` figure is marked as a one-off measurement,
`createClusterSnapper`'s signature gained a second parameter in #388, the guard
list omitted `describe('truncation from the start')`, and
`getGraphemeSegmenter()`'s module-level memo — a second cache, distinct from the
per-value view, covered by no test — was documented nowhere.

Adds one §2 invariant: **`sanitizeSnippet` splits on the tag**. Upstream's
placeholder round-trip lets a snippet forge `<mark>` out of its own input, so a
port that replays upstream reverts #405. Not reported upstream, so the conflict
recurs on every port that touches the function.

The four sub-bullets that restated numbers also living in the code comments now
point at the code instead — one of those figures had already rotted in one of
its two homes.

Verified by a mutation pass over every constant and branch in the file: 62
mutations, 55 killed, 5 provably equivalent, 2 real gaps, filed as #410 and
#411. Running the check this file now prescribes is what found them.

No `src/` change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWWrBHgfqGSbeU3V6UuMF8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CommandPalette: the grapheme-snap ceiling is weighed against the escaped copy, so long-ish labels lose the snap

2 participants