<?php
declare(strict_types=1);require __DIR__.'/oracle.php';$runtime=getenv('SM7_RUNTIME');$lane=getenv('SM7_LANE');$port=$lane==='B'?18421:18422;
if(!preg_match('#^/tmp/cdx-catalog7-[BC]-[A-Za-z0-9]+$#D',__DIR__)||realpath($runtime)!==__DIR__.'/private-runtime'||is_file(__DIR__.'/worker_state.json')){throw new RuntimeException('Stop exact own worker before cleanup');}if($socket=@fsockopen('127.0.0.1',$port,$n,$e,1)){fclose($socket);throw new RuntimeException('Own port remains');}
$db=smPdo();catActor($db);$own=n7OwnedRestaurant($db);$full=n7Rows($db,'restaurants',['*'],'id=?',[$own[0]['id']]);n7SafeOwnedStar($db,$full);$keys=['zpkey'=>['empty'=>$full[0]['zpkey']===null||$full[0]['zpkey']==='','type'=>gettype($full[0]['zpkey'])],'zpchargekey'=>['empty'=>$full[0]['zpchargekey']===null||$full[0]['zpchargekey']==='','type'=>gettype($full[0]['zpchargekey'])]];
$stats=[];$requests=0;$assertions=0;$remove=[];foreach(['first4-original','dining-original','restaurant-original','card-green','restaurant-green'] as $stage){$file=$runtime.'/native-report/'.$stage.'.json';if(!is_file($file)){continue;}$raw=file_get_contents($file);$r=json_decode($raw,true,512,JSON_THROW_ON_ERROR)['run']['stats'];$stats[$stage]=['requests'=>$r['requests']['total'],'assertions'=>$r['assertions']['total'],'failures'=>$r['assertions']['failed'],'report_sha256'=>hash('sha256',$raw)];$requests+=$r['requests']['total'];$assertions+=$r['assertions']['total'];$remove[]=$file;}
smSave('native-stats-private.json',['native_cli_version'=>'2.2.8','requests'=>$requests,'assertions'=>$assertions,'stages'=>$stats]);
foreach(['collection-private.json','dining-collection-private.json','restaurant-collection-private.json','card-green-collection-private.json','restaurant-green-collection-private.json'] as $name){if(is_file($runtime.'/'.$name)){$remove[]=$runtime.'/'.$name;}}$removed=[];foreach($remove as $file){if(is_link($file)){throw new RuntimeException('Token artifact symlink');}$removed[]=['name'=>str_replace($runtime.'/','',$file),'sha256'=>hash_file('sha256',$file)];unlink($file);}
$clear=static function(string $path):int{if(!file_exists($path)&&!is_link($path)){return 0;}if(is_link($path)||!is_dir($path)){throw new RuntimeException('Expected owned directory only');}$n=0;foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path,FilesystemIterator::SKIP_DOTS),RecursiveIteratorIterator::CHILD_FIRST) as $entry){if($entry->isLink()||$entry->isFile()){unlink($entry->getPathname());$n++;}elseif($entry->isDir()){rmdir($entry->getPathname());}}return $n;};
$cacheRemoved=$clear($runtime.'/cache');$clear($runtime.'/runtime');$clear($runtime.'/safe-log');$source=__DIR__.'/source';if(realpath($source)!==$source){throw new RuntimeException('Source copy boundary');}$sourceRemoved=$clear($source);rmdir($source);
$remaining=0;foreach($remove as $file){$remaining+=(int)is_file($file);}$cacheRemaining=0;if(is_dir($runtime.'/cache')){foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($runtime.'/cache',FilesystemIterator::SKIP_DOTS)) as $entry){if($entry->isFile()||$entry->isLink()){$cacheRemaining++;}}}
$cleanup=['lane'=>$lane,'port'=>$port,'port_listening'=>false,'worker_state_exists'=>false,'new_pdo_owned_actor_verified'=>true,'owned_restaurant_verified'=>true,'integration_key_flags'=>$keys,'private_cache_files_removed'=>$cacheRemoved,'private_cache_files_remaining'=>$cacheRemaining,'token_artifacts_removed'=>$removed,'token_artifacts_remaining'=>$remaining,'credential_bearing_source_files_removed'=>$sourceRemoved,'credential_bearing_source_remaining'=>(int)is_dir($source),'child_business_dml'=>0,'child_ddl'=>0,'root_approved_ddl'=>$lane==='C'?3:0,'business_rows_deleted'=>0,'natural_global_unchanged_claimed'=>false,'private_raw_and_source_preserved'=>true,'shared_cli_cache_preserved'=>'/tmp/cdx-apifox-cli-2.2.8-cache/package'];if($remaining||$cacheRemaining||is_dir($source)){throw new RuntimeException('Cleanup incomplete');}smSave('cleanup-private.json',$cleanup);
$destination=__DIR__.'/private-evidence';if(is_dir($destination)){throw new RuntimeException('First terminal evidence export only');}mkdir($destination,0700);
$files=['spec-private.json','after-private.json','report-private.json','spec-before-card-projection-private.json','report-before-card-projection-private.json','card-oracle-tool-repair-private.json','card-projection-probe-private.json','dining-spec-private.json','dining-after-private.json','dining-report-private.json','restaurant-spec-private.json','restaurant-after-private.json','restaurant-report-private.json','restaurant-spec-before-canonical-private.json','restaurant-report-before-canonical-private.json','restaurant-oracle-tool-repair-private.json','boundary-private.json','queries.jsonl','source-mysql-metadata-private.json','metadata-private.json','schema-plan-private.json','restaurant-credential-precheck-private.json','native-stats-private.json','cleanup-private.json'];
foreach(['card-green-spec-private.json','card-green-after-private.json','card-green-report-private.json','restaurant-green-spec-private.json','restaurant-green-after-private.json','restaurant-green-report-private.json','metadata-after-root-column-private.json','root-column-preflight.json','root-column-DDL-journal.json','root-column-final.json','root-column-error-apply.json'] as $name){if(is_file($runtime.'/'.$name)){$files[]=$name;}}
foreach(glob($runtime.'/raw-*-private.json')?:[] as $file){$files[]=basename($file);}$manifest=[];
foreach($files as $name){$content=file_get_contents($runtime.'/'.$name);if(is_link($runtime.'/'.$name)){throw new RuntimeException('Evidence symlink');}copy($runtime.'/'.$name,$destination.'/'.$name);chmod($destination.'/'.$name,0600);$manifest[$name]=['bytes'=>strlen($content),'sha256'=>hash('sha256',$content)];}
file_put_contents($destination.'/EVIDENCE_MANIFEST.json',json_encode($manifest,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR));chmod($destination.'/EVIDENCE_MANIFEST.json',0600);foreach(['actor-private.json','actor-baseline-private.json'] as $name){unlink($runtime.'/'.$name);}
echo json_encode(['lane'=>$lane,'requests'=>$requests,'assertions'=>$assertions,'private_evidence_path'=>$destination,'files'=>count($manifest),'manifest_sha256'=>hash_file('sha256',$destination.'/EVIDENCE_MANIFEST.json'),'port_listening'=>false,'cache_remaining'=>$cacheRemaining,'token_artifacts_remaining'=>$remaining,'child_dml_ddl'=>0,'root_approved_ddl'=>$lane==='C'?3:0]),PHP_EOL;
