<?php

declare(strict_types=1);

$lane=(string)getenv('CDX_DMR5_LANE');$mode=(string)($argv[1]??'');$selfSha=(string)hash_file('sha256',__FILE__);
if(!in_array($lane,['B','C'],true)||count($argv)!==2||!in_array($mode,['--preflight','--execute','--audit'],true)
    ||($mode==='--execute'&&((string)getenv('CDX_DMR5_APPROVE')!=='ROOT_DATEMENU_READ5_V1'
        ||!hash_equals($selfSha,(string)getenv('CDX_DMR5_SHA'))))){
    echo json_encode(['status'=>'default_deny','connected'=>false,'http_sent'=>false,'dml'=>false]),PHP_EOL;exit(78);}
$stage='bootstrap';
set_exception_handler(static function(Throwable $e)use(&$stage):void{echo json_encode(['status'=>'redacted_stop','stage'=>$stage,
    'class'=>get_class($e),'code'=>(string)$e->getCode(),'message_sha'=>hash('sha256',$e->getMessage()),
    'recovery'=>'inspect_private_journal_if_present']),PHP_EOL;exit(2);});
[$root,$pid,$port,$dialect]=[
    'B'=>['/tmp/zhct-http-store-mysql.dQTTBP',10001,18081,'mysql'],
    'C'=>['/tmp/zhct-dm-poc-20260928.fcpiiN/store',112175,18080,'dm'],
][$lane];
$hashes=[
    '/application/p/controller/DateMenu.php'=>'792b56de2dc42d36e19fc1d0f852cd853dab8f7768c06276070d02a9bfc76013',
    '/application/p/logic/DateMenu.php'=>'8035342ab42efa94eaaf832a89d8f5302451c3d6a5219d1b6e574b89791a4506',
    '/application/model/DateMenu.php'=>'61dd192dc186c334346bac06fb50243dc9dceb6315e75b836b2132b7c6173154',
    '/application/model/MenuRecommend.php'=>'93cd644f5ac965702165fd206b788d3d381e18edb3d6904c94851a7b8611af6c',
    '/application/model/MenuRecommendRecord.php'=>'59d08376292493c1825509476ebbdce0ac199a5d014bfda07a6a08f7d35583ef',
    '/application/model/Staff.php'=>'e709b91af8e78758b0adbb29697dba4d16d62402d8c365712afe9c47e72277d3',
    '/application/model/Recipes.php'=>'cd0bf238f33277efbbf0bed8fde4c7c6b3774018ea7fe2dea89aa0e8017ddc7f',
    '/application/model/Department.php'=>'9cd5a91f10f238d932d062e1fe8fae74208496b65d639314c545ecec49cc0e1f',
    '/application/base/AdminController.php'=>'7565b36fa4dda2c21cc4fa3b37753dbffb7c3a464bb8c11ea0f17ca00bececa5',
];
if(PHP_VERSION_ID<70300||PHP_VERSION_ID>=70400||is_link($root))throw new RuntimeException('Runtime/root drift');
foreach($hashes as $path=>$sha)if(!is_file($root.$path)||hash_file('sha256',$root.$path)!==$sha)throw new RuntimeException('Business source drift');
$stage='http_boundary';$base='http://127.0.0.1:'.$port;$cmd=(string)@file_get_contents('/proc/'.$pid.'/cmdline');
$childrenPath='/proc/'.$pid.'/task/'.$pid.'/children';$boundary=json_decode((string)@file_get_contents($base.'/__poc_boundary'),true);
if(strpos($cmd,$root.'/public')===false||strpos($cmd,'127.0.0.1:'.$port)===false
    ||trim((string)@file_get_contents($childrenPath))!==''||!is_array($boundary)
    ||($boundary['external_stubs']??null)!==true||($boundary['redis_isolated']??null)!==true
    ||($boundary['real_queue']??true)!==false)throw new RuntimeException('Isolated HTTP boundary drift');
$stage='database_boundary';$runtime=require $root.'/application/database.php';
if($dialect==='mysql'){$local=require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
    foreach(['hostname','database','username','password']as$key)if(($runtime[$key]??null)!==($local[$key]??null))throw new RuntimeException('Not code-local MySQL');
    if((int)($runtime['hostport']??3306)!==(int)($local['hostport']??3306))throw new RuntimeException('MySQL port drift');
    $dsn='mysql:host='.$runtime['hostname'].';port='.(int)($runtime['hostport']??3306).';dbname='.$runtime['database'].';charset='.(string)($runtime['charset']??'utf8');
}else{foreach(['hostname'=>'POC_HOST','hostport'=>'POC_PORT','database'=>'POC_SCHEMA','username'=>'POC_USER','password'=>'POC_PASSWORD']as$key=>$env)
        if((string)($runtime[$key]??'')!==(string)getenv($env))throw new RuntimeException('C worker config drift');
    if((string)getenv('POC_HOST')!=='127.0.0.1'||(string)getenv('POC_PORT')!=='5237'||strtoupper((string)getenv('POC_SCHEMA'))!=='ZHCT_APP')throw new RuntimeException('Not approved DM');
    $dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';}
$connect=static function()use($dsn,$runtime):PDO{return new PDO($dsn,(string)$runtime['username'],(string)$runtime['password'],[
    PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_TIMEOUT=>5]);};
$db=$connect();$identity=$dialect==='mysql'?(string)$db->query("SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")->fetchColumn()
    :'ZHCT_APP|5237|'.(string)$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn();
$approved=$dialect==='mysql'?'003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401':'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194';
if(!hash_equals($approved,hash('sha256',$identity)))throw new RuntimeException('DB identity drift');
$p=$dialect==='dm'?'YDY_':'ydy_';
$allowed=['user','department','staff_department','staff','date_menu','dishes','menu_recommend','menu_recommend_record','recipes','rpe','rpe_info','menu_recommend_set','initial_menu_log','task'];
$t=static function(string$name)use($allowed,$p):string{if(!in_array($name,$allowed,true))throw new RuntimeException('Unapproved table');return $p.$name;};
$fetch=static function(PDO$pdo,string$sql,array$args=[]):array{$q=$pdo->prepare($sql);$q->execute($args);return $q->fetchAll(PDO::FETCH_ASSOC);};
$count=static function(PDO$pdo,string$sql,array$args=[]):int{$q=$pdo->prepare($sql);$q->execute($args);return(int)$q->fetchColumn();};
$trim=static function($v):string{return rtrim((string)$v);};

$stage='candidate_scan';$cutoff=date('Y-m-d');
$baseSql='SELECT DM.STAFF_UUID,DM.MENU_DATE,DM.MEAL_TIMES,SD.DEPARTMENT_UUID,DM.ID'
    .' FROM '.$t('date_menu').' DM JOIN '.$t('staff').' S ON S.UUID=DM.STAFF_UUID'
    .' JOIN '.$t('staff_department').' SD ON SD.STAFF_UUID=S.UUID'
    .' JOIN '.$t('department').' D ON D.UUID=SD.DEPARTMENT_UUID'
    .' JOIN '.$t('dishes').' DI ON DI.UUID=DM.DISHES_UUID'
    .' WHERE DM.MEAL_TYPE=1 AND DM.MENU_DATE<? AND S.IS_SHOW=1 AND D.IS_SHOW=1 AND DI.STATUS=1'
    ." AND S.UUID NOT LIKE 'CDX%' AND S.NAME NOT LIKE 'CDX%'"
    ." AND (DM.CREATE_BY IS NULL OR DM.CREATE_BY NOT LIKE 'CDX%')"
    .' ORDER BY DM.MENU_DATE DESC,DM.ID DESC';
$candidateRows=$fetch($db,$dialect==='dm'?'SELECT * FROM ('.$baseSql.') WHERE ROWNUM<=200':$baseSql.' LIMIT 200',[$cutoff]);
$candidate=null;$seen=[];
foreach($candidateRows as$row){$staff=$trim($row['staff_uuid']);$date=substr((string)$row['menu_date'],0,10);$meal=(int)$row['meal_times'];$department=$trim($row['department_uuid']);
    $key=$staff.'|'.$date.'|'.$meal.'|'.$department;if(isset($seen[$key]))continue;$seen[$key]=true;
    $mr=$fetch($db,'SELECT * FROM '.$t('menu_recommend').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID DESC',[$staff,$date]);if(count($mr)!==1)continue;
    $mrr=$fetch($db,'SELECT * FROM '.$t('menu_recommend_record').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID DESC',[$staff,$date]);if($mrr===[]||trim((string)($mrr[0]['rpe_info']??''))!=='[]')continue;
    if($count($db,'SELECT COUNT(*) FROM '.$t('rpe').' WHERE STAFF_UUID=? AND TRAIN_DATE=?',[$staff,$date])!==0)continue;
    if($count($db,'SELECT COUNT(*) FROM '.$t('menu_recommend_set').' WHERE STAFF_UUID=? AND DATE=?',[$staff,$date])!==0)continue;
    $menuRows=$count($db,'SELECT COUNT(*) FROM '.$t('date_menu').' DM JOIN '.$t('dishes').' DI ON DI.UUID=DM.DISHES_UUID'
        .' WHERE DM.STAFF_UUID=? AND DM.MENU_DATE=? AND DM.MEAL_TIMES=? AND DM.MEAL_TYPE=1 AND DI.STATUS=1',[$staff,$date,$meal]);if($menuRows<1||$menuRows>100)continue;
    $recipeRows=$count($db,'SELECT COUNT(*) FROM '.$t('recipes').' WHERE MENU_DATE=?',[$date]);if($recipeRows<1||$recipeRows>500)continue;
    $candidate=['staff_uuid'=>$staff,'date'=>$date,'meal'=>$meal,'department_uuid'=>$department,'menu_rows'=>$menuRows,'recipe_rows'=>$recipeRows,'recommend'=>$mr[0],'record'=>$mrr[0]];break;}
$oldActors=$count($db,'SELECT COUNT(*) FROM '.$t('user')." WHERE ACCOUNT LIKE 'CDXDMR5%' OR UUID LIKE 'CDXDMR5%'");
if($dialect==='mysql'){$q=$db->prepare('SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?');$q->execute([$t('user')]);$triggers=(int)$q->fetchColumn();
    $q=$db->prepare('SELECT COUNT(*) FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=DATABASE() AND (TABLE_NAME=? OR REFERENCED_TABLE_NAME=?)');$q->execute([$t('user'),$t('user')]);$fks=(int)$q->fetchColumn();
}else{$triggers=(int)$db->query("SELECT COUNT(*) FROM ALL_TRIGGERS WHERE OWNER='ZHCT_APP' AND TABLE_NAME='YDY_USER'")->fetchColumn();
    $fks=(int)$db->query("SELECT COUNT(*) FROM ALL_CONSTRAINTS WHERE OWNER='ZHCT_APP' AND CONSTRAINT_TYPE='R' AND TABLE_NAME='YDY_USER'")->fetchColumn();}
if($triggers!==0||$fks!==0)throw new RuntimeException('Unreviewed actor trigger or FK');

$snapshot=static function(PDO$pdo,array$c)use($t,$fetch):array{$staff=$c['staff_uuid'];$date=$c['date'];$dept=$c['department_uuid'];
    return[
        'staff'=>$fetch($pdo,'SELECT * FROM '.$t('staff').' WHERE UUID=?',[$staff]),
        'staff_department'=>$fetch($pdo,'SELECT * FROM '.$t('staff_department').' WHERE STAFF_UUID=? ORDER BY ID',[$staff]),
        'department'=>$fetch($pdo,'SELECT * FROM '.$t('department').' WHERE UUID=?',[$dept]),
        'date_menu'=>$fetch($pdo,'SELECT * FROM '.$t('date_menu').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID',[$staff,$date]),
        'dishes'=>$fetch($pdo,'SELECT DI.* FROM '.$t('dishes').' DI JOIN '.$t('date_menu').' DM ON DM.DISHES_UUID=DI.UUID WHERE DM.STAFF_UUID=? AND DM.MENU_DATE=? ORDER BY DI.ID',[$staff,$date]),
        'menu_recommend'=>$fetch($pdo,'SELECT * FROM '.$t('menu_recommend').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID',[$staff,$date]),
        'menu_recommend_record'=>$fetch($pdo,'SELECT * FROM '.$t('menu_recommend_record').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID',[$staff,$date]),
        'recipes'=>$fetch($pdo,'SELECT * FROM '.$t('recipes').' WHERE MENU_DATE=? ORDER BY ID',[$date]),
        'rpe'=>$fetch($pdo,'SELECT * FROM '.$t('rpe').' WHERE STAFF_UUID=? AND TRAIN_DATE=? ORDER BY ID',[$staff,$date]),
        'menu_recommend_set'=>$fetch($pdo,'SELECT * FROM '.$t('menu_recommend_set').' WHERE STAFF_UUID=? AND DATE=? ORDER BY ID',[$staff,$date]),
        'initial_menu_log'=>$fetch($pdo,'SELECT * FROM '.$t('initial_menu_log').' WHERE STAFF_UUID=? AND MENU_DATE=? ORDER BY ID',[$staff,$date]),
        'task'=>$fetch($pdo,'SELECT * FROM '.$t('task').' WHERE STAFF_UUID=? AND DATE=? ORDER BY ID',[$staff,$date]),
    ];};
$journal=(string)getenv('CDX_DMR5_JOURNAL');
if($mode==='--audit'){$stage='independent_audit';if(!preg_match('~^/tmp/cdx-dmr5-[a-f0-9]{12}/recovery\.json$~D',$journal)||!is_file($journal)||is_link($journal)||is_link(dirname($journal))
        ||(fileperms(dirname($journal))&0777)!==0700||(fileperms($journal)&0777)!==0600)throw new RuntimeException('Audit journal invalid');
    $saved=json_decode((string)file_get_contents($journal),true);if(!is_array($saved)||($saved['lane']??null)!==$lane||($saved['phase']??null)!=='actor_deleted')throw new RuntimeException('Audit ownership invalid');
    $fresh=$connect();$q=$fresh->prepare('SELECT COUNT(*) FROM '.$t('user').' WHERE ID=? OR UUID=? OR ACCOUNT=?');$q->execute([(int)$saved['actor_id'],$saved['actor_uuid'],$saved['marker']]);
    if((int)$q->fetchColumn()!==0)throw new RuntimeException('Actor remains');
    if(hash('sha256',serialize($snapshot($fresh,$saved['candidate'])))!==(string)$saved['source_sha'])throw new RuntimeException('Natural source changed');
    unlink($journal);rmdir(dirname($journal));echo json_encode(['status'=>'independent_zero_pass','lane'=>$lane,'actor_rows'=>0,'source_unchanged'=>true,'private_journal_removed'=>true]),PHP_EOL;exit(0);}
if($mode==='--preflight'){$ready=is_array($candidate)&&$oldActors===0;
    echo json_encode(['status'=>$ready?'select_only_ready':'source_or_marker_stop','lane'=>$lane,'candidate_ready'=>is_array($candidate),
        'menu_rows'=>is_array($candidate)?$candidate['menu_rows']:0,'recipe_rows'=>is_array($candidate)?$candidate['recipe_rows']:0,
        'source_sha'=>is_array($candidate)?hash('sha256',serialize($snapshot($db,$candidate))):null,'old_actor_rows'=>$oldActors,
        'actor_fk'=>$fks,'actor_triggers'=>$triggers,'http_sent'=>false,'dml'=>false]),PHP_EOL;exit($ready?0:2);}
if(!is_array($candidate)||$oldActors!==0)throw new RuntimeException('Natural source or marker gate failed');

$marker='CDXDMR5'.strtoupper(bin2hex(random_bytes(6)));$actorUuid=$marker.'U';$dir='/tmp/cdx-dmr5-'.strtolower(bin2hex(random_bytes(6)));
if(file_exists($dir)||!mkdir($dir,0700))throw new RuntimeException('Private directory unavailable');chmod($dir,0700);$journal=$dir.'/recovery.json';
$source=$snapshot($connect(),$candidate);$sourceSha=hash('sha256',serialize($source));
$saved=['lane'=>$lane,'marker'=>$marker,'actor_uuid'=>$actorUuid,'actor_id'=>0,'phase'=>'before_insert','candidate'=>$candidate,'source_sha'=>$sourceSha];
unset($saved['candidate']['recommend'],$saved['candidate']['record']);
$save=static function()use(&$saved,$journal):void{if(file_put_contents($journal,json_encode($saved),LOCK_EX)===false||!chmod($journal,0600))throw new RuntimeException('Journal write failed');};$save();
$result=['status'=>'FAIL','lane'=>$lane,'cases'=>[]];$failure='';$httpUncertain=false;
try{$stage='actor_insert';$q=$db->prepare('INSERT INTO '.$t('user').' (UUID,ACCOUNT,PWD,SALT,NAME,TYPE,STATUS,CREATE_TIME,CREATE_BY,IS_DELETE) VALUES (?,?,?,?,?,0,0,?,?,0)');
    $q->execute([$actorUuid,$marker,'DISABLED',strtoupper(bin2hex(random_bytes(8))),$marker,date('Y-m-d H:i:s'),$marker]);
    $f=$db->prepare('SELECT ID FROM '.$t('user').' WHERE UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');$f->execute([$actorUuid,$marker,$marker]);$ids=$f->fetchAll(PDO::FETCH_COLUMN);
    if(count($ids)!==1||(int)$ids[0]<=0)throw new RuntimeException('Actor ownership ambiguous');$saved['actor_id']=(int)$ids[0];$saved['phase']='actor_inserted';$save();
    require_once $root.'/application/base/Security.php';$token=\app\base\Security::encrypt(implode("\t",[(string)$saved['actor_id'],$actorUuid,$marker,'0','','',$marker]));
    $send=static function(string$path,array$form,string$token='')use($base,&$httpUncertain):array{$headers="Content-Type: application/x-www-form-urlencoded\r\n".($token!==''?'token: '.$token."\r\n":'');
        $stream=@fopen($base.$path,'rb',false,stream_context_create(['http'=>['method'=>'POST','timeout'=>20,'ignore_errors'=>true,'header'=>$headers,'content'=>http_build_query($form,'','&',PHP_QUERY_RFC3986)]]));
        $raw=$stream===false?false:stream_get_contents($stream,2097153);$hs=$http_response_header??[];if(is_resource($stream))fclose($stream);preg_match('/HTTP\/\S+\s+(\d+)/',(string)($hs[0]??''),$m);$http=(int)($m[1]??0);
        if($stream===false||$raw===false||$http===0)$httpUncertain=true;return[$http,is_string($raw)?json_decode($raw,true):null];};
    $shape=static function($node)use(&$shape){if(!is_array($node))return gettype($node);if($node===[])return[];$keys=array_keys($node);if($keys===range(0,count($node)-1))return['[]'=>$shape($node[0])];$out=[];foreach($node as$k=>$v)$out[(string)$k]=$shape($v);ksort($out);return$out;};
    $case=static function($data,array$types)use($shape):array{$keys=is_array($data)?array_keys($data):[];sort($keys);return['source_match'=>true,'key_sha'=>hash('sha256',serialize($keys)),'type_sha'=>hash('sha256',serialize($shape($data))),'selected_types'=>$types];};
    $paths=[
        'getButton'=>['/p/dateMenu/getButton',['date'=>$candidate['date'],'staff_uuid'=>$candidate['staff_uuid'],'type'=>1,'meal_times'=>$candidate['meal']]],
        'getWhere'=>['/p/dateMenu/getWhere',['date'=>$candidate['date'],'staff_uuid'=>$candidate['staff_uuid']]],
        'getBound'=>['/p/dateMenu/getBound',['date'=>$candidate['date'],'staff_uuid'=>$candidate['staff_uuid'],'meal'=>$candidate['meal']]],
        'getMenuInfo'=>['/p/dateMenu/getMenuInfo',['date'=>$candidate['date'],'staff_uuid'=>$candidate['staff_uuid'],'type'=>1,'meal'=>$candidate['meal'],'flag'=>'true']],
        'foodSurveyIndex'=>['/p/dateMenu/foodSurveyIndex',['date'=>$candidate['date'],'department_uuid'=>$candidate['department_uuid'],'staff_name'=>$source['staff'][0]['name'],'page'=>1,'page_size'=>200]],
    ];
    $only=(string)getenv('CDX_DMR5_ONLY');
    if($only!==''){
        if($only!=='getMenuInfo'||!isset($paths[$only]))throw new RuntimeException('Unsupported focused retest');
        $paths=[$only=>$paths[$only]];
    }
    foreach($paths as$name=>[$path,$form]){$stage='unauth_'.$name;[$http,$body]=$send($path,$form);if($http!==200||!is_array($body)||(int)($body['code']??0)===0)throw new RuntimeException('Unauthenticated route not rejected');}
    if(hash('sha256',serialize($snapshot($connect(),$candidate)))!==$sourceSha)throw new RuntimeException('Unauthenticated route changed source');
    $mr=$candidate['recommend'];
    foreach($paths as$name=>[$path,$form]){$stage='http_'.$name;[$http,$body]=$send($path,$form,$token);if($http!==200||!is_array($body)||(int)($body['code']??-1)!==0)throw new RuntimeException('Authenticated route failed');$data=$body['data']??null;$types=[];
        if($name==='getButton'){if(!is_array($data)||($data['menu_nutrition']??null)!==true||($data['edit']??null)!==false||($data['change']??null)!==false)throw new RuntimeException('Button source mismatch');
            $types=['edit'=>gettype($data['edit']),'change'=>gettype($data['change']),'menu_nutrition'=>gettype($data['menu_nutrition'])];}
        elseif($name==='getWhere'){if(!is_array($data)||($data['rpe'][0]['time']??null)!=='120min'||($data['environment']['temperature']??null)!=='常温'||($data['environment']['altitude']??null)!=='平原'||($data['nutrition_rescription']??null)!=='不考虑')throw new RuntimeException('Where source mismatch');
            $types=['rpe'=>gettype($data['rpe']??null),'environment'=>gettype($data['environment']??null),'special_function'=>gettype($data['special_function']??null),'nutrition_rescription'=>gettype($data['nutrition_rescription']??null)];}
        elseif($name==='getBound'){$mealKey=[1=>'morning',2=>'noon',3=>'night'][$candidate['meal']];$ratio=[1=>0.3,2=>0.4,3=>0.3][$candidate['meal']];
            $expected=['power_min'=>round((float)$mr[$mealKey.'_power']*.8),'power_max'=>round((float)$mr[$mealKey.'_power']*1.2),
                'carbohydrate_min'=>round((float)$mr['carbohydrate_weight']*.8*$ratio),'carbohydrate_max'=>round((float)$mr['carbohydrate_weight']*1.2*$ratio),
                'protein_min'=>round((float)$mr['protein_weight']*.8*$ratio),'protein_max'=>round((float)$mr['protein_weight']*1.2*$ratio),
                'fat_min'=>round((float)$mr['fat_weight']*.8*$ratio),'fat_max'=>round((float)$mr['fat_weight']*1.2*$ratio)];
            if(!is_array($data))throw new RuntimeException('Bound data absent');foreach($expected as$k=>$v)if((float)($data[$k]??NAN)!==(float)$v)throw new RuntimeException('Bound source mismatch');foreach(array_keys($expected)as$k)$types[$k]=gettype($data[$k]);}
        elseif($name==='getMenuInfo'){$flat=[];foreach(['staple_food','vegetable','meat_dishes','custard','fruit','soup']as$category){if(!isset($data[$category])||!is_array($data[$category]))throw new RuntimeException('Menu category absent');foreach($data[$category]as$item)$flat[]=$item;}
            $sourceMenu=[];foreach($source['date_menu']as$dm)if((int)$dm['meal_type']===1&&(int)$dm['meal_times']===$candidate['meal'])$sourceMenu[]=$trim($dm['dishes_uuid']);
            $actual=[];foreach($flat as$item)$actual[]=$trim($item['dishes_uuid']??'');sort($sourceMenu);sort($actual);if($actual!==$sourceMenu||count($flat)!==$candidate['menu_rows'])throw new RuntimeException('Menu rows mismatch');
            $mealKey=[1=>'morning',2=>'noon',3=>'night'][$candidate['meal']];$recommend=round((float)$mr[$mealKey.'_power']*.8).'~'.round((float)$mr[$mealKey.'_power']*1.2);
            if(($data['recomment_power']??null)!==$recommend||($data['change']??null)!==false||!is_array($data['total_nutrition']??null))throw new RuntimeException('Menu summary mismatch');
            $representative=$flat[0];$numericKeys=['number','total_weight','unit','unit_number','weight','category','total_energy','energy','total_carbohydrate','carbohydrate','total_protein','protein','total_fat','fat','total_iron','total_calcium','total_vb1','total_vc'];
            $representativeTypes=[];$representativeValues=[];$representativeInteger=[];foreach($numericKeys as$numericKey)if(array_key_exists($numericKey,$representative)){$representativeTypes[$numericKey]=gettype($representative[$numericKey]);$representativeValues[$numericKey]=$representative[$numericKey];$representativeInteger[$numericKey]=is_numeric($representative[$numericKey])&&floor((float)$representative[$numericKey])===(float)$representative[$numericKey];}
            $sourceDish=null;foreach($source['dishes']as$sourceDishRow)if($trim($sourceDishRow['uuid']??'')===$trim($representative['dishes_uuid']??'')){$sourceDish=$sourceDishRow;break;}
            $sourceDishTypes=[];$sourceDishValues=[];foreach(['weight','energy','carbohydrate','protein','fat']as$sourceDishKey)if(is_array($sourceDish)&&array_key_exists($sourceDishKey,$sourceDish)){$sourceDishTypes[$sourceDishKey]=gettype($sourceDish[$sourceDishKey]);$sourceDishValues[$sourceDishKey]=$sourceDish[$sourceDishKey];}
            $nutritionTypes=[];foreach($data['total_nutrition']as$nutritionKey=>$nutritionValue)$nutritionTypes[$nutritionKey]=gettype($nutritionValue);ksort($nutritionTypes);
            $types=['representative_type_sha'=>hash('sha256',serialize($shape($representative))),'representative_types'=>$representativeTypes,'representative_values'=>$representativeValues,'representative_integer_flags'=>$representativeInteger,'source_dish_types'=>$sourceDishTypes,'source_dish_values'=>$sourceDishValues,'total_nutrition_type_sha'=>hash('sha256',serialize($shape($data['total_nutrition']))),'total_nutrition_types'=>$nutritionTypes,'change'=>gettype($data['change']),'edit'=>gettype($data['edit']),'recomment_power'=>gettype($data['recomment_power'])];}
        else{$rows=$data['rows']??null;$found=null;if(is_array($rows))foreach($rows as$row)if($trim($row['staff_uuid']??'')===$candidate['staff_uuid']){$found=$row;break;}
            if(!is_array($found)||(int)($data['total']??0)<1||$trim($found['staff_name']??'')!==$trim($source['staff'][0]['name']))throw new RuntimeException('Survey source mismatch');
            $meal3=[1=>false,2=>false,3=>false];foreach($source['date_menu']as$dm)if((int)$dm['meal_type']===3)$meal3[(int)$dm['meal_times']]=true;
            if(($found['morning']??null)!==$meal3[1]||($found['noon']??null)!==$meal3[2]||($found['night']??null)!==$meal3[3])throw new RuntimeException('Survey meal flags mismatch');
            $types=['total'=>gettype($data['total']),'height'=>gettype($found['height']??null),'height_value'=>$found['height']??null,'weight'=>gettype($found['weight']??null),'weight_value'=>$found['weight']??null,'source_height_type'=>gettype($source['staff'][0]['height']??null),'source_height_value'=>$source['staff'][0]['height']??null,'source_weight_type'=>gettype($source['staff'][0]['weight']??null),'source_weight_value'=>$source['staff'][0]['weight']??null,'morning'=>gettype($found['morning']??null),'noon'=>gettype($found['noon']??null),'night'=>gettype($found['night']??null),'row_type_sha'=>hash('sha256',serialize($shape($found)))];}
        $result['cases'][$name]=$case($data,$types);
    }
    $afterSha=hash('sha256',serialize($snapshot($connect(),$candidate)));$result['source_unchanged']=$afterSha===$sourceSha;if(!$result['source_unchanged'])throw new RuntimeException('Natural source changed');$result['status']='HTTP_PASS_PENDING_CLEANUP';
}catch(Throwable$e){$failure=get_class($e).':'.(string)$e->getCode().':'.hash('sha256',$e->getMessage());$result['failure_stage']=$stage;}
if($httpUncertain||!is_array(json_decode((string)@file_get_contents($base.'/__poc_boundary'),true))||trim((string)@file_get_contents($childrenPath))!==''){$saved['phase']='uncertain_http_retain_actor';$save();echo json_encode(['status'=>'uncertain_http_retain_actor','lane'=>$lane,'journal'=>$journal],JSON_UNESCAPED_SLASHES),PHP_EOL;exit(3);}
$stage='actor_cleanup';$clean=$connect();$q=$clean->prepare('DELETE FROM '.$t('user').' WHERE ID=? AND UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');$q->execute([$saved['actor_id'],$actorUuid,$marker,$marker]);if($q->rowCount()!==1)throw new RuntimeException('Actor cleanup mismatch');
$saved['phase']='actor_deleted';$save();$result['cleanup']=['actor_rows'=>0,'journal'=>$journal];if($failure!==''){$result['status']='HTTP_FAIL_CLEANED';$result['failure']=$failure;}else$result['status']='HTTP_PASS_CLEANED_PENDING_AUDIT';
echo json_encode($result,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),PHP_EOL;exit($failure===''?0:2);
