<?php
declare(strict_types=1);
ini_set('display_errors','0');ini_set('log_errors','0');error_reporting(E_ALL);
set_error_handler(static function($severity){throw new ErrorException('Sanitized PHP warning',0,$severity);});
$stage='start';$checks=0;
function fwSame($e,$a):void{global $checks;++$checks;if($e!==$a)throw new RuntimeException('Framework assertion '.$checks);}
try{
    require __DIR__.'/../old-driver-shadow-fetch-prototype/ProbeRuntime.php';
    require __DIR__.'/../old-driver-shadow-fetch-prototype/SyntheticFixtures.php';
    require __DIR__.'/../old-driver-shadow-fetch-prototype/ShadowStatement.php';
    require __DIR__.'/IteratorShadowStatement.php';
    $stage='identity';$identity=runtimeIdentity();if(PHP_MINOR_VERSION!==4)throw new RuntimeException('AI framework PHP74-only gate');
    $vendorRoot='/tmp/zhct-ai-http-20260929.3XDj3w';
    $appRoot=__DIR__.'/framework-source';
    $sources=[
        'app/common/database/Dm.php'=>'ab5d44a9915af0f0a01186b0c72fc759075ebe9651a6c28cee40123a65218727',
        'app/common/database/DmBuilder.php'=>'c0d0b7a2668cded72b2c7a28fcbe3255e7cf1ff232b6c871f6bddc4259e699b0',
        'vendor/topthink/think-orm/src/db/PDOConnection.php'=>'42b04b0f6b66f719e5f697f5407f0f1c02ae5336e4a5c67c800f1034aeb0727f',
        'vendor/topthink/think-orm/src/db/Connection.php'=>'74ed663bfe2bfd5f6cfcb5b5d3b98e38e33742c9c73ff8844c04e7090d75f8b9',
        'vendor/topthink/think-orm/src/DbManager.php'=>'2c412e36e8f46520a2d23908f15432450096d81cc38ac040c78c796c1d9a80ab',
        'vendor/topthink/framework/src/think/cache/driver/File.php'=>'7845a82948a116e7625e92d7acefde100093533d8d4785038cb510e8cf59d31e',
    ];
    $sourcePath=static function(string $f)use($appRoot,$vendorRoot):string{return (strpos($f,'vendor/')===0?$vendorRoot:$appRoot).'/'.$f;};
    foreach($sources as $f=>$sha)fwSame($sha,hash_file('sha256',$sourcePath($f)));
    $loader=require $vendorRoot.'/vendor/autoload.php';$loader->setPsr4('app\\',$appRoot.'/app/');
    spl_autoload_register(static function(string $class)use($appRoot):void{if(strpos($class,'app\\')===0){$f=$appRoot.'/app/'.str_replace('\\','/',substr($class,4)).'.php';if(is_file($f))require $f;}},true,true);
    class SyntheticFrameworkConnection extends \app\common\database\Dm {
        private $syntheticPdo;private $allowed;public $executions=0;public $denied=0;
        public function __construct(PDO $pdo,array $allowed){parent::__construct(['database'=>'synthetic_only','trigger_sql'=>false,'break_reconnect'=>false]);$this->syntheticPdo=$pdo;$this->allowed=$allowed;}
        public function connect(array $config=[],$linkNum=0,$autoConnection=false):PDO{return $this->syntheticPdo;}
        public function getPDOStatement(string $sql,array $bind=[],bool $master=false,bool $procedure=false):PDOStatement{
            if($procedure||!in_array($sql,$this->allowed,true)){++$this->denied;throw new RuntimeException('Non-synthetic SQL denied');}
            ++$this->executions;return parent::getPDOStatement($sql,$bind,$master,$procedure);
        }
        public function execute(string $sql,array $bind=[]):int{++$this->denied;throw new RuntimeException('DML denied');}
        public function getFields(string $tableName):array{++$this->denied;throw new RuntimeException('Business metadata denied');}
        public function getTables(string $dbName=''):array{++$this->denied;throw new RuntimeException('Business metadata denied');}
        public function cachedSynthetic(string $sql,array $bind,string $key):array{
            if(!in_array($sql,$this->allowed,true))throw new RuntimeException('Cached SQL gate');
            $q=$this->newQuery();$q->cache($key,60);return $this->pdoQuery($q,$sql,$bind,false);
        }
    }
    class SyntheticValueModel extends \think\Model {
        protected $autoWriteTimestamp=false;protected $name='cdx_dual_only';
        public function getValueAttr($value){if(!is_string($value)&&!is_int($value)&&$value!==null)throw new UnexpectedValueException('Lossy getter input');return $value;}
    }
    $class=($argv[1]??'')==='old'?ShadowStatement::class:IteratorShadowStatement::class;
    $fixtures=syntheticFixtures();$registry=new ShadowRegistry(array_column($fixtures,'plan'));
    $pdo=probePdo($class,[$registry,PDO::FETCH_ASSOC]);$identity['mapped']=mappedComponents($identity);$target=independentTarget($pdo);
    $connection=new SyntheticFrameworkConnection($pdo,array_map(static function($x){return $x['plan']->sql();},$fixtures));
    $manager=new \think\DbManager();$connection->setDb($manager);$manager->setConfig(['auto_timestamp'=>false]);
    foreach(['app\\common\\database\\Dm'=>'app/common/database/Dm.php','app\\common\\database\\DmBuilder'=>'app/common/database/DmBuilder.php','think\\db\\PDOConnection'=>'vendor/topthink/think-orm/src/db/PDOConnection.php','think\\db\\Connection'=>'vendor/topthink/think-orm/src/db/Connection.php','think\\DbManager'=>'vendor/topthink/think-orm/src/DbManager.php'] as $c=>$f){fwSame(realpath($sourcePath($f)),realpath((new ReflectionClass($c))->getFileName()));}
    $stage='framework_query';$numeric=0;
    foreach($fixtures as $name=>$fixture){if(!isset($fixture['cases']))continue;foreach($fixture['cases'] as $pair){
        $bind=[[$pair[0],$pair[0]===null?PDO::PARAM_NULL:PDO::PARAM_STR]];
        $rows=$connection->query($fixture['plan']->sql(),$bind);fwSame([['value'=>$pair[1]]],$rows);
        $model=(new SyntheticValueModel())->newInstance($rows[0]);fwSame($pair[1],$model->getAttr('value'));fwSame($rows[0],$model->toArray());
        fwSame($rows[0],json_decode(json_encode($model->toArray(),JSON_THROW_ON_ERROR),true));++$numeric;
    }}
    $stage='framework_pdo_foreach';$values=['9007199254740993.01',null];$bind=[[$values[0],PDO::PARAM_STR],[null,PDO::PARAM_NULL]];
    $s=$connection->getPDOStatement($fixtures['pair']['plan']->sql(),$bind);$rows=[];foreach($s as $row)$rows[]=$row;fwSame([['k'=>1,'v'=>$values[0]],['k'=>2,'v'=>null]],$rows);
    $stage='framework_file_cache';$cachePath=__DIR__.'/runtime-cache-'.$class.'/';
    if(is_dir($cachePath))throw new RuntimeException('Fresh private cache directory required');
    $app=new \think\App(__DIR__.'/runtime-app-'.$class.'/');$cache=new \think\cache\driver\File($app,['path'=>$cachePath,'data_compress'=>false]);$connection->setCache($cache);
    $before=$connection->executions;$key='CDX_SYNTHETIC_WIDE_ONLY';
    $cold=$connection->cachedSynthetic($fixtures['pair']['plan']->sql(),$bind,$key);fwSame([['k'=>1,'v'=>$values[0]],['k'=>2,'v'=>null]],$cold);fwSame($before+1,$connection->executions);
    $hot=$connection->cachedSynthetic($fixtures['pair']['plan']->sql(),$bind,$key);fwSame($cold,$hot);fwSame($before+1,$connection->executions);
    fwSame($cold,$cache->get($key));fwSame(true,$cache->delete($key));fwSame(null,$cache->get($key));
    $files=[];if(is_dir($cachePath)){foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cachePath,FilesystemIterator::SKIP_DOTS)) as $f)if($f->isFile())$files[]=$f->getPathname();}fwSame([], $files);fwSame(0,$connection->denied);
    echo json_encode(['status'=>'pass','stage'=>'complete','php'=>PHP_VERSION,'statement_class'=>$class,'assertions'=>$checks,'numeric_scenarios'=>$numeric,'actual_framework_prepares'=>$connection->executions,'actual_query_method_used'=>true,'actual_file_cache_cold_hot_verified'=>true,'cache_files_remaining'=>count($files),'synthetic_model_getter_only'=>true,'real_business_ORM_getter_tested'=>false,'builder_auto_projection_tested'=>false,'identity'=>$identity,'target'=>$target,'sources'=>$sources,'business_reads'=>0,'dml'=>0,'ddl'=>0,'global_p0_closed'=>false],JSON_UNESCAPED_SLASHES).PHP_EOL;
}catch(Throwable $e){echo json_encode(['status'=>'fail','stage'=>$stage,'assertions'=>$checks,'class'=>get_class($e),'file'=>basename($e->getFile()),'line'=>$e->getLine(),'business_reads'=>0,'dml'=>0,'ddl'=>0,'global_p0_closed'=>false]).PHP_EOL;exit(1);}
