<?php
declare(strict_types=1);
date_default_timezone_set('Asia/Shanghai');$lane=getenv('ROPE_LANE');$dm=getenv('POC_DIALECT')==='dm';$runtime=__DIR__.'/private';$root=__DIR__.'/source';
if(!is_dir($runtime))mkdir($runtime,0700);chmod($runtime,0700);
$check=static function($ok,$message){if(!$ok)throw new RuntimeException($message);};
$persist=static function($name,$data)use($runtime){$j=json_encode($data,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRESERVE_ZERO_FRACTION);if($j===false)throw new RuntimeException('Evidence encoding');file_put_contents($runtime.'/'.$name,$j);chmod($runtime.'/'.$name,0600);};
$dsn=static function($key)use($dm){return $dm?'dm:host='.getenv('POC_'.$key.'_HOST').';port='.getenv('POC_'.$key.'_PORT').';schema='.getenv('POC_'.$key.'_SCHEMA'):'mysql:host='.getenv('POC_'.$key.'_HOST').';port='.getenv('POC_'.$key.'_PORT').';dbname='.getenv('POC_'.$key.'_SCHEMA').';charset='.getenv('POC_'.$key.'_CHARSET');};
$connect=static function($key='AI')use($dsn){return new PDO($dsn($key),getenv('POC_'.$key.'_USER'),getenv('POC_'.$key.'_PASSWORD'),[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]);};
$read=static function($sql,$params=[],$key='AI')use($connect,$runtime){if(!preg_match('/^SELECT\b/',$sql)||preg_match('/;|\b(?:INSERT|UPDATE|DELETE|ALTER|CREATE|DROP|INTO|CALL)\b/i',$sql))throw new RuntimeException('Independent SELECT gate');$s=$connect($key)->prepare($sql);$bound=[];foreach(array_values($params) as $i=>$v){$s->bindValue($i+1,(string)$v,PDO::PARAM_STR);$bound[]=['position'=>$i+1,'value'=>(string)$v,'pdo_type'=>PDO::PARAM_STR];}$s->execute();$rows=$s->fetchAll(PDO::FETCH_ASSOC);foreach($rows as &$r){foreach($r as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);ksort($r);}unset($r);$r=['connection'=>$key,'queryString'=>$s->queryString,'bindValue'=>$bound,'rowCount'=>$s->rowCount(),'rows'=>$rows];file_put_contents($runtime.'/independent-read.jsonl',json_encode($r,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION)."\n",FILE_APPEND|LOCK_EX);chmod($runtime.'/independent-read.jsonl',0600);return $rows;};
$users=$lane==='B'?[46914,46915]:[1928,1929];$staff=$lane==='B'?[46334,46335]:[1851,1852];$tenants=[2147001111,2147001112];
$small=static function()use($read,$dm,$users,$staff,$tenants){$out=[];$out['rope']=$read('SELECT *,CAST(stopped_at AS '.($dm?'VARCHAR(40)':'CHAR').') exact_stopped_at FROM yoshop_rope_skipping WHERE store_id IN (?,?) AND user_id IN (?,?) ORDER BY id',array_merge($tenants,$users));$out['users']=$read('SELECT * FROM yoshop_user WHERE store_id IN (?,?) AND user_id IN (?,?) ORDER BY user_id',array_merge($tenants,$users));$out['staff']=$read('SELECT * FROM yoshop_staff WHERE store_id IN (?,?) AND id IN (?,?) ORDER BY id',array_merge($tenants,$staff));$out['store']=$read('SELECT * FROM yoshop_store WHERE store_id IN (?,?) ORDER BY store_id',$tenants);return $out;};
$large=static function()use($read,$small,$tenants){$out=$small();foreach(['nutrition_meals','nutrition_lack','nurtrition'] as $table)$out[$table]=$read('SELECT * FROM yoshop_'.$table.' WHERE store_id IN (?,?) ORDER BY id',$tenants);$out['rope_sentinel']=$read('SELECT COUNT(*) n,MIN(id) min_id,MAX(id) max_id,SUM(id) sum_id FROM yoshop_rope_skipping');return $out;};
function ropeApp(string $root,string $runtime,string $scenario):\think\App {
 if(!defined('TP_ENV')){define('TP_ENV','poc');define('BUSINESS','aizhct');define('ENTERPRISE_NO','10001');require $root.'/vendor/autoload.php';spl_autoload_register(static function($class)use($root){if(preg_match('/printer|MQTT|BaiduDishes|\\\\Face$|storage\\\\Driver|QwRobot/i',$class))throw new RuntimeException('External SDK forbidden');foreach(['app\\'=>'app/','cores\\'=>'cores/'] as $p=>$d)if(strpos($class,$p)===0){$f=$root.'/'.$d.str_replace('\\','/',substr($class,strlen($p))).'.php';if(is_file($f))require $f;}},true,true);}
 $app=new \think\App($root);$app->setEnvName('poc');$app->setRuntimePath($runtime.'/runtime/');$app->initialize();$app->config->set(['default'=>'file','stores'=>['file'=>['type'=>'File','path'=>$runtime.'/cache/','prefix'=>'','expire'=>0]]],'cache');$app->instance('cache',new \think\Cache($app));$log=$app->config->get('log');$log['close']=true;foreach($log['channels'] as &$c)$c['close']=true;unset($c);$app->config->set($log,'log');$app->instance('log',new \think\Log($app));$app->log->channel()->close();
 require_once __DIR__.'/NativePdo.php';RopeSqlGate::$runtime=$runtime;RopeSqlGate::$scenario=$scenario;RopeSqlGate::$started=time();
 $cfg=$app->config->get('database');foreach(['mysql'=>'AI','mysql_zhct'=>'ZHCT'] as $name=>$key){$c=$cfg['connections'][$name];$c['type']=getenv('POC_DIALECT')==='dm'?'\\'.RopeGuardDm::class:'\\'.RopeGuardMysql::class;foreach(['HOST'=>'hostname','PORT'=>'hostport','SCHEMA'=>'database','USER'=>'username','PASSWORD'=>'password','CHARSET'=>'charset','PREFIX'=>'prefix'] as $k=>$to)$c[$to]=getenv('POC_'.$key.'_'.$k);$c['debug']=false;$c['trigger_sql']=true;$c['break_reconnect']=false;$c['fields_cache']=false;$c['dsn']='';$c['params']=[];$cfg['connections'][$name]=$c;}$cfg['default']='mysql';$app->config->set($cfg,'database');$app->db->setConfig($app->config);return $app;
}
