"""One numerical worker, finite study modes, sampled tree watchdog, failure ledger."""
import argparse, datetime, json, os, pathlib, resource, signal, subprocess, sys, time
ROOT=pathlib.Path(__file__).resolve().parent
def main():
    p=argparse.ArgumentParser(); p.add_argument('mode',choices=['fixtures','freeze','smoke','full','rerun']); mode=p.parse_args().mode
    ledger=ROOT/'attempts.json'; old=json.loads(ledger.read_text()) if ledger.exists() else []
    # Earlier ledger preserved separately; conservatively carry its already
    # inclusive combined totals, plus 60 s this-study setup/analysis allowance.
    prior_cpu,prior_wall=248.178326,214.930280
    timeout=600 if mode=='full' else 120
    if prior_cpu+60+sum(x['cpu_seconds'] for x in old)+timeout>3600 or prior_wall+60+sum(x['wall_seconds'] for x in old)+timeout>5400:
        raise SystemExit('aggregate reservation unavailable')
    env=dict(os.environ,OMP_NUM_THREADS='1',OPENBLAS_NUM_THREADS='1',MKL_NUM_THREADS='1',VECLIB_MAXIMUM_THREADS='1',NUMEXPR_NUM_THREADS='1',PYTHONDONTWRITEBYTECODE='1')
    def limits():
        os.setsid(); resource.setrlimit(resource.RLIMIT_CPU,(timeout,timeout+1)); resource.setrlimit(resource.RLIMIT_FSIZE,(32*1024**2,32*1024**2))
    start=time.monotonic(); usage=resource.getrusage(resource.RUSAGE_CHILDREN); stamp=datetime.datetime.now(datetime.timezone.utc).isoformat()
    log=ROOT/f'{len(old)+1:02d}-{mode}.log'; reason=None; peak=0; samples=0
    with log.open('x') as output:
        child=subprocess.Popen([sys.executable,'experiment.py',mode],cwd=ROOT,env=env,stdout=output,stderr=subprocess.STDOUT,preexec_fn=limits)
        while child.poll() is None:
            try:
                raw=subprocess.run(['ps','-axo','pid=,ppid=,rss='],capture_output=True,text=True,check=True).stdout.splitlines()
            except BaseException as error:
                reason='monitor failure: '+type(error).__name__
                os.killpg(child.pid,signal.SIGKILL); break
            table=[tuple(map(int,r.split())) for r in raw if len(r.split())==3]; ids={child.pid}
            for _ in range(4): ids.update(pid for pid,ppid,rss in table if ppid in ids)
            peak=max(peak,sum(rss*1024 for pid,ppid,rss in table if pid in ids)); samples+=1
            if peak>1024**3: reason='tree RSS ceiling'
            if time.monotonic()-start>timeout: reason='job wall ceiling'
            if sum(f.stat().st_size for f in ROOT.rglob('*') if f.is_file())>128*1024**2: reason='artifact ceiling'
            if reason: os.killpg(child.pid,signal.SIGKILL); break
            time.sleep(.1)
        rc=child.wait()
    end=resource.getrusage(resource.RUSAGE_CHILDREN)
    rec=dict(mode=mode,started_utc=stamp,returncode=rc,failure=reason,cpu_seconds=end.ru_utime+end.ru_stime-usage.ru_utime-usage.ru_stime,
             wall_seconds=time.monotonic()-start,peak_sampled_tree_rss_bytes=peak,samples=samples,timeout_seconds=timeout,
             prior_cpu_seconds=prior_cpu,prior_wall_seconds=prior_wall,setup_analysis_allowance_seconds=60,
             enforcement='CPU/file-size rlimits and 100 ms sampled tree RSS/wall/artifact watchdog; not instantaneous RSS guarantee')
    old.append(rec); ledger.write_text(json.dumps(old,indent=2)+'\n')
    if mode=='full' and rc and (ROOT/'status.json').exists():
        s=json.loads((ROOT/'status.json').read_text()); s.update(active_run=False,execution_status='stopped',worker_returncode=rc,worker_failure=reason); (ROOT/'status.json').write_text(json.dumps(s,indent=2)+'\n')
    print(log.read_text()[-6000:]); print(json.dumps(rec)); raise SystemExit(rc or bool(reason))
if __name__=='__main__': main()
