<?php

declare(strict_types=1);

// C nonproduction dishesInfo-only regression. Business tables are SELECT-only;
// only one synthetic type1 user and its restaurant type3 scope are written.
if ($argc!==2 || $argv[1]!=='--run-approved-c-dishesinfo-weight'
    || getenv('CDX_APPROVED_C_DISHESINFO_WEIGHT')!=='1') {
    fwrite(STDERR,"Explicit reviewed C Bill-more fixture gate required\n");
    exit(2);
}

$root='/tmp/zhct-dm-poc-20260928.fcpiiN/store';
$manifestDir='/tmp/zhct-store-billmore.j3HlId';
$marker='CDXPARBILLMORE'.strtoupper(bin2hex(random_bytes(4)));
$hex=bin2hex(random_bytes(16));
$userUuid=substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4)
    .'-'.substr($hex,16,4).'-'.substr($hex,20,12);
$restaurantUuid='';
$fixtureTouched=false;
$transportUncertain=false;
$phase='runtime-boundary';
$result=['lane'=>'C','cases'=>[],'manifest'=>[
    'marker'=>$marker,'user_uuid'=>$userUuid,
    'only_synthetic_identifiers'=>true,
]];
$open=null;
$count=null;

try {
    $pid=(string)getenv('POC_RUNTIME_PID');
    if ($pid!=='112175') throw new RuntimeException('Wrong C PID');
    $cmd=str_replace("\0",' ',(string)file_get_contents('/proc/'.$pid.'/cmdline'));
    if (strpos($cmd,' -S 127.0.0.1:18080 ')===false
        || strpos($cmd,$root.'/public')===false
        || substr_count($cmd,' -S ')!==1) {
        throw new RuntimeException('Wrong C isolated Store runtime');
    }
    $env=array_fill_keys(['POC_HOST','POC_PORT','POC_SCHEMA','POC_USER',
        'POC_PASSWORD','PHP_CLI_SERVER_WORKERS'],'');
    foreach (explode("\0",(string)file_get_contents('/proc/'.$pid.'/environ')) as $entry) {
        $parts=explode('=',$entry,2);
        if (count($parts)===2 && array_key_exists($parts[0],$env)) {
            $env[$parts[0]]=$parts[1];
        }
    }
    if ($env['POC_HOST']!=='127.0.0.1' || $env['POC_PORT']!=='5237'
        || strtoupper($env['POC_SCHEMA'])!=='ZHCT_APP'
        || strtoupper($env['POC_USER'])!=='ZHCT_APP'
        || $env['POC_PASSWORD']===''
        || !in_array($env['PHP_CLI_SERVER_WORKERS'],['','1'],true)) {
        throw new RuntimeException('Wrong C DB or worker boundary');
    }
    $sources=[
        'application/model/Bill.php'=>'daa8f7181928d06b53e57504f229eaf04088e3ea7eaccfad55c07d091db03c18',
        'application/p/controller/Bill.php'=>'8d99ea508e165d694a156d43420cb98f3a809a0fb9a120716e4f9dd90a4b9cf2',
        'application/p/logic/Bill.php'=>'699e733b42157762d6af98e07c6366c3dc553bb2ff2d7676c0f758b7ff065daa',
        'application/common/service/DecimalResponseFormatter.php'=>'cce23d98388321732faded562fd212c609f1e0160c116de537aa0d5becaa437a',
        'application/model/Food.php'=>'068aabef6b5172cfcab35c406cb1a5eeb0938be75f3bd82b699538def203017c',
        'application/model/Cater.php'=>'8d98dc0c54769b6e476be2bba86971debc63ba0c1b3475e8f6f338b17e73c892',
    ];
    foreach ($sources as $file=>$expected) {
        if ((string)hash_file('sha256',$root.'/'.$file)!==$expected) {
            throw new RuntimeException('Bill source changed');
        }
    }
    $boundaryRaw=@file_get_contents('http://127.0.0.1:18080/__poc_boundary',
        false,stream_context_create(['http'=>[
            'timeout'=>3,'ignore_errors'=>true,
        ]]));
    $boundaryHeaders=$http_response_header??[];
    $boundaryStatus=preg_match('/^HTTP\/\S+\s+(\d+)/',
        (string)($boundaryHeaders[0]??''),$match)?(int)$match[1]:0;
    $boundary=json_decode((string)$boundaryRaw,true);
    if ($boundaryStatus!==200 || !is_array($boundary)
        || empty($boundary['external_stubs'])
        || empty($boundary['redis_isolated']) || !empty($boundary['real_queue'])) {
        throw new RuntimeException('C isolated external boundary failed');
    }

    $phase='database-schema';
    $open=static function() use ($env): PDO {
        return new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP',
            $env['POC_USER'],$env['POC_PASSWORD'],[
                PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
            ]);
    };
    $db=$open();
    if (strtoupper((string)$db->query(
        "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")
        ->fetchColumn())!=='ZHCT_APP') {
        throw new RuntimeException('Wrong current schema');
    }
    $count=static function(PDO $conn,string $sql,array $args=[]): int {
        $stmt=$conn->prepare($sql);
        $stmt->execute($args);
        return (int)$stmt->fetchColumn();
    };
    $required=[
        'YDY_DISHES'=>['ID','UUID','NAME','CATEGORY','IS_DEL','STATUS',
            'IS_DELETE','STORE_ID','WEIGHT'],
        'YDY_DISH'=>['DISHES_UUID','COMPOSITION_ID','COMPOSITION_RATIO',
            'IS_DELETE'],
        'YDY_FOODS_COMPOSITION'=>['ID','NAME','SUB_NAME','IS_DELETE'],
        'YDY_RECIPES'=>['DISHES_UUID','MENU_DATE','RESTAURANT_ID','MEAL_TIMES'],
        'YDY_DATE_MENU'=>['DISHES_UUID','MENU_DATE','RESTAURANT_ID',
            'MEAL_TIMES','MEAL_TYPE'],
        'YDY_RESTAURANTS'=>['ID','UUID','STATUS','IS_DELETE'],
        'YDY_USER'=>['ID','UUID','ACCOUNT','PWD','SALT','NAME','TYPE','STATUS',
            'CREATE_TIME','CREATE_BY','IS_DELETE'],
        'YDY_USER_DATA'=>['ID','USER_UUID','DATA_UUID','TYPE'],
    ];
    $columns=$db->prepare('SELECT COLUMN_NAME,NULLABLE,DATA_DEFAULT'
        .' FROM USER_TAB_COLUMNS WHERE TABLE_NAME=?');
    foreach ($required as $table=>$names) {
        $columns->execute([$table]);
        $rows=$columns->fetchAll(PDO::FETCH_ASSOC);
        $actual=[];
        foreach ($rows as $row) {
            $row=array_change_key_case($row,CASE_LOWER);
            $actual[strtoupper((string)$row['column_name'])]=$row;
        }
        if (array_diff($names,array_keys($actual))) {
            throw new RuntimeException('Bill-more required column missing');
        }
        if ($table==='YDY_USER' || $table==='YDY_USER_DATA') {
            $inserted=$table==='YDY_USER'
                ? ['UUID','ACCOUNT','PWD','SALT','NAME','TYPE','STATUS',
                    'CREATE_TIME','CREATE_BY','IS_DELETE']
                : ['USER_UUID','DATA_UUID','TYPE'];
            foreach ($actual as $name=>$column) {
                if ($name!=='ID' && (string)$column['nullable']==='N'
                    && $column['data_default']===null
                    && !in_array($name,$inserted,true)) {
                    throw new RuntimeException('Permission insert omits required field');
                }
            }
            if ($count($db,'SELECT COUNT(*) FROM USER_TRIGGERS'
                .' WHERE TABLE_NAME=?',[$table])!==0
                || $count($db,'SELECT COUNT(*) FROM USER_CONSTRAINTS'
                    .' WHERE TABLE_NAME=? AND CONSTRAINT_TYPE=\'R\'',
                    [$table])!==0) {
                throw new RuntimeException('Permission trigger/FK gate failed');
            }
        }
    }
    $indexStmt=$db->prepare('SELECT i.INDEX_NAME,i.UNIQUENESS,'
        .' ic.COLUMN_NAME,ic.COLUMN_POSITION FROM USER_INDEXES i'
        .' JOIN USER_IND_COLUMNS ic ON i.INDEX_NAME=ic.INDEX_NAME'
        .' WHERE i.TABLE_NAME=? ORDER BY i.INDEX_NAME,ic.COLUMN_POSITION');
    $indexStmt->execute(['YDY_USER_DATA']);
    $indexes=[];
    foreach ($indexStmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $row=array_change_key_case($row,CASE_LOWER);
        $name=(string)$row['index_name'];
        $indexes[$name]['unique']=strtoupper((string)$row['uniqueness'])==='UNIQUE';
        $indexes[$name]['columns'][]=strtoupper((string)$row['column_name']);
    }
    $hasUnique=false;
    foreach ($indexes as $index) {
        if ($index['unique']
            && $index['columns']===['USER_UUID','DATA_UUID','TYPE']) {
            $hasUnique=true;
        }
    }
    if (!$hasUnique || $count($db,'SELECT COUNT(*) FROM YDY_USER'
        .' WHERE ACCOUNT LIKE ?', ['CDXPARBILLMORE%'])!==0) {
        throw new RuntimeException('User-data unique/marker gate failed');
    }

    $phase='safe-natural-candidate';
    $sql='SELECT d.UUID D_UUID,d.NAME D_NAME,d.CATEGORY D_CATEGORY,'
        .' d.WEIGHT D_WEIGHT,f.ID F_ID,f.NAME F_NAME,'
        .' r.MENU_DATE MENU_DATE,r.RESTAURANT_ID RESTAURANT_ID,'
        .' r.MEAL_TIMES MEAL_TIMES,st.UUID RESTAURANT_UUID'
        .' FROM YDY_DISHES d JOIN YDY_DISH c ON c.DISHES_UUID=d.UUID'
        .' JOIN YDY_FOODS_COMPOSITION f ON f.ID=c.COMPOSITION_ID'
        .' JOIN YDY_RECIPES r ON r.DISHES_UUID=d.UUID'
        .' JOIN YDY_RESTAURANTS st ON st.ID=r.RESTAURANT_ID'
        .' WHERE d.STATUS=1 AND d.IS_DEL=1 AND d.IS_DELETE=0'
        .' AND d.STORE_ID=10001 AND d.CATEGORY BETWEEN 1 AND 6'
        .' AND c.IS_DELETE=0 AND c.COMPOSITION_RATIO>10'
        .' AND f.IS_DELETE=0 AND st.STATUS=1 AND st.IS_DELETE=2'
        .' AND r.MEAL_TIMES BETWEEN 1 AND 3 AND EXISTS('
        .' SELECT 1 FROM YDY_DATE_MENU dm'
        .' WHERE dm.DISHES_UUID=r.DISHES_UUID'
        .' AND dm.MENU_DATE=r.MENU_DATE'
        .' AND dm.RESTAURANT_ID=r.RESTAURANT_ID'
        .' AND dm.MEAL_TIMES=r.MEAL_TIMES AND dm.MEAL_TYPE=3)'
        .' ORDER BY r.MENU_DATE DESC,d.ID DESC FETCH FIRST 300 ROWS ONLY';
    $safe=static function(string $name): bool {
        if ($name==='' || mb_strlen($name)>50
            || preg_match('/[\x00-\x1f]/u',$name)) return false;
        foreach (["'",'"','\\','%','_'] as $unsafe) {
            if (strpos($name,$unsafe)!==false) return false;
        }
        return true;
    };
    $nameCount=$db->prepare('SELECT COUNT(*) FROM YDY_DISHES WHERE NAME=?');
    $foodMatches=$db->prepare('SELECT COUNT(*) FROM YDY_FOODS_COMPOSITION'
        .' WHERE NAME LIKE ? OR SUB_NAME LIKE ?');
    $target=null;
    $sourceCount=0;
    foreach ($db->query($sql)->fetchAll(PDO::FETCH_ASSOC) as $raw) {
        $row=array_change_key_case($raw,CASE_LOWER);
        if (!$safe((string)$row['d_name']) || !$safe((string)$row['f_name'])) {
            continue;
        }
        $nameCount->execute([(string)$row['d_name']]);
        if ((int)$nameCount->fetchColumn()!==1) continue;
        $term='%'.(string)$row['f_name'].'%';
        $foodMatches->execute([$term,$term]);
        $foodCount=(int)$foodMatches->fetchColumn();
        if ($foodCount<1 || $foodCount>50) continue;
        if (substr(hash('sha256',(string)$row['d_uuid']),0,12)==='1b1f73e2b07d'
            && substr(hash('sha256',(string)$row['f_id']),0,12)==='fa7aec4efb72'
            && substr(hash('sha256',(string)$row['d_name']),0,12)==='e233a13a49e5'
            && substr(hash('sha256',(string)$row['f_name']),0,12)==='4e5a5e503cae'
            && substr(hash('sha256',substr((string)$row['menu_date'],0,10)),0,12)
                ==='9c84d43649ee'
            && substr(hash('sha256',(string)$row['restaurant_uuid']),0,12)
                ==='67851cd5df6c'
            && (int)$row['d_category']===1
            && (int)$row['meal_times']===1
            && is_numeric($row['d_weight'])) {
            $target=$row;
            $sourceCount++;
        }
    }
    if ($target===null || $sourceCount<1) {
        throw new RuntimeException('Pinned safe natural candidate absent');
    }
    $day=substr((string)$target['menu_date'],0,10);
    if (!preg_match('/^\d{4}-\d{2}-\d{2}$/',$day)
        || substr(hash('sha256',$day),0,12)!=='9c84d43649ee'
        || (int)$target['d_category']!==1
        || (int)$target['meal_times']!==1) {
        throw new RuntimeException('Pinned natural date/category/meal changed');
    }
    $dishUuid=(string)$target['d_uuid'];
    $foodId=(int)$target['f_id'];
    $dishName=(string)$target['d_name'];
    $foodName=(string)$target['f_name'];
    $restaurant=(int)$target['restaurant_id'];
    $restaurantUuid=(string)$target['restaurant_uuid'];
    if ($count($db,'SELECT COUNT(*) FROM YDY_USER WHERE UUID=?',[$userUuid])!==0
        || $count($db,'SELECT COUNT(*) FROM YDY_USER_DATA'
            .' WHERE USER_UUID=?',[$userUuid])!==0) {
        throw new RuntimeException('Synthetic UUID collision');
    }
    $sourceSnapshot=static function(PDO $conn) use ($dishUuid,$foodId,$day,
        $restaurant): array {
        $dishStmt=$conn->prepare('SELECT UUID,NAME,WEIGHT,CATEGORY,STATUS,IS_DEL'
            .' FROM YDY_DISHES WHERE UUID=?');
        $dishStmt->execute([$dishUuid]);
        $dish=$dishStmt->fetch(PDO::FETCH_ASSOC);
        $foodStmt=$conn->prepare('SELECT ID,NAME,SUB_NAME'
            .' FROM YDY_FOODS_COMPOSITION WHERE ID=?');
        $foodStmt->execute([$foodId]);
        $food=$foodStmt->fetch(PDO::FETCH_ASSOC);
        $countQuery=static function(string $sql,array $args) use ($conn): int {
            $stmt=$conn->prepare($sql);
            $stmt->execute($args);
            return (int)$stmt->fetchColumn();
        };
        $recipeCount=$countQuery('SELECT COUNT(*) FROM YDY_RECIPES'
            .' WHERE MENU_DATE=? AND RESTAURANT_ID=?',[$day,$restaurant]);
        $anomalyCount=$countQuery('SELECT COUNT(*) FROM YDY_RECIPES r'
            .' JOIN YDY_DISHES d ON d.UUID=r.DISHES_UUID'
            .' WHERE r.MENU_DATE=? AND r.RESTAURANT_ID=?'
            .' AND (d.IS_DEL=0 OR d.STATUS=0)',[$day,$restaurant]);
        $relationCount=$countQuery('SELECT COUNT(*) FROM YDY_DISH'
            .' WHERE DISHES_UUID=? AND COMPOSITION_ID=?'
            .' AND COMPOSITION_RATIO>10',[$dishUuid,$foodId]);
        if (!is_array($dish) || !is_array($food)
            || $recipeCount<1 || $relationCount<1) {
            throw new RuntimeException('Natural source row disappeared');
        }
        $encoded=json_encode([$dish,$food,$recipeCount,
            $anomalyCount,$relationCount],JSON_UNESCAPED_UNICODE);
        if (!is_string($encoded)) {
            throw new RuntimeException('Source snapshot cannot be hashed');
        }
        return [
            'hash'=>hash('sha256',$encoded),
            'recipe_count'=>$recipeCount,
            'anomaly_count'=>$anomalyCount,
            'relation_count'=>$relationCount,
            'dish_weight'=>array_change_key_case($dish,CASE_LOWER)['weight']??null,
        ];
    };
    $before=$sourceSnapshot($db);
    if ($before['recipe_count']!==112 || $before['anomaly_count']!==16) {
        throw new RuntimeException('Approved natural source counts changed');
    }
    $result['candidate']=[
        'dish_uuid_sha12'=>'1b1f73e2b07d',
        'food_id_sha12'=>'fa7aec4efb72',
        'date_sha12'=>'9c84d43649ee',
        'category'=>1,'meal_times'=>1,
        'recipe_count'=>$before['recipe_count'],
        'anomaly_count'=>$before['anomaly_count'],
        'source_hash_sha12'=>substr($before['hash'],0,12),
    ];

    $phase='private-manifest';
    if (!is_dir($manifestDir) || is_link($manifestDir)
        || (fileperms($manifestDir)&0777)!==0700) {
        throw new RuntimeException('Private manifest directory invalid');
    }
    $manifestPath=$manifestDir.'/manifest-'.$marker.'.json';
    $manifest=[
        'lane'=>'C','schema'=>'ZHCT_APP','marker'=>$marker,
        'user_uuid'=>$userUuid,'restaurant_uuid'=>$restaurantUuid,
        'business_tables_written'=>false,
        'permission_fixture_phase'=>'planned',
    ];
    $manifestFile=@fopen($manifestPath,'x');
    if (!$manifestFile) throw new RuntimeException('Manifest collision');
    chmod($manifestPath,0600);
    $manifestJson=json_encode($manifest,JSON_UNESCAPED_SLASHES);
    if (!is_string($manifestJson)
        || fwrite($manifestFile,$manifestJson)!==strlen($manifestJson)) {
        fclose($manifestFile);
        throw new RuntimeException('Manifest write incomplete');
    }
    fclose($manifestFile);
    $result['manifest']['private_path']=$manifestPath;

    $phase='fixture-user';
    $fixtureTouched=true;
    $now=date('Y-m-d H:i:s');
    $db->prepare('INSERT INTO YDY_USER'
        .' (UUID,ACCOUNT,PWD,SALT,NAME,TYPE,STATUS,CREATE_TIME,CREATE_BY,IS_DELETE)'
        .' VALUES (?,?,?,?,?,1,1,?,?,0)')
        ->execute([$userUuid,$marker,'DISABLED',
            strtoupper(bin2hex(random_bytes(8))),$marker,$now,$marker]);
    $actorStmt=$open()->prepare('SELECT ID,TYPE,STATUS,NAME FROM YDY_USER'
        .' WHERE UUID=? AND ACCOUNT=?');
    $actorStmt->execute([$userUuid,$marker]);
    $actor=$actorStmt->fetch(PDO::FETCH_ASSOC);
    $actor=$actor?array_change_key_case($actor,CASE_LOWER):null;
    if (!$actor || (int)$actor['type']!==1 || (int)$actor['status']!==1
        || (string)$actor['name']!==$marker) {
        throw new RuntimeException('Synthetic type1 actor readback failed');
    }
    $result['manifest']['user_id']=(int)$actor['id'];
    $db->prepare('INSERT INTO YDY_USER_DATA'
        .' (USER_UUID,DATA_UUID,TYPE) VALUES (?,?,3)')
        ->execute([$userUuid,$restaurantUuid]);
    if ($count($open(),'SELECT COUNT(*) FROM YDY_USER_DATA'
        .' WHERE USER_UUID=? AND DATA_UUID=? AND TYPE=3',
        [$userUuid,$restaurantUuid])!==1) {
        throw new RuntimeException('Type3 restaurant scope readback failed');
    }
    require_once $root.'/application/base/Security.php';
    $token=\app\base\Security::encrypt(implode("\t",[
        (string)$actor['id'],$userUuid,$marker,'1','','',$marker,
    ]));
    if (!is_string($token) || $token==='') {
        throw new RuntimeException('Synthetic token unavailable');
    }
    $result['permission_positive']=['type1_and_type3_restaurant'=>true];

    $post=static function(string $path,array $form,string $token): array {
        $allowed=['/p/bill/dishesInfo'];
        if (!in_array($path,$allowed,true)) {
            throw new RuntimeException('Non-whitelisted Bill read route');
        }
        $context=stream_context_create(['http'=>[
            'method'=>'POST',
            'header'=>"Content-Type: application/x-www-form-urlencoded\r\n"
                .'token: '.$token."\r\n",
            'content'=>http_build_query($form,'','&',PHP_QUERY_RFC3986),
            'timeout'=>25,'ignore_errors'=>true,
        ]]);
        $body=@file_get_contents('http://127.0.0.1:18080'.$path,
            false,$context);
        $headers=$http_response_header??[];
        $status=preg_match('/^HTTP\/\S+\s+(\d+)/',
            (string)($headers[0]??''),$match)?(int)$match[1]:0;
        if (!is_string($body)) return [
            'http_status'=>$status,'transport'=>'incomplete',
            'body_bytes'=>0,'json'=>null,
        ];
        if (strlen($body)>8000000) return [
            'http_status'=>$status,'transport'=>'oversize',
            'body_bytes'=>strlen($body),'json'=>null,
        ];
        $json=json_decode($body,true);
        return [
            'http_status'=>$status,
            'transport'=>is_array($json)?'json':'non-json',
            'body_bytes'=>strlen($body),
            'body_sha256'=>hash('sha256',$body),
            'json'=>is_array($json)?$json:null,
        ];
    };
    $hasUuid=static function($node) use (&$hasUuid,$dishUuid): bool {
        if (!is_array($node)) return false;
        foreach (['uuid','dishes_uuid'] as $key) {
            if (array_key_exists($key,$node)
                && (string)$node[$key]===$dishUuid) return true;
        }
        foreach ($node as $child) {
            if (is_array($child) && $hasUuid($child)) return true;
        }
        return false;
    };
    $cases=[
        ['dishesInfo','/p/bill/dishesInfo',[
            'dishes_name'=>$dishName,
        ]],
    ];
    foreach ($cases as [$label,$path,$form]) {
        $phase='http-'.$label;
        $response=$post($path,$form,$token);
        $json=$response['json'];
        $data=is_array($json)?($json['data']??null):null;
        $evidence=[
            'route'=>$path,'http_status'=>$response['http_status'],
            'transport'=>$response['transport'],
            'body_bytes'=>$response['body_bytes'],
            'body_sha256'=>$response['body_sha256']??null,
            'business_code'=>is_array($json)?($json['code']??null):null,
            'data_type'=>gettype($data),
        ];
        if (is_array($data)) {
            $evidence['data_key_sha12']=substr(hash('sha256',
                json_encode(array_keys($data),JSON_UNESCAPED_UNICODE)),0,12);
            $evidence['data_count']=count($data);
        }
        $fields=['uuid','dishes_uuid','weight','value','category',
            'file_path','img','children','select','active','name'];
        $types=[];
        $walk=static function($node) use (&$walk,&$types,$fields): void {
            if (!is_array($node)) return;
            foreach ($fields as $field) {
                if (array_key_exists($field,$node)) {
                    $types[$field][gettype($node[$field])]=true;
                }
            }
            foreach ($node as $child) {
                if (is_array($child)) $walk($child);
            }
        };
        $walk($data);
        $evidence['safe_field_types']=[];
        foreach ($types as $field=>$choices) {
            $values=array_keys($choices); sort($values);
            $evidence['safe_field_types'][$field]=$values;
        }
        $weightMatches=false;
        $fixedTwo=false;
        if (is_array($data) && count($data)===1
            && $hasUuid($data) && isset($data[0]['weight'])
            && is_string($data[0]['weight'])
            && preg_match('/^-?\\d+\\.\\d{2}$/',$data[0]['weight'])===1
            && is_numeric($before['dish_weight'])) {
            $fixedTwo=true;
            $weightMatches=abs((float)$data[0]['weight']
                -(float)$before['dish_weight'])<0.001;
        }
        $good=$response['http_status']===200
            && $response['transport']==='json'
            && is_array($json) && ($json['code']??null)===0
            && $fixedTwo && $weightMatches;
        $evidence['weight_fixed_two_string']=$fixedTwo;
        $evidence['one_dish_weight_matches_source']=$weightMatches;
        $evidence['limited_pass']=$good;
        $result['cases'][]=$evidence;
        if (!$good) {
            if ($response['transport']==='incomplete') $transportUncertain=true;
            $result['stopped_early']=in_array($response['transport'],
                ['incomplete','oversize'],true)
                ? 'transport-boundary'
                : 'first-business-or-contract-failure';
            break;
        }
    }
    $phase='source-readback';
    $after=$sourceSnapshot($open());
    $result['readback']=[
        'business_source_hash_unchanged'=>hash_equals($before['hash'],$after['hash']),
        'recipe_count_unchanged'=>$after['recipe_count']===$before['recipe_count'],
        'anomaly_count_unchanged'=>$after['anomaly_count']===$before['anomaly_count'],
    ];
    $result['status']='readonly-http-executed';
} catch (Throwable $error) {
    $result['status']='blocked';
    $result['phase']=$phase;
    $result['error_class']=get_class($error);
    $result['error_code']=(string)$error->getCode();
} finally {
    if ($fixtureTouched) {
        try {
            $cleanup=$open();
            $scopeUser=$count($cleanup,'SELECT COUNT(*) FROM YDY_USER'
                .' WHERE UUID=?',[$userUuid]);
            $exactUser=$count($cleanup,'SELECT COUNT(*) FROM YDY_USER'
                .' WHERE UUID=? AND ACCOUNT=?',[$userUuid,$marker]);
            $scopeData=$count($cleanup,'SELECT COUNT(*) FROM YDY_USER_DATA'
                .' WHERE USER_UUID=?',[$userUuid]);
            $exactData=$count($cleanup,'SELECT COUNT(*) FROM YDY_USER_DATA'
                .' WHERE USER_UUID=? AND DATA_UUID=? AND TYPE=3',
                [$userUuid,$restaurantUuid]);
            $markerRows=$count($cleanup,'SELECT COUNT(*) FROM YDY_USER'
                .' WHERE ACCOUNT=?',[$marker]);
            if ($scopeUser!==$exactUser || $scopeData!==$exactData
                || $markerRows!==$exactUser || $exactUser>1 || $exactData>1) {
                throw new RuntimeException('Unknown fixture association; refuse wide delete');
            }
            $delete=static function(PDO $conn,string $table,
                string $where,array $args): void {
                $stmt=$conn->prepare('DELETE FROM '.$table.' WHERE '.$where);
                $stmt->execute($args);
            };
            // Revoke this run's restaurant data scope. Token itself is not revoked.
            $delete($cleanup,'YDY_USER_DATA',
                'USER_UUID=? AND DATA_UUID=? AND TYPE=3',
                [$userUuid,$restaurantUuid]);
            $result['cleanup']['type3_scope_revoked']=$count($open(),
                'SELECT COUNT(*) FROM YDY_USER_DATA WHERE USER_UUID=?',
                [$userUuid])===0;
            if (!$result['cleanup']['type3_scope_revoked']) {
                throw new RuntimeException('Type3 scope revocation failed');
            }
            if ($transportUncertain) {
                $currentCmd=str_replace("\0",' ',(string)file_get_contents(
                    '/proc/'.$pid.'/cmdline'));
                $currentWorkers='';
                foreach (explode("\0",(string)file_get_contents(
                    '/proc/'.$pid.'/environ')) as $entry) {
                    $parts=explode('=',$entry,2);
                    if (count($parts)===2 && $parts[0]==='PHP_CLI_SERVER_WORKERS') {
                        $currentWorkers=$parts[1];
                    }
                }
                if ($currentCmd!==$cmd
                    || strpos($currentCmd,' -S 127.0.0.1:18080 ')===false
                    || strpos($currentCmd,$root.'/public')===false
                    || substr_count($currentCmd,' -S ')!==1
                    || !in_array($currentWorkers,['','1'],true)) {
                    $result['cleanup']['remaining_user_retained']=true;
                    throw new RuntimeException('Single-worker barrier process changed');
                }
                $barrierRaw=@file_get_contents('http://127.0.0.1:18080/__poc_boundary',
                    false,stream_context_create(['http'=>[
                        'timeout'=>5,'ignore_errors'=>true,
                    ]]));
                $barrierHeaders=$http_response_header??[];
                $barrierStatus=preg_match('/^HTTP\/\S+\s+(\d+)/',
                    (string)($barrierHeaders[0]??''),$barrierMatch)
                    ? (int)$barrierMatch[1]:0;
                $barrier=json_decode((string)$barrierRaw,true);
                if ($barrierStatus!==200 || !is_array($barrier)
                    || empty($barrier['external_stubs'])
                    || empty($barrier['redis_isolated'])
                    || !empty($barrier['real_queue'])) {
                    $result['cleanup']['remaining_user_retained']=true;
                    throw new RuntimeException('HTTP barrier failed');
                }
                $result['cleanup']['barrier']='passed';
            }
            $delete($cleanup,'YDY_USER','UUID=? AND ACCOUNT=?',
                [$userUuid,$marker]);
            $verify=$open();
            $remainingUser=$count($verify,'SELECT COUNT(*) FROM YDY_USER'
                .' WHERE UUID=? OR ACCOUNT=?',[$userUuid,$marker]);
            $remainingData=$count($verify,'SELECT COUNT(*) FROM YDY_USER_DATA'
                .' WHERE USER_UUID=?',[$userUuid]);
            if ($remainingUser!==0 || $remainingData!==0) {
                throw new RuntimeException('Synthetic user/data cleanup incomplete');
            }
            $result['cleanup']=[
                'type3_scope_revoked'=>true,
                'user_rows'=>0,'user_data_rows'=>0,
                'synthetic_two_tables_zero'=>true,
            ];
            $manifest['permission_fixture_phase']='cleaned';
            $serialized=json_encode($manifest,JSON_UNESCAPED_SLASHES);
            $written=file_put_contents($manifestPath,$serialized,LOCK_EX);
            if (!is_int($written) || $written!==strlen($serialized)) {
                throw new RuntimeException('Manifest cleaned-state write failed');
            }
        } catch (Throwable $cleanupError) {
            $result['status']='cleanup-blocked';
            $result['cleanup']['error_class']=get_class($cleanupError);
            $result['cleanup']['error_code']=(string)$cleanupError->getCode();
        }
    }
}
$allOne=count($result['cases'])===1;
foreach ($result['cases'] as $case) {
    if (empty($case['limited_pass'])) $allOne=false;
}
$readback=isset($result['readback'])
    && count($result['readback'])===3;
foreach ((array)($result['readback']??[]) as $passed) {
    if ($passed!==true) $readback=false;
}
$result['all_one_limited_pass']=$allOne;
$result['all_source_readback_pass']=$readback;
echo json_encode($result,JSON_UNESCAPED_SLASHES).PHP_EOL;
if ($result['status']!=='readonly-http-executed' || !$allOne
    || !$readback
    || empty($result['cleanup']['synthetic_two_tables_zero'])) exit(1);
