import importlib.util, json, os, pathlib, shutil, signal, subprocess, tarfile, time
os.umask(0o077)
R=pathlib.Path(__file__).parent
spec=importlib.util.spec_from_file_location('gate','/tmp/codex/ltb1021/2026-09-11_service-stop_r01/gate.py')
g=importlib.util.module_from_spec(spec);spec.loader.exec_module(g)
HEAD='492a95b4214e1bd17539a46a0bef5ad5c7239567'
EDITED=['app/main.py','tests/test_composition_architecture.py']
def main():
 assert not (R/'build.json').exists()
 assert json.loads((R/'source-verify.json').read_text())['errors']==0
 assert g.sh(['git','-C',str(g.REPO),'rev-parse','HEAD']).strip()==HEAD
 assert not g.sh(['git','-C',str(g.REPO),'diff','--cached','--name-only']).strip()
 assert sorted(x[3:] for x in g.sh(['git','-C',str(g.REPO),'status','--porcelain']).splitlines())==sorted(EDITED)
 root=g.sh(['docker','info','--format','{{.DockerRootDir}}']).strip()
 assert shutil.disk_usage(root).free>=15*1024**3
 assert subprocess.run(['pgrep','-f',r'(^|/)docker (build|buildx build|pull)'],capture_output=True).returncode==1
 hashes={p:g.sha(g.REPO/p) for p in EDITED}
 digest=g.hashlib.sha256(json.dumps(hashes,sort_keys=True).encode()).hexdigest()
 tag='contextra-analytics:lifespan-492a95b-'+digest[:8]
 assert subprocess.run(['docker','image','inspect',tag],capture_output=True).returncode!=0
 snap=R/'snapshot';snap.mkdir(mode=0o700)
 p=subprocess.Popen(['git','-C',str(g.REPO),'archive',HEAD],stdout=subprocess.PIPE)
 with tarfile.open(fileobj=p.stdout,mode='r|') as arc:arc.extractall(snap,filter='data')
 assert p.wait()==0
 for path in EDITED:shutil.copyfile(g.REPO/path,snap/path)
 (R/'source.json').write_text(json.dumps(dict(base=HEAD,hashes=hashes,tag=tag,digest=digest),indent=2))
 start=time.monotonic();reason=None
 with (R/'build.log').open('w') as log:
  p=subprocess.Popen(['docker','build','-f','docker/Dockerfile','--target','app','-t',tag,'.'],cwd=snap,
    stdout=log,stderr=log,start_new_session=True,env=dict(os.environ,DOCKER_BUILDKIT='1'))
  while p.poll() is None:
   if time.monotonic()-start>1200 or shutil.disk_usage(root).free<15*1024**3:
    reason='TIME_OR_DISK_CAP';os.killpg(p.pid,signal.SIGTERM)
    try:p.wait(15)
    except subprocess.TimeoutExpired:os.killpg(p.pid,signal.SIGKILL)
    break
   time.sleep(2)
  code=p.wait()
 out=dict(tag=tag,returncode=code,abort_reason=reason,elapsed_s=time.monotonic()-start,disk_free=shutil.disk_usage(root).free)
 if code==0:out['image_id']=json.loads(g.sh(['docker','image','inspect',tag]))[0]['Id']
 (R/'build.json').write_text(json.dumps(out,indent=2));print(json.dumps(out));assert code==0 and reason is None
if __name__=='__main__':main()
