<?php
declare(strict_types=1);
$lane=getenv('MR3_LANE');$root=getenv('MR3_ROOT');$cfg=(static function($f){return require $f;})($root.'/application/database.php');
if($lane==='B'){$local=(static function($f){return require $f;})('/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');$dsn='mysql:host='.$cfg['hostname'].';port='.($cfg['hostport']?:3306).';dbname='.$cfg['database'].';charset=utf8mb4';}else{if($cfg['hostname']!=='127.0.0.1'||(string)$cfg['hostport']!=='5237'||$cfg['database']!=='ZHCT_APP')throw new RuntimeException('DM scope');$dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';}
$db=new PDO($dsn,$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER]);$p=$lane==='B'?'ydy_':'YDY_';
$q=static function(string $sql,array $args=[])use($db):array{$s=$db->prepare($sql);$s->execute($args);$rows=[];while($r=$s->fetch(PDO::FETCH_ASSOC)){$r=array_change_key_case($r,CASE_LOWER);foreach($r as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);$rows[]=$r;if(count($rows)>10000)throw new RuntimeException('Bounded result cap');}return $rows;};
$check=static function(bool $ok,string $why):void{if(!$ok)throw new RuntimeException($why);};$hash=static function($v):string{return hash('sha256',serialize($v));};$report=['lane'=>$lane,'business_dml'=>0,'ddl'=>0,'safe'=>false,'tables'=>[],'failure'=>null];
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');
 $staff=$q('SELECT UUID,NAME,AI_USER_ID,IS_SHOW,JOB_STATUS FROM '.$p.'staff WHERE NAME LIKE ? ORDER BY ID',['CDXPAY%']);$expected=$lane==='B'?'f483ba1c130ac167b850ae5099196f085b2f5b7db2faf5787a201eb5f7dbf321':'8b7f1416ace012169e9ac5c94fceb49115287a7006c1f0712ebac2d30af000b4';$matches=array_values(array_filter($staff,static function($r)use($expected){return preg_match('/^CDXPAY[A-F0-9]{8}$/D',$r['name'])===1&&hash('sha256',$r['name'])===$expected;}));$check(count($matches)===1,'Exact synthetic staff lease');$staff=$matches[0];$users=$q('SELECT ID,UUID,STAFF_UUID,ACCOUNT,TYPE FROM '.$p.'user WHERE STAFF_UUID=? AND IS_DELETE=0',[$staff['uuid']]);$check(count($users)===1&&$users[0]['account']===$staff['name']&&(int)$staff['is_show']===1,'Exact synthetic user mapping');$report['synthetic_reference']=['marker_sha256'=>$expected,'staff_projection_sha256'=>$hash($staff),'user_projection_sha256'=>$hash($users[0]),'readonly_only'=>true];file_put_contents(__DIR__.'/private-lease.json',json_encode(['staff'=>$staff,'user'=>$users[0]]));chmod(__DIR__.'/private-lease.json',0600);
 foreach(['grade_estimation','judgment_rank']as $key){$table=$p.$key;$entry=['safe'=>false];try{$entry['columns']=$lane==='B'?$q('SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA 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($entry['columns']!==[],'Table absent');$entry['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)]);$entry['triggers']=$lane==='B'?$q('SELECT TRIGGER_NAME,EVENT_MANIPULATION FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?',[$table]):$q('SELECT TRIGGER_NAME,STATUS,TRIGGERING_EVENT FROM USER_TRIGGERS WHERE TABLE_NAME=?',[strtoupper($table)]);$entry['foreign_keys']=$lane==='B'?$q('SELECT TABLE_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND (TABLE_NAME=? OR REFERENCED_TABLE_NAME=?) ORDER BY TABLE_NAME,CONSTRAINT_NAME',[$table,$table]):$q("SELECT C.TABLE_NAME,C.CONSTRAINT_NAME,P.TABLE_NAME AS REFERENCED_TABLE_NAME FROM USER_CONSTRAINTS C LEFT JOIN USER_CONSTRAINTS P ON C.R_CONSTRAINT_NAME=P.CONSTRAINT_NAME WHERE C.CONSTRAINT_TYPE='R' AND (C.TABLE_NAME=? OR P.TABLE_NAME=?) ORDER BY C.TABLE_NAME,C.CONSTRAINT_NAME",[strtoupper($table),strtoupper($table)]);$check($entry['triggers']===[]&&$entry['foreign_keys']===[],'Unknown trigger/FK');$rows=$q('SELECT * FROM '.$table.' ORDER BY ID');$entry['rows']=count($rows);$entry['sha256']=$hash($rows);$entry['safe']=true;$entry['failure']=null;}catch(Throwable $e){$entry['failure']=['class'=>get_class($e),'reason'=>$e->getMessage()];}$report['tables'][$key]=$entry;}
 $report['safe']=(bool)array_filter($report['tables'],static function($v){return $v['safe'];});$report['original_debug']=$cfg['debug']??null;
}catch(Throwable $e){$report['failure']=['class'=>get_class($e),'reason'=>$e->getMessage()];}
file_put_contents(__DIR__.'/private-preflight.json',json_encode($report,JSON_PRETTY_PRINT));chmod(__DIR__.'/private-preflight.json',0600);if(defined('CDX_GRADE_CONTEXT')){if(!$report['safe'])throw new RuntimeException('No safe grade table');return;}echo json_encode($report),"\n";exit($report['safe']?0:2);
