{
  "summary": "Source-grounded verdict: the highest-confidence mechanism for the screenshot’s exact two-column displacement and the two-character scraps (`To`, `Wh`, `Es`) is the server `ScreenGrid`’s missing wide-glyph/continuation-cell model, not rc’s status overlay and not final-output ordering. `Cell` stores only one Unicode scalar plus pen, with no continuation/combining state, and `GridState::put_char` advances exactly one column for every `char`. Later CUP/EL/ECH/ICH/DCH operations address physical terminal columns but mutate this under-width logical row. A concrete deterministic shape explains the fragments: after two display-width-2 glyphs, the model is two cells behind the physical terminal; an absolute CUP to the physical start of `Tools`/`Where`/`Escape` followed by EL indexes two logical cells too far right, preserving the first two ASCII characters — exactly `To`/`Wh`/`Es`. `render_repaint` clears the client first, so it cannot preserve pre-existing physical garbage; it can, however, faithfully repaint those scraps from its already-corrupted model and place another row two columns left. This path affects a cold attach/repaint; live frames are forwarded raw before the grid is advanced, so a no-attach/no-repaint occurrence would require a different path.\n\nThe CPR/DSR path is a separate, real protocol defect/contamination risk. Timeline: (1) Claude Code or ConPTY emits `ESC[6n` on PTY output; (2) `spt-term`’s drain matcher writes the hard-coded CPR `ESC[1;1R` directly to the PTY writer; (3) only after that write does it call `sink(chunk)`; (4) the original `ESC[6n` remains in the output chunk, is retained/fanned out by the broker, carried as `AttachRecord::Output`, and written verbatim by rc to the physical terminal; (5) a real terminal may answer with its actual CPR; (6) rc has no terminal-reply discriminator, so its stdin reader treats that response like operator input and sends it through `AttachRecord::Input` → target `serve_attach` → broker PTY input. The child can therefore receive a guaranteed first, inaccurate `1;1` CPR plus a delayed physical-terminal CPR. The existing unit test explicitly asserts both halves: exactly one fixed reply is written and the query is forwarded unchanged. `ScreenGrid::csi_dispatch` has no `n` arm and does not answer DSR, so DSR does not directly mutate the server grid. [INFERENCE] A wrong/double CPR can perturb Claude Code’s own cursor state and should be fixed/tested, but source alone does not make it the direct wrap/scrap mechanism; the exact two-cell/prefix signature maps more tightly to the missing continuation cells.\n\nA second DSR-shaped input source exists only on idle-message injection: broker `settle_before_inject` enqueues `ESC[6n` directly into child input as a readiness probe. That is the reverse direction from a terminal DSR query and is indistinguishable from a CSI key sequence to a raw-mode TUI. It can contaminate child input around an injected delivery, but it is not exercised merely by rc attach/resize and cannot explain the screenshot without a temporally coincident idle delivery.\n\nRuled paths: current main cannot render the legacy rc identity overlay because `STATUS_ROW_ENABLED` is `false` and `status_row_active` therefore returns false for controllers and viewers; when historically enabled it subtracted one PTY row only, never columns. A visible identity banner is evidence of an older running binary or stale terminal content, not current-main overlay wiring. Current resize routing preserves `(cols, rows)` correctly, sends `(rows, cols)` to the PTY, and performs no two-column subtraction. Current final-output ordering waits for drain quiescence and enqueues Exit behind queued Output, while display teardown runs only when the viewport ends; neither explains a stable live settings-row shift.\n\nDeterministic regressions: (A) add a stateful ScreenGrid contract using captured/minimized settings-frame bytes: paint three rows containing two width-2 glyphs before `Tools`, `Where`, and `Escape`; issue the same absolute CUP + EL/ECH/overwrite operations the TUI uses; synthesize `render_repaint`; apply it and one subsequent raw frame to a width-aware reference emulator. Assert server/reference cell equality, no `To`/`Wh`/`Es`, and exact row columns. Also cover one width-2 glyph, two width-2 glyphs (the screenshot’s exact delta), combining marks, overwrite/erase/ICH/DCH, wrap at the final column, and resize. The test must compare cell geometry, not repaint strings. (B) add a PTY/attach DSR loop test: scripted child paints to a known non-`1;1` cursor and emits a chunk-split `ESC[6n`; a fake terminal frontend observes output and supplies the correct CPR. Assert the child receives exactly one accurate CPR, the query cannot be answered by both server and frontend, and ordinary bytes remain ordered. Run it through the production drain → broker Output → attach/rc-input seam; a lower unit can first pin query consumption/filtering across chunk boundaries. (C) separately feed the idle settle probe into a raw-mode fixture and assert readiness traffic is not surfaced as application keystrokes/text.",
  "files": [
    {
      "path": "crates/spt-term/src/screen.rs",
      "description": "Primary screenshot seam. `Cell` at lines 122–145 has only `{ ch, pen }`; `GridState::put_char` at lines 327–344 advances one column per Unicode scalar. EL/ECH/ICH/DCH at lines 380–438 operate on those incorrect cell indices. `render_repaint` at lines 577–642 clears first and re-emits the modeled rows, so it repaints model corruption rather than leaving old physical cells. `csi_dispatch` at lines 754–814 handles positioning/erase/modes but has no DSR `n` handling. Existing tests around lines 883–1080 cover DECSTBM, repaint, alt screen, resize, SGR, and cursor visibility, but no wide glyph, continuation cell, combining mark, or Unicode-width case."
    },
    {
      "path": "crates/spt-term/src/reader.rs",
      "description": "DSR responder seam. Constants at lines 31–36 define query `ESC[6n` and fixed reply `ESC[1;1R`. `Drain::spawn` at lines 118–143 scans output, writes fixed replies through the shared PTY writer, then forwards the original chunk unchanged to the sink. Unit `auto_answers_synthetic_dsr_query` at lines 236–262 explicitly proves both fixed reply and unchanged query forwarding, including the double-responder precondition. Chunk-split matching is covered at lines 186–198."
    },
    {
      "path": "crates/spt-term/tests/dsr.rs",
      "description": "Existing integration coverage lines 1–85 proves only that output flows/not withheld under a real PTY. It does not assert accurate cursor coordinates, suppression of a server-answered query, exactly one responder, or the rc frontend round trip."
    },
    {
      "path": "crates/spt/src/rc.rs",
      "description": "Frontend terminal boundary. `spawn_stdin_reader`/raw-byte reader at lines 1223–1267 forwards stdin without distinguishing terminal replies from human input; Windows interactive events at lines 1280–1334 are likewise translated into input bytes. `pump` drains those bytes into `send_attach_input` at lines 2238–2242, and writes `AttachRecord::Output` verbatim to physical stdout at lines 2275–2304. Thus a forwarded DSR can solicit a physical CPR that returns as child input. Status overlay is conclusively off on current main at lines 198–215 (`STATUS_ROW_ENABLED=false`); construction at lines 1550–1563 yields `None`. Resize polling at lines 2210–2230 uses terminal `(cols, rows)` and sends `(rows, cols)` with no horizontal adjustment. Display teardown/final prose ordering is at lines 1578–1600 and only runs after viewport completion."
    },
    {
      "path": "crates/spt-daemon/src/attach.rs",
      "description": "Wire input/output carrier. `AttachRecord::Input` at lines 469–493 decodes every controller input byte and sends it as an rc-minted PTY effect; there is no CPR classification. `AttachRecord::Resize` at lines 499–505 forwards controller dimensions. Broker Output and Exit become ordered attach records at lines 600–618."
    },
    {
      "path": "crates/spt-daemon/src/broker.rs",
      "description": "Broker render/PTY seams. `OutputLog::append` around lines 875–1010 fans raw live output to controller/viewers before `grid.advance(bytes)`, so ScreenGrid corruption affects synthesized cold repaints, not already-forwarded live frames. `repaint_initial`/`become_controller` around lines 849–1065 uses the grid for cold `from_seq==0`. `set_size_and_notify` lines 1440–1466 and `dispatch_resize` lines 4447–4475 resize ConPTY then the grid without any column subtraction. `INJECT_SETTLE_PROBE` lines 446–449 is `ESC[6n`; `settle_before_inject` lines 2386–2413 enqueues it directly into child input. Exit waiter lines 3965–4010 drains/quiesces output and enqueues Exit behind output, ruling the old final-output race out for current main."
    },
    {
      "path": "crates/spt-term/src/pty.rs",
      "description": "ConPTY/forkpty surface and shared-writer mechanics. `SharedWriter` lines 25–27 serializes direct DSR replies with other PTY writes; `write_input` lines 228–232 locks/writes/flushes; `resize` lines 234–242 holds the master lock. This prevents torn writes and reader/resize handle races but does not provide terminal-query ownership or correct CPR geometry."
    },
    {
      "path": "docs/KNOWN-HAZARDS.md",
      "description": "Hazard 5.5 at lines 200–204 requires ConPTY DSR auto-answer to avoid withheld output, but states fixed `1;1` or a real cursor position and does not address downstream forwarding/double response. Hazard 7.47 at lines 711–716 covers renderer ownership/final output/teardown, not Unicode cell width."
    },
    {
      "path": "docs/adr/0031-server-side-screen-grid-render-repaint.md",
      "description": "Governing ScreenGrid decision: server grid reconstructs current visible screen and cold attach receives synthesized repaint while live frames remain raw. This makes cell-width correctness part of the authoritative render model and explains why the wide-cell omission is at the exact cold-repaint seam."
    },
    {
      "path": "docs/adr/0043-terminal-render-lifecycle.md",
      "description": "Separates four prior lifecycle defects and establishes one renderer, FIFO Output-before-Exit, unconditional rc teardown, and complete tracked-mode replay. Current implementation reflects those decisions; none supplies Unicode-width semantics."
    },
    {
      "path": "docs/NEXT-MILESTONE-BUG-TRIAGE.md",
      "description": "Historical terminal RCA around lines 74–134 records legacy StatusRow artifacts and disables the marker, supporting the current-main overlay refutation. Those older marker defects were client-side absolute paint/scroll issues and are distinct from the new ScreenGrid width-model gap."
    }
  ],
  "architecture": "Terminal/output ownership is split into five layers. (1) The child writes VT bytes into a daemon-owned ConPTY/forkpty. (2) `spt-term::Drain` reads the PTY; today it also acts as an unconditional DSR responder, writing fixed CPR directly back to PTY input while preserving the query in output. (3) broker `OutputLog` sequences/retains/fans raw bytes and advances one authoritative `ScreenGrid`; cold attaches receive `ScreenGrid::render_repaint`, while existing live attaches receive raw bytes. (4) target `serve_attach` translates broker events to `AttachRecord`; operator rc writes Output to its real terminal and sends all stdin back as Input. No protocol ownership boundary distinguishes terminal-generated replies from human keystrokes. (5) the physical terminal emulator finally interprets live VT and may itself answer forwarded queries. Consequently, two independent invariants are missing: the authoritative grid must model terminal cells (including wide-glyph continuation and combining behavior), and exactly one terminal-query responder must own DSR with accurate geometry. The screenshot’s two-cell/prefix pattern lands at the first invariant; the current DSR route is a separate confirmed double-response/input-contamination seam."
}