# Proof audit, pass 1 — [#27671](https://git.cafe/pingdotgg/t3code/pull/27671)

Client request: `lead-27671-r1-audit1-1`. Read-only review of `/home/ubuntu/wt/pr-27671`.
Reviewed head [4b65d930a7](https://git.cafe/pingdotgg/t3code/commit/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25), branch `fix/issue-27622`, against merge-base [616c426f5f](https://git.cafe/pingdotgg/t3code/commit/616c426f5f199865e34974777740dff678ffb7f5) on `main`.
GitCafe metadata independently matched head and target. Complete diff: five mobile files, twelve insertions; four prop additions and one platform constant. No captures were made or accepted in this pass. Historical PR images/scripts are references only and are not evidence for these exact revisions.

## Findings

1. **Proof pending, not a confirmed code defect:** every affected momentum row lacks before/after recordings at the audited revisions. A still or initial-frame pixel diff cannot demonstrate a change after finger release.
2. The historical six row names cover the core four WebViews but omit the both-axis inline state (H4), linked-PDF container/return (P2), and full browser PDF overlay (P3). Include them in the minimum set. The floating PDF view (P4) is a separate render path but blocks user touches; it is not a second momentum target.
3. Seed traps: archive HTML is deliberately rendered as source; iOS Open PDF/attachment PDFs use Quick Look; an arbitrary public PDF URL does not activate the browser's native PDF overlay. They are unsuitable substitutes for the intended rows.
4. Android is outside the affected capture set: the helper returns undefined, and PDFs have a separate `.android.tsx` renderer. This is a code-based scope decision, not a claim that an Android runtime was tested.
5. No implementation defect is established by this fixture audit. This pass does not certify the native physics claim, CI, or full merge readiness.

## Call graph and branch inventory

- [WorkspaceFileWebPreview](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/files/WorkspaceFileWebPreview.tsx#L17): uri null → preparation screen; nonnull is keyed by URI → DocumentWebPreview. PDF pathname → direct PdfPreview; non-PDF → document WebView. linkedPdf state overlays PdfPreview and Back to document while hiding/retaining original view. Top-frame-or-unspecified PDF navigation intercepts; explicit subframe navigation does not. Platform/header inset, progress 0/interior/1, initial loading and error description/fallback all covered below. URI change remounts all state. Its only direct callers are [ThreadFilesRouteScreen.FileContent](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx#L230) (workspace SVG image preview or .htm/.html/.pdf browser preview) and [AttachmentDocumentBody](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/files/AttachmentDocumentBody.tsx#L21) (kind=html, htmlRender=false, URI present, no text/native/loading/error branch). ThreadFileScreen also backs NewTaskFile. AttachmentFileScreen backs ThreadAttachment and NewTaskAttachment. ZIP is another body caller but cannot reach this branch for HTML.
- [HtmlRenderWebView / ThreadHtmlRender](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/threads/HtmlRenderWebView.tsx#L77): only direct HtmlRenderWebView callers are ThreadHtmlRender(nested=true) and AttachmentDocumentBody(htmlRender=true,nested=false). Only ThreadHtmlRender caller is [ThreadFeed html-render entry](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/threads/ThreadFeed.tsx#L1391). The body is called by AttachmentFileScreen and ZipArchiveView; the latter passes htmlRender=false and converts HTML to text. Inline output branches: URI pending, asset/load failure with Reload, or mounted view + Open button. First load failure refreshes/retries, second fails. First process death remounts, second invokes optional load-error handler. Frame width and stored `height`/`heights` determine frame; root/body overflow selects four boolean combinations, with >1px threshold. nested determines gutters, insets, bounce, indicators, scroll enablement and Android nested-scroll settings. Full-screen is always scrollEnabled, even if content fits. Initial-theme fragment and live postTheme affect paint, not rate. Title is accessibility/navigation data rather than a visible title inside this component.
- [PdfPreview](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/components/PdfPreview.tsx#L8): direct importers/callers are WorkspaceFileWebPreview (direct and linked states), [PreviewStreamWebView](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/browser/PreviewStreamWebView.tsx#L424) (truthy pdfUri overlay), and [generic FilePreview](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/components/FilePreview.tsx#L13) (PDF modal). The generic modal is not an iOS/Android proof path: [FilePreview.ios.tsx](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/components/FilePreview.ios.tsx#L69) overrides it on iOS, and [PdfPreview.android.tsx](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/components/PdfPreview.android.tsx#L42) overrides its PDF renderer on Android. PdfPreview itself branches on initial loading, native error description/fallback, HTTP status error and success; error notice retains WebView beneath it. Its sole prop is URI. PdfPreview state does not reset merely because URI changes; actual direct workspace, linked and browser call paths remount with their parent/keys.
- Browser overlay callers: [BrowserPreviewRouteScreen](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/browser/BrowserPreviewRouteScreen.tsx#L176) (full-screen interactive) and [ThreadBrowserFloat](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/browser/ThreadBrowserFloat.tsx#L109) (compact, pointerEvents=none). [previewPdfAssetUrl](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/packages/shared/src/preview.ts#L9) gates PDF by prepared connection + http(s) + /api/assets/ + .pdf pathname, rewriting loopback/same-origin assets through client connection. Access/pause gate whether the document/overlay mounts. Full route focus/foreground/PiP gate live rendering; missing tabs, pending auth and stream errors are unchanged wrappers. Tab count changes tab menu; no rate branch. Compact width/height depends on viewport aspect; it is not user-scrollable.
- [SettingsLegalDocumentRouteScreen](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/settings/components/SettingsLegalDocumentRouteScreen.tsx#L53) has one caller: [SettingsLegalRouteScreen](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/settings/SettingsLegalRouteScreen.tsx#L4) with fixed Legal name/URL. Entry is Settings → About → Legal, or SettingsLegal route. Error screen unmounts WebView; retry increments key. Initial loading/progress, successful allowed URL updating external header, native error and allowed-URL HTTP error are branches. [allowed legal URL identity](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/features/settings/lib/legal-document-url.ts#L29) includes Legal, Privacy, Security and Terms; trailing slash/query/hash do not select a new screen. Other links open externally. Browser-open and Close headers remain available. documentName changes only failure copy. All pages share JavaScript-disabled/cache-disabled WebView.
- [Platform helper](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/lib/webViewDecelerationRate.ts#L1) has exactly two outputs: normal for iOS and undefined elsewhere. No theme, width, item-count, title-length, provider or connection-mode rate branch exists. Zero/many HTML entries only controls whether/how many independent cards mount. Long documents and page counts are fixture requirements to expose coast, not new data-render branches.
- [frame sizing](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/packages/shared/src/htmlRender.ts#L99) uses fallback height or width-neighbor measurements, clamps to 80..2000 for mobile's no-contentHeight call, and caps explicit requested height when measured desktop content exceeds it. Published reference title trims/defaults/truncates; generated full-screen filename sanitizes title. These do not create additional momentum implementations.

## Capture contract and minimum

`A` = changed iOS momentum surface. `C` = no-coast/unchanged-behavior control. `T` = transitional or prop-touched state without a stable scroll surface. `N` = changed scroll behavior not reached. Status describes this pass, not historical evidence. Supplemental rows enumerate the remaining visible branches without requiring a Cartesian product for a single platform-only prop.

**Minimum: one iPhone 17 Pro portrait viewport × one dark theme × nine rows: F1, H1, H2, H3, H4, P1, P2, P3, L1.** Capture each at both audited revisions: 18 row-side recordings (P2 may be one combined navigation/flick/return sequence per side; H4 needs separately identifiable X and Y gestures). Target the lead's nominated 402×874 pt viewport, but measure/log actual logical and capture pixel dimensions before using that number. Keep device, OS, native client fingerprint, content bytes, fonts/text size, accessibility settings, appearance and start position equal. Add light/wide rows only if a different overflow class or clipping issue is found; the rate does not branch on them.

Each required row is `recording`: show initial landmarks, the drag and finger release, sufficient room for coast, and motion through a stable endpoint. Log actual gesture coordinates/duration and any reported release velocity, not merely intended input. Use identical start positions per trial; avoid bottom/side clamping. An on-page HUD may help HTML but final landmarks/position and release-to-rest motion are authoritative; do not rely on an early timer-based coast counter. PDFs/legal need numbered page/text landmarks because JS telemetry is absent/unavailable. Transient blank PDF pages should be visible in the recording and checked for fully drawn rest states. Stills and diffs supplement layout checks only.

Required row collapse is deliberate: F2/F5/F6 mount the same ordinary-document WebView as F1; H1X composes the full-screen mount verified by H1 with axes verified by H3/H4; all legal documents share L1 settings. P2 and P3 remain separate because they change visible viewport/overlay ownership and involve actual navigation. Loading, fallback and disabled-scroll states cannot prove momentum and are outside the minimum; their interactions/time-dependent appearance are still labelled recording. No Android capture is required for this platform-only change; optional smoke is welcome but must be described as new evidence.

## Fixture matrix

| Row | Named fixture / data shape | Diff effect / minimum | Evidence kind | Pass-1 status | Data and observation | Real-app seed or harness |
|---|---|---|---|---|---|---|
| F1 | Long HTML file, root Y overflow | A; required | recording | MISSING | Self-contained HTML with viewport meta, at least 20,000 CSS px of numbered vertical landmarks; root scroll, not only a CSS overflow box. ThreadFile Preview, start at top, flick upward and record release through rest. | Seed a synthetic workspace file and stopped thread/project in isolated state; use Files or a markdown file link. ThreadFile params environmentId, threadId, path. Record Preview mode, not Source. |
| F2 | Large standalone SVG | A; equivalent to F1 | recording | NOT CAPTURED; supplemental | SVG with explicit narrow width and very tall height, numbered landmarks; verify root overflow before flick. Fits-content SVG is F3 instead. Distinct image dispatch, same DocumentWebPreview WebView. | Put .svg in the synthetic workspace; Files → SVG → Preview. This branch applies to workspace SVG, not an image attachment opened in Quick Look. |
| F3 | Short or empty HTML / fitted SVG | C; outside minimum | recording | NOT CAPTURED; control | Root content fits viewport; include truly empty and short readable variants as equivalent no-overflow states. Drag/release; no long content coast should appear. | Workspace file → Preview; blank valid HTML or a small SVG. A bare empty source file must still be served successfully, not as an error. |
| F4 | Inner CSS scroller | C; outside minimum | recording | NOT CAPTURED; control | A fixed-height overflow:auto box with long numbered content; document root fits. Flick inside box, then outside. Distinguishes WebKit inner scrolling from the changed outer WebView scroll view. | Self-contained workspace HTML fixture via F1 route. Can share the F1 file, but must label the inner-scroller gesture separately. |
| F5 | Ordinary HTML attachment | A; equivalent to F1 | recording | NOT CAPTURED; supplemental | text/html attachment, htmlRender absent/false; same tall root document. AttachmentDocumentBody reaches WorkspaceFileWebPreview. | ThreadAttachment with attachmentId, name, mimeType=text/html, sizeBytes, environmentId/threadId; tap an ordinary HTML attachment. Publish/upload via app attachment flow or isolated test seed. Do not set htmlRender=1. |
| F6 | Draft workspace or local HTML attachment | A; equivalent to F1/F5 | recording | NOT CAPTURED; supplemental | NewTaskFile shares ThreadFileScreen; NewTaskAttachment shares AttachmentFileScreen. A local file URI and a signed remote URI do not select different scroll configuration. Draft header differs. | Select synthetic project in New Task → Files, or attach local .html to composer and open it. NewTaskFile needs environmentId, cwd, projectName and path; NewTaskAttachment needs draftKey and a matching file-backed draft attachment. |
| F7 | Preparing file URI | N; no WebView mounted | recording | CODE-REVIEWED; outside minimum | uri=null yields Preparing preview spinner. Caller can also show metadata/access/asset-error screens before reaching this component. | Delay asset authorization in an isolated environment while opening F1. For deterministic uri=null state, labelled harness of WorkspaceFileWebPreview is acceptable; no stable app setting forces it. |
| F8 | Document loading / progress | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | Initial loading overlay; progress strictly between 0 and 1 shows strip at iOS header inset; progress 0 or 1 hides strip. LoadStart clears prior error; LoadEnd clears strip. | Use a controlled slow response reachable through the real file route, otherwise labelled event harness. Capture the whole transition, not a still of the spinner. |
| F9 | Document load error banner | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | onError nonempty description or fallback displays Preview failed banner above retained WebView. No separate onHttpError handler here. Return/reopen or file Refresh remounts and restores F1. | Invalidate/expire a signed file URL or interrupt isolated asset delivery. Controlled error text needs a labelled harness if native error wording cannot be fixed. |
| H0 | Inline HTML, no overflow | C; scrollEnabled=false | recording | NOT CAPTURED; control | nested=true, x=false,y=false; short content below frame height with width 100%. Drag inside card should leave document fixed and permit feed interaction as before. Empty page shares the same branch. | Publish html_render in isolated thread with height=300 and intrinsic content about 120 px. Inspect actual measured frame/overflow. Surround with enough messages for feed scrolling. |
| H1 | Expanded HTML, root Y overflow | A; required | recording | MISSING | nested=false; full-screen 16 px side gutters, automatic content inset, bounces and indicators enabled. Long numbered document; frame no longer constrains height. | Tap Open <title> on a real inline html_render. It navigates ThreadAttachment with htmlRender=1, MIME text/html and generated HTML filename. Start at document top and flick. |
| H1X | Expanded HTML, root X or XY overflow | A; equivalent to H1/H3/H4 | recording | NOT CAPTURED; supplemental | Full-screen horizontal/diagonal panning, with indicators and bounces unlike nested cards. Short fitted full-screen content has no sustained content coast. | Expand the H3 or H4 render; use same root-overflow fixture. H1 proves this mount configuration; H3/H4 prove affected axes, so no mandatory duplicate. |
| H2 | Inline HTML, Y only | A; required | recording | MISSING | nested=true, x=false,y=true; height=500, root width fits and content at least 20,000 px tall. Indicators hidden, bounces=false, never inset; nestedScrollEnabled=true. Surrounding feed landmarks stay visible. | html_render(html=complete vertical document,title=Vertical momentum,height=500) in the isolated thread. Ensure published measured heights and mobile frame actually leave Y overflow. Flick inside interior, observe feed position and release through rest. |
| H3 | Inline HTML, X only | A; required | recording | MISSING | nested=true, x=true,y=false; height=300, long numbered horizontal strip about 24,000 px wide, intrinsic page height below frame. nestedScrollEnabled=false. | html_render complete horizontal document, title Horizontal momentum, height=300. Ensure no accidental body Y overflow. Horizontal flick with finger release visible; a vertical feed drag is a separate optional control segment. |
| H4 | Inline HTML, both axes | A; required | recording | MISSING | nested=true, x=true,y=true; root grid about 12,000×20,000 px and height=500, numbered row/column landmarks. Distinct overflow combination missing from the old six-row set. | html_render complete two-axis grid, title Both axes momentum, height=500. Record X and Y flicks from reproducible starts, optionally diagonal; each gesture must have room to coast before an edge. Keep feed landmarks visible. |
| H5 | Responsive frame / one-pixel overflow boundary | C/A depending on resulting overflow; equivalent to H0/H2/H3/H4 | recording | NOT CAPTURED; supplemental | heights absent/empty uses clamped height; measured heights select taller width neighbors with cap. Frame clamp 80..2000. Overflow compares root/body scroll dimensions to inner size +1. 0..1 px excess stays no-overflow; >1 px enables axis. | Publish self-contained responsive CSS; inspect saved HtmlRenderReference.heights. Resize/rotate real app for width-dependent overflow. Precisely forcing missing/invalid measured heights or exact subpixel boundaries requires a labelled reference/message harness, not an assumption about html_render output. |
| H6 | Asset pending before inline WebView | N; no WebView mounted | recording | CODE-REVIEWED; outside minimum | uri remains null until first Success; spinner occupies computed frame. Empty feed/zero html-render entries mounts no such component. | Open thread while attachment URL mint is delayed. Deterministic pending state requires isolated delay fixture or labelled useAssetUrlState harness. |
| H10 | Mounted HTML still loading | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | Asset URI is already available but loaded=false: activity overlay above mounted WebView. onLoadEnd marks loaded and posts current theme if it changed since mount; restart resets loaded. Distinct from the pre-URI H6 spinner. | Use a slow isolated HTML asset response for inline or expanded render; for exact load-event ordering use a labelled WebView event harness. Continue recording until content is ready before any claimed momentum gesture. |
| H7 | Inline failure / reload affordance | N while fallback visible; remount returns to H2/H3/H4 | recording | NOT CAPTURED; supplemental | asset Failure or exhausted load retry shows Page unavailable + Reload <title>; Open button absent on failure. First load/HTTP failure refreshes URL; new URL changes key, unchanged URL increments attempt; second fails. | Make isolated attachment unavailable, open thread, tap Reload <title>, then restore asset. A deterministic refreshed-same vs refreshed-new URL uses a labelled asset/RPC harness. Do not call a fallback still momentum proof. |
| H8 | Web content process restart | A on remount; equivalent to initial H1/H2 | recording | NOT CAPTURED; supplemental | First process termination resets loaded/overflow, increments generation and remounts; second calls optional onLoadError. Inline caller has retry handler; full-screen caller has none. | No normal app setting triggers native process death. Requires native simulator diagnostic or explicitly labelled event harness; synthetic callback is not evidence that a real native crash recovers. |
| H9 | Theme update during mounted HTML | C; same rate in every theme | recording | NOT CAPTURED; supplemental | Initial theme in URI fragment; later theme posted into same mounted view after first load. App themeId, light/dark, systemColors, platform and color variables alter painting, not deceleration. | Settings → Appearance; use a CSS-variable fixture, switch light/dark and revisit/scroll. Material You falls back to default palette for HTML. One dark capture is minimum; no light×all-rows duplication needed. |
| P1 | Direct workspace PDF | A; required | recording | MISSING | WorkspaceFileWebPreview URI pathname ends .pdf, case-insensitive, query/hash allowed. iOS header-top padding; PdfPreview disables automatic inset adjustment and uses never. At least 40 numbered pages; start page 1. | Synthetic momentum.pdf in workspace; ThreadFile → Preview. Record flick/release and final page landmarks; document remains drawn at rest. Open PDF menu is Quick Look and cannot substitute. |
| P2 | PDF linked from document, then return | A; required | recording | MISSING | A top-frame navigation (isTopFrame not false) to a .pdf path sets linkedPdf, hides but retains document WebView; PDF has header padding plus bottom Back to document pill. | F1 includes valid signed absolute PDF link (sibling resolution must be verified for signed asset URLs). Tap link, flick PDF, tap Back to document, then flick restored document. Record transition and both releases. Android hardware-back branch is outside iOS minimum. |
| P3 | Full-screen browser PDF overlay | A; required | recording | MISSING | PreviewStreamWebView overlays PdfPreview only when pdfUri truthy. Full browser route is live/focused and authorized, with address/control chrome affecting height. Underlying streamed WebView has scrollEnabled=false. | In same isolated thread create/open a browser tab at a valid signed environment /api/assets/.../momentum.pdf URL, navigate ThreadBrowserPreview (tabId optional). previewPdfAssetUrl needs prepared httpBaseUrl, http(s), /api/assets/ prefix and .pdf pathname. Arbitrary public .pdf is not this path. Real app/RPC browser-open flow; harness only if actual browser access is unavailable, labelled as such. |
| P4 | Floating browser PDF preview | T; prop touched, direct pan blocked | recording | NOT CAPTURED; supplemental | compact player dimensions derived from viewport aspect, long side 184; pointerEvents=none on content. User tap opens full screen; cannot prove PDF momentum by panning float. Background pause removes authorized content. | Reveal same browser PDF tab after browser list initialized, with revealRequest/reveal=true; floating player appears. Tap Open browser to reach P3. Use real browser reveal RPC/tool; static compact harness must be labelled. |
| P5 | PDF loading | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | startInLoadingState renders Loading PDF spinner/card; PDF WebView already exists. Page count, page lengths, title, URI query do not select a different rate. | Open P1 through a controlled slow asset response; otherwise labelled loading callback harness. One-page/short PDF is no-coast control, equivalent to F3 for the changed behavior. |
| P6 | PDF network error | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | onError description or fallback shows Could not load PDF notice; WebView remains below it. No built-in retry in this iOS component; caller remount/reopen is recovery. | Use broken/expired .pdf asset URI in isolated route or linked PDF; reopen after restoring delivery. Native exact description fallback may need labelled event harness. |
| P7 | PDF HTTP error | T; same no-coast rationale as P6 | recording | NOT CAPTURED; supplemental | onHttpError uses The server returned HTTP <status>. Notice changes layout; distinct error text path. | Use controlled 404/500 .pdf endpoint reached through P1/P2 or labelled onHttpError harness. Restore/reopen for recovery. |
| L1 | Long allowed legal document | A; required | recording | MISSING | SettingsLegalRouteScreen uses documentName=Legal and LEGAL_URL. Follow Terms of Service; JS disabled, no storage/cache/cookies. Long top-level legal text, start at title, flick/release through rest. | Settings → About → Legal → Terms, or SettingsLegal route settings/legal followed by allowed internal link. Privacy and Security use the same component/scroll settings; select a sufficiently long page. Freeze/record response identity across before/after; no JS HUD. |
| L2 | Legal landing / other allowed document | A if scrollable, else C; equivalent to L1/F3 | recording | NOT CAPTURED; supplemental | Allowed paths: legal, privacy-policy, terms-of-service, security-policy; trailing slash/query/fragment preserve identity. Landing count/length depends on served page; no per-document component switch. | Same SettingsLegal route; follow allowed page links and back/forward gesture. EXPO_PUBLIC_MARKETING_SITE_URL can select an isolated deterministic marketing origin before bundling. A replacement fixture response must be labelled synthetic. |
| L3 | Legal loading/progress | T; no stable momentum surface | recording | NOT CAPTURED; supplemental | Spinner plus strip only for 0<progress<1. LoadStart clears errors; allowed LoadEnd updates external-header URL and clears progress. | Delay legal origin response or use controlled marketing origin in isolated capture setup. Exact progress needs labelled event harness. |
| L4 | Legal network/HTTP error and retry | N while error screen visible; recovery returns to L1 | recording | NOT CAPTURED; supplemental | onError fallback or allowed-URL HTTP status replaces WebView with error screen, Try Again and Open in Browser. Retry clears error, increments reloadKey, remounts. HTTP errors for nonlegal URL are ignored. documentName only changes error text; sole production caller says Legal. | Offline/failing controlled marketing origin, then restore and tap Try Again. Exact nonlegal callback/filter is a labelled event harness; opening external browser is not proof for embedded legal momentum. |
| I1 | Navigation and ancillary controls | C; outside minimum | recording | NOT CAPTURED; supplemental | File back/forward, top-frame PDF interception vs subframe PDF; full-screen video/multiple-window behavior; HTML same-document/fragment vs blocked top-frame link and http(s) new-window external open; legal allowed links vs external/mailto, header Safari and Close. | Use explicit anchors/iframe/new-window/video only in synthetic fixture; legal uses real or labelled synthetic allowed origin. Record any interaction claimed. These handlers are unchanged; P2 and L1 already include minimum relevant navigation. |
| W1 | Wide / split layout and light theme | A; equivalent rate to phone-dark rows | recording | NOT CAPTURED; supplemental | iOS header uses column safeArea.top when available, otherwise global safe inset; Android top padding zero. Wide panes change contentWidth, responsive frame/overflow and PDF visible area. Light colors do not change native scroll setting. | Rotate or use supported wide client layout; Settings Appearance → Light. Keep actual overflow class equal to intended H row. No extra viewport×theme minimum because rate has only a platform branch; add if captures expose clipping/overflow defects. |
| A1 | Android WebViews | N; value undefined | recording if smoke-tested | CODE-REVIEWED; no Android capture required | Workspace document, inline/fullscreen HTML and Legal receive undefined; no string or numeric native deceleration change intended. Android nested scrolling patch remains unchanged. Passing undefined is source evidence, not runtime crash verification. | Optional Android smoke through F1/H2/L1 after installing matching native client. This audit launches none. Do not claim Android tested. |
| A2 | Android PDFs | N; separate native implementation | recording if smoke-tested | CODE-REVIEWED; no Android capture required | Metro resolves PdfPreview.android.tsx to react-native-pdf-jsi, with its own fetch/loading/error/retry/page/link handling; changed PdfPreview.tsx is not used. | Optional workspace, linked or browser PDF Android smoke; no required row for this iOS-rate change. |
| N1 | iOS Quick Look and ZIP entries | N; no changed WebView reached | recording if demonstrated | CODE-REVIEWED; outside minimum | FilePreview.ios.tsx handles Open PDF, PDF/image attachments and native ZIP viewers with NativeControls. ZIP HTML is explicitly reclassified to text and always needsText, so AttachmentDocumentBody never takes its HTML WebView branch. | Open PDF menu, PDF attachment, or ZIP HTML entry in real app only as exclusion checks. Neither Quick Look nor ZIP HTML can stand in for P1 or F5. |
| N2 | Other WebViews / other clients | N; unchanged | recording if demonstrated | CODE-REVIEWED; outside minimum | McpAppWebView wraps a fixed-height iframe; PreviewStreamWebView outer transport and DeviceStreamWebView disable scroll. Web/desktop code, contracts, providers, transports and server are unchanged by the complete diff. | No capture required. Browser PDF exception is P3/P4; do not omit it merely because transport scrolling is disabled. |

## Seeding and provenance rules

- Use a dedicated synthetic project/thread and isolated T3 home, never the live database read-write. This audit supplies a seed plan; it has not created fixtures, called app mutation RPCs or launched a device/server.
- The actual app routes and component flags above are code-verified. Native linking definitions are in [Stack routes](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/mobile/src/Stack.tsx#L778) (thread prefix `threads/:environmentId/:threadId`, `files/:path*`, `attachments/:attachmentId`, `browser`, `settings/legal`). Prefer tapping the real flow; a deep link additionally needs valid project/thread/attachment state and query params. A route string alone does not seed a file or attachment.
- html_render uses the real tool/service publication path: complete self-contained HTML, nonempty title ≤200 characters, height 80..2000. Publishing also measures widths and injects bootstrap. Store the returned reference including `heights`; verify actual mobile overflow after publication instead of assuming the requested height is the effective frame height. Avoid vh/100%-height page roots rejected by publisher. The seed schema is in [html tool](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/server/src/mcp/toolkits/html/tools.ts#L78) and storage/measurement in [HtmlRender.publish](https://github.com/pingdotgg/t3code/blob/4b65d930a7312e350ab5b4a7ba8d2da87aea7c25/apps/server/src/htmlRender/HtmlRender.ts#L409). A T3-launched seed agent in the isolated fixture thread can perform these calls; this review did not spawn one.
- F1/P1 can be reached by Files without an agent message. F5 needs an ordinary HTML attachment; H1 needs htmlRender=1. For F6 local attachment, use the real composer file picker and matching draft record. Never substitute ZIP HTML, a Quick Look sheet, an MCP iframe or the browser transport stream.
- Keep generated HTML/PDF fixtures, seed scripts and manifests in the lead's designated scratch tree. Each future run writes to a fresh timestamped directory rather than deleting prior evidence. A seed may copy fixture bytes into its dedicated temporary project; the lead's reviewed checkout remains read-only during this audit.
- Capture manifest must bind row, full before/after SHA, fixture hashes/reference metadata, route/entry, platform/device/OS, viewport/theme, native fingerprint, driver command, gesture/start position and raw recording. Any controlled error/callback harness or replacement legal response must be labelled. A component harness does not establish real navigation or remote signed-asset access.
- Historical captures at earlier revisions cannot satisfy current missing statuses. This artifact is a specification, not proof that seeded states were rendered.

## Coverage and limits

Read complete diff, all four changed component implementations, direct/transitive mobile callers and route configuration, PDF platform overrides, HTML frame/theme helpers, attachment/ZIP dispatch, browser PDF URL gating, and installed react-native-webview iOS rate conversion / drag delegate and Android prop forwarding. No edits, pushes, comments, browsers, simulators, test suite, CI certification or runtime proof. No downloads or screenshots were needed. Disk preflight: 17 GB available; audit stayed above the 5 GB stop threshold. Git status was clean at initial inspection.

FRICTION: none

VERDICT: INSUFFICIENT <all affected rows: no captures yet>
