<?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-fixed-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_FIXED_PRIMARY'||$plan['ports']!==['B'=>18997,'C'=>18998])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([['new-read',0,400],['total-read',$lane==='B'?595:677,$lane==='B'?995:1077]]as $limit){$f=__DIR__.'/private/budget-'.$limit[0].'.json';$h=fopen($f,'c+');flock($h,LOCK_EX);$v=stream_get_contents($h);$n=$v!==''?(int)$v:$limit[1];if($n>=$limit[2])throw new RuntimeException('Unified readonly cap before PDO');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('Kind budget before PDO');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;};
$batch=static function($id=null,$full=true)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',['%CDXFOOD11W2%','%CDXFOOD11W2%']):$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_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;};
$source=static function($id=null)use($q){return ['own'=>$id===null?$q('store','SELECT * FROM ydy_foods_composition WHERE name LIKE ? OR sub_name LIKE ? ORDER BY id',['%CDXFOOD11W2%','%CDXFOOD11W2%']):$q('store','SELECT * FROM ydy_foods_composition WHERE id=?',[(int)$id]),'categories'=>$q('store','SELECT * FROM ydy_foods_cate WHERE id IN (?,?) ORDER BY id',[1,19])];};
$guard=static function($before,$after){unset($before['own'],$after['own']);if($before!==$after)throw new RuntimeException('Original protected fields drift');};
