<?php
declare(strict_types=1);
$lane=(string)getenv('BC_LANE');$root=(string)getenv('BC_ROOT');$mode=$argv[1]??'';$stage='setup';
set_exception_handler(static function(Throwable $e)use(&$stage,$lane){echo json_encode(['status'=>'stop','lane'=>$lane,'stage'=>$stage,'class'=>get_class($e),'message_sha'=>hash('sha256',$e->getMessage())]).PHP_EOL;exit(2);});
if(!in_array($lane,['B','C'],true)||!in_array($mode,['red','green','audit','no_meal'],true)||$root!==__DIR__.'/source')exit(78);
$cfg=require $root.'/application/database.php';
if($lane==='B'){$local=require '/workspace/zhct/zhctproject/store/application/config/local/database.php';foreach(['hostname','database','username','password'] as $k)if($cfg[$k]!==$local[$k])throw new RuntimeException('Not code local');if((int)($cfg['hostport']??3306)!==(int)($local['hostport']??3306))throw new RuntimeException('Not local port');$dsn='mysql:host='.$cfg['hostname'].';port='.$cfg['hostport'].';dbname='.$cfg['database'].';charset='.$cfg['charset'];}
else{if($cfg['hostname']!=='127.0.0.1'||(int)$cfg['hostport']!==5237||$cfg['database']!=='ZHCT_APP')throw new RuntimeException('Not approved DM');$dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';}
$connect=static function()use($cfg,$dsn){return new PDO($dsn,$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_TIMEOUT=>5]);};
$db=$connect();$q=static function(PDO $d,string $sql,array $a=[]){$s=$d->prepare($sql);$s->execute($a);return $s->fetchAll(PDO::FETCH_ASSOC);};
$identity=$lane==='B'?(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();
if(hash('sha256',$identity)!==($lane==='B'?'003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401':'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194'))throw new RuntimeException('Identity drift');
$natural=static function(PDO $d)use($q){$rows=$q($d,'SELECT * FROM ydy_recipes WHERE MENU_DATE=? AND RESTAURANT_ID=? ORDER BY ID',['2026-10-10',1]);$dishes=[];foreach(array_unique(array_column($rows,'dishes_uuid')) as $uuid)$dishes[$uuid]=$q($d,'SELECT * FROM ydy_dishes WHERE UUID=?',[$uuid]);ksort($dishes);return ['sha'=>hash('sha256',serialize([$rows,$dishes,$q($d,'SELECT * FROM ydy_recipes_log WHERE MENU_DATE=? ORDER BY ID',['2026-10-10'])])),'recipe_rows'=>count($rows)];};
$source=[];foreach(['/application/p/controller/Bill.php','/application/p/logic/Bill.php','/application/model/Bill.php','/application/model/Cater.php'] as $file)$source[$file]=hash_file('sha256',$root.$file);
if($mode==='audit'){$r=json_decode(file_get_contents(__DIR__.'/result-'.$lane.'.json'),true);$m=$r['marker'];$date=$r['date'];$counts=['dishes'=>count($q($db,'SELECT ID FROM ydy_dishes WHERE UUID IN (?,?)',[$m.'A',$m.'B'])),'recipes'=>count($q($db,'SELECT ID FROM ydy_recipes WHERE MENU_DATE=?',[$date])),'recipes_log'=>count($q($db,'SELECT ID FROM ydy_recipes_log WHERE MENU_DATE=?',[$date])),'user'=>count($q($db,'SELECT ID FROM ydy_user WHERE UUID=? AND ACCOUNT=?',[$m.'U',$m]))];$n=$natural($db);$ok=array_sum($counts)===0&&$n['sha']===$r['natural_before']['sha'];echo json_encode(['status'=>$ok?'independent_zero_and_natural_unchanged':'audit_failed','lane'=>$lane,'counts'=>$counts,'natural'=>$n]).PHP_EOL;exit($ok?0:2);}
$base='http://127.0.0.1:'.($lane==='B'?18088:18087);$boundary=json_decode((string)file_get_contents($base.'/__poc_boundary'),true);if(($boundary['external_stubs']??null)!==true||($boundary['redis_isolated']??null)!==true||($boundary['real_queue']??true)!==false)throw new RuntimeException('Unsafe HTTP boundary');
$marker='CDXBC10'.strtoupper(bin2hex(random_bytes(5)));$uuids=[$marker.'A',$marker.'B'];$date='';$actorId=0;$logId=0;$checks=[];$samples=[];$states=[];
for($i=0;$i<90;$i++){$candidate=date('Y-m-d',strtotime('2060-01-01 +'.(hexdec(substr($marker,-4))%1800+$i).' days'));if(!$q($db,'SELECT ID FROM ydy_recipes WHERE MENU_DATE=?',[$candidate])&&!$q($db,'SELECT ID FROM ydy_recipes_log WHERE MENU_DATE=?',[$candidate])){$date=$candidate;break;}}
if(!$date)throw new RuntimeException('No private future slot');$naturalBefore=$natural($db);
$result=['status'=>'failed','lane'=>$lane,'mode'=>$mode,'marker'=>$marker,'date'=>$date,'source'=>$source,'natural_before'=>$naturalBefore];
$insert=static function(string $table,array $row)use($db){if(!in_array($table,['dishes','user','recipes','recipes_log'],true))throw new RuntimeException('Unapproved insert');$names=array_keys($row);foreach($names as $name)if(!preg_match('/^[a-z_][a-z0-9_]*$/D',$name))throw new RuntimeException('Unsafe field');$sql='INSERT INTO ydy_'.$table.' ('.implode(',',$names).') VALUES ('.implode(',',array_fill(0,count($row),'?')).')';$s=$db->prepare($sql);$s->execute(array_values($row));};
$snapshot=static function(PDO $d)use($q,$uuids,$date){return ['dishes'=>$q($d,'SELECT UUID,MENU_QUANTITY,ATTRIBUTE FROM ydy_dishes WHERE UUID IN (?,?) ORDER BY UUID',$uuids),'recipes'=>$q($d,'SELECT * FROM ydy_recipes WHERE MENU_DATE=? ORDER BY UUID',[$date]),'log'=>$q($d,'SELECT * FROM ydy_recipes_log WHERE MENU_DATE=? ORDER BY ID',[$date])];};
try{
 $stage='own_fixtures';$sql='SELECT * FROM ydy_dishes WHERE IS_DEL=1 AND STATUS=1 ORDER BY ID';$templates=$q($db,$lane==='B'?$sql.' LIMIT 1':'SELECT * FROM ('.$sql.') WHERE ROWNUM<=1');if(count($templates)!==1)throw new RuntimeException('No safe dish template');
 foreach($uuids as $uuid){if($q($db,'SELECT ID FROM ydy_dishes WHERE UUID=?',[$uuid]))throw new RuntimeException('Dish collision');$row=$templates[0];unset($row['id']);$row['uuid']=$uuid;$row['name']=$uuid;$row['file_path']='/'.$marker.'/disabled.png';$row['create_by']=$marker;$row['menu_quantity']=0;$row['attribute']=0;$row['price']='0.00';if(isset($row['create_time']))$row['create_time']=date('Y-m-d H:i:s');$insert('dishes',$row);}
 $insert('user',['uuid'=>$marker.'U','account'=>$marker,'pwd'=>'DISABLED','salt'=>'CDX_DISABLED','name'=>$marker,'type'=>0,'status'=>0,'create_time'=>date('Y-m-d H:i:s'),'create_by'=>$marker,'is_delete'=>0]);$actorRows=$q($db,'SELECT ID FROM ydy_user WHERE UUID=? AND ACCOUNT=?',[$marker.'U',$marker]);if(count($actorRows)!==1)throw new RuntimeException('Actor ambiguous');$actorId=(int)$actorRows[0]['id'];
 $insert('recipes',['uuid'=>$marker.'R','dishes_uuid'=>$uuids[0],'restaurant_id'=>1,'menu_date'=>$date,'meal_times'=>1,'type'=>1,'create_by'=>$marker,'create_time'=>date('Y-m-d H:i:s'),'limit_num'=>7]);
 $insert('recipes',['uuid'=>$marker.'S','dishes_uuid'=>$uuids[0],'restaurant_id'=>2,'menu_date'=>$date,'meal_times'=>1,'type'=>1,'create_by'=>$marker,'create_time'=>date('Y-m-d H:i:s'),'limit_num'=>11]);
 $insert('recipes_log',['menu_date'=>$date,'version'=>17,'is_delete'=>0,'create_time'=>date('Y-m-d H:i:s')]);$logs=$q($db,'SELECT ID FROM ydy_recipes_log WHERE MENU_DATE=?',[$date]);if(count($logs)!==1)throw new RuntimeException('Owned version row ambiguous');$logId=(int)$logs[0]['id'];
 require_once $root.'/application/base/Security.php';$token=\app\base\Security::encrypt(implode("\t",[(string)$actorId,$marker.'U',$marker,'0','','',$marker]));
 $http=static function(string $label,array $data,string $fault='')use($base,$token,$date,&$samples,&$stage){$stage='http_'.$label;$ctx=stream_context_create(['http'=>['method'=>'POST','ignore_errors'=>true,'timeout'=>20,'follow_location'=>0,'header'=>"Content-Type: application/x-www-form-urlencoded\r\ntoken: ".$token."\r\n".($fault?"X-DB-Pilot-Case: ".$fault."\r\n":''),'content'=>http_build_query(['menu_date'=>$date,'restaurant_id'=>1,'data'=>json_encode($data)],'','&',PHP_QUERY_RFC3986)]]);$raw=(string)file_get_contents($base.'/p/bill/add',false,$ctx);preg_match('/HTTP\/\S+\s+(\d+)/',$http_response_header[0]??'',$m);$body=json_decode($raw,true);$underflow=is_array($body)&&strpos((string)($body['message']??''),'1690')!==false;$saved=$body;if(is_array($body)&&strpos((string)($body['message']??''),'SQLSTATE')!==false){$saved['message_sha']=hash('sha256',(string)$body['message']);$saved['message']='DATABASE_ERROR_REDACTED';}$samples[$label]=['http'=>(int)($m[1]??0),'body'=>$saved,'mysql_1690'=>$underflow];if((int)($m[1]??0)!==200||!is_array($body))throw new RuntimeException('Invalid formal HTTP');return $body;};
 $item=static function(string $uuid,int $meal=1){return ['uuid'=>$uuid,'meal_times'=>$meal,'type'=>1];};
 $states['initial']=$snapshot($db);$r=$http('underflow_save',[$item($uuids[0])]);$states['underflow_save']=$snapshot($connect());
 if($mode==='red'){$http('underflow_clear',[]);$states['underflow_clear']=$snapshot($connect());$observed=$lane==='B'?$samples['underflow_save']['mysql_1690']:(($r['code']??null)===0&&(int)$states['underflow_save']['dishes'][0]['menu_quantity']!==2);$result['status']=$observed?'red_observed':'not_reproduced';}
 else{
  $checks['underflow_fixed']=($r['code']??null)===0&&count($states['underflow_save']['recipes'])===2&&(int)$states['underflow_save']['dishes'][0]['menu_quantity']===2;
  $r=$http('replace',[$item($uuids[1]),$item($uuids[1],2)]);$states['replace']=$snapshot($connect());$checks['replace']=($r['code']??null)===0&&count($states['replace']['recipes'])===3&&(int)$states['replace']['dishes'][0]['menu_quantity']===1&&(int)$states['replace']['dishes'][1]['menu_quantity']===2;
  $r=$http('repeat_save',[$item($uuids[1]),$item($uuids[1],2)]);$states['repeat_save']=$snapshot($connect());$checks['repeat_save']=($r['code']??null)===0&&count($states['repeat_save']['recipes'])===3&&(int)$states['repeat_save']['dishes'][1]['menu_quantity']===2;
  $r=$http('clear',[]);$states['clear']=$snapshot($connect());$checks['clear']=($r['code']??null)===0&&count($states['clear']['recipes'])===1&&(int)$states['clear']['dishes'][0]['menu_quantity']===1&&(int)$states['clear']['dishes'][1]['menu_quantity']===0;
  $r=$http('repeat_clear',[]);$checks['repeat_clear']=($r['code']??null)===0&&count($snapshot($connect())['recipes'])===1;
  $r=$http('no_meal_setup',[$item($uuids[0]),$item($uuids[1],2)]);$beforeKeep=$snapshot($connect());
  require $root.'/env.php';require $root.'/external_stubs.php';define('APP_PATH',$root.'/application/');require $root.'/thinkphp/base.php';\think\App::initCommon();\think\Config::set($cfg,'database');\think\Config::set('isSanmeiLiuyang',false);\think\Db::clear();$service=new \app\p\logic\Bill();$cli=$service->add([$item($uuids[0])],$date,1,[2]);$states['no_meal']=$snapshot($connect());$result['cli_no_meal_response']=$cli;
  $kept=static function(array $s){return array_values(array_filter($s['recipes'],static function(array $r){return (int)$r['restaurant_id']===1&&(int)$r['meal_times']===2;}));};
  $checks['no_meal_real_service']=($r['code']??null)===0&&($cli['code']??null)===0&&$kept($beforeKeep)===$kept($states['no_meal'])&&(int)$states['no_meal']['dishes'][0]['menu_quantity']===2&&(int)$states['no_meal']['dishes'][1]['menu_quantity']===1;
  $r=$http('final_clear',[]);$checks['final_clear']=($r['code']??null)===0&&count($snapshot($connect())['recipes'])===1;
  $foreign=static function(array $s){return array_values(array_filter($s['recipes'],static function(array $r){return (int)$r['restaurant_id']===2;}));};$checks['other_restaurant_exactly_unchanged']=true;foreach($states as $s)if($foreign($s)!==$foreign($states['initial']))$checks['other_restaurant_exactly_unchanged']=false;
  $checks['never_negative']=true;foreach($states as $s)foreach($s['dishes'] as $dish)if((int)$dish['menu_quantity']<0)$checks['never_negative']=false;
  $result['status']=!in_array(false,$checks,true)?'pass':'assertion_failed';
 }
}finally{
 $stage='cleanup';$owned=$q($db,'SELECT ID,UUID FROM ydy_dishes WHERE UUID IN (?,?) AND CREATE_BY=?',[$uuids[0],$uuids[1],$marker]);
 if(count($owned)===2){$other=$q($db,'SELECT DISHES_UUID FROM ydy_recipes WHERE MENU_DATE=?',[$date]);foreach($other as $row)if(!in_array($row['dishes_uuid'],$uuids,true))throw new RuntimeException('Foreign recipe appeared; deny cleanup');$s=$db->prepare('DELETE FROM ydy_recipes WHERE MENU_DATE=? AND DISHES_UUID IN (?,?)');$s->execute([$date,$uuids[0],$uuids[1]]);if($logId>0){$s=$db->prepare('DELETE FROM ydy_recipes_log WHERE MENU_DATE=? AND ID=?');$s->execute([$date,$logId]);}}
 foreach($uuids as $uuid){$s=$db->prepare('DELETE FROM ydy_dishes WHERE UUID=? AND CREATE_BY=?');$s->execute([$uuid,$marker]);}
 $s=$db->prepare('DELETE FROM ydy_user WHERE UUID=? AND ACCOUNT=? AND CREATE_BY=?');$s->execute([$marker.'U',$marker,$marker]);
 $result['owned_log_id']=$logId;$result['checks']=$checks;$result['samples']=$samples;$result['states']=$states;$result['natural_after']=$natural($connect());$result['natural_unchanged']=$result['natural_before']===$result['natural_after'];
 file_put_contents(__DIR__.'/result-'.$lane.'.json',json_encode($result,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));echo json_encode(['status'=>$result['status'],'lane'=>$lane,'samples'=>count($samples),'checks'=>$checks,'natural_unchanged'=>$result['natural_unchanged']]).PHP_EOL;
}
exit(in_array($result['status'],['pass','red_observed'],true)&&$result['natural_unchanged']?0:2);
