Skip to content

fix(paste): lower threshold to 100 — Claude accumulator engages well below 800 - #72

Merged
Juliusolsson05 merged 1 commit into
mainfrom
fix/paste-threshold
May 11, 2026
Merged

Juliusolsson05 merged 1 commit into
mainfrom
fix/paste-threshold

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Summary

  • Follow-up to feat(paste): event-driven submit + per-paste debug dump + headless quirks docs #71. The bracketed-paste + event-driven submit fix shipped there worked correctly for its targeted scenario but never engaged for the more common case: 100–800 char single-line messages.
  • Lowers CLAUDE_PASTE_THRESHOLD from 800 → 100 so those messages go through the bracketed-paste path that already has the placeholder-detector behind it.
  • Lowers CLAUDE_PASTE_EVENT_DRIVEN_TIMEOUT_MS from 2000 → 500 because in this size range the [Pasted text #N] placeholder never renders (no collapse), so every submit was eating the full 2 s timeout fallback.

Root cause

800 conflated two different Claude TUI thresholds:

  • Collapse threshold (~800): point at which Claude renders [Pasted text #N] instead of inlining bytes. Upstream PASTE_THRESHOLD refers to this one.
  • Accumulator threshold (~100): point at which Claude's paste state machine starts swallowing trailing \r during its ~100 ms debounce. Fires regardless of whether collapse happens.

PR #71 fixed the accumulator race for text that ALSO crossed the collapse threshold. Everything between accumulator-engaged and collapse-engaged stayed on the broken plain-text path.

Evidence

From per-paste debug dumps captured by the journal added in #71 (in ~/Library/Application Support/cc-shell/paste-debug/):

File Length Route Outcome
9da6e430-...paste.jsonl 215 chars route:claude-plain-text bug repros
b387f634-...paste.jsonl 145 chars route:claude-plain-text bug repros
53f74065-...paste.jsonl 156 chars route:claude-plain-text bug repros
5c2b319c-...paste.jsonl 177 chars route:claude-plain-text bug repros

All four show isPasteLike: false and a single main:write with text+\r in one PTY frame — the exact pattern PR #71's bracketed-paste path was supposed to replace.

Test plan

  • Type a ~150 char single-line message into a Claude session and press Enter — message submits cleanly (no need for a follow-up .).
  • Type a multi-line message and press Enter — still submits cleanly.
  • Type a 1-char message (.) and press Enter — should NOT be re-routed through bracketed paste; plain-text path still handles short input.
  • Check the per-paste debug journal for a 150 char message — should now see route:claude-paste, write:paste-payload, and a separate write:submit-cr event with strategy timeout-skip-timer (since the placeholder won't render in this size range).

Followups

  • 100 may need empirical tuning. If short typed messages (50–100 chars) start feeling laggy under the 500 ms placeholder fallback, raise the threshold a bit. The per-paste journal makes this easy to observe.

🤖 Generated with Claude Code

… well below 800

PR #71 shipped the event-driven submit-after-paste fix but the bug kept
firing in practice. Per-paste debug dumps from real usage tell the
story: a 215-char single-line message ("i can say that something DID
NOt work…") was routed as `route:claude-plain-text` and submitted as
text+`\r` in ONE PTY write — the exact code path PR #71's
bracketed-paste + placeholder-detector was supposed to bypass. The
800-char gate held the door shut for the most common case.

Root cause: 800 confused two different Claude TUI thresholds.

  * COLLAPSE threshold (~800): the point at which Claude renders
    `[Pasted text #N]` in the composer instead of inlining the bytes.
    This is the one upstream's PASTE_THRESHOLD const refers to.
  * ACCUMULATOR threshold (~100): the point at which Claude's paste
    state machine starts swallowing trailing `\r` during its ~100 ms
    debounce window. This fires regardless of whether collapse happens.

PR #71 fixed the accumulator race for text that ALSO crossed the
collapse threshold (≥800 chars or multi-line). Everything in
100–800 chars without newlines — i.e. most ordinary chat messages —
stayed on the broken plain-text path. Lowering the gate to 100 routes
those through the bracketed-paste + event-driven submit path, which
is where the actual fix lives.

Also lowers CLAUDE_PASTE_EVENT_DRIVEN_TIMEOUT_MS from 2000 → 500:
in the 100–800 char range the `[Pasted text #N]` placeholder never
renders, so every submit hits the timeout fallback. 2000 ms there is
a noticeable per-message lag. 500 ms is still well past Claude's
100 ms accumulator window so `\r` is always safe by then.

Evidence: per-paste debug dumps in ~/Library/Application Support/cc-shell/paste-debug/
  - 9da6e430-...paste.jsonl: 215 chars, isPasteLike=false, plain-text route → bug
  - b387f634-...paste.jsonl: 145 chars, same shape, same bug
  - 53f74065-...paste.jsonl: 156 chars, same
  - 5c2b319c-...paste.jsonl: 177 chars, same

Follows up #71. Numbers may need empirical tuning if 100 is too
aggressive (i.e., normal-typed short messages get unnecessarily
routed through bracketed paste and feel the 500 ms fallback lag),
but the per-paste debug journal from #71 makes that easy to spot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant