"""Same MEASURE protocol, more samples per consecutive batch. No outcomes discarded.
Usage: confirm.py side checkout original-run-directory
Run only after both first-pass servers have stopped, sequentially on the same machine.
"""
import os,sys,json,time,subprocess,pathlib,signal,datetime,sqlite3
ROOT=pathlib.Path(__file__).resolve().parent
SIDE=sys.argv[1];CHECKOUT=pathlib.Path(sys.argv[2]);ORIGINAL=pathlib.Path(sys.argv[3]);HOME=ORIGINAL/'home'
OUT=ROOT/('confirm-'+SIDE+'-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S'));OUT.mkdir();(ROOT/('confirm-'+SIDE+'-latest')).write_text(str(OUT));(OUT/'source-home').write_text(str(HOME))
node=subprocess.check_output(['which','node'],text=True).strip();AGENT_LOG=OUT/'agent.ndjson'
settings=json.loads((HOME/'userdata/settings.json').read_text());settings['providerInstances']['perf']['config']['commandArgs']=[str(ROOT/'agent.mjs'),str(AGENT_LOG)];(HOME/'userdata/settings.json').write_text(json.dumps(settings))
env={**os.environ,'T3CODE_DEV_SEED':'0','T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD':'0','T3CODE_TRACE_MAX_BYTES':'1073741824','T3CODE_TRACE_MAX_FILES':'4','T3CODE_TRACE_BATCH_WINDOW_MS':'100','T3CODE_TRACE_FILE':str(OUT/'trace.ndjson')}
port=18351 if SIDE=='head' else 18352
log=open(OUT/'server.log','w');server=subprocess.Popen([node,'apps/server/src/bin.ts','--base-dir',str(HOME),'--port',str(port),'--dev-url','http://127.0.0.1:5733','--no-browser'],cwd=CHECKOUT,env=env,stdout=log,stderr=log);(OUT/'pid').write_text(str(server.pid))
threads=json.loads((ORIGINAL/'threads.json').read_text());(OUT/'threads.json').write_text(json.dumps(threads))
try:
 import urllib.request
 for i in range(120):
  if server.poll()!=None:raise Exception('server exited')
  try:urllib.request.urlopen(f'http://127.0.0.1:{port}/.well-known/t3/environment');break
  except:time.sleep(1)
 windows=[]
 for batch in range(3):
  for subround in range(9):
   before=AGENT_LOG.read_text().count('"type":"measureDone"') if AGENT_LOG.exists() else 0;begin=time.time_ns()
   r=subprocess.run([node,'apps/server/src/bin.ts','thread','send',threads['large'],'PERF:MEASURE','--wait','--json','--base-dir',str(HOME)],cwd=CHECKOUT,env=env,capture_output=True,text=True,timeout=900)
   if r.returncode:raise Exception('CLI '+r.stdout[-1000:]+r.stderr[-1000:])
   for j in range(1200):
    if AGENT_LOG.exists() and AGENT_LOG.read_text().count('"type":"measureDone"')>before:break
    time.sleep(.25)
   else:raise Exception('measurement did not finish')
   time.sleep(2);windows.append({'size':'large','round':batch,'subround':subround,'start':str(begin),'end':str(time.time_ns())});(OUT/'windows.json').write_text(json.dumps(windows,indent=2));print('measured batch',batch,'round',subround,flush=True)
 db=sqlite3.connect(f'file:{HOME}/userdata/statev2.sqlite?mode=ro',uri=True);counts={}
 for size,thread in threads.items():
  counts[size]={t:db.execute(f'select count(*) from orchestration_v2_projection_{t} where thread_id=?',(thread,)).fetchone()[0] for t in ['runs','nodes','subagents','turn_items']}
 db.close();(OUT/'counts.json').write_text(json.dumps(counts,indent=2));print(counts,flush=True)
finally:
 server.send_signal(signal.SIGINT)
 try:server.wait(timeout=30)
 except:server.kill();server.wait()
 log.close()
