from pathlib import Path
from datetime import datetime
import json
root=Path('/tmp/lead-32866-r2/evidence-capture-1')
def t(x):return datetime.fromisoformat(x['time'])
def ms(a,b):return round((t(b)-t(a)).total_seconds()*1000)
summary={}
for side in ['before','after']:
 runs=sorted(root.glob('*-'+side+'-R33'))
 assert len(runs)==1,runs
 transcript=runs[0]/'transcript.jsonl'
 events=[json.loads(x) for x in transcript.read_text().splitlines()]
 server_lines=[x.removeprefix('CAPTURE ') for x in (root/('server-'+side+'.private.log')).read_text().splitlines() if x.startswith('CAPTURE ')]
 (root/('server-'+side+'.jsonl')).write_text('\n'.join(server_lines)+'\n')
 server=[json.loads(x) for x in server_lines]
 def find(event,operation=None,requestId=None):
  return next(x for x in server if x['event']==event and (operation is None or x.get('operation')==operation) and (requestId is None or x.get('requestId')==requestId))
 def results(name):return [x for x in events if x['event']=='MCP.result' and x['name']==name]
 evaluated=results('preview_evaluate');assert len(evaluated)==3
 assert evaluated[0]['result']['structuredContent']['value']=='A settled'
 assert evaluated[2]['result']['structuredContent']['value']=='ok'
 assert results('preview_status')[0]['result']['structuredContent']['available']
 assert not results('t3_preview_close')[0]['result']['isError']
 wait=find('request.delivered','waitFor'); start=find('operation.start','waitFor');end=find('operation.settled','waitFor')
 assert 2000<ms(wait,start)<wait['timeoutMs']
 assert 4000<=ms(start,end)<4500
 aend=find('operation.settled','evaluate');assert t(aend)<=t(start)
 evals=[x for x in server if x['event']=='request.delivered' and x.get('operation')=='evaluate']
 probe=evals[1];recovery=evals[2]
 assert ms(wait,probe)>4000 and t(probe)<t(end)
 assert t(end)<t(recovery)
 probe_started=[x for x in server if x['event']=='operation.start' and x.get('requestId')==probe['requestId']]
 connections=[x for x in server if x['event']=='host.connected']
 if side=='after':
  assert 'busy' in evaluated[1]['result']['content'][0]['text']
  assert not probe_started
  assert len(connections)==1
  assert probe['connectionId']==recovery['connectionId']==wait['connectionId']
 else:
  assert 'disconnected during evaluate' in evaluated[1]['result']['content'][0]['text']
  assert len(probe_started)==1 and t(probe_started[0])>=t(end)
  assert len(connections)==2
  assert wait['connectionId']!=recovery['connectionId']
 # Compare user-issued steps after replacing the generated tab identifier.
 normalized=[{'name':x['name'],'args':{k:('<TAB>' if k=='tabId' else v) for k,v in x['args'].items()}} for x in events if x['event']=='MCP.send']
 sends=[x for x in events if x['event']=='MCP.send' and x['name']=='preview_evaluate']
 summary[side]={'sha':events[0]['sha'],'queuedMs':ms(wait,start),'operationDurationMs':ms(start,end),'requestDeadline':datetime.fromtimestamp(t(wait).timestamp()+4,tz=t(wait).tzinfo).isoformat(timespec='milliseconds'),'probeAfterWaitDeliveryMs':ms(wait,probe),'probeMcpLatencyMs':ms(sends[1],evaluated[1]),'waitMcpLatencyMs':ms(next(x for x in events if x['event']=='MCP.send' and x['name']=='preview_wait_for'),results('preview_wait_for')[0]),'hostConnectionIds':[x['connectionId'] for x in connections],'normalizedSteps':normalized}
assert summary['before']['normalizedSteps']==summary['after']['normalizedSteps']
(root/'verification.json').write_text(json.dumps(summary,indent=2)+'\n')
print(json.dumps({side:{k:v for k,v in data.items() if k!='normalizedSteps'} for side,data in summary.items()},indent=2))
print('PASS: identical MCP inputs; late start before deadline; W crosses deadline; no overlap; transient busy only after; same-tab recovery; retained host after; broker eviction/reconnect before.')
