# Composer list-marker proof matrix — pass 1

Scope: [#22997](https://github.com/pingdotgg/t3code/pull/22997), mirrored [#23000](https://git.cafe/pingdotgg/t3code/pulls/23000), branch `fix/issue-22989`, reviewed head [9c3c3acbc6](https://github.com/pingdotgg/t3code/commit/9c3c3acbc65b6cd756052c03ce9a41a905e40b90), merge base [680152e27b](https://github.com/pingdotgg/t3code/commit/680152e27b2a961686389ca69a1557cbb2c55f08). Diff: production helper plus focused tests; no React component changed. This is a source-derived capture specification, not an assertion that fixtures passed or captures exist.

## Capture contract and seeding

Every table row below depends on interaction or time: **recording is mandatory; stills are insufficient**. Record from seed through every intermediate prefix/caret state to final outcome. Parameter alternatives within a row share a visual class but each must appear as a labeled segment. Bullet glyph variants collapse only at the visual level; all five exact marker spellings still receive explicit input segments. Checked/unchecked, literal/rich, nested containers and styled markers remain separate rows.

Minimum for EACH row: four recordings, **1440×900 light, 1440×900 dark, 390×844 light, 390×844 dark**. Do not substitute a 390px crop of a desktop capture. One recording may contain several labeled rows, but all row × viewport × theme cells must be identifiable. Record both merge base and head for affected/regression rows when building before/after evidence; controls require head only. Theme changes themselves need no separate fixture. Keep focus, caret, checkbox and overflowing/wrapping text visible. Long-content segment uses `existing text — verify the marker gutter and caret while this line wraps on a narrow viewport`.

Seed only an isolated dev worktree .t3 via `vp run migrate-dev-db` with its server stopped; that command snapshots live data read-only. Use a stopped project/thread, remove draft text through the UI and enable Settings → composer rich text. Do not submit ordinary fixtures to a provider. Use real keyboard, clipboard, editor controls and thread/settings navigation; do not inject a hand-built ProseMirror document and call it app proof. `Shift+Enter` means the app's insert-newline gesture; verify configured send binding before using it. Typing a Markdown literal before returning to complete its marker deliberately bypasses the end-of-line input-rule path. Clipboard seeds use real plain-text clipboard, not `.insertText`. Save/restore is real thread switching or sandbox reload. No server/browser was launched in this matrix-only pass.

Path R = normal rich composer in both new thread and existing stopped thread; these share the editor/visual class and can occupy labeled segments in each recording. Web-hosted and Electron-hosted web use the same production editor; native mobile has a separate implementation and is outside this apps/web diff. Width 390 means responsive web, not native mobile. Repeat one representative M1/F1/H1/C1 smoke sequence in Electron for OS input/history integration when desktop proof is collected; no provider-specific matrix multiplier, since normalization is local client state and does not depend on provider or local/relay/tunnel transport.

Other actual production render paths: Q ordinary free-text pending answer; A approval decline/redirect; F plan feedback; PL rich setting off; LQ pending question with initialAnswer (literalText forces plain); TP/TI the two typography previews (richTextEnabled omitted); DIS disabled versions of ChatComposer. Q/A/F share rich extensions but have distinct surrounding controls and value swaps; V2–V4 capture those differences. Citation comments are inline node views, not a second list editor; A1 covers the containing editor. Settings/command palette/keybinding entry points into the same rich-text toggle belong to R1 rather than new normalization components.

Question/approval/plan/queued fixtures require genuine sandbox app states: use a disposable provider conversation to request the relevant question/approval/plan, or repository-supported isolated test fixtures. Do not fabricate these in live state. If no suitable provider/fixture exists, mark those cells blocked with the exact missing prerequisite; do not silently replace them with an empty normal composer. Stash/queue controls likewise require an actual available sandbox queue. IME requires a real host IME and preedit events; scripted transactions with composition metadata alone cannot satisfy C1.

## Fixture matrix

| ID | Named fixture | Render path | Affected | Evidence | Real-app seed / interaction | Required observation |
|---|---|---|---|---|---|---|
| M1 | - at empty caret | R | Yes | recording | Clear R; type `-` then Space then `existing text`, pausing at each stage. | Correct bullet/number gutter, no duplicate literal prefix; caret follows content. Dash-space may remain literal until content; star/plus/ordered input rules may convert at Space. |
| F1 | - before existing text | R | Yes | recording | Seed R with `existing text`; Home; type `-` then Space; insert `Z`. | Converts immediately with existing content; Z lands before existing text; marker spelling and caret preserved. |
| L1 | - completed later | R | Yes | recording | Type `-existing text`; add a second paragraph via Shift+Enter; return after marker on first line; insert Space; return to second line. | First line converts, second line survives, cursor stays where directed; serialized/rebuilt view agrees. |
| M2 | * at empty caret | R | Yes | recording | Clear R; type `*` then Space then `existing text`, pausing at each stage. | Correct bullet/number gutter, no duplicate literal prefix; caret follows content. Dash-space may remain literal until content; star/plus/ordered input rules may convert at Space. |
| F2 | * before existing text | R | Yes | recording | Seed R with `existing text`; Home; type `*` then Space; insert `Z`. | Converts immediately with existing content; Z lands before existing text; marker spelling and caret preserved. |
| L2 | * completed later | R | Yes | recording | Type `*existing text`; add a second paragraph via Shift+Enter; return after marker on first line; insert Space; return to second line. | First line converts, second line survives, cursor stays where directed; serialized/rebuilt view agrees. |
| M3 | + at empty caret | R | Yes | recording | Clear R; type `+` then Space then `existing text`, pausing at each stage. | Correct bullet/number gutter, no duplicate literal prefix; caret follows content. Dash-space may remain literal until content; star/plus/ordered input rules may convert at Space. |
| F3 | + before existing text | R | Yes | recording | Seed R with `existing text`; Home; type `+` then Space; insert `Z`. | Converts immediately with existing content; Z lands before existing text; marker spelling and caret preserved. |
| L3 | + completed later | R | Yes | recording | Type `+existing text`; add a second paragraph via Shift+Enter; return after marker on first line; insert Space; return to second line. | First line converts, second line survives, cursor stays where directed; serialized/rebuilt view agrees. |
| M4 | 1. at empty caret | R | Yes | recording | Clear R; type `1.` then Space then `existing text`, pausing at each stage. | Correct bullet/number gutter, no duplicate literal prefix; caret follows content. Dash-space may remain literal until content; star/plus/ordered input rules may convert at Space. |
| F4 | 1. before existing text | R | Yes | recording | Seed R with `existing text`; Home; type `1.` then Space; insert `Z`. | Converts immediately with existing content; Z lands before existing text; marker spelling and caret preserved. |
| L4 | 1. completed later | R | Yes | recording | Type `1.existing text`; add a second paragraph via Shift+Enter; return after marker on first line; insert Space; return to second line. | First line converts, second line survives, cursor stays where directed; serialized/rebuilt view agrees. |
| M5 | 1) at empty caret | R | Yes | recording | Clear R; type `1)` then Space then `existing text`, pausing at each stage. | Correct bullet/number gutter, no duplicate literal prefix; caret follows content. Dash-space may remain literal until content; star/plus/ordered input rules may convert at Space. |
| F5 | 1) before existing text | R | Yes | recording | Seed R with `existing text`; Home; type `1)` then Space; insert `Z`. | Converts immediately with existing content; Z lands before existing text; marker spelling and caret preserved. |
| L5 | 1) completed later | R | Yes | recording | Type `1)existing text`; add a second paragraph via Shift+Enter; return after marker on first line; insert Space; return to second line. | First line converts, second line survives, cursor stays where directed; serialized/rebuilt view agrees. |
| T1 | Task unchecked | R | Yes | recording | Clear R; type `- [ ]` character by character, pause, add Space then `task text`; click checkbox twice. | Incomplete gesture stays literal while active; completed gesture becomes matching checkbox; toggles and text/caret survive. Uppercase checked value may serialize canonically. |
| T1F | Task unchecked before text | R | Yes | recording | Seed `existing text`; Home; type `- [ ]` then Space. | Checkbox conversion at completion, existing text retained. |
| T2 | Task checked lowercase | R | Yes | recording | Clear R; type `- [x]` character by character, pause, add Space then `task text`; click checkbox twice. | Incomplete gesture stays literal while active; completed gesture becomes matching checkbox; toggles and text/caret survive. Uppercase checked value may serialize canonically. |
| T2F | Task checked lowercase before text | R | Yes | recording | Seed `existing text`; Home; type `- [x]` then Space. | Checkbox conversion at completion, existing text retained. |
| T3 | Task checked uppercase | R | Yes | recording | Clear R; type `- [X]` character by character, pause, add Space then `task text`; click checkbox twice. | Incomplete gesture stays literal while active; completed gesture becomes matching checkbox; toggles and text/caret survive. Uppercase checked value may serialize canonically. |
| T3F | Task checked uppercase before text | R | Yes | recording | Seed `existing text`; Home; type `- [X]` then Space. | Checkbox conversion at completion, existing text retained. |
| T4 | Incomplete task inactive | R | Yes | recording | Type `- [x]` with no final space; move caret to another paragraph using Shift+Enter or pointer. | Exercise inactive-task branch: recognized complete bracket gesture may normalize without content space once no longer active. |
| T5 | Dash pending fragments | R | Yes | recording | In separate resets type `- `, `- [`, `- [ `, `- [x`, `- [X`, `- [x]`; move within the same paragraph; then finish each valid gesture. | Each pending prefix stays editable without premature checkbox/bullet conversion; only completed gesture converts. |
| N1 | Literal a - b | R | Guard | recording | Clear R; type `a - b`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N2 | Literal -x | R | Guard | recording | Clear R; type `-x`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N3 | Literal - | R | Guard | recording | Clear R; type `-`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N4 | Literal * | R | Guard | recording | Clear R; type `*`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N5 | Literal + | R | Guard | recording | Clear R; type `+`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N6 | Literal 1. | R | Guard | recording | Clear R; type `1.`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| N7 | Literal 1) | R | Guard | recording | Clear R; type `1)`; move caret within paragraph; add and remove a non-space trailing character. | Remains paragraph until a valid separated prefix exists; no loss or unsolicited list. |
| B1 | Bracket content [link](url) | R | Yes | recording | Type `[link](url)` in R; Home; type dash then Space. | Bullet with full bracket-prefixed content; not mistaken for unfinished task; existing inline rendering preserved. |
| B2 | Bracket content [ordinary text] | R | Yes | recording | Type `[ordinary text]` in R; Home; type dash then Space. | Bullet with full bracket-prefixed content; not mistaken for unfinished task; existing inline rendering preserved. |
| B3 | Bracket content [x]text | R | Yes | recording | Type `[x]text` in R; Home; type dash then Space. | Bullet with full bracket-prefixed content; not mistaken for unfinished task; existing inline rendering preserved. |
| W1 | Whitespace and indentation | R | Guard | recording | In separate R resets: type two leading spaces then `- x`; repeat leading Tab, `1. x`, task prefix; separately insert two spaces or a tab between unindented marker and content. | Indented paragraphs excluded by normalizer; nonempty separator metadata preserved for unindented conversion. Input-rule/Tab interception is recorded, not assumed. |
| O1 | Ordered starts and wide gutter | R | Yes | recording | In separate resets prefix existing text with `0. `, `3) `, `4. `, `123456789. `, `1234567890) `. | Non-one starts and delimiter preserved; zero uses list start fallback 1 internally while item marker remains 0.; gutter stays aligned and wraps without clipping; overlong parser acceptance documented. |
| E1 | Empty pending dash leaves paragraph | R | Yes | recording | Type `- ` in R; Shift+Enter to another paragraph; click back and type text. | Inactive pending dash normalizes; empty list/caret and trailing paragraph remain usable. |
| P1 | Clipboard marker only | R | Yes | recording | For each of `- `, `* `, `+ `, `1. `, `1) `, `- [ ] `, `- [x] `: seed existing text, Home, paste exact plain text via real clipboard. | Immediate correct list, text and caret retained; no extra keystroke needed. Record actual clipboard path; direct transaction test is insufficient. |
| P2 | Clipboard multiline and replacement | R | Yes | recording | Seed two ordinary paragraphs; select part across both; paste mixed bullet, ordered and task lines plus trailing blank; undo/redo. | Multiple changed paragraphs convert in document order without offset drift, selection loss, duplicate wrappers or deleted neighbors. |
| H1 | Undo conversion and redo | R | Yes | recording | Seed existing text; Home; paste `- `; undo then redo using platform shortcuts. | One insertion/conversion history operation returns exact original paragraph; redo restores list. |
| H2 | Undo literal restoration remains literal | R | Yes | recording | Type `- `; create separate undo group by blur/refocus or sufficient normal history pause; type `text`; undo; click/start-arrow in same paragraph. | Undo restores literal dash-space; selection-only transaction does not reconvert; record timing/grouping used. |
| C1 | IME composition deferral | R | Yes | recording | Activate real Japanese IME in R; produce a literal `- ` prefix with composition text, update provisional 日本語, replace with 確定, commit; move caret; undo/redo. | No structural change during active composition; next noncomposition transaction normalizes; committed text/caret and undo/redo preserved. Show composing candidate/preedit phase. |
| C2 | Composition pending positions map | R | Yes | recording | Prepare pending first-line dash gesture; during composition edit a later paragraph and insert/delete a preceding block; commit then move selection. | Pending positions remap or discard deleted blocks; no conversion of wrong paragraph, stale position errors or composition interruption. |
| D1 | Unchanged paragraph isolation | R | Guard | recording | Create a styled literal `- untouched` first paragraph; second paragraph ordinary text; edit only second paragraph and move selection. | Unchanged first paragraph remains literal; selection-only no-pending transaction causes no work. |
| D2 | Multiple changed top-level blocks | R | Yes | recording | Seed three ordinary paragraphs; select all and paste mixed lists, then edit first and last list content; delete middle block; undo/redo. | Descending wrapping and position mapping keep all items, separators, selection and metadata correct. |
| S1 | Styled marker bold | R | Guard | recording | Paste `**- x**` into R; switch thread away/back to rebuild; edit content (for inline code insert Space after dash). | Marker with any mark remains paragraph/inline code; style survives restoration and subsequent edit. |
| S2 | Styled marker italic marker | R | Guard | recording | Paste `*-* x` into R; switch thread away/back to rebuild; edit content (for inline code insert Space after dash). | Marker with any mark remains paragraph/inline code; style survives restoration and subsequent edit. |
| S3 | Styled marker strike | R | Guard | recording | Paste `~~- x~~` into R; switch thread away/back to rebuild; edit content (for inline code insert Space after dash). | Marker with any mark remains paragraph/inline code; style survives restoration and subsequent edit. |
| S4 | Styled marker styled number | R | Guard | recording | Paste `a ⏎ **1.** b` into R; switch thread away/back to rebuild; edit content (for inline code insert Space after dash). | Marker with any mark remains paragraph/inline code; style survives restoration and subsequent edit. |
| S5 | Styled marker inline code | R | Guard | recording | Paste ``-text`` into R; switch thread away/back to rebuild; edit content (for inline code insert Space after dash). | Marker with any mark remains paragraph/inline code; style survives restoration and subsequent edit. |
| S6 | Styled content, unstyled marker | R | Yes | recording | Paste `**text**` into R; move Home; ensure bold is off for new prefix; type `- `; continue typing, undo/redo. | List conversion preserves bold content and caret at intended content boundary; no accidental marker styling. |
| G1 | Excluded container fenced code | R | Guard | recording | Paste ```` ⏎ code ⏎ ```` into R; put caret before innermost text; insert `- ` then edit and undo. | No normalization wrapping inside code/list/task/quote or nonparagraph heading; existing container remains. |
| G2 | Excluded container nested list | R | Guard | recording | Paste `- outer ⏎   - inner` into R; put caret before innermost text; insert `- ` then edit and undo. | No normalization wrapping inside code/list/task/quote or nonparagraph heading; existing container remains. |
| G3 | Excluded container blockquote | R | Guard | recording | Paste `> quoted` into R; put caret before innermost text; insert `- ` then edit and undo. | No normalization wrapping inside code/list/task/quote or nonparagraph heading; existing container remains. |
| G4 | Excluded container task item | R | Guard | recording | Paste `- [ ] task` into R; put caret before innermost text; insert `- ` then edit and undo. | No normalization wrapping inside code/list/task/quote or nonparagraph heading; existing container remains. |
| G5 | Excluded container heading | R | Guard | recording | Paste `# heading` into R; put caret before innermost text; insert `- ` then edit and undo. | No normalization wrapping inside code/list/task/quote or nonparagraph heading; existing container remains. |
| A1 | Inline atoms and wrapping | R | Yes | recording | Add real @file, enabled $skill and citation/context chip through composer menus; insert `- ` before each in separate resets; use a long wrapping text tail. | Atoms, references and formatting survive prefix deletion; caret and narrow-width gutter align; no replacement-character leakage. |
| I1 | List editing reverse operations | R | Regression | recording | Create bullet, ordered and task items; Shift+Enter to continue and exit empty item; Backspace at item start; Delete at previous item end; Tab/Shift+Tab; select across items; cut/paste and undo. | Existing continuation/join/removal rules remain consistent; disabled nesting chords do not silently nest; no reconversion loop. |
| I2 | Task-to-bullet gesture | R | Regression | recording | Create bullet with ordinary text; insert `[ ] ` at item start; toggle checkbox then remove task prefix with normal editing. | Existing task input rules and new normalizer cooperate without duplicate lists or dropped text. |
| R1 | Rich/plain remount and restore | R | Yes | recording | Create mixed bullet/ordered/task draft with caret inside content; toggle composer rich text off/on; switch thread away/back; reload sandbox. | Literal Markdown and rich lists round-trip, cursor maps correctly and drafts retain source; no changed-block normalization of styled markers on restore. |
| R2 | Queued/edit/recalled draft | R | Regression | recording | In isolated stopped thread create a mixed list draft; use available stash/restore, edit queued message or recall last message flow; edit earlier marker. | Controlled value rebuild and draftKey remount retain content and list semantics. Seed queued/history state only in sandbox. |
| V1 | Resting-to-expanded composer | R | Regression | recording | In thread with normal resting composer focus and type dash gesture; grow into multiline long list, blur/refocus and collapse/expand where offered. | Resting max-height/overflow transitions reveal full list and caret; no clipped markers or unexpected collapse. |
| V2 | Rich contextual Q | Q | Yes | recording | In sandbox request an ordinary free-text question (no initialAnswer); seed custom answer with existing text; prefix `- `; switch question and back. | Correct rich list and context controls remain visible; controlled value switch does not leak prior prompt or lose answer. |
| V3 | Rich contextual A | A | Yes | recording | In sandbox trigger a pending approval; focus decline/redirect editor; seed existing text then prefix `1) `. | Correct rich list and context controls remain visible; controlled value switch does not leak prior prompt or lose answer. |
| V4 | Rich contextual F | F | Yes | recording | In sandbox finish a plan to show follow-up feedback; prefix existing feedback with `- [ ] `. | Correct rich list and context controls remain visible; controlled value switch does not leak prior prompt or lose answer. |
| V5 | Plain composer control | PL | No—control | recording | Turn rich text off in Settings; seed existing text, prefix `- `; repeat ordered/task, paste, undo, switch thread. | Markers remain literal; plugin absent. |
| V6 | Literal question control | LQ | No—control | recording | In sandbox issue question with initialAnswer set to literal `- existing text`; keep rich setting on; edit prefix, compose and undo; return to normal prompt. | Answer remains literal; remount back to normal prompt restores rich behavior without answer contamination. |
| V7 | Prompt typography preview | TP | No—control | recording | Open Settings → typography prompt font preview; replace sample with marker/list text; paste and undo. | Preview remains plain (richTextEnabled omitted); font/layout stays usable. |
| V8 | Interface typography preview | TI | No—control | recording | Open Settings → typography interface font preview (Advanced as needed); replace sample with dash/task/ordered text; edit and undo. | Separate preview instance remains plain; correct preview font/layout. |
| V9 | Disabled editor states | DIS | No—control | recording | In sandbox visit project-unselected, connecting, choice-only question, and responding-question states; attempt input; return to editable state. | Disabled editor cannot mutate; re-enable preserves draft/list and caret. Distinct banners are separate labeled segments. |
| K1 | Existing block chords | R | Regression | recording | In rich quote/list/task fixtures press platform Mod-Shift-8/7/9/b and Mod-Alt-c/1/3; Tab/Shift+Tab on nested lists. | Existing shortcut suppression remains; no surprising block/nesting conversion. |

Minimum head capture grid: **70 rows × 4 viewport/theme combinations = 280 row-cells**, each recording. Labeled segments can share video files. Source text alternatives explicitly listed inside a row are all required, not pick-one suggestions. Before/after doubles affected/regression/guard cells, not the unaffected controls.

## Branch coverage ledger

- History transaction → pending cleared/no normalization: H1, H2, C1. No doc change and no pending → return: N1–N7, D1. Pending plus selection-only flush → L1–L5, T4, E1, C1.
- Changed-range collection, only top-level paragraphs, pending mapping/deletion and reverse-order conversion: D1/D2, C2, P2. Existing list/task/quote/code/heading excluded: G1–G5. Deleting a pending block exercises missing/deleted pending position; no extra standalone visual row is needed.
- Browser `view.composing` OR transaction composition metadata: C1 needs real browser composition; metadata path is covered by source tests but is not browser proof. C2 covers accumulation/remap during deferral.
- No prefix, no marker separator, leading indentation: N1–N7, W1. Active versus inactive paragraph: T4/T5/E1. Dash empty/incomplete bracket regex, task missing content space: M1/T1–T5. Non-dash empty marker input-rule differences: M2–M5. Recognized task without content-space but with following text falls back to bullet grammar: B3; `- [x]text` must remain bullet content rather than checkbox.
- Any mark touching prefix blocks conversion: S1–S5; marks only on content survive: S6. Atom-safe `textBetween` placeholder and caret mapping: A1.
- Task/bullet/ordered list dispatch, checked and spacing metadata, start integer fallback: M/F/L groups, T1–T3, W1/O1. Prefix removal/wrapping/caret: F1–F5/S6. Return changed transaction vs no-op: all positive versus guard rows.
- Missing list node schema and `!range || !wrapping` are defensive guards, not independently reachable app fixtures: production rich extension set installs all list nodes and permits top-level paragraph wrapping. Do not fabricate unsupported schemas for screenshots. `depth !== 0` and nonparagraph stale pending checks are guarded internally; C2/G rows cover observable deletion/container consequences.
- App clipboard parser versus test direct insertion: P1/P2. Controlled setContent restoration and rich/plain keyed remount: R1/R2, S rows, V2–V6. List continuation/deletion/checkbox/selection/paste/history interactions: I1/I2, T rows, H rows, K1.

## Source anchors

- [normalizer and list-prefix grammar](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/composer-rich-text-doc.ts#L450)
- [production extension selection and input rules](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/components/ComposerPromptEditorTiptap.tsx#L834)
- [real clipboard handler](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/components/ComposerPromptEditorTiptap.tsx#L1387)
- [chat render paths and mode props](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/components/chat/ChatComposer.tsx#L6134)
- [plain typography preview](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/components/settings/SettingsFontPreviews.tsx#L24), [both typography placements](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/components/settings/TypographySettings.tsx#L111)
- [added headless regression tests](https://github.com/pingdotgg/t3code/blob/9c3c3acbc65b6cd756052c03ce9a41a905e40b90/apps/web/src/composer-block-shortcuts.test.ts#L106)

## FRICTION

- Matrix-only pass: no browser/computer use, server, test suite or visual captures run. Outcomes above are acceptance criteria, not observed passes. No forge comments/posts, edits, pushes or watchers.
- Checkout HEAD matched requested full SHA; working tree clean at inspection; disk had 7.5 GB free, above 2 GB stop threshold. Artifacts live outside worktree. No processes were started that need stopping.
- Headless tests explicitly install plugins and dispatch transactions; they do not prove browser input rules, real paste, composition lifecycle, history grouping, responsive layout or contextual render paths. IME and app pending-state seeds need the prerequisites stated above.
