<?php
require __DIR__.'/common.php';if(!in_array($casPhase,['zero','restore'],true))throw new RuntimeException('CAS phase');$file='cas-'.$casPhase.'.json';if(is_file(__DIR__.'/private/'.$file))throw new RuntimeException('No CAS replay');
$origin=json_decode(file_get_contents(__DIR__.'/private/original100.json'),true);$before=$source(true);$expect=$origin;$oldLogs=json_decode(file_get_contents(__DIR__.'/private/logs-before10.json'),true);$currentLogs=$logs();
if($casPhase==='restore'){$expect['dishes'][0]['raw_flag_weight']=$lane==='B'?'0.00':0.0;$plan=json_decode(file_get_contents(__DIR__.'/log-http-plan.json'),true);$prior=$oldLogs;foreach($plan['cases']as $case){$f=__DIR__.'/private/wire-'.$case['label'].'.json';if(!is_file($f))continue;$wire=json_decode(file_get_contents($f),true);if($wire['logs_before']!==$prior||!$wire['old_logs_unchanged'])throw new RuntimeException('Restore old logs drift');$prior=$wire['logs_after'];}if($currentLogs!==$prior)throw new RuntimeException('Restore unknown log delta');}
elseif($currentLogs!==$oldLogs)throw new RuntimeException('Zero log drift');
$a=$before;$b=$expect;unset($a['sentinel'],$b['sentinel']);if($a!==$b)throw new RuntimeException('Full8 before CAS drift');
$triggers=$lane==='B'?$q('SELECT TRIGGER_NAME,ACTION_TIMING,EVENT_MANIPULATION,ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=? ORDER BY TRIGGER_NAME',['ydy_dishes']):$q('SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME=? ORDER BY TRIGGER_NAME',['YDY_DISHES']);if($triggers!==[])throw new RuntimeException('Dishes trigger unknown');
$target=$casPhase==='zero'?'0.00':'100.00';$prior=$casPhase==='zero'?'100.00':'0.00';$journal=['phase'=>$casPhase,'before'=>$before,'events'=>[],'triggers'=>$triggers,'committed'=>false];
$run=static function(string $sql,array $binds)use($db,&$journal){$ev=['queryString'=>$sql,'binds'=>$binds,'success'=>false];try{$s=$db->prepare($sql);foreach($binds as $i=>$v)$s->bindValue($i+1,$v,PDO::PARAM_STR);$s->execute();$ev['success']=true;$ev['rowCount']=$s->rowCount();$ev['errorInfo']=$s->errorInfo();$rows=[];if(strpos($sql,'SELECT')===0)while($r=$s->fetch(PDO::FETCH_ASSOC))$rows[]=array_change_key_case($r,CASE_LOWER);$ev['rows']=$rows;$journal['events'][]=$ev;return [$ev['rowCount'],$rows];}catch(Throwable $e){$ev['error']=['class'=>get_class($e),'message'=>$e->getMessage()];$journal['events'][]=$ev;throw $e;}};
$db->beginTransaction();try{
 [$n,$rows]=$run('SELECT * FROM ydy_dishes WHERE uuid=? AND create_by=? FOR UPDATE',['C8EAA110-0002-4000-8000-202610110002','CDXNR11A']);if($rows!==$before['dishes'])throw new RuntimeException('Locked original full row drift');
 $sql='UPDATE ydy_dishes SET raw_flag_weight=?'.($lane==='B'?', update_time=update_time':'').' WHERE uuid=? AND create_by=? AND raw_flag_weight=?';[$affected]=$run($sql,[$target,'C8EAA110-0002-4000-8000-202610110002','CDXNR11A',$prior]);if($affected!==1)throw new RuntimeException('Exact one CAS affected');
 $after=$source(true);$wanted=$before;$wanted['dishes'][0]['raw_flag_weight']=$lane==='B'?$target:(float)$target;if($after!==$wanted||$logs()!==$currentLogs)throw new RuntimeException('Only raw_flag_weight may change');
 $db->commit();$journal['committed']=true;$journal['after']=$after;$journal['logs_unchanged']=true;$save($file,$journal);if($casPhase==='zero')$save('batch-before10.json',$after);else $save('restored100.json',$after);
 echo json_encode(['lane'=>$lane,'phase'=>$casPhase,'affected'=>1,'committed'=>true,'other_full_columns_unchanged'=>true]),"\n";
}catch(Throwable $e){if($db->inTransaction())$db->rollBack();$journal['failure']=['class'=>get_class($e),'message'=>$e->getMessage()];$journal['rollback_verified']=$source(true)===$before&&$logs()===$currentLogs;$save($file,$journal);throw $e;}
