from pathlib import Path
import json,html,runpy,sys
m=runpy.run_path('/tmp/lead-29548-r1/evidence-capture-2/public-manifest.py');r=m['ROOT']
u=json.loads((r/'upload-map.json').read_text()) if (r/'upload-map.json').exists() else {}
def link(n):return u.get(n,{}).get('url',str(r/n))
def md(n):return u.get(n,{}).get('markdown',('!' if n.endswith('.png') else '')+f'[{n}]({r/n})')
b='[6f41364805](https://github.com/pingdotgg/t3code/commit/6f41364805e31a1f8d59c18c7cc451630cd9265d)';a='[941452f31c](https://github.com/pingdotgg/t3code/commit/941452f31c1f7015f57e913da9da4ca34627af0d)'
body=f'''## Evidence

**Capture-only difference outside the PR text change:** native Android gesture-bar antialiasing differs by 1/255 in 13 pixels (M1) and 11 pixels (M2), zero pixels above 16/255. Status bars are identical at Diff0. No unrelated application change was observed.

**Round 2: 7/7 affected fixture rows captured, 8 matrix rows total.** C1 is explicitly unaffected. W1 covers 1440×900 and 390×900 CSS, light and dark, with narrow timeline supplements. W2 has before/after narrated recordings plus lossless dismissed-state stills. W3, D1 and P1 use 1440×900 dark. M1/M2 use the real native Android client. **P1 is a labelled protocol harness through the real app.** No real Factory Droid account or external model inference was used.

Before {b}; after {a}. No source edits, commits, pushes or PR-body changes were made.

**Two-fresh-run determinism:** W1-after-1440-dark.png versus W1-rerun-1440-dark.png, distinct fresh databases, **Diff0 = 0 pixels; Diff16 = 0 pixels**. Both screenshots also passed independent same-side stability pairs. The driver fixes server wall time, sends Droid then Generic strictly sequentially, and moves the pointer away before every still. Browser text, sidebar order, 9:00 PM persisted failure time and unhovered Dismiss button match exactly.

**Web environment:** fs-32, Linux x86_64, T3 preview Chrome 156.0.0.0; desktop user agent at both widths; no device emulation; DPR 2; zoom/visualViewport.scale 1; font scaling 100% (root 16 px, interface 14 px). Whole viewports 1440×900 or 390×900 CSS as labelled. **Desktop PNG exports are 1280×800, proportionally scaled from 1440×900 CSS**, narrow exports 780×1800. W2 MP4s are 2880×1800. Sidebar open at 1440, responsive hidden at 390; conversation scroll 0. W1/W2 details closed, W3/P1 open, D1 closed. Explicit light/dark themes. Server/Vite run under normal-speed advancing libfaketime, with monotonic clock bypass; clocks reset to the same starting instant immediately before each sequential fixture. Browser Date is fixed on both sides of each pair: 2026-11-02T21:00:00Z for W1/W2 and the two-run determinism check; 21:05:00Z for W3/D1/P1. Persisted W1/W3 failure items display 9:00 PM, D1/P1 9:01 PM on both revisions. Preview cannot emulate reduced motion; all accepted web stills had fonts loaded, no pending resources and pixel-identical stability witnesses. The browser reported one active animation while preparing one narrow supplement, but its accepted screenshots were pixel-identical; other final web preparation snapshots reported zero.

**Native environment:** leased Pixel 9 Android API36 emulator; real T3 dev client, each checkout's own Metro bundle and respective isolated backend. Native fingerprint 971743703b097b8870b39ff842d130f50b115eeb is shared by both revisions. Portrait logical window/screen **411.428571×923.428571**, pixel ratio **2.625**, measured fontScale **0.9399999976** (OS text-size category medium). Full-display exports **1080×2424**, dark, animations disabled, airplane mode enabled with Wi-Fi retained, keyboard absent. App Date fixed to 21:05 UTC via CDP; emulator system time manually reset immediately before each side so both status bars display **9:00**. M1 uses the same bottom-anchored feed position; M2 list starts at its top. No copy/long-press/transition performance claim is made.

**Fixture and protocol:** each real server started with `T3CODE_DEV_SEED=0` and a separate new scratch home; no live T3 database or other lead's data was read/copied. The app RPC creates a synthetic project and local stock-ACP instances `proof_droid` (agentId factory-droid) and `proof_generic` (agentId omitted), probes them healthy, then enables an auth-required launcher marker. Auth method, lifecycle and Antigravity variables are unset. One “Review the README” message per thread, awaiting the committed failed item before creating the next thread. W1/W3 reject **session/new** with -32000. D1 creates a real app-owned delegated child against that failing mock; only the child's own static view is claimed, with no stall-duration, parent-notification or navigation claim. P1 forwards successful stock-mock session creation with auth disabled, then a custom shim rejects only model `composer-2`'s **session/set_config_option** with -32000. It demonstrates the model-write auth class in the real app; it is not the repository's replay-model-b fixture or a claim that the stock mock supports this flag.

**Settled frames and diffs:** every accepted still has two lossless screenshots at least 500 ms apart with exact same-side Diff0=0. Witness frames are in the synthetic-only source archive. All accepted captures and difference images were visually reviewed. Diff0 highlights **every max-RGB-channel difference >0/255** in magenta, amplified to full brightness. DiffT highlights **>16/255** in amber. Both retain the whole viewport with dimmed after-image context. Exact counts and bounding boxes are in diff-stats.json.

### W1 — Droid session open

At narrow width the longer baseline banner covers the timeline heading; the supplemental dismissed-banner stills show the complete timeline item on both sides. They add to the full-surface banner captures.

'''
header=f'| Viewport × theme / state | Before<br>{b} | After<br>{a} | Diff0<br>{b} → {a} | DiffT >16/255<br>{b} → {a} |\n|---|---|---|---|---|\n'
def row(k,v,label):return '| '+label+' | '+' | '.join(md(n) for n in [f'{k}-before-{v}.png',f'{k}-after-{v}.png',f'{k}-{v}-Diff0.png',f'{k}-{v}-DiffT.png'])+' |\n'
body+=header
for v in ['1440-dark','1440-light','390-dark','390-light','390-dark-timeline','390-light-timeline']:body+=row('W1',v,v.replace('-',' · '))
body+='''
### W2 — Dismiss banner, retain failed item

**Same scripted interaction:** start on W1's settled Droid thread, hold, click Dismiss error, move pointer away, hold the same failed timeline item. No new turn or navigation occurs. W1's baseline has no Show full error control. The actual encoded boundary was checked using ffmpeg at 20 fps: **before banner present through 00:04.40, first absent frame 00:04.45; after present through 00:04.00, first absent 00:04.05** (50 ms sampling bounds). From those first-absent frames through each recording's end (8.2851 s before / 8.023267 s after), the banner stays absent and the failure item remains. Added narration says “Banner dismissed” at 00:04.50, after both measured boundaries. Raw recordings remain available.

'''
body+=f'| 1440×900 CSS · dark | Before<br>{b} | After<br>{a} |\n|---|---|---|\n| Narrated recording | {md("W2-before-narrated.mp4")} | {md("W2-after-narrated.mp4")} |\n| Original recording | {md("W2-before-raw.mp4")} | {md("W2-after-raw.mp4")} |\n\n'+header+row('W2','dismissed','1440×900 CSS · dark · lossless dismissed state')
for k,title,v,label,desc in [('W3','Generic local ACP','1440-dark','1440×900 CSS · dark','The registry identity is omitted; separate failed thread, details open. Both failures were generated with default. After failure the selector is set to Composer 2 on both sides, without a new turn, to avoid a legacy Default/config-option Auto catalog-label race.'),('M1','Native failed-thread content','android-dark','411.43×923.43 logical · Android · dark','The complete guidance is visible in the real native work-log row.'),('M2','Native failed-thread list excerpt','android-dark','411.43×923.43 logical · Android · dark','One-line truncation is intentional; complete text is in M1.'),('D1',"Delegated child's own failed thread",'1440-dark','1440×900 CSS · dark · real app-owned child','A real orchestration-created child fails session opening. Only its own static view is captured; the baseline long banner has Show full error and the after short message does not.'),('P1','Model-write authentication — protocol harness','1440-dark','1440×900 CSS · dark · protocol harness in real app','The custom shim lets session/new succeed and rejects the subsequent model write with authentication-required -32000. This is separately labelled from W1/W3.')]:body+=f'\n### {k} — {title}\n\n{desc}\n\n'+header+row(k,v,label)
body+='''
### What else changed

- W1/W3, D1 and P1 replace the baseline wrapper/internal session ID with the exact fixed sign-in guidance in the banner and timeline paragraph. The error heading and failed badges remain the same. Synthetic baseline IDs are deliberately unmasked and will change on another before run.
- W1's narrow banner shrinks from five text lines to three, moving its lower edge up and uncovering the timeline heading/timestamp. The narrow timeline paragraph also takes less height. D1's longer baseline banner loses its Show full error button after replacement and becomes shorter, uncovering more of the prompt bubble.
- M1's failure paragraph changes to the complete guidance; M2's two one-line excerpts change to its beginning. Surrounding native controls and list order match. Existing native timestamp contrast/provider-badge presentation is present on both sides and was not edited.
- W2 removes the banner on both sides and uncovers the prompt bubble; the failed timeline item survives. Independent video encodes have cursor/timing/compression differences, which are not used as still-image diff evidence. Narration is an added audio track, with original recordings linked above.
- Native OS gesture-bar edges have 13 (M1) / 11 (M2) one-level antialiasing differences; their status bars match exactly. See native-OS-delta.json.
- **No unrelated application pixels differ outside the changed failure-text/banner-geometry regions in the accepted still pairs at zero threshold.** No sidebar reversal, persisted-time mismatch or hover state remains in W1. The native system-clock display was aligned before final capture.

### Matrix coverage and limits

| Row | Capture status |
|---|---|
| W1 | Captured: both widths/themes, plus narrow timeline supplements. |
| W2 | Captured: before/after narrated and raw recordings; lossless dismissed-state pair. |
| W3 | Captured: generic ACP, 1440 dark. |
| M1 | Captured: real native Android failed-thread content. |
| M2 | Captured: real native Android list excerpts. |
| D1 | Captured: real app-owned delegated child's own failed thread. No timing/navigation/parent-notification claim. |
| P1 | Captured: explicitly labelled custom protocol harness through real app. The exact replay-model-b test fixture was not rerun. |
| C1 | Unaffected control row, not captured or claimed. |

**Unverified affected rows: none.** Native iOS, Electron, relay/tunnel-specific behavior, copying the message, actual provider sign-in/recovery and the reported long delegation stall are outside these captured static states and are not claimed.

### Sheets

'''
for n in m['SHEETS']:body+=md(n)+'\n\n'
body+='### Rebuild scripts and source data\n\n'
for n in m['SCRIPTS']+m['DATA']+['evidence-sources.tar.gz']:body+=md(n)+'\n\n'
body+='### Exact ghdrop output\n\nThe following is ghdrop stdout verbatim for public artifacts uploaded before this document was generated. No credential files, raw ACP requests, server logs or dev homes are included.\n\n'
if (r/'ghdrop-output.md').exists():body+=(r/'ghdrop-output.md').read_text()+'\n'
if '--index-only' not in sys.argv: (r/'evidence.md').write_text(body)
sections=[]
for title,names in [('Sheets',m['SHEETS']),('Recordings',[f'W2-{s}-{v}.mp4' for s in ['before','after'] for v in ['narrated','raw']]),('Scripts',m['SCRIPTS']),('Data',m['DATA']+['evidence-sources.tar.gz'])]:
 content=''.join('<li><a href="'+html.escape(link(n))+'">'+html.escape(n)+'</a>'+('<br><img loading="lazy" src="'+html.escape(link(n))+'" alt="'+html.escape(n)+'">' if n.endswith('.png') else '')+'</li>' for n in names)
 sections.append('<section><h2>'+title+'</h2><ul>'+content+'</ul></section>')
evidenceLink=md('evidence.md')
(r/'index.html').write_text('<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>PR 29548 round-2 evidence</title><style>body{font:16px system-ui;max-width:1500px;margin:32px auto;padding:0 20px;background:#101114;color:#eee}a{color:#a7c5ff}img{max-width:100%;height:auto;margin:16px 0}li{margin:12px 0}</style></head><body><h1>ACP sign-in failure — round 2</h1><p>7/7 affected fixture rows captured. W1 fresh-run determinism: 0 differing pixels.</p><p><a href="'+html.escape(link('evidence.md'))+'">Evidence markdown with all Before / After / Diff0 / DiffT tables, revisions, environments and limitations</a></p>'+''.join(sections)+'</body></html>')
print('Wrote evidence.md and index.html')
