<?php
require __DIR__.'/common.php';require __DIR__.'/observe.php';
$mode=$argv[1]??'';
try{
 if($mode==='failed-closure'){
  pp_need(is_file(pp_private().'/send-attempt-code.json')&&!is_file(pp_private().'/send-attempt-scan.json'),'Only exact stopped code chain, no scan');
  pp_protect('final-failed-code');
  $p=pp_input('fresh-plan.json');$s=array_values(array_filter($p['steps'],static function($s){return $s['label']==='collision.prepay';}))[0];$r=pp_read($s['db'],$s['SQL'],$s['binds'],'failed-code-independent-marker');pp_need($r['rows']===[],'Exact new Prepay marker0 after failed code');
  $eq=pp_read('ZHCT','SELECT * FROM ydy_equipment WHERE code=? OR sn=? ORDER BY id',['CDXPPFORM11_E1','CDXPPFORM11_M1'],'final-owned-equipment-full31');$e=pp_saved('equipment.json');pp_equal($eq['rows'],$e['full']['rows'],'Unique generated device complete31 unchanged after failed code');pp_need(count($eq['rows'])===1&&(int)$eq['rows'][0]['id']===$e['id'],'Original generated owned equipment only');
  pp_save('failed-code-checkpoint.json',['failed_HTTP'=>true,'old29_unchanged'=>true,'new_prePay_marker0'=>$r,'owned_device_full31'=>$eq,'generated_device_ID'=>$e['id'],'code_business_DML'=>0,'scan_HTTP'=>0,'no_payment'=>true]);
 }elseif($mode==='cleanup'){
  pp_need(is_file(pp_private().'/failed-code-checkpoint.json'),'Durable physical failure checkpoint before cleanup');$workers=[];
  foreach(['launch-store','launch-ai']as $k){$lease=pp_saved('worker-'.$k.'.json');pp_need(in_array($lease['router'],[__DIR__.'/router.php',__DIR__.'/router-v2.php'],true),'Exact own router lease');$proc='/proc/'.$lease['pid'].'/cmdline';if(is_file($proc)){$cmd=(string)file_get_contents($proc);pp_need(strpos($cmd,$lease['router'])!==false&&strpos($cmd,'127.0.0.1:'.$lease['port'])!==false,'Never kill unknown worker');pp_need(posix_kill($lease['pid'],15),'Exact own worker SIGTERM');$workers[]=$lease['pid'];}}
  $removed=[];foreach(['ai-cache','store-cache']as $name){$root=pp_private().'/'.$name;if(!is_dir($root))continue;pp_need(realpath($root)===$root&&!is_link($root),'Exact owned cache directory');$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root,FilesystemIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST);foreach($it as $f){pp_need(!$f->isLink()&&strpos($f->getPathname(),$root.'/')===0,'No unknown cache path/symlink');if($f->isFile()){$removed[]=['path'=>$f->getPathname(),'bytes'=>$f->getSize(),'sha256'=>hash_file('sha256',$f->getPathname())];pp_need(unlink($f->getPathname()),'Exact own cache file removal');}elseif($f->isDir())pp_need(rmdir($f->getPathname()),'Exact empty own cache subdirectory');}}
  pp_save('cleanup.json',['worker_SIGTERM'=>$workers,'only_owned_cache_removed'=>$removed,'token_revoked_by_exact_original_FileCache_removal'=>true,'business_DELETE'=>0,'marked_device_retained'=>true,'new_prePay0'=>true,'new_meal0'=>true]);
 }else throw new RuntimeException('Only physical stopped-path closure or exact private cleanup');
 echo pp_json(['status'=>'PHASE_COMPLETE','phase'=>$mode,'side'=>getenv('PP_SIDE'),'budget'=>pp_saved('budget.json')])."\n";
}catch(Throwable $e){pp_event(['event'=>'failure-closure-stopped','mode'=>$mode,'class'=>get_class($e),'message'=>$e->getMessage()]);fwrite(STDERR,pp_json(['status'=>'STOP_KEEP_ORIGINAL','phase'=>$mode,'message'=>$e->getMessage()])."\n");exit(1);}
