<?php
declare(strict_types=1);
set_exception_handler(static function(Throwable $e){$r=['class'=>get_class($e),'message'=>$e->getMessage(),'line'=>$e->getLine(),'file'=>basename($e->getFile())];$f=__DIR__.'/private/tool-error-'.str_replace('.','-',sprintf('%.6f',microtime(true))).'.json';file_put_contents($f,json_encode($r,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));chmod($f,0600);fwrite(STDERR,'Stopped: '.get_class($e).' at '.basename($e->getFile()).':'.$e->getLine().PHP_EOL);exit(1);});
$mode=$argv[1]??'';
if($mode==='puregate'){
 require __DIR__.'/Gate.php';require __DIR__.'/Oracle.php';ActivityGate::$dry=true;$n=0;$test=static function($sql,$schema,$valid)use(&$n){try{ActivityGate::sql($sql,$schema);$ok=true;}catch(Throwable $e){$ok=false;}if($ok!==$valid)throw new RuntimeException('Pure SQL gate expectation');$n++;};
 $test('SELECT * FROM yoshop_activity WHERE uuid = :where_AND_uuid','ai',true);foreach(['DELETE FROM ydy_user','DROP TABLE yoshop_activity','SELECT * FROM external_table','SELECT * FROM yoshop_activity; DELETE FROM yoshop_activity','SELECT * FROM yoshop_activity -- comment']as $sql)$test($sql,'store',false);
 $b=[':data__status'=>['value'=>'0','type'=>1,'php_type'=>'string','ok'=>true],':where_AND_uuid'=>['value'=>'OWN-UUID','type'=>2,'php_type'=>'string','ok'=>true]];$case=['allowed'=>['kind'=>'update','uuid'=>'OWN-UUID','data'=>['status'=>'0']]];ActivityGate::$case=$case;ActivityGate::execute('UPDATE `yoshop_activity` SET `status`=:data__status WHERE `uuid` = :where_AND_uuid',$b,null,'ai');$n++;
 foreach(['wrong-uuid','wrong-data','extra-bind','wrong-type','store-write','second-write']as $mutation){ActivityGate::$dml=0;ActivityGate::$case=$case;$m=$b;$schema='ai';if($mutation==='wrong-uuid')$m[':where_AND_uuid']['value']='OTHER';if($mutation==='wrong-data')$m[':data__status']['value']='1';if($mutation==='extra-bind')$m[':extra']=['value'=>'x','type'=>2,'php_type'=>'string','ok'=>true];if($mutation==='wrong-type')$m[':data__status']['type']=2;if($mutation==='store-write')$schema='store';if($mutation==='second-write')ActivityGate::$dml=1;try{ActivityGate::execute('UPDATE `yoshop_activity` SET `status`=:data__status WHERE `uuid` = :where_AND_uuid',$m,null,$schema);throw new LogicException('Mutation accepted');}catch(RuntimeException $e){$n++;}}
 $dto=activityOracle([['id'=>1,'img'=>null,'detail_img'=>'','status'=>0]],'info');if($dto!==['code'=>0,'message'=>'信息获取成功','data'=>['id'=>1,'img'=>null,'detail_img'=>'','status'=>0,'activity_status'=>'未开始','participants'=>0]])throw new RuntimeException('Full DTO oracle');$n++;echo json_encode(['puregate_checks'=>$n,'DB'=>0,'HTTP'=>0]),"\n";exit;
}
if($mode==='cleanup'){
 $p=json_decode(file_get_contents(__DIR__.'/private/pid.json'),true);$cmd=(string)@file_get_contents('/proc/'.$p['pid'].'/cmdline');if($cmd!==''&&(strpos($cmd,__DIR__.'/index.php')===false||strpos($cmd,'127.0.0.1:'.$p['port'])===false))throw new RuntimeException('Exact own PID');$removed=[];$walk=static function($dir)use(&$walk,&$removed){if(!is_dir($dir))return;foreach(scandir($dir)as $n){if($n==='.'||$n==='..')continue;$f=$dir.'/'.$n;if(is_link($f))throw new RuntimeException('Cache symlink');if(is_dir($f)){$walk($f);rmdir($f);}else{$removed[]=['path'=>$f,'sha256'=>hash_file('sha256',$f)];unlink($f);}}};$walk(__DIR__.'/cache');foreach(['auth.json','current.json','lease.json']as $n){$f=__DIR__.'/private/'.$n;if(is_file($f)){if(is_link($f))throw new RuntimeException('Auth symlink');$removed[]=['path'=>$n,'sha256'=>hash_file('sha256',$f)];unlink($f);}}if($cmd!=='')posix_kill($p['pid'],SIGTERM);usleep(300000);if(@fsockopen('127.0.0.1',$p['port'],$n,$e,0.3))throw new RuntimeException('Port open');$r=['own_worker'=>$p,'own_port_closed'=>true,'removed'=>$removed,'original_parent_alive'=>is_file('/proc/'.(getenv('ACT_LANE')==='B'?10001:112175).'/cmdline'),'DB'=>0,'HTTP'=>0];$f=__DIR__.'/private/cleanup.json';$h=fopen($f,'xb');fwrite($h,json_encode($r,JSON_PRETTY_PRINT));fclose($h);chmod($f,0600);echo json_encode(['cleanup'=>true,'port_closed'=>true]),"\n";exit;
}
require __DIR__.'/common.php';require __DIR__.'/Oracle.php';
$mutable=static function($file,$v){file_put_contents(__DIR__.'/private/'.$file,json_encode($v,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|JSON_PRESERVE_ZERO_FRACTION));chmod(__DIR__.'/private/'.$file,0600);};
if($mode==='preflight'){
 if(file_exists(__DIR__.'/private/baseline.json'))throw new RuntimeException('Fresh preflight only');$s=$source();if(count($s['actor'])!==1||$s['actor'][0]['id']!==($lane==='B'?97260:2791)||$s['actor'][0]['type']!==0||strpos($s['actor'][0]['name'],'CDX')!==0)throw new RuntimeException('Original disabled actor mapping');$own=array_filter($s['activity'],static function($r){return strpos($r['title'],'CDXACT11W1')!==false;});if(count($own)!==0)throw new RuntimeException('Marker collision');$types=array_values(array_filter($s['activity_type'],static function($r){return (int)$r['is_delete']===0;}));if(!$types)throw new RuntimeException('No existing active activity type');$metadata=[];
 if($lane==='B'){$metadata['activity_columns']=$q('ai','SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',['yoshop_activity']);$metadata['triggers']=$q('ai','SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?',['yoshop_activity']);$metadata['version']=$q('ai','SELECT VERSION() AS version, DATABASE() AS db');}
 else{$metadata['activity_columns']=$q('ai','SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',['YOSHOP_ACTIVITY']);$metadata['triggers']=$q('ai','SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME=?',['YOSHOP_ACTIVITY']);$metadata['version']=$q('ai',"SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS db FROM DUAL");}
 $save('baseline.json',$s);$save('preflight.json',['lane'=>$lane,'marker_collision'=>0,'existing_valid_type'=>$types[0],'metadata'=>$metadata,'observer'=>$GLOBALS['ACT_OBSERVER'],'actor_permission_source'=>'Original full actor type=0; real AdminController checkLogin and beforeActionList preserved']);echo json_encode(['lane'=>$lane,'preflight'=>true,'collision'=>0,'activity_count'=>count($s['activity']),'type_id'=>$types[0]['id'],'metadata_columns'=>count($metadata['activity_columns'])]),"\n";exit;
}
if($mode==='auth'){$s=$source();$base=json_decode(file_get_contents(__DIR__.'/private/baseline.json'),true);$guard($base,$s);require __DIR__.'/init.php';$token=(new \app\p\logic\Login())->userTokenSet($s['actor'][0]);if(ActivityGate::$journal!==[])throw new RuntimeException('Token SQL unexpected');$save('auth.json',['token'=>$token]);$save('auth-proof.json',['original_actor_sha256'=>hash('sha256',serialize($s['actor'])),'token_chain_SQL'=>0,'observer'=>$GLOBALS['ACT_OBSERVER']]);echo json_encode(['lane'=>$lane,'auth'=>true,'business_SQL'=>0]),"\n";exit;}
if($mode==='tap-proof'){
 $s=$source();$base=json_decode(file_get_contents(__DIR__.'/private/baseline.json'),true);$owned=json_decode(file_get_contents(__DIR__.'/private/owned.json'),true);$guard($base,$s,$owned['uuid']);$own=array_values(array_filter($s['activity'],static function($r)use($owned){return $r['uuid']===$owned['uuid'];}));if(count($own)!==1||$own[0]!==$owned['full_created_row'])throw new RuntimeException('Original created row unchanged');
 require __DIR__.'/init.php';$proof=[];foreach(['store'=>\think\Db::connect(),'ai'=>get_ai_db()]as $which=>$conn){$rp=new ReflectionProperty(\think\db\Connection::class,'linkID');$rp->setAccessible(true);$pdo=$rp->getValue($conn);if(!($pdo instanceof ActPDO)||$pdo->schema!==$which)throw new RuntimeException('Effective native tap missing');$c=$conn->getConfig();$expected=$which==='store'?$cfg:$ai;foreach(['hostname','database','username','password','prefix']as $k)if($c[$k]!==$expected[$k])throw new RuntimeException('Effective config identity');$expectedClass=$lane==='B'?'think\\db\\connector\\Mysql':'app\\cores\\database\\Dm';if(get_class($conn)!==$expectedClass)throw new RuntimeException('Original Driver class');$identity=$conn->query($lane==='B'?'SELECT DATABASE() AS db':'SELECT SYS_CONTEXT(\'USERENV\',\'CURRENT_SCHEMA\') AS db FROM DUAL');$row=$which==='store'?$conn->query('SELECT id,uuid FROM ydy_user WHERE id=:actor',['actor'=>[$lane==='B'?97260:2791,1]]):$conn->query('SELECT id,uuid FROM yoshop_activity WHERE uuid=:own',['own'=>[$owned['uuid'],2]]);$proof[$which]=['class'=>get_class($conn),'native_class'=>get_class($pdo),'config_database'=>$c['database'],'identity'=>$identity,'row'=>$row];}
 $schemas=array_column(ActivityGate::$journal,'schema');if(!in_array('store',$schemas,true)||!in_array('ai',$schemas,true)||ActivityGate::$dml!==0)throw new RuntimeException('Both actual journal scopes');$save('tap-proof-v2.json',['proof'=>$proof,'native'=>ActivityGate::$journal,'source'=>$s,'observer'=>$GLOBALS['ACT_OBSERVER'],'initial_insert_limited_native_not_captured'=>true]);echo json_encode(['lane'=>$lane,'both_original_drivers_tapped'=>true,'native_statements'=>count(ActivityGate::$journal),'natural_state_exact'=>true,'own_created_row_exact'=>true]),"\n";exit;
}
if($mode==='finish'){$s=$source();$base=json_decode(file_get_contents(__DIR__.'/private/baseline.json'),true);$guard($base,$s);$save('final.json',['source'=>$s,'baseline_exact'=>true,'observer'=>$GLOBALS['ACT_OBSERVER']]);echo json_encode(['lane'=>$lane,'original_state_exact'=>true]),"\n";exit;}
if($mode!=='step')throw new RuntimeException('Mode');$stage=(int)($argv[2]??0);if($stage<1||$stage>11)throw new RuntimeException('Approved 11 stages');$label=sprintf('%02d',$stage);if(is_file(__DIR__.'/private/sent-'.$label.'.json'))throw new RuntimeException('No request replay');$before=$stage>=6?json_decode(file_get_contents(__DIR__.'/private/wire-'.sprintf('%02d',$stage-1).'.json'),true)['after']:$source();$base=json_decode(file_get_contents(__DIR__.'/private/baseline.json'),true);$owned=is_file(__DIR__.'/private/owned.json')?json_decode(file_get_contents(__DIR__.'/private/owned.json'),true):null;$uuid=$owned['uuid']??null;$guard($base,$before,$uuid);$matching=array_values(array_filter($before['activity'],static function($r)use($uuid){return $uuid!==null&&$r['uuid']===$uuid;}));$row=$matching[0]??null;
$method=[1=>'add',2=>'info',3=>'lists',4=>'update',5=>'info',6=>'able',7=>'info',8=>'able',9=>'info',10=>'delete',11=>'lists'][$stage];$params=[];$allowed=null;
if($stage===1){$meta=json_decode(file_get_contents(__DIR__.'/private/preflight.json'),true);$params=['title'=>'CDXACT11W1','type_id'=>(string)$meta['existing_valid_type']['id'],'register_start'=>'2099-01-01 00:00:00','register_end'=>'2099-01-02 00:00:00','start_time'=>'2099-01-03 00:00:00','end_time'=>'2099-01-04 00:00:00','status'=>'1','description'=>'自有活动初始说明','rules'=>'自有活动规则'];$allowed=['kind'=>'insert','data'=>$params+['create_by'=>(string)$before['actor'][0]['name'],'store_id'=>10001]];}
elseif($method==='lists')$params=['title'=>'CDXACT11W1','page'=>'1'];
else{if(!$row||$row['id']!==$owned['id']||(int)$row['store_id']!==10001||strpos($row['title'],'CDXACT11W1')!==0)throw new RuntimeException('Own UUID PK title tenant closure');$params=['uuid'=>$uuid];if($stage===4){$params+=['title'=>'CDXACT11W1-U','description'=>'自有活动修改说明','rules'=>'自有活动修改规则'];$data=$params;unset($data['uuid']);$allowed=['kind'=>'update','uuid'=>$uuid,'data'=>$data];}elseif($method==='able'){$params['status']='0';if((int)$row['status']!==($stage===6?1:0))throw new RuntimeException('Status exact transition');$allowed=['kind'=>'update','uuid'=>$uuid,'data'=>['status'=>'0']];}elseif($method==='delete'){$refs=$q('ai','SELECT * FROM yoshop_activity_register WHERE activity_id=?',[$row['id']]);if($refs!==[])throw new RuntimeException('Registration references not zero');$save('delete-lease.json',['new_created_journal'=>'owned.json','full_own_row'=>$row,'references'=>$refs,'observer'=>$GLOBALS['ACT_OBSERVER']]);$allowed=['kind'=>'delete','uuid'=>$uuid,'data'=>[]];}}
$case=['label'=>$label,'stage'=>$stage,'method'=>$method,'path'=>'/p/Activity/'.$method,'params'=>$params,'allowed'=>$allowed,'own_uuid'=>$uuid];$mutable('current.json',$case);$mutable('lease.json',$before);$save('before-'.$label.'.json',['source'=>$before,'case'=>$case,'observer'=>$GLOBALS['ACT_OBSERVER']]);$budget('HTTP',12);$save('sent-'.$label.'.json',['case'=>$case,'started'=>microtime(true)]);$auth=json_decode(file_get_contents(__DIR__.'/private/auth.json'),true);$headers=[];$c=curl_init('http://127.0.0.1:'.$plan['ports'][$lane].$case['path']);curl_setopt_array($c,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>json_encode($params,JSON_UNESCAPED_UNICODE),CURLOPT_RETURNTRANSFER=>true,CURLOPT_HTTPHEADER=>['Content-Type: application/json','token: '.$auth['token'],'X-CDX-CASE: '.$label],CURLOPT_CONNECTTIMEOUT=>5,CURLOPT_TIMEOUT=>30,CURLOPT_HEADERFUNCTION=>static function($c,$s)use(&$headers){$headers[]=$s;return strlen($s);}]);$body=curl_exec($c);$info=curl_getinfo($c);$err=curl_error($c);curl_close($c);$save('client-'.$label.'.json',['status'=>$info['http_code'],'headers'=>$headers,'body'=>$body,'error'=>$err,'duration'=>$info['total_time']]);
usleep(150000);$wire=json_decode((string)file_get_contents(__DIR__.'/private/wire-'.$label.'.json'),true);$response=json_decode((string)file_get_contents(__DIR__.'/private/response-'.$label.'.json'),true);if(!$wire||!$response||$body!==$response['body']||$body!==$wire['body']||$info['http_code']!==200||empty($wire['protected_equal']))throw new RuntimeException('Original full wire or observer failure');$after=$stage>=6?$wire['after']:$source();if($after!==$wire['after'])throw new RuntimeException('Independent source mismatch');
if($stage===1){$new=array_values(array_filter($after['activity'],static function($r){return $r['title']==='CDXACT11W1';}));if(count($new)!==1||!preg_match('/^[A-Fa-f0-9-]{36}$/D',$new[0]['uuid']))throw new RuntimeException('Single actual newly created row');$owned=['id'=>$new[0]['id'],'uuid'=>$new[0]['uuid'],'title'=>$new[0]['title'],'store_id'=>$new[0]['store_id'],'full_created_row'=>$new[0],'journal_label'=>$label];$save('owned.json',$owned);$uuid=$owned['uuid'];}
$guard($base,$after,$uuid);$target=array_values(array_filter($after['activity'],static function($r)use($uuid){return $r['uuid']===$uuid;}));
if($stage>=2){if($wire['DML_attempts']!==($allowed===null?0:1))throw new RuntimeException('Actual native DML attempt count');$schemas=array_column($wire['native'],'schema');if(!in_array('store',$schemas,true)||!in_array('ai',$schemas,true))throw new RuntimeException('Actual HTTP both native connection journals');}
if($allowed!==null&&$method!=='delete'){if(count($target)!==1)throw new RuntimeException('One exact persisted activity');$expectedRow=$stage===1?$target[0]:$row;foreach($allowed['data']as $k=>$v){if((string)$target[0][$k]!==(string)$v)throw new RuntimeException('Persisted approved field '.$k);$expectedRow[$k]=is_int($target[0][$k])?(int)$v:$v;}if($expectedRow!==$target[0])throw new RuntimeException('Full own immutable columns');}
$expected=activityOracle($method==='lists'?array_values(array_filter($after['activity'],static function($r){return strpos($r['title'],'CDXACT11W1')!==false;})):$target,$method);$decoded=json_decode($body,true);$equal=$decoded===$expected;$noop=$stage===8&&$lane==='B'&&$decoded===['code'=>1,'message'=>'修改失败','data'=>[]];if(!$equal&&!$noop)throw new RuntimeException('Independent full DTO mismatch');if($stage===10&&$target!==[])throw new RuntimeException('Own row deletion readback');$save('result-'.$label.'.json',['lane'=>$lane,'stage'=>$stage,'expected_full_DTO'=>$expected,'actual_full_DTO'=>$decoded,'full_DTO_exact'=>$equal,'original_MySQL_noop_red'=>$noop,'independent_after'=>$after,'protected_exact'=>true,'observer'=>$GLOBALS['ACT_OBSERVER'],'native_DML'=>$wire['DML_attempts']]);echo json_encode(['lane'=>$lane,'stage'=>$stage,'HTTP'=>$info['http_code'],'code'=>$decoded['code'],'full_DTO_equal'=>$equal,'original_MySQL_noop'=>$noop,'DML'=>$wire['DML_attempts']],JSON_UNESCAPED_UNICODE),"\n";
