from pathlib import Path
source=Path('/tmp/lead-25978-r2/evidence-capture/capture-core.py').read_text().split('def run():')[0].replace('evidence-thread','turn-thread').replace("SIDE+'-core-'","SIDE+'-reconnect-'")
exec(source)
def snapshot():
 return server('const tab=[...c.tabs.values()].find(t=>t.threadId==="turn-thread");const r=await tab.cdp.send("Page.captureScreenshot",{format:"png",captureBeyondViewport:false});const b=Buffer.from(r.data,"base64");return {bytes:b.length,width:b.readUInt32BE(16),height:b.readUInt32BE(20)};')
main('process.env.CAP_LOG='+json.dumps(str(RUN/'events.jsonl'))+';process.env.CAP_REV='+json.dumps(REV)+';globalThis.capRow="setup";')
main((ROOT/'observe.js').read_text());display=main('return process.env.DISPLAY;');env={**os.environ,'DISPLAY':display,'XAUTHORITY':main('return process.env.XAUTHORITY;')}
v=subprocess.Popen(['ffmpeg','-y','-f','x11grab','-framerate','10','-video_size','1440x1000','-i',display+'+0,0','-an','-c:v','libx264','-preset','ultrafast','-crf','25','-pix_fmt','yuv420p',str(RUN/(SIDE+'-reconnect.mp4'))],stdout=(RUN/'ffmpeg.log').open('w'),stderr=subprocess.STDOUT,env=env)
(RUN/'ffmpeg.pid').write_text(str(v.pid))
try:
 mark('R2','instrumented real-app: actual backend restart; frontend reconnect held; synthetic tab snapshot restored after native completion')
 snapshot_state=server('return (await c.runPromise(c.manager.list({threadId:"turn-thread"}))).sessions[0];')
 wc=main('return capGuest.id;');note('surviving_guest_required',wc=wc)
 hide();i=len(events());f=EXEC.submit(snapshot)
 wait_event(lambda e:e['event']=='native_send' and e.get('method')=='Page.captureScreenshot',start=i)
 wait_event(lambda e:e['event']=='B' and e.get('pending')==1 and e.get('B'),start=i)
 oldpid=main('capLog("backend_restart_requested",{pid:capBackendPid});const pid=capBackendPid;process.kill(pid,"SIGTERM");return pid;')
 wait_event(lambda e:e['event']=='backend_started' and e.get('pid')!=oldpid,timeout=20,start=i)
 wait_event(lambda e:e['event']=='announceAll',timeout=20,start=i)
 wait_event(lambda e:e['event']=='native_resolve' and e.get('method')=='Emulation.setFocusEmulationEnabled' and e.get('F') is False,timeout=20,start=i)
 time.sleep(.6);restore()
 if SIDE=='before':time.sleep(2);note('bounded_stall_end');rescue()
 else:wait_event(lambda e:e['event']=='native_resolve' and e.get('method')=='Page.captureScreenshot',start=i);idle()
 note('guest_survived',sameWebContents=main('return capGuest.id=== '+str(wc)+' && !capGuest.isDestroyed();'))
 # Fresh backend service reconnects the same native tab via its real fd endpoint.
 deadline=time.monotonic()+20
 while True:
  try:server('return {ready:true};');break
  except Exception:
   if time.monotonic()>deadline:raise
   time.sleep(.2)
 server('const s='+json.dumps(snapshot_state)+';await c.restoreSnapshot(s);const t=await c.ensureTab(s);return {threadId:t.threadId,tabId:t.tabId,desktop:!!t.desktop};')
 note('synthetic_tab_snapshot_restored',reason='backend preview registry is in-memory; frontend reconnect held to preserve existing guest')
 note('new_backend_snapshot',**snapshot());idle()
 note('row_end')
except Exception as e:
 (RUN/'driver-error.txt').write_text(repr(e));print('FAILED',repr(e),flush=True)
 try:restore()
 except:pass
finally:
 v.send_signal(2)
 try:v.wait(timeout=15)
 except subprocess.TimeoutExpired:v.kill();v.wait()
 (RUN/(SIDE+'-R2.jsonl')).write_text(''.join(json.dumps(e)+'\n' for e in events() if e.get('row')=='R2'))
 print('RUN',RUN,flush=True)
