<?php
require __DIR__.'/db.php';$report=['lane'=>$lane,'safe'=>false,'business_dml'=>0,'ddl'=>0,'HTTP'=>0];try{
if($lane==='B')$check(strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')===0,'MySQL5.6');else $check($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()==='ZHCT_APP','DM identity');$report['identity_verified']=true;
$actors=$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)');$check(count($actors)===1&&(int)$actors[0]['type']===0&&(int)$actors[0]['is_delete']===0&&!empty($actors[0]['uuid']),'Actual actor');$save('private-actor.json',$actors[0]);$report['actor_sha256']=$hash($actors[0]);
foreach(['syllabus_evaluate'=>['id','uuid','staff_uuid','test_content','test_time','achievement','demo'],'syllabus_evaluate_ext'=>['id','uuid','staff_uuid','content'],'staff'=>['id','uuid']]as $name=>$required){$table=$p.$name;$cols=$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)]);if($name==='staff')$cols=array_values(array_filter($cols,static function($r){return in_array(strtolower($r['column_name']),['id','uuid'],true);}));$names=array_map(static function($r){return strtolower($r['column_name']);},$cols);$missing=array_values(array_diff($required,$names));$report['tables'][$name]=['columns'=>$cols,'missing'=>$missing];$check($missing===[],'Required table or columns absent '.$name);if($name!=='staff')$report['tables'][$name]['indexes']=$lane==='B'?$q('SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',[$table]):$q('SELECT I.INDEX_NAME,I.UNIQUENESS,C.COLUMN_POSITION,C.COLUMN_NAME FROM USER_INDEXES I JOIN USER_IND_COLUMNS C ON I.INDEX_NAME=C.INDEX_NAME WHERE I.TABLE_NAME=? ORDER BY I.INDEX_NAME,C.COLUMN_POSITION',[strtoupper($table)]);}
$sql='SELECT E.STAFF_UUID,COUNT(*) AS CNT FROM '.$p.'syllabus_evaluate E WHERE E.STAFF_UUID IS NOT NULL AND EXISTS (SELECT 1 FROM '.$p.'staff S WHERE S.UUID=E.STAFF_UUID) GROUP BY E.STAFF_UUID HAVING COUNT(*) BETWEEN 1 AND 100 ORDER BY E.STAFF_UUID';$groups=$q($lane==='B'?$sql.' LIMIT 1':'SELECT * FROM ('.$sql.') WHERE ROWNUM<=1');$nonempty=$groups!==[];if($nonempty)$staff=$groups[0]['staff_uuid'];else{$seed=$q('SELECT UUID FROM '.$p.'staff WHERE ID=(SELECT MIN(ID) FROM '.$p.'staff WHERE UUID IS NOT NULL)');$check(count($seed)===1,'No existing Staff for empty read');$staff=$seed[0]['uuid'];}
$save('private-scope.json',['staff_uuid'=>$staff,'natural_nonempty'=>$nonempty]);require __DIR__.'/oracle.php';$state=$source();$save('private-baseline.json',['source'=>$state,'actor'=>$actors[0]]);$report['natural_rows']=count($state['rows']);$report['ext_rows']=count($state['ext']);$report['source_sha256']=$hash($state);require __DIR__.'/init.php';$pagesize=\think\Config::get('pagesize');$check(is_numeric($pagesize)&&(int)$pagesize>=1&&(int)$pagesize<=100,'Actual original pagesize bounded');$report['pagesize']=(int)$pagesize;$report['safe']=true;
}catch(Throwable $e){$save('private-preflight-error.json',['class'=>get_class($e),'message'=>$e->getMessage()]);$report['failure']=['class'=>get_class($e),'reason_sha256'=>hash('sha256',$e->getMessage())];}$save('private-preflight.json',$report);echo json_encode($report,JSON_UNESCAPED_UNICODE),"\n";exit($report['safe']?0:2);
