Skip to content

refactor(runtime): dedup UTF-8 byte counters to shared measureUtf8ByteLength - #12136

Closed
YuriNachos wants to merge 1 commit into
stablyai:mainfrom
YuriNachos:runtime-utf8-byte-counter-dedup
Closed

refactor(runtime): dedup UTF-8 byte counters to shared measureUtf8ByteLength#12136
YuriNachos wants to merge 1 commit into
stablyai:mainfrom
YuriNachos:runtime-utf8-byte-counter-dedup

Conversation

@YuriNachos

Copy link
Copy Markdown
Contributor

Summary

Three co-located modules in src/renderer/src/runtime/ each carried a byte-identical private getCodePointUtf8ByteLength and a byte-identical ~12-line UTF-8 byte-counting loop:

  • runtime-provider-search-bounds.ts (isRuntimeProviderSearchQueryWithinLimit)
  • runtime-repo-search-bounds.ts (isRuntimeRepoRefSearchQueryWithinLimit)
  • runtime-file-search-bounds.ts (isRuntimeFileSearchTextWithinLimit)

The canonical src/shared/utf8-byte-limits.ts already exports measureUtf8ByteLength — the same loop, with the same stopAfterBytes early-exit and the same surrogate-pair index += 1 step. This finishes the extraction the shared module was clearly meant to replace (same shape as the recent #12078 FrameDecoder collapse, #12082 provider-contract share, #12091 push-target reuse).

Each bound helper now delegates:

return !measureUtf8ByteLength(text, { stopAfterBytes: maxBytes }).exceededLimit

The provider variant keeps its null | undefined → true guard; the repo and file variants take non-nullable input and delegate directly.

Screenshots

No visual change — pure refactor.

Testing

  • pnpm lint
  • pnpm typecheck
  • pnpm test
  • Added or updated high-quality tests that would catch regressions, or explained why tests were not needed

Passed:

  • Behaviour is 1:1 — proven by the existing regression net, not new tests. The three co-located *.test.ts suites already pin the multibyte + ASCII-oversize + null/undefined behaviour each helper must preserve:
    • runtime-provider-search-bounds.test.tsundefined/null → true; '😀' @ 3 → false; 'x'.repeat(9*1024) → false.
    • runtime-repo-search-bounds.test.ts'😀' @ 3 → false; 'x'.repeat(3*1024) → false.
    • runtime-file-search-bounds.test.ts'😀' @ 3 → false; oversized includePattern'includePattern'.
    • All 8/8 stay green after the refactor — the delegation is logically identical to the old byteLength > maxBytes check, including the surrogate index += 1 step.
  • pnpm typecheck green across all three tsconfigs (node, tc.cli, tc.web).
  • pnpm exec oxlint clean (exit 0).
  • git diff --stat = 3 files, -66 net lines (8 insertions, 74 deletions).

AI Review Report

  • Cross-platform (macOS/Linux/Windows): pure renderer TypeScript string math; no platform assumptions. The bounds apply identically for Linear/Jira/repo/file callers.
  • SSH/remote/local + folder-workspace: N/A — renderer-side query length guards, no SSH/folder/git path.
  • Provider/agent neutrality: N/A — byte-budget guard shared by Linear/Jira/repo/file search.
  • Performance / hot path: if anything marginally faster (one early-exit helper vs three); the stopAfterBytes short-circuit matches the old > maxBytes check exactly.
  • UI quality: none — internal bound check.

Security Audit

Pure refactor: three private byte-counter copies replaced by a call to an existing, already-tested shared helper. No new input handling, IPC, auth, path, or dependency surface. The shared measureUtf8ByteLength is already imported across the codebase (clipboard-text.ts, terminal-input.ts, etc.).

Notes

  • measureUtf8ByteLength returns { byteLength, exceededLimit }; the bound helpers consume only .exceededLimit, which is exactly the old byteLength > maxBytes outcome.
  • A few more private getCodePointUtf8ByteLength copies exist elsewhere (e.g. monaco-large-text-paste.ts, comment-body-submit-state.ts); they carry additional logic (getNextChunkBoundary) and are a cleaner separate follow-up, intentionally out of scope to keep this PR small.
  • No open or closed PR deduplicates these three counters.
  • A maintainer may need to approve-and-run the CI workflows for this fork PR; let me know if anything else is needed.

@YuriNachos

Copy link
Copy Markdown
Contributor Author

/track-community-pr

…eLength

The three runtime search-bound modules (provider / repo-ref / file) each
carried a byte-identical private getCodePointUtf8ByteLength plus a hand-rolled
UTF-8 byte-counting loop. The canonical src/shared/utf8-byte-limits.ts already
exports measureUtf8ByteLength — the same loop, with the same early-exit on the
byte budget and the same surrogate-pair step. This finishes the extraction the
shared module was clearly meant to replace.

Each bound helper now delegates to measureUtf8ByteLength(text, { stopAfterBytes
}). Behaviour is 1:1 (the three co-located \*.test.ts suites stay green), and a
future UTF-8 edge-case fix lands once instead of three times.

Co-authored-by: Claude <noreply@anthropic.com>
@YuriNachos
YuriNachos force-pushed the runtime-utf8-byte-counter-dedup branch from 41c11c9 to a46e1b3 Compare August 2, 2026 20:04
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 33a572e9-c6e7-47ad-a2ba-fddf7eca5021

📥 Commits

Reviewing files that changed from the base of the PR and between 41c11c9 and a46e1b3.

📒 Files selected for processing (3)
  • src/renderer/src/runtime/runtime-file-search-bounds.ts
  • src/renderer/src/runtime/runtime-provider-search-bounds.ts
  • src/renderer/src/runtime/runtime-repo-search-bounds.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/renderer/src/runtime/runtime-provider-search-bounds.ts
  • src/renderer/src/runtime/runtime-repo-search-bounds.ts
  • src/renderer/src/runtime/runtime-file-search-bounds.ts

📝 Walkthrough

Walkthrough

The file, provider, and repository runtime search-bound validators now use the shared measureUtf8ByteLength utility. Each validator passes its configured byte limit and uses the utility result to determine whether the input remains within the limit. Local UTF-8 byte-counting helpers and manual iteration logic were removed. The existing limits and public validator interfaces remain unchanged.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main refactor: replacing duplicate UTF-8 byte counters with the shared measureUtf8ByteLength utility.
Description check ✅ Passed The description includes all required sections and detailed testing, review, security, and scope information; pnpm build is not reported.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR removes three duplicate private UTF-8 byte-counting implementations from co-located runtime-*-search-bounds.ts modules and replaces each with a call to the already-established shared helper measureUtf8ByteLength from src/shared/utf8-byte-limits.ts.

  • The old loop (byteLength > maxBytes → return false) and the shared helper's early-exit condition (byteLength > stopAfterBytes → exceededLimit: true) are logically identical, including the surrogate-pair skip (index += 1) and the exact-boundary treatment where equal-to-limit returns true.
  • The null | undefined guard in runtime-provider-search-bounds.ts is preserved; the other two helpers take non-nullable strings and delegate directly.
  • Net change is –66 lines; all three companion test suites (covering multibyte emoji, ASCII-oversize, and null/undefined inputs) continue to pass unmodified.

Confidence Score: 5/5

Safe to merge — the refactor is a clean mechanical substitution of three identical private implementations with an already-tested shared helper.

The old loop (byteLength > maxBytes → return false) and the shared helper's early-exit path (byteLength > stopAfterBytes → exceededLimit: true) are structurally and semantically identical, including the surrogate-pair skip and exact-boundary behaviour. The null/undefined guard in the provider variant is untouched. All three companion test suites cover the key multibyte, ASCII-oversize, and null/undefined cases and continue to pass without modification.

Files Needing Attention: No files require special attention.

Important Files Changed

Filename Overview
src/renderer/src/runtime/runtime-file-search-bounds.ts Removes private getCodePointUtf8ByteLength + manual loop; delegates to measureUtf8ByteLength with stopAfterBytes. Semantically identical.
src/renderer/src/runtime/runtime-provider-search-bounds.ts Same dedup as the other two files; null/undefined early-return guard is preserved before the delegate call.
src/renderer/src/runtime/runtime-repo-search-bounds.ts Removes private helper and manual loop; delegates to measureUtf8ByteLength. Logic is unchanged.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[isRuntimeProviderSearchQueryWithinLimit] -->|null/undefined| B[return true]
    A -->|string| C[measureUtf8ByteLength]
    D[isRuntimeRepoRefSearchQueryWithinLimit] --> C
    E[isRuntimeFileSearchTextWithinLimit] --> C
    C -->|stopAfterBytes = maxBytes| F{byteLength > maxBytes?}
    F -->|yes| G[exceededLimit: true → return false]
    F -->|no| H[exceededLimit: false → return true]
Loading

Reviews (1): Last reviewed commit: "refactor(runtime): dedup UTF-8 byte coun..." | Re-trigger Greptile

@AmethystLiang
AmethystLiang requested a review from OrcaWin August 3, 2026 18:28
@AmethystLiang AmethystLiang added the P2 Normal priority: nice-to-have or lower urgency label Aug 3, 2026
@YuriNachos

Copy link
Copy Markdown
Contributor Author

Closing for now — this has gone stale against main (which moves fast) and I'd rather open a fresh, focused change than keep rebasing this one. Thanks for the project!

@YuriNachos YuriNachos closed this Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority: nice-to-have or lower urgency

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants