# Usage: python3 prove.py BASE_CHECKOUT HEAD_CHECKOUT
import pathlib, json, os, subprocess, threading, http.server, urllib.request, urllib.error, http.cookiejar, time, re, signal, sys, datetime
ROOT=pathlib.Path(__file__).parent
run=ROOT/datetime.datetime.now().strftime('%Y%m%d-%H%M%S'); run.mkdir()
requests=[]
class API(http.server.BaseHTTPRequestHandler):
 def log_message(self,*a): pass
 def do_GET(self):
  data=json.dumps({'data':[{'id':'fake-model'}]}).encode(); self.send_response(200); self.end_headers(); self.wfile.write(data)
 def do_POST(self):
  body=json.loads(self.rfile.read(int(self.headers['Content-Length']))); requests.append({'path':self.path,'model':body.get('model')})
  data=json.dumps({'choices':[{'message':{'content':json.dumps({'transcription':'Hello, world. Cleaned by fake API.'})},'finish_reason':'stop'}]}).encode()
  self.send_response(200); self.send_header('Content-Type','application/json'); self.end_headers(); self.wfile.write(data)
api=http.server.ThreadingHTTPServer(('127.0.0.1',18999),API); threading.Thread(target=api.serve_forever,daemon=True).start()
for side,checkout,sha,port in [('before',sys.argv[1],'0035cb55bb1853b8646117d8650588cf69c5293b',19001),('after',sys.argv[2],'028ae223d2eca9b3f8ca8f7b2acbe8faac92fbc6',19002)]:
 home=run/side; (home/'userdata').mkdir(parents=True)
 settings={'providerInstances':{x:{'driver':x,'enabled':False} for x in ['codex','claudeAgent','cursor','grok','muse','pi','opencode','antigravity']},'textGenerators':{'fakeapi':{'kind':'openaiCompatible','baseUrl':'http://127.0.0.1:18999/v1','enabled':True}},'textGenerationModelSelection':{'instanceId':'fakeapi','model':'fake-model'},'speechPostProcessingModelSelection':{'instanceId':'acp_local','model':'default'}}
 settings['providerInstances']['acp_local']={'driver':'acpRegistry','enabled':True,'config':{'source':'local','commandPath':'opencode','commandArgs':['acp']}}
 (home/'userdata/settings.json').write_text(json.dumps(settings))
 env={**os.environ,'T3CODE_DEV_SEED':'0','T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD':'0'}
 raw=open(home/'server.log','w')
 proc=subprocess.Popen(['node','scripts/dev-runner.ts','dev:server','--home-dir',str(home),'--no-seed','--port',str(port)],cwd=checkout,env=env,stdout=raw,stderr=subprocess.STDOUT,start_new_session=True)
 try:
  for i in range(180):
   log=(home/'server.log').read_text()
   match=re.search(r'pairingUrl:\s*(\S+)',log)
   if match: break
   if proc.poll() is not None: raise RuntimeError('server stopped: '+log[-4000:])
   time.sleep(1)
  else: raise RuntimeError('startup timeout: '+log[-4000:])
  url=match.group(1); from urllib.parse import urlparse,parse_qs
  parsed=urlparse(url); params={**parse_qs(parsed.query),**parse_qs(parsed.fragment)}
  credential=(params.get('token') or params.get('credential') or [None])[0]
  if not credential: raise RuntimeError('unknown pairing parameter keys '+str(params.keys()))
  origin=f'http://127.0.0.1:{port}'
  opener=urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
  def post(path,payload):
   req=urllib.request.Request(origin+path,data=json.dumps(payload).encode(),headers={'Content-Type':'application/json','Origin':origin})
   try:
    with opener.open(req,timeout=90) as r: return r.status,r.read().decode()
   except urllib.error.HTTPError as e: return e.code,e.read().decode()
  status,auth=post('/api/auth/browser-session',{'credential':credential})
  if status!=200: raise RuntimeError('auth '+str(status)+' '+auth)
  requests.clear()
  payload={'transcript':'um hello world','draft':{'text':'','selection':{'start':0,'end':0}},'options':{'speechCustomWords':[],'speechPostProcessingPrompt':{'mode':'default','customInstructions':''}}}
  status,body=post('/api/voice/post-process',payload)
  lines=[f'Voice transcript cleanup | {side.upper()}',f'Commit: {sha}','Environment: Linux, real T3 development server, fresh isolated home','All built-in agent instances disabled','Text generation: fakeapi / fake-model (local HTTP fixture)','Voice cleanup: acp_local / default (ACP Registry, opencode acp)','Browser session: authenticated with startup pairing credential','', 'POST /api/voice/post-process', 'Transcript: "um hello world"',f'HTTP {status}',body,f'Fake API requests: {json.dumps(requests)}']
  time.sleep(1)
  log=(home/'server.log').read_text()
  for line in log.splitlines():
   if 'ACP Registry instances do not provide application text generation.' in line:
    lines+=['Server cause: ACP Registry instances do not provide application text generation.']; break
  text='\n'.join(lines)+'\n'; (run/f'{side}.txt').write_text(text); print(text,flush=True)
 finally:
  os.killpg(proc.pid,signal.SIGTERM)
  try: proc.wait(timeout=15)
  except subprocess.TimeoutExpired: os.killpg(proc.pid,signal.SIGKILL); proc.wait()
  raw.close()
api.shutdown()
print('Output:',run)
