<?php
declare(strict_types=1);
$lane=getenv('FOOD_LANE');$root=getenv('FOOD_ROOT');if(!in_array($lane,['B','C'],true)||__DIR__!=='/tmp/cdx-store-food-crud3-20261011')throw new RuntimeException('Exact scope before PDO');
$plan=json_decode(file_get_contents(__DIR__.'/plan.json'),true);if(($plan['approval_status']??'')!=='ROOT_APPROVED_FOOD_PRIMARY_PHASE'||$plan['ports']!==['B'=>18995,'C'=>18996])throw new RuntimeException('Concrete primary phase approval');
$map=json_decode(file_get_contents(__DIR__.'/source-lock.json'),true);if(hash_file('sha256',__DIR__.'/source-lock.json')!=='f26f6dd15e86f3b34e23cde8413b660683cc5656f542b85973581c441c747738')throw new RuntimeException('Root mapping');$actual=[];$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/source/application',FilesystemIterator::SKIP_DOTS));foreach($it as $f){if($f->isLink())throw new RuntimeException('No source symlink');if($f->isFile()){$rel=substr($f->getPathname(),strlen(__DIR__.'/source/application/'));if(strpos(basename($rel),'._')===0)throw new RuntimeException('AppleDouble');$actual[$rel]=hash_file('sha256',$f->getPathname());}}ksort($actual);ksort($map);if(count($actual)!==959||$actual!==$map)throw new RuntimeException('APP959 exact');
defined('TP_ENV')||define('TP_ENV','local');defined('BUSINESS')||define('BUSINESS','');defined('APP_PATH')||define('APP_PATH',__DIR__.'/source/application/');defined('ROOT_PATH')||define('ROOT_PATH',$root.'/');$cfg=(static function($f){return require $f;})($root.'/application/database.php');$ai=$cfg;foreach(['hostname','hostport','database','username','password','prefix']as $k)$ai[$k]=$cfg['ai_zhct'][$k]??$cfg[$k];if($cfg['prefix']!=='ydy_'||$ai['prefix']!=='yoshop_')throw new RuntimeException('Dual prefixes');
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]||$ai[$k]!==$local['ai_zhct'][$k])throw new RuntimeException('Exact code-local pair');}else foreach([[$cfg,5237,'ZHCT_APP'],[$ai,5238,'AIZHCT_APP']]as $c)if($c[0]['hostname']!=='127.0.0.1'||(int)$c[0]['hostport']!==$c[1]||$c[0]['database']!==$c[2]||$c[0]['username']!==$c[2])throw new RuntimeException('Exact loopback DM pair');
$options=[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER,PDO::ATTR_ORACLE_NULLS=>PDO::NULL_NATURAL,PDO::ATTR_STRINGIFY_FETCHES=>false,PDO::ATTR_EMULATE_PREPARES=>false];$dsn=static function($c)use($lane){return $lane==='B'?'mysql:host='.$c['hostname'].';port='.($c['hostport']?:3306).';dbname='.$c['database'].';charset='.$c['charset']:'dm:host=127.0.0.1;port='.$c['hostport'].';schema='.$c['database'];};
$save=static function($name,$v){$j=json_encode($v,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION);if($j===false)throw new RuntimeException('Finite JSON only');$h=fopen(__DIR__.'/private/'.$name,'xb');if(!$h)throw new RuntimeException('Immutable record collision');fwrite($h,$j);fclose($h);chmod(__DIR__.'/private/'.$name,0600);};
$budget=static function($kind,$max)use($lane){if(in_array($kind,['observer','business-read'],true)){foreach(['FOOD_READ_BATCH_ACTIVE'=>['read8-extra',350],'FOOD_DATE_FRESH_ACTIVE'=>['date-fresh',$lane==='B'?8:18]]as $flag=>$bound)if(!empty($GLOBALS[$flag])){$pf=__DIR__.'/private/budget-'.$bound[0].'.json';$ph=fopen($pf,'c+');flock($ph,LOCK_EX);$pn=(int)stream_get_contents($ph);if($pn>=$bound[1])throw new RuntimeException('Phase readonly cap');rewind($ph);ftruncate($ph,0);fwrite($ph,(string)($pn+1));flock($ph,LOCK_UN);fclose($ph);chmod($pf,0600);}$f=__DIR__.'/private/budget-total-read.json';$h=fopen($f,'c+');flock($h,LOCK_EX);$v=stream_get_contents($h);$n=$v!==''?(int)$v:($lane==='B'?12:11);if($n>=800)throw new RuntimeException('All readonly hard cap800 incl prior');rewind($h);ftruncate($h,0);fwrite($h,(string)($n+1));flock($h,LOCK_UN);fclose($h);chmod($f,0600);}$f=__DIR__.'/private/budget-'.$kind.'.json';$h=fopen($f,'c+');flock($h,LOCK_EX);$n=(int)stream_get_contents($h);if($n>=$max)throw new RuntimeException('Budget '.$kind);rewind($h);ftruncate($h,0);fwrite($h,(string)($n+1));flock($h,LOCK_UN);fclose($h);chmod($f,0600);};
$db=new PDO($dsn($cfg),$cfg['username'],$cfg['password'],$options);$adb=new PDO($dsn($ai),$ai['username'],$ai['password'],$options);$GLOBALS['FOOD_OBSERVER']=[];
$q=static function($role,$sql,$bind=[],$digest=false)use($db,$adb,$budget){require_once __DIR__.'/ObserverGate.php';FoodROGate::sql($sql);$budget('observer',800);$s=($role==='ai'?$adb:$db)->prepare($sql);foreach($bind as $i=>$v)$s->bindValue($i+1,$v,is_int($v)?1:($v===null?0:2));$s->execute();$rows=[];$h=hash_init('sha256');$n=0;while($row=$s->fetch(PDO::FETCH_ASSOC)){foreach($row as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);$row=array_change_key_case($row,CASE_LOWER);hash_update($h,serialize($row));$n++;if(!$digest)$rows[]=$row;}$value=$digest?['rows'=>$n,'typed_sha256'=>hash_final($h)]:$rows;$GLOBALS['FOOD_OBSERVER'][]=['role'=>$role,'sql'=>$s->queryString,'binds'=>$bind,'result'=>$value,'rowCount'=>$s->rowCount()];return $value;};
$source=static function($id=null,$full=false)use($q,$lane){$s=[];$s['own']=$id===null?$q('store','SELECT * FROM ydy_foods_composition WHERE name LIKE ? OR sub_name LIKE ? ORDER BY id',['%CDXFOOD11W1%','%CDXFOOD11W1%']):$q('store','SELECT * FROM ydy_foods_composition WHERE id=?',[(int)$id]);$s['natural_food']=$id===null?$q('store','SELECT * FROM ydy_foods_composition ORDER BY id',[],true):$q('store','SELECT * FROM ydy_foods_composition WHERE id<>? ORDER BY id',[(int)$id],true);$s['categories']=$q('store','SELECT * FROM ydy_foods_cate ORDER BY id');$s['actor']=$q('store','SELECT * FROM ydy_user WHERE id=?',[$lane==='B'?97260:2791]);$s['critical_config']=$q('store','SELECT * FROM ydy_config WHERE config_key IN (?,?,?) ORDER BY id',['tchef_sync_config','ai_sync_switch','ai_api_host'],true);foreach(['nutrition','nutrition_template','nutrition_set','nutrition_category','nutrition_time']as $t)$s[$t]=$q('store','SELECT * FROM ydy_'.$t.' WHERE name LIKE ? ORDER BY id',['CDXNF11F5%']);$uuids=array_column($s['nutrition_template'],'uuid');$s['nutrition_template_ext']=$uuids?$q('store','SELECT * FROM ydy_nutrition_template_ext WHERE template_uuid IN ('.implode(',',array_fill(0,count($uuids),'?')).') ORDER BY id',$uuids):[];$s['own_dish_references']=$id===null?[]:$q('store','SELECT * FROM ydy_dish WHERE composition_id=? ORDER BY id',[(int)$id]);if($full){$s['all_primary_users']=$q('store','SELECT * FROM ydy_user ORDER BY id',[],true);$s['all_config']=$q('store','SELECT * FROM ydy_config ORDER BY id',[],true);$s['all_dish']=$q('store','SELECT * FROM ydy_dish ORDER BY id',[],true);}return $s;};
$guard=static function($before,$after){unset($before['own'],$after['own']);if(!isset($before['all_primary_users'])||!isset($after['all_primary_users']))unset($before['all_primary_users'],$before['all_config'],$before['all_dish'],$after['all_primary_users'],$after['all_config'],$after['all_dish']);if($before!==$after)throw new RuntimeException('Protected complete scoped state drift');};
