# Read-only proof audit, pass 1

PR [#24611](https://git.cafe/pingdotgg/t3code/pulls/24611), head [43cb239](https://git.cafe/pingdotgg/t3code/commit/43cb23920cf601caaf146c75477abc5dfee95cb2).

Audited only `/home/ubuntu/wt/pr-24611`; HEAD matched exactly and worktree was clean. No source changes, servers, browser, live userdata, or PR-state reads. This is source reachability plus an executed helper probe, not an observed client rendering test.

## Complete shared-helper inventory

Used `git grep -n '\btruncate\b'`, `git grep -n -E 'truncate\('`, and `git grep -n '@t3tools/shared/String'` across apps/web, apps/server, packages/client-runtime, apps/mobile. CSS truncate, filesystem truncate, and unrelated local helpers are excluded. All imports are named `truncate`; no aliased import found.

| Group | Every direct shared truncate call |
|---|---|
| Web | `apps/web/src/components/chat/useProposedPlanSend.ts:304`: plan implementation thread title; default 50 |
| Shared client runtime | `packages/client-runtime/src/operations/threadTitle.ts:34`: prompt text; :44: `File: ${attachmentName}`; :50: fallback label; each default 50 |
| Mobile | `apps/mobile/src/lib/threadActivity.ts:278`: compact work entry text; :317: expanded preview; :938: single tool command label; each 200 |
| Server | None: no shared String import and no shared truncate caller |

Indirect runtime callers: web `useComposerSend.ts:1157`, `useMultipleModelSend.ts:132`; mobile `projectThreadStartTurn.ts:41`, `use-thread-outbox-drain.ts:865`. These are all deriveThreadTitleSeed call sites in the requested trees. No separate shared-helper web preview/label calls exist.

## Exact boundary matrix

Notation: `A(n)` means exactly `"a".repeat(n)`; expressions below specify exact strings, not approximate examples. `\uD83D` is a lone high surrogate: rendered as replacement glyph U+FFFD. The old shared helper uses slice(0,N); this head drops its trailing high surrogate when the next code unit is its low surrogate. ASCII/BMP budgets and `...` are preserved.

| Group / caller | Exact input and cut | Reachability / visible destination | Result at audited head |
|---|---|---|---|
| Web new-thread title (runtime :34) | Send `A(49) + "😀 tail"`; N=50 splits the emoji | Create a new thread and send that plain prompt. useComposerSend computes seed, sends it as creation title/titleSeed (:1229, :1277); title appears in thread navigation. Multi-model send uses same derivation. | Old: `A(49)+"\uD83D..."`; now `A(49)+"..."` |
| Web plan implementation title (useProposedPlanSend :304) | Plan heading `"# " + A(39) + "😀 tail"`; derived title `"Implement " + A(39) + "😀 tail"`; 10+39 ASCII units precede emoji | Open a thread with a proposed plan, use the new-thread implementation action with an available provider/interaction mode. buildPlanImplementationThreadTitle prepends `Implement `; createThread receives result (:315 onward). | Old: `"Implement "+A(39)+"\uD83D..."`; now `"Implement "+A(39)+"..."` |
| Mobile work-log preview/label (threadActivity :278, :317) | Detail `A(199)+"😀 tail"`; N=200 splits emoji | Open a thread containing a reasoning work-log entry with that detail. Collapsed workEntryRowLabel takes detail through compactWorkEntryText; thread-work-log.tsx :1027/:1032 computes preview/display, :1087/:1122 renders label. Expanding reasoning intentionally changes header to Thought/Thinking, so use a non-reasoning detail entry without tool presentation/command to exercise :317. | Old: `A(199)+"\uD83D..."`; now `A(199)+"..."` |
| Mobile new-thread title (runtime :34) | Prompt `A(49)+"😀 tail"`; N=50 | Start a project thread with this plain prompt. projectThreadStartTurn.ts :41 derives title; result contains titleSeed and bootstrap.createThread.title. Outbox drain also derives titleSeed. Visible in thread navigation. | Old: `A(49)+"\uD83D..."`; now `A(49)+"..."` |
| Server → client title (separate helper; cli/thread.ts :453–456) | Message `A(78)+"😀 tail"`; max=80, slice(0,79) | CLI thread start without explicit title derives titleFromMessage, passes it to t3_thread_launch (:575–585). Client navigation receives that title. | Still `A(78)+"\uD83D…"`; shared patch does not affect this path |
| Server → PR/commit notification toast (separate helper; git/GitManager.ts :449–490) | PR title or commit subject `A(68)+"😀 tail"`; max=72, content cut=69 | Run Git action that creates/opens a PR, or creates/pushes a commit with this subject. summarizeGitActionResult calls truncateText; buildCompletionToast :1906 uses summary; web GitActionsControl.tsx :1295/:1345/:1355 forwards actionResult.toast.description to UI. | Still `A(68)+"\uD83D..."`; affects both PR and commit descriptions |

Additional exact runtime seed branches: a non-image attachment named `A(43)+"😀 tail.txt"` yields `"File: "+A(43)+"..."` at :44 (old ends in lone surrogate); empty prose/attachments and fallback label `A(49)+"😀 tail"` exercises :50. Attachment-only UI submission requirements vary, so these are branch probes rather than claims of an independently verified composer flow.

Mobile :938 is the third direct call: a command `A(199)+"😀 tail"` produces the same old/new boundary as above when singleToolCallLabel reaches its command branch (reasoning and resolved tool presentations take earlier returns).

## Server notification / provider-send preview scope

There are no shared-helper callers in either category. Two concrete independent paths explain why the PR should not claim all server previews are covered:

1. PR-watch comment snippet: orchestration-v2/pullRequestWatch.ts :162–167, :199 uses max=200 but slices at 197. Comment body `A(196)+"😀 tail"` becomes `A(196)+"\uD83D..."`. With a watched PR, a new comment produces a remarks change; PullRequestWatchReactor.ts :546 calls pullRequestWatchMessage, whose remarks lines embed that snippet in the wake message. This is a notification/prompt preview reaching the agent thread, not a shared truncate call.
2. Provider-send restart note: RestartBackgroundNote.ts :16–20 compactLabel defaults to 160 and slices at 159. A cancelled shell command input `A(158)+"😀 tail"` becomes `A(158)+"\uD83D…"`. cancelledTurnItemWork chooses that input for command_execution; restartCancelledBackgroundWorkNote includes its label. ProviderTurnStartService.ts :1065 builds the note for the next provider turn (RestartContinuation.ts :276 also constructs it). Reachable after a server restart cancels background work and the next user message resumes activity. This is provider prompt content; no claim that its label is independently rendered as a client preview.

## Executed proof and recommendations

Executed the actual packages/shared/src/String.ts with Node `--experimental-strip-types`, no app initialization. For N=50 and N=200, input `A(N-1)+"😀 tail"` returned `A(N-1)+"..."`, and output.isWellFormed() was true. Compared old slice expression returned the lone high surrogate. Existing String.test.ts also covers split pair, pair fitting exactly, trimming, ASCII/BMP, and short input; tests were read, not run.

- Accept the shared helper fix for its documented scope: seven direct calls plus the listed indirect client callers. Concrete web and mobile title/work-log paths benefit. No defect found in this pair-boundary guard for those positive integer budgets.
- Scope release/PR claims to the shared helper. Server titles, Git action descriptions, watch comment snippets, and provider restart labels use independent cuts and remain vulnerable; track separately if whole-product removal of replacement glyphs is intended. They are pre-existing gaps, not regressions established by this pass.
- This protects surrogate pairs, not grapheme clusters (ZWJ emoji/combining sequences). Do not describe it as complete grapheme preservation. Browser/mobile visual proof was expressly excluded; source reachability is not a screenshot.
