fix(web): file previews copy text beyond visible rows#23244

draft8
main
fix/issue-15927
opened20d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

Copying a long external file from the read-only Files panel copies only mounted rows, and scrolling can discard the selection. On main, clicking a 226-line SQL file then pressing Ctrl+A/C and pasting returned only lines 1–100.

Change

Keep selection anchor and focus as source offsets, copy the corresponding source slice, and redraw its visible portion after virtualization. Follow the text Pierre actually rendered during asynchronous highlighting. Preserve selection ownership when the narrow sheet receives focus after a source click. Add a deterministic fixture generator.

Scope and approval

Fixes #15927 GitCafe: https://git.cafe/pingdotgg/t3code/issues/15927 Triaged bug via the automated issue flow: #15927. Shared read-only web previews include Files and attachment/context source previews; writable editors and native mobile use separate renderers. No provider, server contract, authentication, permissions, or MCP changes. Draft for dispatcher review: proof remains incomplete; do not auto-land.

Verification

  • Changed-files checks passed: format, lint, knip, and affected-package typechecks. The fixture's namespace imports were subsequently corrected and its targeted lint/format checks passed.
  • After merging main, 23 tests passed across FilePreviewPanel, fileLineReveal, and fileEditorVirtualization. These existing tests do not prove native clipboard behavior.
  • Both independent code reviewers returned MERGE after the narrow-sheet focus correction. Exact-head diagnostics cover ancestor focus and relinquishing ownership to the composer. No new test file was added under the requested existing-file constraint; native interaction proof uses recordings.
  • Final captured implementation: 6130ec9628. Current head adds only fixture-import corrections. All four final native copy/paste checks exactly match 11,752 characters and 226 statements. A 572-character partial selection survived eviction of its original rows. Regenerating the committed fixture produces a byte-identical canonical file.

Evidence is partial. Full report and matrix disposition · Oracles, recordings metadata, and pixel maps.

Environment: Linux x64, Chrome 154 through T3 Browser panel, CSS viewports 1440×720 and 390×720, light/dark, synthetic SQL and isolated worktree state. Saved wide rasters are 1280×640; narrow rasters are 780×1440. Base frontend uses port 6455, after uses 6454, with the same isolated backend/fixture. Captured base is b5a226e49c; the later main merge changes build files without changing this renderer. Font scaling/DPR were not independently recorded.

Interaction: click a source row, Ctrl+A, Ctrl+C, focus a temporary plain-text oracle, Ctrl+V; no messages sent. Final recordings use row locators after dismissing notifications. The preserved original before recording shows the 100-line copy. Fresh base gestures were notification-contaminated and are not accepted as clean before proof.

The table below contains diagnostic initial stills, not a clean visual-regression assertion. Diff0 amplifies any RGB channel delta greater than 0; Diff16 marks deltas greater than 16. What else changed: before includes an update toast, after dismisses it; wide panel width differs (539→359 CSS px), composer/sidebar state and relative-time labels differ, and localhost origin differs. These differences are not attributed to this fix.

Partial selection then scroll eviction recording. The original 572-character source slice equals the pasted result after rows 1–100 were evicted. This is scroll after release, not held auto-scroll.

Unverified: clean paired base gestures in all cells; final-head held auto-scroll; newline/Unicode and other data fixtures; native context-menu copy; attachment/review/element-context entry points; full lifecycle matrix; independent pixel rebuild; Firefox/WebKit and remote/relay. cannot-verify desktop: native Electron/macOS/Windows could not be exercised here. The primary's separate integrated replay was blocked at pairing; the evidence child completed the recorded final checks. Proof audit: INSUFFICIENT for the full prescribed matrix (2 pass, 13 partial, 24 gaps across 39 rows). The auditor independently checked fixture hashes, four exact copy/paste results, the 572-character eviction result and pixel-diff counts; no new confirmed code blocker was found. Clean base pairing, held auto-scroll, data/ownership/lifecycle/caller coverage and independent rebuild remain missing. Keep this PR draft pending dispatcher/Julius review. All owned verification servers were stopped.

Models: Claude Opus 5.5 (implementation), GPT-6.1 Sol and Claude Opus 5.5 (review), GPT-6.1 Sol (evidence/audit and lead). Harnesses: T3 Code, Codex, and Claude Agent.

Checks

2 failing · 19 successful · 6 skipped
Some checks failed

Failing2

a073960

Added 8 commits

  • fix(web): select all in the narrow file sheet copies the whole file1bd91fd
  • Merge main into fix/issue-1592734bbb62
  • fix(web): arrow-key collapse cancels a file preview selection before copy4873233
  • test(web): add reproducible source selection fixtures6130ec9
  • fix(web): file preview copy follows the text Pierre has drawn6832fee
  • chore(web): use namespace imports in selection fixturesa073960
  • fix(web): read-only file previews copy the whole selectiona8d0b86
  • fix(web): keep the drag anchor and CRLF lines in file preview selectionse659111
Synced from GitHub

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for a073960.

This comment will update automatically after the next completed run.