<?php
// Root explicitly authorized exact classification worker/Auth/cache/source cleanup.
// This script has no DB connection or SQL and preserves all evidence directories.
$lane=$argv[1]??getenv('PM_LANE');
$runtime=$lane==='B'?'/tmp/cdx-store-category9-B.cVux2z':'/tmp/cdx-store-category9-C.Hr1w83';
$worker=$lane==='B'?99408:1939876;$port=$lane==='B'?18321:18322;
$parent=$lane==='B'?10001:112175;$parentPort=$lane==='B'?18081:18080;
$original=$lane==='B'?'/tmp/zhct-http-store-mysql.dQTTBP/public':'/tmp/zhct-dm-poc-20260928.fcpiiN/store/public';
$check=static function($ok,$message){if(!$ok)throw new RuntimeException($message);};
$emit=static function($kind,$data){echo json_encode(['kind'=>$kind,'data'=>$data],JSON_UNESCAPED_UNICODE),"\n";flush();};
$rawFingerprint=static function($root){$files=[];foreach(['terminal-read9','crud-evidence','crud-noop-evidence','scratch-v2-evidence','schema-api-evidence']as $directory){$path=$root.'/'.$directory;if(!is_dir($path))continue;$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path,FilesystemIterator::SKIP_DOTS));foreach($it as $file)if($file->isFile()&&$file->getFilename()!=='phase.json')$files[substr($file->getPathname(),strlen($root)+1)]=['bytes'=>$file->getSize(),'sha256'=>hash_file('sha256',$file->getPathname())];}ksort($files);return ['files'=>count($files),'sha256'=>hash('sha256',json_encode($files,JSON_UNESCAPED_SLASHES))];};
$remove=static function($path)use($runtime,$check){
 $check(strpos($path,$runtime.'/')===0&&strlen($path)>strlen($runtime)+1,'Exact runtime descendant');
 $files=0;$bytes=0;
 if(is_link($path)||is_file($path)){$bytes=is_file($path)?filesize($path):0;$check(unlink($path),'Remove exact file');return ['files'=>1,'bytes'=>$bytes];}
 if(!is_dir($path))return ['files'=>0,'bytes'=>0,'already_absent'=>true];
 $it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path,FilesystemIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST);
 foreach($it as $file){$name=$file->getPathname();if($file->isLink()||!$file->isDir()){$bytes+=$file->isFile()?$file->getSize():0;$check(unlink($name),'Remove exact source/cache child');$files++;}else $check(rmdir($name),'Remove exact empty child directory');}
 $check(rmdir($path),'Remove exact source/cache root');return ['files'=>$files,'bytes'=>$bytes];
};
try{
 $check(in_array($lane,['B','C'],true)&&realpath($runtime)===$runtime,'Exact nonsymlink runtime');
 $cmd=(string)file_get_contents('/proc/'.$worker.'/cmdline');$parentCmd=(string)file_get_contents('/proc/'.$parent.'/cmdline');
 $check(strpos($cmd,$runtime.'/index.php')!==false&&strpos($cmd,'127.0.0.1:'.$port)!==false,'Only exact classification worker');
 $check(strpos($parentCmd,$original)!==false,'Protected original parent matches');
 $rawBefore=$rawFingerprint($runtime);$emit('before',['lane'=>$lane,'worker'=>$worker,'worker_cmdline_sha256'=>hash('sha256',$cmd),'parent'=>$parent,'parent_cmdline_sha256'=>hash('sha256',$parentCmd),'raw'=>$rawBefore]);
 $check(function_exists('posix_kill'),'Available exact PID signal');$check(posix_kill($worker,SIGTERM),'TERM exact worker');
 for($i=0;$i<20;$i++){if(!file_exists('/proc/'.$worker.'/cmdline')||file_get_contents('/proc/'.$worker.'/cmdline')==='')break;usleep(100000);}
 $running=file_exists('/proc/'.$worker.'/cmdline')&&(string)file_get_contents('/proc/'.$worker.'/cmdline')!=='';$check(!$running,'Classification worker stopped');
 $socket=@fsockopen('127.0.0.1',$port,$errno,$error,1);if($socket)fclose($socket);$check(!$socket,'Exact worker port closed');$emit('worker-stopped',['worker'=>$worker,'port'=>$port,'running'=>false,'port_closed'=>true]);
 $removed=[];foreach(['private-request.json','source.tgz','source','cache','runtime','schema-api-evidence/phase.json','crud-evidence/phase.json','crud-noop-evidence/phase.json']as $suffix){$removed[$suffix]=$remove($runtime.'/'.$suffix);$emit('removed',['target'=>$suffix,'result'=>$removed[$suffix]]);}
 $rawAfter=$rawFingerprint($runtime);$check($rawAfter===$rawBefore,'All raw evidence unchanged');$check(file_get_contents('/proc/'.$parent.'/cmdline')===$parentCmd,'Original parent exact preserved');
 $parentSocket=@fsockopen('127.0.0.1',$parentPort,$errno,$error,1);$check((bool)$parentSocket,'Original parent port live');fclose($parentSocket);
 $remaining=[];foreach(['private-request.json','source.tgz','source','cache','runtime']as $suffix)$remaining[$suffix]=file_exists($runtime.'/'.$suffix);$check(!in_array(true,$remaining,true),'Exact sensitive targets absent');
 $emit('summary',['lane'=>$lane,'passed'=>true,'DB_queries'=>0,'worker_stopped'=>true,'port_closed'=>true,'removed'=>$removed,'sensitive_targets_remaining'=>$remaining,'raw_before'=>$rawBefore,'raw_after'=>$rawAfter,'protected_original_parent_alive'=>true]);
}catch(Throwable $e){$emit('stopped',['lane'=>$lane,'class'=>get_class($e),'message'=>$e->getMessage()]);exit(1);}
