# Proof audit pass 1 reassessment — mobile chip contrast

Target [#22585](https://git.cafe/pingdotgg/t3code/pulls/22585), [GitHub mirror #22585](https://github.com/pingdotgg/t3code/pull/22585). Read-only code inspection exclusively in `/home/ubuntu/wt/pr-22585`, branch `takeover/pr-22585`. Report written outside the worktree; no captures, source edits, forge comments, pushes, rebases or merges.

Inspected head [02b0a6d7f0](https://git.cafe/pingdotgg/t3code/commit/02b0a6d7f079caef48562d93f4fa50e9292e0160), required baseline [a93b03c8a5](https://git.cafe/pingdotgg/t3code/commit/a93b03c8a5a888cfa7fac1fd6cb7a814221adf72). Working fixture changes were also read, but are NOT part of that head: `ChipEvidenceApp.tsx`, `fixtures.ts`, and untracked `CallerFixtures.tsx`. Their coverage below is provisional. No delivered captures assessed. This is a pre-capture plan, not permission to land.

## Findings first

1. Keep **29 iOS coverage rows**, plus the explicit Android-unverified row. No entire row can presently be removed. E2/G3 admit conditional component-level equivalences below, not an unconditional screen-level collapse. Android Material You is expected UNVERIFIED and is not an iOS acceptance requirement. A frozen-palette harness is only supplemental.
2. **E2 lacks real surroundings and repository context.** Current E2 mounts actual `PullRequestMarkdown` in a padded ScrollView, but on `--color-thread-canvas`, whereas discussion uses `bg-screen`; guide attention uses `bg-grouped-card`; notes reduce available width. It has no `PullRequestMarkdownRepository`. Shared component identity proves the color computation is the same for identical inputs, not that these pixels or readability on each surface are the same. Capture at least the distinct surface/width/clip classes detailed below. No need to launch each network-backed screen if a labelled production-component fixture reproduces its actual wrappers/context.
3. **G3 actual sizes and opacity matter.** Actual callers use 15 (pending-task and thread rows), 18 (archive), 20 (palette and regular new-task choice), 24 (grouped new-task choice), and 48 points (Settings). The current G1 grid is 20/42; 42 is the default, not an observed caller here. One thread row wraps the icon in `opacity-40`. Monogram backgrounds are `/15` alpha, so equal icon props on different parent backgrounds do NOT yield equal composited pixels. G3-home currently seeds no pending tasks and does not establish pending-task or dimmed-row coverage. Settings is absent. Capture actual sizes and representative distinct parent backgrounds/opacity, or explicitly limit the claim to intrinsic component output.
4. **W2 remains actual accessibility scaling.** `fontSize=22` calls app `setBaseFontSize(22)`. This is valuable but must be called W2-font22, supplemental; it does not set or demonstrate OS accessibility scale. W2-a11y needs the actual recorded native font scale and chat/composer outcome. If those native renderers deliberately ignore scaling, demonstrate that with actual OS scale and report it, rather than treating 22 points as equivalent.
5. **In-progress fixtures are incomplete.** At inspection, `SCENES` has no T5/G2/K2 scenes, T4 only has missing lookup, and all T1–T4 scenes resolve to user role. `P3-streaming` also resolves to user role (only names containing `assistant` or starting `A1` choose assistant). Thus it does not prove assistant streaming. C2 has new-task draft pages, but not the collapsed/expanded thread-composer pair. VoiceInputProvider is present only in the working edit, not inspected committed head. These may be fixed by the capturer; require final committed manifest and recheck, not assurances.
6. **Snapshot provenance needs tightening before capture.** Snapshot script copies working fixture files yet labels them with `git rev-parse HEAD`; a dirty overlay is not reproducible from that SHA. Commit the completed fixture before building, record separate sourceSha and fixtureSha (and ideally overlay hashes), and use the identical overlay on baseline/head. The baseline no-op rasterizer adapter must be disclosed; it is not itself a contrast change. A final head different from this report needs updated metadata and diff review.
7. **Additional E2 callers were missing from original inventory:** PR description expanded/clipped+fade, timeline review comment expanded/clipped+fade, guide outline summary, guide excerpt caption. These all transit the changed hook. Empty/loading screens without markdown need no separate affected capture. Group their visible markdown by proven equivalence, not by feature names.
8. **Attribution:** baseline-to-head includes lower-layer icon/monogram/palette work. To assert contrast leaves project imagery unchanged, use a same-main lower-layer-only control (equivalent source with only contrast delta absent), not main-before imagery. Comparing the inherited `ProjectFavicon.tsx`, `projectIcon.ts`, `ProjectChipIconImages.tsx`, `CommandPalette.tsx`, and `commandPaletteItems.ts` against lower tip [fd101156b0](https://git.cafe/pingdotgg/t3code/commit/fd101156b0fbd6897f982b2a76e4940f2a944e29) produced no diff. This establishes source preservation for those files, not native screenshot equality.

## Equivalence rulings and mandatory coverage

**E2:** `PullRequestMarkdown` owns its native text style via `useMarkdownPreviewStyles`; caller Text styles do not become its native style. It accepts only markdown and imageGroupMarkdown; RepositoryContext rewrites relative GitHub links, and media context changes assets. Therefore discussion body, guide summary/questions, outline summary and excerpt caption can share one production-component representative only when markdown after rewriting, typography, font scale, resolved theme, effective width, background and clip state match. Guide notes have narrower flex width; attention/timeline use grouped-card backgrounds; PR description/timeline have clipped fade states. These are distinct. Minimum E2 subfixtures in B: (a) screen surface/full-width markdown, (b) grouped-card/inset markdown, (c) narrow note-width markdown with a long wrapping chip, (d) description and timeline clipping/fade using their actual wrappers. Expanded states can share (a)/(b) if their computed inputs match; clipped states cannot. Use both repository-aware links and absolute file/context links. One actual `PullRequestMarkdown` fixture with correct wrappers can establish those classes; a naked component on thread-canvas cannot establish all callers. Underlying excerpt diff loading does not affect caption colors and need not multiply this contrast matrix.

**G3:** For equal props, equal atom/resource snapshot/cache lifecycle, equal resolved Uniwind theme/fonts/DPR/scale, equal size, parent constraints, background and effective opacity, actual `ProjectFavicon` rendering is equivalent regardless of which screen owns it. A labelled real-app static fixture CAN establish that component equivalence. This is appropriate for unchanged icon/monogram rendering under this contrast-only takeover; separate complete screens are not inherently required. But the fixture must reproduce actual wrappers or document the restricted intrinsic-icon claim. Enumerate sizes 15/18/20/24/48, normal and 0.4 opacity, selected palette and normal card/screen/sidebar surroundings where their resolved backgrounds differ. G1 supplies all palette colors; G2 supplies state transitions; G3 need not cross every glyph color with every caller. Pick a representative loaded favicon, emoji and one/two-glyph monogram per genuinely distinct size/compositing class, sharing named pages with G1/G2/K1 where visible. A 20-point isolated render does not stand in for 48-point Settings or 15-point dimmed thread rows. The two 15-point pending/thread row uses may share a representative when wrappers and state match. New-task 20 and 24 remain separate. Do not demand screenshots of identical route-name variants after these conditions are proven in the manifest.

**G2 internal states:** absent URL, recognized placeholder URL, pending remote URL and failed URL can share the same *visible fallback* representative for identical title/size/theme, because `showImage` is false and `projectAutoMonogram` selects identical JSX. Their state/transition coverage is still mandatory: record deterministic setup and tests/events proving each source reaches that state. Loaded-image output is separate; revision-change must show fallback→new-image and no stale image. Blank title folder is separate. A static fallback screenshot cannot prove a load/revision transition occurred.

**No other theme reduction approved:** T remains 12 states (six built-in themes × LIGHT/DARK) for U1/A1/C1/P1; B is t3-code LIGHT/DARK for other rows. A color helper's identical output does not prove identical surface readability across themes. Distinct branch, native image tinting, smaller detail, role, theme invalidation and width observations remain mandatory. Reuse one delivered image across rows only with exact visible subcase mapping; no offscreen cases count.

## Scope and comparison contract

Takeover scope remains six original contrast files from [cd01fe744b](https://git.cafe/pingdotgg/t3code/commit/cd01fe744b05d2ef076043b02c623b17089405a3) and [09de6c7063](https://git.cafe/pingdotgg/t3code/commit/09de6c7063067f48cd6da674a74af50a74efd255), with shared-helper replacement. Lower layers [#22237](https://git.cafe/pingdotgg/t3code/pulls/22237), [#22243](https://git.cafe/pingdotgg/t3code/pulls/22243), [#22481](https://git.cafe/pingdotgg/t3code/pulls/22481) are preserved scope, not new contrast work. Upstream main merge changes are excluded from review scope.

The changed color path maps chip label/detail and tintable icon accents when foreground luminance is <0.18, aiming for 6.2:1 against white. Light/unparseable foreground and unparseable accent retain input; already compliant accents retain input. Saturated Material You bubbles with light text must retain original accents. Enriched file/mention and project imagery are untinted; composer thread still uses its generic icon. No layout or provider/wire change is part of contrast itself.

Use real production components in the offline native fixture, labelled as a fixture, not a claim of network-backed navigation. Route is `t3code-preview://chip-fixture?scene=<scene>&theme=<id>&appearance=<light|dark>`; record exact scene/page manifest and all state transitions. Existing fixture is a starting point, not full coverage. Use deterministic resources for loading/error states rather than timing races. Real native Material You cannot be established on iOS; any injected native Android palette is labelled supplemental.

Viewport P=390×844 logical points portrait, W=844×390 landscape, unless actual device differs and is declared/reassessed. Record device/OS/build/source+fixture SHAs, DPR, fonts, OS font scale, app base font size, theme variables, safe area/keyboard/scroll offset. Before=a93b03c8a5a888cfa7fac1fd6cb7a814221adf72; after=final committed head, currently 02b0a6d7f079caef48562d93f4fa50e9292e0160. Same overlay/render environment both sides. Each pair needs amplified zero-threshold diff and separately N=8/255 channel-delta diff with exact algorithm; inventory every visible difference. For lower-layer-only rows, distinguish inherited baseline differences from contrast preservation with the lower-layer control. Pass 2 must rebuild one affected capture from committed fixture and compare pixels.

## Row matrix

A=contrast affected; I=inherited; C=control. PLANNED means coverage required, not rendered/accepted. GAP means the inspected fixture does not yet represent every required subcase. M1/Z1 are expected platform limitations rather than required iOS native captures. Rows not flagged GAP still require a final manifest/visibility check.

| ID | Named fixture / exact data distinctions | Ownership and expected observation to inspect | Seed / full app surface | Minimum viewport × theme | Status |
|---|---|---|---|---|---|
| U1 | User context atlas: image, video, file, mention, terminal, element, preview-annotation, review-comment, skill, thread; short labels next to prose | A labels + tintable symbols; file/mention imagery C | Thread message with valid context references + records; skill registry | P × T | PLANNED |
| A1 | Assistant enriched atlas: context links for each U1 kind without record list, recognized currency-prefixed skill, explicit and auto-recognized file path | A; no-record context has kind default, no size; file imagery C | Assistant message and skills | P × T | PLANNED |
| C1 | Composer atlas: all U1 kinds plus raw mention and skill tokens; empty/plain text control | A; label/detail and symbols, file icons C; generic thread icon, not project icon | ThreadComposer expanded with seeded draft; page chips as needed | P × T | PLANNED |
| P1 | PR state atlas: open non-draft, open draft, merged, closed, missing/unknown state | A; green/gray/purple/red/default-indigo text and symbols | User context + draft context; same five states in both surfaces | P × T | PLANNED |
| P2 | Review-comment `sectionId:pull-request:...` with all P1 states, ordinary review-comment beside it | A; section prefix selects PR presentation, ordinary stays comment | User message + draft | P × B | PLANNED |
| P3 | Raw GitHub PR URL, GitCafe PR URL, unrelated external URL, ordinary Markdown label; duplicate URL with two different labels | C external link appearance; preserve contributor/agent label | User and assistant messages; assistant partial/streaming then settled | P × B | GAP |
| F1 | File atlas: `.tsx` known icon, unknown extension fallback, file with image MIME, file with video MIME, extension-detected image/video, nonmedia MIME control | A kind/color branch; untinted file imagery C | User + assistant + composer; local bundled attachment payloads | P × B | PLANNED |
| F2 | Image/file size absent, zero, normal, large formatted size; same records with short and very long labels | A detail text (composer smaller detail; enriched appended label) | User + composer, fixed content | P × B | PLANNED |
| N1 | Missing record with valid context href; unknown context kind; no records supplied versus supplied empty list; unknown accent and accent absent | Missing user record no accent/circle-dashed; assistant no-list kind default; composer missing record retains kind color with unavailable suffix. Pure custom accents (already high contrast, low contrast, and unparseable) = harness supplemental | User + assistant + composer; inject custom props only in labelled supplement | P × B | PLANNED |
| M1 | Actual Android Material You saturated user bubble with white foreground and canvas/composer palette | Native Android remains UNVERIFIED, expected; frozen palette harness supplemental only, not iOS requirement | iOS cannot provide actual Android Material You; no Android capture required | None native under this iOS scope; supplemental P × frozen LIGHT/DARK if provided | UNVERIFIED |
| E1 | Markdown preview containing file link, known skill if caller provides skills, context link without records, external control | A hook; use real caller props, do not add unsupported skills | Open bundled markdown in FileMarkdownPreview | P × B | PLANNED |
| E2 | PR markdown equivalence classes: screen/full-width; grouped-card/inset; narrow note-width; description/timeline clipped+fade. Include discussion, guide summary/attention/notes/questions, outline, excerpt captions, description and timeline mapping. | A hook. Collapse only identical effective inputs/wrappers per rulings above; current bare fixture insufficient. | Actual PullRequestMarkdown with repository/media contexts and production caller wrappers; labelled static fixture acceptable | P × B per distinct compositing/width/clip class | GAP |
| E3 | Pending question text containing file/context links, expanded and collapsed card; normal choices visible | A when text visible; collapsed shell C | Thread pending-input card with static request | P × B, both layouts | PLANNED |
| E4 | Nonempty review body containing file/context links; empty body control; user prose before/after review segment | A hook in body and surrounding prose; empty no markdown | ReviewCommentCard within user message, valid comment/diff shape | P × B | PLANNED |
| C2 | New task draft atlas with same C1/P1 tokens; thread composer collapsed one-line versus expanded | A both entry points; collapsed truncation/inert tap control | NewTaskDraftScreen + ThreadComposer states | P × B, each screen/layout | GAP |
| W1 | One long chip wider than line; many chips wrapping; short chip next to plain text; long file suffix; no tokens | A color, layout C; mid truncation and measured-width repaint | Thread chat + expanded composer; same token text at both widths | P and W × B | PLANNED |
| W2 | W2-a11y actual native accessibility scale with long chips in chat/composer; separately W2-font22 app base font size supplement | A text; C clipping/layout. 22-point app font is not OS scale evidence. | Record actual OS font scale and app base size; native fixture chat/composer | P × B at actual stated OS scale; 22pt supplement separately | GAP |
| T1 | Linked thread with loaded bundled project favicon | A thread text; I favicon; imagery C against lower-layer control | User context thread + user raw thread link + assistant raw thread link; real shell/project atoms | P × B | GAP |
| T2 | Same three thread paths with emoji override (multi-codepoint), explicit monogram one glyph and two glyphs, lucide override mapped to monogram | A text; I imagery; untinted project glyph C | Project overrides + rasterizer mounted through AppContent | P × B | GAP |
| T3 | Automatic monogram with no favicon URL, generated placeholder URL, nonblank title; punctuation-only and digit-containing title cases | A text; I glyph fallback/derived palette | Thread project mocks; bundled placeholder recognized by shared helper | P × B | GAP |
| T4 | Missing thread/project; scratch project; blank project title/no icon; remote icon not yet ready and rasterizer rejection | A thread text; I generic symbol fallback; no invented error chip | Seed lookup misses/scratch roots; deterministic deferred/failed glyph mocks | P × B | GAP |
| T5 | Cross-environment context record plus alias-resolved raw thread link, project icon differing from current environment; rename label refresh | I lookup; A resulting text; verify correct project, no stale label | Two static environments, shell/ref alias maps, update snapshot deterministically | P × B, before/after snapshot states | GAP |
| G1 | ProjectFavicon override emoji, one/two-glyph monogram, lucide monogram; glyph palette all 18 colors | I only; contrast must not recolor project glyphs | Palette projects and thread-list project rows; pack colors across pages | P × B | PLANNED |
| G2 | Loaded favicon; absent URL; placeholder URL; pending load; error; changed favicon revision; whitespace title fallback folder | I only; auto monogram while image unavailable, image after load; blank folder | ProjectFavicon state mocks via actual callers, deterministic image callbacks | P × B, each distinct visible stage | GAP |
| G3 | Actual caller classes: 15pt pending/thread and 0.4-opacity thread; 18pt archive; 20pt palette/regular new-task; 24pt grouped new-task; 48pt Settings. Representative favicon/emoji/one+two-glyph mono. | I shared component; C contrast preservation. Group only matching size/theme/background/opacity/constraints/state; do not cross every G1 color with every caller. | Actual ProjectFavicon in real caller or faithful production wrapper in labelled native fixture; shared G1/G2/K1 pages allowed | P × B per distinct size/compositing class | GAP |
| K1 | Palette project row selected/unselected with loaded favicon, emoji, auto monogram, explicit mono, lucide fallback | I only; original glyph colors under selection | Open command palette and select each project; static project items | P × B, selected and unselected visible | PLANNED |
| K2 | Palette long title/detail, no detail, thread search excerpt, thread/action symbol; indices 8 and 9 (digit vs none), empty filtered results | I project plumbing, C unrelated symbols/text/empty; selection foreground | Palette query + selected index + static items; avoid fake project on thread row | P × B, each distinct row state | GAP |
| X1 | Theme switch with unchanged draft value/context; repeated identical URL assets; initially no document assets then settled | A memo invalidation and delayed enriched variants; no stale LIGHT accent on DARK | Static scene state switch after native ready signal, then settle | P, LIGHT→DARK→LIGHT, t3-code; frozen M only as labelled supplement | GAP |
| X2 | Select chip, native copy/context menu, tap mention/file/thread/context; collapsed composer inert tap expands | C interactions unchanged; include selected readable text/image | Seed U1/T1/C1 then use normal native UI, local navigation targets | P × B; labelled capture sequence | GAP |
| Z1 | Android generic native composer + enriched rendering | Implementation changed; no iOS evidence may be claimed for Android | Not run under this authorization | None; explicitly unverified | UNVERIFIED |

## Exact checks and limits

- Ran `./node_modules/.bin/vp test run apps/mobile/src/lib/composerChipPresentation.test.ts apps/mobile/src/lib/enrichedLinkPresentation.test.ts apps/mobile/src/lib/projectIcon.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/nativeComposerTheme.test.ts apps/mobile/src/features/chip-evidence/fixtures.test.ts` in the requested worktree: **6 test files passed, 38 tests passed, 0 failed**, duration 2.98s. Five presentation/theme files account for 37 tests; fixture contract validation accounts for one. This does not prove fixture completeness, screen mount success, native tint/rendering, or accessibility behavior.
- `git diff --check`: exit 0, no output, including working edits at check time.
- Read actual contrast hunks and ProjectFavicon/PR markdown callers, current fixture sources, snapshot script and README. No forge state read through GitHub or gh. No browser, simulator, native build, lint or typecheck run by this auditor. Worktree remained untouched by this auditor.
- Prior matrix's historical 37-test count is not this run's count. The current run includes the additional fixture test.

Pass-1 matrix derivation is complete. Current committed/working fixtures do not yet satisfy that plan. Pass 2 must assess final delivered evidence and updated committed fixture independently; no readability or pixel-preservation claim is accepted here.

VERDICT: INSUFFICIENT E2 G2 G3 W2 P3 C2 T1 T2 T3 T4 T5 K2 X1 X2 (pre-capture fixture coverage; no delivered evidence assessed)
