<?php
set_exception_handler(static function(Throwable $e):void{$message=preg_replace('/[\'"][^\'"]*[\'"]/','<redacted>',$e->getMessage());echo json_encode(['safe'=>false,'class'=>get_class($e),'reason'=>substr($message,0,300)]),"\n";exit(2);});
require __DIR__.'/db.php';$mode=$argv[1]??'preflight';$table=$p.'annex';$fields=['id','uuid','master_uuid','name','file_path','upload_time','file_size'];
if($mode==='preflight'){
 $check($lane==='B'?strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')===0:$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()==='ZHCT_APP','DB identity');
 $lock=['route.php'=>'081b0186b7f40f0bdd237cecb3e2d678fc9344c656932c0d3b3052404e4f1510','p/controller/TrainAnnex.php'=>'49a8745836e04247d394884811e3803c62a5892ff0084f850c4b463d0aa8fbb4','p/logic/TrainAnnex.php'=>'bcf5b789ac5e197708740f945b4f732b63205af6e9af4c2870c265fb5d15b5bf','model/TrainAnnex.php'=>'7ff493e018148c7aedcbebb14848379ec86f806dcc9cd091da72eca4d0b1a875'];foreach($lock as $f=>$sha)$check(hash_file('sha256',__DIR__.'/source/application/'.$f)===$sha,'Source drift');$save('private-lock.json',$lock);
 $columns=$lane==='B'?$q('SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA,DATETIME_PRECISION FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',[$table]):$q('SELECT COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[strtoupper($table)]);$check($columns!==[],'Annex source absent');
 $first=$q('SELECT MASTER_UUID FROM '.$table.' WHERE ID=(SELECT MIN(ID) FROM '.$table.')');$scope=(string)($first[0]['master_uuid']??'');if($scope==='')$scope='00000000-0000-4000-8000-000000001011';$empty='00000000-0000-4000-8000-000000001012';
 $missing=array_values(array_diff($fields,array_map('strtolower',array_column($columns,'column_name'))));$source=$q('SELECT * FROM '.$table.' WHERE MASTER_UUID=? ORDER BY ID DESC',[$scope]);$check($q('SELECT ID FROM '.$table.' WHERE MASTER_UUID=?',[$empty])===[],'Empty sentinel not empty');
 $actor=$q('SELECT ID,UUID,STAFF_UUID,ACCOUNT,TYPE,IS_DELETE FROM '.$p.'user WHERE ID=(SELECT MIN(ID) FROM '.$p.'user WHERE TYPE=0 AND IS_DELETE=0)')[0];
 $private=['scope'=>$scope,'empty'=>$empty,'source'=>$source,'actor'=>$actor,'columns'=>$columns,'missing_projection_columns'=>$missing];$save('private-baseline.json',$private);
 $out=['lane'=>$lane,'safe'=>true,'business_dml'=>0,'ddl'=>0,'annex_columns'=>$columns,'missing_projection_columns'=>$missing,'fixed_scope_rows'=>count($source),'fixed_scope_sha256'=>$hash($source),'actor_projection_sha256'=>$hash($actor),'unit_controller_present'=>false,'unit_probe_not_business_success'=>true,'source_lock'=>$lock,'original_debug'=>$cfg['debug']??null,'unrelated_background'=>'unknown'];$save('sanitized-preflight.json',$out);echo json_encode($out),"\n";exit;
}
$baseline=json_decode(file_get_contents(__DIR__.'/private-baseline.json'),true);
if($mode==='prepare'){
 require_once $root.'/application/base/Security.php';$a=$baseline['actor'];$token=\app\base\Security::encrypt(implode("\t",[(string)$a['id'],(string)$a['uuid'],'CDXTRAINADMIN','0','','','CDXTRAINADMIN']));
 $expected=$baseline['source'];foreach($expected as &$r){foreach(['id']as $k)$r[$k]=(int)$r[$k];if(is_string($r['upload_time'])&&preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{1,6}$/',$r['upload_time']))$r['upload_time']=substr($r['upload_time'],0,19);}unset($r);
 $spec=[];foreach(['lists','info','allunit']as $action)$spec[]=['label'=>'unit-'.$action,'path'=>'/p/trainunit/'.$action,'params'=>[],'kind'=>'missing-controller'];
 foreach([1,2]as $page)$spec[]=['label'=>'annex-page-'.$page,'path'=>'/p/trainannex/lists','params'=>['uuid'=>$baseline['scope'],'type'=>1,'page'=>$page,'pagesize'=>2],'kind'=>'query','expected'=>['rows'=>array_slice($expected,($page-1)*2,2),'total'=>count($expected)]];
 $spec[]=['label'=>'annex-empty','path'=>'/p/trainannex/lists','params'=>['uuid'=>$baseline['empty'],'type'=>1,'pagesize'=>2],'kind'=>'query','expected'=>['rows'=>[],'total'=>0]];$spec[]=['label'=>'annex-missing-uuid','path'=>'/p/trainannex/lists','params'=>['type'=>1],'kind'=>'rejection','message'=>'参数错误'];$spec[]=['label'=>'annex-missing-type','path'=>'/p/trainannex/lists','params'=>['uuid'=>$baseline['scope']],'kind'=>'rejection','message'=>'类型为空'];
 $spec=array_values(array_filter($spec,static function($s){return $s['kind']==='missing-controller'||$s['label']==='annex-page-1';}));if($baseline['missing_projection_columns'])foreach($spec as &$s)if($s['kind']==='query')$s['kind']='missing-column';unset($s);$items=[];foreach($spec as $i=>$s){$tests=["const b=pm.response.json();"];if($s['kind']==='missing-controller'){$tests[]="pm.test('HTTP404 missing controller',()=>pm.response.to.have.status(404));";$tests[]="pm.test('missing controller is not business success',()=>{pm.expect(b.code).not.to.eql(0);pm.expect(b.message).to.match(/trainunit|controller|控制器/i)});";}elseif($s['kind']==='missing-column'){$tests[]="pm.test('shared source column gap is not business success',()=>{pm.expect(b.code).not.to.eql(0);pm.expect(b.message).to.match(/upload_time/i)});";}else{$tests[]="pm.test('HTTP200',()=>pm.response.to.have.status(200));";$tests[]="pm.test('business code',()=>pm.expect(b.code).to.eql(".($s['kind']==='rejection'?1:0)."));";if($s['kind']==='query')$tests[]='pm.test("independent seven-column source values and native JSON shape",()=>pm.expect(b.data).to.deep.equal('.json_encode($s['expected'],JSON_UNESCAPED_UNICODE).'));';else $tests[]='pm.test("specific rejection",()=>pm.expect(b.message).to.eql('.json_encode($s['message'],JSON_UNESCAPED_UNICODE).'));';}
  $items[]=['id'=>'train-read-'.$i,'name'=>$s['label'],'type'=>'http','metaInfo'=>['type'=>'HTTP'],'request'=>['method'=>'POST','header'=>[['key'=>'token','value'=>$token],['key'=>'X-CDX-Case','value'=>$s['label']],['key'=>'Content-Type','value'=>'application/x-www-form-urlencoded']],'url'=>'http://127.0.0.1:'.($lane==='B'?18321:18322).$s['path'],'body'=>['mode'=>'urlencoded','urlencoded'=>array_map(static function($k,$v){return ['key'=>$k,'value'=>(string)$v,'type'=>'text'];},array_keys($s['params']),array_values($s['params']))]],'event'=>[['listen'=>'test','script'=>['type'=>'text/javascript','exec'=>$tests]]]];
 }
 $save('private-spec.json',$spec);$save('private-collection.apifox-cli.json',['apifoxCli'=>'2.2.8','info'=>['name'=>'Train missing source and annex readonly '.$lane],'item'=>[['name'=>'Frozen four operations','item'=>$items]]]);echo json_encode(['lane'=>$lane,'cases'=>count($spec)]),"\n";exit;
}
if($mode==='finish'){$source=$q('SELECT * FROM '.$table.' WHERE MASTER_UUID=? ORDER BY ID DESC',[$baseline['scope']]);$actor=$q('SELECT ID,UUID,STAFF_UUID,ACCOUNT,TYPE,IS_DELETE FROM '.$p.'user WHERE ID=?',[$baseline['actor']['id']])[0];$out=['lane'=>$lane,'fixed_scope_rows'=>count($source),'fixed_scope_sha256'=>$hash($source),'fixed_scope_unchanged'=>json_encode($source)===json_encode($baseline['source']),'actor_projection_unchanged'=>json_encode($actor)===json_encode($baseline['actor']),'business_dml'=>0,'ddl'=>0,'unrelated_background'=>'unknown'];$save('sanitized-finish.json',$out);echo json_encode($out),"\n";exit;}
exit(78);
