<?php
date_default_timezone_set('Asia/Shanghai');
function pp_read($db,$sql,$bind=[],$label=''){
 // Only this explicit new independent money projection differs by dialect.
 if($label==='scan-new-meal112-and-all-decimal-CAST'&&getenv('PP_SIDE')==='C')$sql=str_replace(' AS CHAR) cast_',' AS VARCHAR(100)) cast_',$sql);
 return pp_read_actual($db,$sql,$bind,$label);
}
function pp_need($v,$m){if(!$v)throw new RuntimeException($m);}
function pp_json($v){$j=json_encode($v,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRESERVE_ZERO_FRACTION);pp_need($j!==false,'JSON encoding');return $j;}
function pp_base(){return dirname(__DIR__);}
function pp_private(){return pp_base().'/private';}
function pp_input($name){return json_decode(file_get_contents(pp_base().'/private-input/'.getenv('PP_SIDE').'/'.$name),true);}
function pp_saved($name){return json_decode(file_get_contents(pp_private().'/'.$name),true);}
function pp_save($name,$v){$f=pp_private().'/'.$name;$h=fopen($f,'x');pp_need(is_resource($h),'Immutable own evidence collision '.$name);chmod($f,0600);$j=pp_json($v)."\n";pp_need(fwrite($h,$j)===strlen($j)&&fflush($h),'Durable evidence');fclose($h);}
function pp_event($r){$r['side']=getenv('PP_SIDE');$r['phase']=getenv('PP_PHASE');$r['microtime']=microtime(true);$f=pp_private().'/events.jsonl';$h=fopen($f,'a');pp_need(is_resource($h)&&flock($h,LOCK_EX),'Journal lock');chmod($f,0600);$s=pp_json($r)."\n";pp_need(fwrite($h,$s)===strlen($s)&&fflush($h),'Append-before/result durable');flock($h,LOCK_UN);fclose($h);}
function pp_budget($category,$max){$f=pp_private().'/budget.json';$h=fopen($f,'c+');pp_need(is_resource($h)&&flock($h,LOCK_EX),'Budget lock');chmod($f,0600);$raw=stream_get_contents($h);$b=$raw===''?['total'=>0]:json_decode($raw,true);pp_need(is_array($b)&&$b['total']<350&&($b[$category]??0)<$max,'Unified350 or category read ceiling');$b['total']++;$b[$category]=($b[$category]??0)+1;rewind($h);ftruncate($h,0);fwrite($h,pp_json($b));fflush($h);flock($h,LOCK_UN);fclose($h);return $b;}
function pp_material($rows){$types=[];$bits=[];$streams=[];$keys=[];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);pp_need(is_string($v),'Full original CLOB');$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,'types'=>$types,'float_bits'=>$bits,'streams'=>$streams,'original_keys'=>$keys];}
function pp_sort($v){if(!is_array($v))return $v;foreach($v as &$x)$x=pp_sort($x);unset($x);if($v!==[]&&array_keys($v)!==range(0,count($v)-1))ksort($v);return $v;}
function pp_equal($a,$b,$m){pp_need(pp_sort($a)===pp_sort($b),$m);}
function pp_sources($role){$root=pp_base().'/source/'.$role;$pins=json_decode(file_get_contents(pp_base().'/'.$role.'-pins.json'),true);pp_need(count($pins)===($role==='ai'?6169:959),'Exact full source count');foreach($pins as $n=>$sha)pp_need(is_file($root.'/'.$n)&&!is_link($root.'/'.$n)&&hash_file('sha256',$root.'/'.$n)===$sha,'Actual approved source byte drift '.$n);return ['files'=>count($pins),'all_bytes_match'=>true];}
function pp_includes($role){$root=pp_base().'/source/'.$role.'/';$pins=json_decode(file_get_contents(pp_base().'/'.$role.'-pins.json'),true);$r=[];foreach(get_included_files()as $f)if(strpos($f,$root)===0){$n=substr($f,strlen($root));$r[$n]=hash_file('sha256',$f);pp_need(isset($pins[$n])&&$pins[$n]===$r[$n],'Actual included source SHA '.$n);}return $r;}
function pp_dsn($db){$s=getenv('POC_'.$db.'_SCHEMA');if(getenv('PP_SIDE')==='C'){pp_need(getenv('POC_'.$db.'_HOST')==='127.0.0.1'&&getenv('POC_'.$db.'_PORT')===($db==='AI'?'5238':'5237')&&$s===($db==='AI'?'AIZHCT_APP':'ZHCT_APP'),'Exact nonproduction DM pair');return 'dm:host=127.0.0.1;port='.getenv('POC_'.$db.'_PORT').';schema='.$s;}pp_need($s===($db==='AI'?'ai_zhct':'zhct'),'Exact code-local B pair');return 'mysql:host='.getenv('POC_'.$db.'_HOST').';port='.getenv('POC_'.$db.'_PORT').';dbname='.$s.';charset='.getenv('POC_'.$db.'_CHARSET');}
function pp_options(){return [PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_ORACLE_NULLS=>PDO::NULL_NATURAL,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false];}
function pp_pdo($db){static $p=[];if(!isset($p[$db]))$p[$db]=new PDO(pp_dsn($db),getenv('POC_'.$db.'_USER'),getenv('POC_'.$db.'_PASSWORD'),pp_options());return $p[$db];}
function pp_read_actual($db,$sql,$bind=[],$label=''){pp_need(preg_match('/^SELECT\b/i',$sql)&&!preg_match('/;|--|\/\*|\b(?:INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|INTO|CALL)\b/i',$sql),'Independent bounded SELECT');$budget=pp_budget('observer',getenv('PP_SIDE')==='B'?139:110);$b=[];foreach($bind as $i=>$v)$b[]=['position'=>$i+1,'value'=>$v,'PHP_type'=>gettype($v),'PDO_type'=>is_int($v)?1:2];pp_event(['event'=>'observer-before','db'=>$db,'SQL'=>$sql,'binds'=>$b,'label'=>$label,'budget'=>$budget]);$s=pp_pdo($db)->prepare($sql);foreach($b as $x)$s->bindValue($x['position'],$x['value'],$x['PDO_type']);try{$s->execute();$r=pp_material($s->fetchAll(PDO::FETCH_ASSOC));pp_event(array_merge(['event'=>'observer-result','db'=>$db,'SQL'=>$s->queryString,'label'=>$label,'errorInfo'=>$s->errorInfo(),'rowCount'=>$s->rowCount()],$r));return $r;}catch(Throwable $e){pp_event(['event'=>'observer-error','label'=>$label,'class'=>get_class($e),'message'=>$e->getMessage(),'errorInfo'=>$s->errorInfo()]);throw $e;}}
function pp_fields($a,$e){$ak=array_keys($a);$ek=array_keys($e);sort($ak);sort($ek);pp_need($ak===$ek,'Exact write field set');foreach($e as $k=>$v){if($v==='@time')pp_need(is_string($a[$k])&&preg_match('/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/D',$a[$k])&&abs(strtotime($a[$k])-time())<=5,'Source current whole-second time');elseif($v==='@expire')pp_need(is_string($a[$k])&&abs(strtotime($a[$k])-time()-900)<=5,'Original15minute expiry');elseif($v==='@no')pp_need(is_string($a[$k])&&preg_match('/^[0-9]{12,32}$/D',$a[$k]),'Original generated order number');else pp_need((string)$a[$k]===(string)$v,'Exact write field '.$k);}}
function pp_where($sql,$bind){$s=preg_replace('/[()\s]+/',' ',trim($sql));$r=[];foreach(preg_split('/\s+AND\s+/i',trim($s))as $p){pp_need(preg_match('/^(?:\w+\.)?(\w+)\s*=\s*(:\w+|\d+)$/D',trim($p),$m)===1,'Only exact bound own AND equality');$k=strtolower($m[1]);pp_need(!isset($r[$k]),'No repeated predicate');$r[$k]=$m[2][0]===':'?($bind[ltrim($m[2],':')][0]??null):(int)$m[2];}pp_need(count($r)<=2,'At most exact ID and CAS0');return $r;}
