<?php
const PF2_PLAN_SHA='9a3df53e798ad01720a47bb1a1695ed0fd82df986c6228f9606826327123a86c';
const PF2_BASELINE_RAW_SHA='477dfdfa69b3fa380629661a6e7521d8e9dff3a59003ec684270b2deb0f9efca';
const PF2_RUNTIME='/tmp/cdx-prepay-formal-2ddl-root-20261011';
function pf2_need($v,$message){if(!$v)throw new RuntimeException($message);}
function pf2_json($v){$j=json_encode($v,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRESERVE_ZERO_FRACTION);
 pf2_need($j!==false,'JSON encoding');
 return $j;}
function pf2_canonical($v){if(!is_array($v))return $v;
 foreach($v as &$x)$x=pf2_canonical($x);unset($x);
 if($v!==[]&&array_keys($v)!==range(0,count($v)-1))ksort($v,SORT_STRING);
 return $v;}
function pf2_equal($a,$b,$label){pf2_need(pf2_canonical($a)===pf2_canonical($b),$label);}
function pf2_gate($p){
 $file=__DIR__.'/../plan.json';
 pf2_need(hash_file('sha256',$file)===PF2_PLAN_SHA,'Frozen Root plan bytes');
 pf2_equal($p,json_decode(file_get_contents($file),true),'Exact external literal plan');
 $counts=['read'=>0,'DDL'=>0];
 foreach($p['steps']as $i=>$s){pf2_need($s['ordinal']===$i+1&&isset($counts[$s['kind']]),'Exact ordinal/read-or-DDL');
 $counts[$s['kind']]++;
 pf2_need(count($s['binds'])===count($s['PDO_types'])&&substr_count($s['SQL'],'?')===count($s['binds']),'Exact bind arity');
 foreach($s['binds']as $j=>$v)pf2_need(is_string($v)&&$s['PDO_types'][$j]===2,'Exact string/PDO2 bind');}
 pf2_equal($counts,['read'=>52,'DDL'=>2],'52read/2DDL only');
 foreach(['ALTER'=>'alter-five-date.sql','CREATE_TRIGGER'=>'create-prepay-trigger.sql']as $k=>$f)pf2_need(hash_file('sha256',__DIR__.'/../'.$f)===$p['DDL_file_SHA256'][$k],'Frozen reviewed DDL file '.$k);
 return $counts;
}
function pf2_baseline($file,$p){
 pf2_need(is_file($file)&&!is_link($file)&&(fileperms($file)&0777)===0600&&(fileperms(dirname($file))&0777)===0700,'Private baseline600/dir700');
 $b=json_decode(file_get_contents($file),true);
 pf2_need($b['source_raw_sha256']===PF2_BASELINE_RAW_SHA,'Original approved baseline raw SHA');
 foreach($b['records']as $label=>$r)pf2_need(hash('sha256',pf2_json(['rows'=>$r['rows'],'types'=>$r['native_types']]))===$p['baseline']['metadata_group_native_SHA'][$label],'Baseline original record SHA '.$label);
 pf2_rows($b['records']['rows_before'],$b,$p,false);
 pf2_equal($b['records']['rows_before']['rows'],$b['records']['rows_after']['rows'],'Original baseline read-window stable');
 return $b;
}
function pf2_physical($r,$types,$cols){$v=[];
 $t=[];
 foreach($cols as $c){$k=strtolower($c);
 pf2_need(array_key_exists($k,$r)&&array_key_exists($k,$types),'Complete native column/type '.$c);
 $v[$k]=$r[$k];
 $t[$k]=$types[$k];}return ['values'=>$v,'native_types'=>$t];}
function pf2_rows($rec,$b,$p,$calibrated){
 $cols=array_column($b['records']['columns']['rows'],'column_name');
 $dates=array_keys($p['baseline']['date_map'][1]);
 pf2_need(count($cols)===27&&count($rec['rows'])===2,'Exact27 columns/2 protected rows');
 $old=$b['records']['rows_before'];
 foreach($rec['rows']as $i=>$r){$id=$r['id_exact'];
 pf2_need($id===(string)($i+1),'Exact original IDs1,2/order');
 $actual=pf2_physical($r,$rec['native_types'][$i],$cols);
 $base=pf2_physical($old['rows'][$i],$old['native_types'][$i],$cols);
 $other=array_values(array_diff($cols,$dates));
  pf2_need(hash('sha256',pf2_json(pf2_physical($old['rows'][$i],$old['native_types'][$i],$other)))===$p['baseline']['protected'][$id]['other22_native_sha256'],'Approved other22 baseline SHA');
  pf2_equal(pf2_physical($r,$rec['native_types'][$i],$other),pf2_physical($old['rows'][$i],$old['native_types'][$i],$other),'Other22 native values/types/full4LOB exact');
  foreach($dates as $c){$k=strtolower($c);
 $map=$p['baseline']['date_map'][$id][$c];
 $want=$calibrated?$map['source_fsp0']:$base['values'][$k];
 pf2_need($actual['values'][$k]===$want&&$actual['native_types'][$k]===$base['native_types'][$k],'Exact old date calibration/native type '.$c);
 pf2_need($r['f_'.$k]===($calibrated?$want.'.000000':$map['original']),'Original FF6/calendar map '.$c);}
 }
}
function pf2_expected_columns($cols,$calibrated){if(!$calibrated)return $cols;
 foreach($cols as &$c)if(in_array($c['column_name'],['EXPIRE_TIME','PAY_TIME','SHIP_TIME','CREATE_TIME','UPDATE_TIME'],true)){$c['data_scale']=0;
 if(in_array($c['column_name'],['CREATE_TIME','UPDATE_TIME'],true)){$c['data_default']='CURRENT_TIMESTAMP(0)';
 $c['default_length']=strlen($c['data_default']);}}unset($c);
 return $cols;}
function pf2_expected_ddl($ddl,$calibrated){if(!$calibrated)return $ddl;
 foreach(['EXPIRE_TIME','PAY_TIME','SHIP_TIME','CREATE_TIME','UPDATE_TIME']as $c){$old='"'.$c.'" DATETIME(6)';
 pf2_need(substr_count($ddl,$old)===1,'One source date declaration');
 $ddl=str_replace($old,'"'.$c.'" DATETIME(0)',$ddl);
 if(in_array($c,['CREATE_TIME','UPDATE_TIME'],true))$ddl=str_replace('"'.$c.'" DATETIME(0) DEFAULT CURRENT_TIMESTAMP NOT NULL','"'.$c.'" DATETIME(0) DEFAULT CURRENT_TIMESTAMP(0) NOT NULL',$ddl);}return $ddl;}
function pf2_tokens($s){preg_match_all('~\x27(?:\x27\x27|[^\x27])*\x27|"(?:""|[^"])*"|--[^\r\n]*|[A-Za-z_][A-Za-z0-9_$]*|(?:<>|:=|<=|>=)|[^\s]~u',$s,$m);
 $out=[];
 foreach($m[0]as $t)if(substr($t,0,2)!=='--')$out[]=($t[0]===chr(39)||$t[0]===chr(34))?$t:strtoupper($t);
 return $out;}
function pf2_trigger($sql,$approved){
 foreach([$sql,$approved]as $i=>$s){pf2_need(preg_match('/FOR\s+EACH\s+ROW\b/i',$s,$m,PREG_OFFSET_CAPTURE)===1,'Full trigger row header');
 $pos=$m[0][1]+strlen($m[0][0]);
 $bodies[$i]=pf2_tokens(substr($s,$pos));
 $h=pf2_tokens(substr($s,0,$pos));
 $headers[$i]=[];
 foreach($h as $t)if(!in_array($t,['OR','REPLACE'],true))$headers[$i][]=$t[0]===chr(34)?strtoupper(substr($t,1,-1)):$t;}
 pf2_equal($headers[0],$headers[1],'Exact owned trigger header');
 pf2_equal($bodies[0],$bodies[1],'Complete literal-preserving26-field trigger body');
}
function pf2_phase($stage,$b,$p,$phase){
 $calibrated=$phase!=='pre_2ddl_fresh_stable';
 $trigger=$phase==='after_trigger_stable';
 $base=$b['records'];
 pf2_need(count($stage)===17,'All17 literal phase reads complete');
 foreach(['identity','version','indexes','index_columns','constraints','constraint_columns','foreign_keys']as $k)pf2_equal($stage[$k]['rows'],$base[$k]['rows'],'Exact unchanged source metadata '.$k);
 foreach(['row_count_before','row_count_after']as $k)pf2_equal($stage[$k]['rows'],$base[$k]['rows'],'Original rowcount2');
 pf2_equal($stage['columns']['rows'],pf2_expected_columns($base['columns']['rows'],$calibrated),'Only five scale/default/defaultLength changes');
 pf2_equal($stage['table_ddl']['rows'][0]['ddl'],pf2_expected_ddl($base['table_ddl']['rows'][0]['ddl'],$calibrated),'Only five date GET_DDL declarations');
 foreach(['rows_before','rows_after']as $k)pf2_rows($stage[$k],$b,$p,$calibrated);
 pf2_equal($stage['rows_before']['rows'],$stage['rows_after']['rows'],'All27 row read-window stability');
 pf2_equal($stage['rows_before']['native_types'],$stage['rows_after']['native_types'],'All27 native type read-window stability');
 foreach(['rows_before','rows_after']as $k){pf2_equal($stage[$k]['native_float_bits'],$base[$k]['native_float_bits'],'All native float bits protected');
 pf2_equal($stage[$k]['native_streams'],$base[$k]['native_streams'],'Original native stream branch protected');
 pf2_equal($stage[$k]['native_keys'],$base[$k]['native_keys'],'Original native key order retained');}
 if(!$trigger){foreach(['triggers','new_trigger_collision','objects','dependencies']as $k)pf2_equal($stage[$k]['rows'],$base[$k]['rows'],'Pre-trigger original0/collision0/TABLE-only '.$k);
 return true;}
 $rows=$stage['triggers']['rows'];
 pf2_need(count($rows)===1,'One own trigger');
 $t=$rows[0];
 pf2_need($t['trigger_name']===$p['trigger']&&$t['table_name']==='YDY_PREPAY_ORDER'&&$t['table_owner']==='ZHCT_APP'&&$t['status']==='Y'&&$t['triggering_type']==='BEFORE ROW'&&$t['triggering_event']==='UPDATE','Actual own trigger Y BEFORE ROW UPDATE');
 pf2_equal($rows,$stage['new_trigger_collision']['rows'],'Both original trigger queries same actual result');
 $objects=$base['objects']['rows'];
 $objects[]=['object_name'=>$p['trigger'],'object_type'=>'TRIGGER','status'=>'VALID'];usort($objects,static function($a,$b){return strcmp($a['object_name'],$b['object_name']);});
 pf2_equal($stage['objects']['rows'],$objects,'WHERE filters exact TABLE+TRIGGER VALID only, not PK');
 pf2_equal($stage['dependencies']['rows'],$b['expected_owned_dependencies'],'Only proven owned trigger dependency shape');
 pf2_trigger($t['trigger_body'],$p['steps'][35]['SQL']);
 return true;
}
function pf2_materialize($rows){$types=[];
 $keys=[];
 $streams=[];
 $bits=[];
 foreach($rows as $i=>&$r){$keys[$i]=array_keys($r);
 foreach($r as $k=>&$v){$n=strtolower($k);
 $types[$i][$n]=gettype($v);
 if(is_float($v))$bits[$i][$n]=bin2hex(pack('d',$v));
 if(is_resource($v)){$v=stream_get_contents($v);
 pf2_need(is_string($v),'Complete original stream');
 $streams[$i][$n]=['bytes'=>strlen($v),'sha256'=>hash('sha256',$v)];}}unset($v);
 $r=array_change_key_case($r,CASE_LOWER);}unset($r);
 return ['rows'=>$rows,'native_types'=>$types,'native_keys'=>$keys,'native_streams'=>$streams,'native_float_bits'=>$bits];}
function pf2_append($h,$event){$j=pf2_json($event)."\n";
 pf2_need(fwrite($h,$j)===strlen($j)&&fflush($h),'Append-before/raw result durable');}
function pf2_connect(){
 $file='/tmp/zhct-dm-poc-20260928.fcpiiN/store/application/database.php';
 pf2_need(realpath($file)===$file&&!is_link($file),'Original code config');
 $cfg=(static function($f){return require $f;})($file);
 pf2_need($cfg['hostname']==='127.0.0.1'&&(string)$cfg['hostport']==='5237'&&$cfg['database']==='ZHCT_APP'&&getenv('POC_HOST')==='127.0.0.1'&&getenv('POC_PORT')==='5237'&&getenv('POC_SCHEMA')==='ZHCT_APP'&&getenv('POC_EXTERNAL_STUBS')==='1'&&getenv('POC_REAL_QUEUE')==='0','Original nonprod loopback C boundary');
 $db=new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP',$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false]);unset($cfg);
 return $db;
}
function pf2_execute($p,$approval){
 pf2_need(isset($approval['baseline_path'],$approval['baseline_sha256'],$approval['runner_sha256'])&&getenv('PF2_ACTOR')==='ROOT'&&getenv('PF2_WINDOW')==='DISEASE_SEALED_ROOT_RELEASED','Root-only explicit protection-window release before config/connection');
 pf2_gate($p);
 pf2_need(getenv('PF2_ROOT_PLAN_SHA')===PF2_PLAN_SHA&&getenv('PF2_ROOT_RUNNER_SHA')===$approval['runner_sha256']&&hash_file('sha256',__FILE__)===$approval['runner_sha256']&&getenv('PF2_ROOT_BASELINE_SHA')===$approval['baseline_sha256']&&hash_file('sha256',$approval['baseline_path'])===$approval['baseline_sha256'],'Exact Root plan/runner/private baseline approval');
 $b=pf2_baseline($approval['baseline_path'],$p);
 pf2_need(!file_exists(PF2_RUNTIME)&&!is_link(PF2_RUNTIME)&&mkdir(PF2_RUNTIME,0700),'Exclusive once Root runtime; never replay successful DDL');
 $h=fopen(PF2_RUNTIME.'/events.jsonl','x');
 pf2_need(is_resource($h)&&chmod(PF2_RUNTIME.'/events.jsonl',0600),'Private original journal');
 $state=['cursor'=>0,'read'=>0,'DDL'=>0,'pre_proven'=>false,'alter_proven'=>false,'final_proven'=>false];
 $stage=[];
 $stmt=null;
 try{pf2_append($h,['event'=>'start','approval'=>$approval,'plan_sha256'=>PF2_PLAN_SHA,'source_baseline_raw_sha256'=>PF2_BASELINE_RAW_SHA]);
 $db=pf2_connect();
  foreach($p['steps']as $s){pf2_need($s===$p['steps'][$state['cursor']]&&$state[$s['kind']]<$p['budget'][$s['kind']],'Exact next statement/budget, no retry');
 if($s['kind']==='DDL')pf2_need($s['ordinal']===18?($state['pre_proven']&&$state['DDL']===0):($s['ordinal']===36&&$state['alter_proven']&&$state['DDL']===1),'DDL only after complete phase protection');
   pf2_append($h,['event'=>'append-before','statement'=>$s,'state'=>$state]);
 $state[$s['kind']]++;
 $stmt=$db->prepare($s['SQL']);
 foreach($s['binds']as $i=>$v)pf2_need($stmt->bindValue($i+1,$v,$s['PDO_types'][$i]),'Exact original native bind');
 pf2_need($stmt->execute(),'Native statement success');
   if($s['kind']==='DDL')pf2_append($h,['event'=>'original-DDL-result','statement'=>$s,'rowCount'=>$stmt->rowCount(),'errorInfo'=>$stmt->errorInfo()]);
   else{$rec=pf2_materialize($stmt->fetchAll(PDO::FETCH_ASSOC));
 pf2_append($h,array_merge(['event'=>'original-read-result','statement'=>$s,'errorInfo'=>$stmt->errorInfo()],$rec));
 pf2_need(count($rec['rows'])<=1000,'Bounded catalog/result rows');
 if(in_array($s['label'],['identity','version'],true))pf2_equal($rec['rows'],$b['records'][$s['label']]['rows'],'Immediate exact identity/build before next read');
 if(strpos($s['label'],'row_count_')===0)pf2_need(count($rec['rows'])===1&&(string)$rec['rows'][0]['cnt']==='2','Exactly old2 rows before any full-row read');
    if($s['phase']==='after_trigger_definition'){pf2_need($state['final_proven']&&count($rec['rows'])===1,'Final actual trigger definition');
 pf2_trigger($rec['rows'][0]['ddl'],$p['steps'][35]['SQL']);}
    else{$stage[$s['phase']][$s['label']]=$rec;
 if($s['label']==='rows_after'){pf2_phase($stage[$s['phase']],$b,$p,$s['phase']);
 $key=$s['phase']==='pre_2ddl_fresh_stable'?'pre_proven':($s['phase']==='after_alter_stable'?'alter_proven':'final_proven');
 $state[$key]=true;
 pf2_append($h,['event'=>'protected-phase','phase'=>$s['phase'],'state'=>$state]);}}
   }$state['cursor']++;
  }pf2_need($state['read']===52&&$state['DDL']===2&&$state['final_proven'],'Exact complete formal ledger');
 pf2_append($h,['event'=>'complete','state'=>$state,'DML'=>0,'HTTP'=>0,'Auth'=>0]);fclose($h);
 return 0;
 }catch(Throwable $e){pf2_append($h,['event'=>'stopped_no_retry_no_DROP_no_reverse_mutation','class'=>get_class($e),'code'=>$e->getCode(),'message'=>$e->getMessage(),'errorInfo'=>$stmt?$stmt->errorInfo():null,'state'=>$state]);fclose($h);fwrite(STDERR,pf2_json(['status'=>'STOPPED_ORIGINAL_STATE_RETAINED','state'=>$state])."\n");
 return 1;}
}
if(realpath($_SERVER['SCRIPT_FILENAME'])===__FILE__){try{$p=json_decode(file_get_contents(__DIR__.'/../plan.json'),true);
 $counts=pf2_gate($p);
 $mode=$argv[1]??'--gate';
 if($mode==='--gate'){if(isset($argv[2]))pf2_baseline($argv[2],$p);echo pf2_json(['status'=>'PURE_ROOT_RUNNER_GATE_GREEN','counts'=>$counts,'plan_sha256'=>PF2_PLAN_SHA,'runner_sha256'=>hash_file('sha256',__FILE__),'DB_connections'=>0,'SQL'=>0])."\n";exit(0);}pf2_need($mode==='--execute'&&isset($argv[2]),'Root explicit execute/private baseline path');exit(pf2_execute($p,['baseline_path'=>$argv[2],'baseline_sha256'=>getenv('PF2_ROOT_BASELINE_SHA'),'runner_sha256'=>getenv('PF2_ROOT_RUNNER_SHA')]));}catch(Throwable $e){fwrite(STDERR,$e->getMessage()."\n");exit(1);}}
