<?php

declare(strict_types=1);

// B-only code-local MySQL dishesInfo regression; A original stays unchanged.
// Business tables are SELECT-only; only one synthetic type1 user+type3 scope.
if ($argc!==2 || !in_array($argv[1],
    ['--run-approved-b-dishesinfo-weight'],true)
    || getenv('CDX_APPROVED_B_DISHESINFO_WEIGHT')!=='1') {
    fwrite(STDERR,"Explicit reviewed A/B Bill-more fixture gate required\n");
    exit(2);
}
$lane='B';
$runtime=$lane==='A'
    ? ['root'=>'/tmp/zhct-http-store-a.l5omH8','pid'=>21023,'port'=>18097]
    : ['root'=>'/tmp/zhct-http-store-mysql.dQTTBP','pid'=>10001,'port'=>18081];
$root=$runtime['root'];
$manifestDir='/tmp/zhct-store-ab-billmore-20261002';
$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'=>$lane,'cases'=>[],'manifest'=>[
    'marker'=>$marker,'user_uuid'=>$userUuid,
    'only_synthetic_identifiers'=>true,
]];
$open=null;
$count=null;

try {
    $pid=(string)$runtime['pid'];
    $cmd=str_replace("\0",' ',(string)file_get_contents('/proc/'.$pid.'/cmdline'));
    if (strpos($cmd,' -S 127.0.0.1:'.$runtime['port'].' ')===false
        || strpos($cmd,$root.'/public')===false
        || substr_count($cmd,' -S ')!==1) {
        throw new RuntimeException('Wrong A/B isolated Store runtime');
    }
    $workers='';
    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') {
            $workers=$parts[1];
        }
    }
    if (!in_array($workers,['','1'],true)) {
        throw new RuntimeException('Multiple HTTP workers not approved');
    }
    $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 $path=>$sha) {
        if ((string)hash_file('sha256',$root.'/'.$path)!==$sha) {
            throw new RuntimeException('Bill/Food/Cater source SHA changed');
        }
    }
    $boundaryRaw=@file_get_contents('http://127.0.0.1:'.$runtime['port']
        .'/__poc_boundary',false,stream_context_create(['http'=>[
            'timeout'=>3,'ignore_errors'=>true,
        ]]));
    $headers=$http_response_header??[];
    $boundaryStatus=preg_match('/^HTTP\/\S+\s+(\d+)/',
        (string)($headers[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('A/B isolated external boundary failed');
    }
    $phase='code-local-development-mysql';
    $load=static function(string $file): array { return require $file; };
    $local=$load('/workspace/zhct/zhctproject/store/application/config/local/database.php');
    $selected=$load($root.'/application/database.php');
    foreach (['hostname','database','username','password'] as $field) {
        if (!isset($local[$field],$selected[$field])
            || $local[$field]!==$selected[$field]) {
            throw new RuntimeException('Runtime not code-local development MySQL');
        }
    }
    if (($selected['type']??null)!=='mysql'
        || (int)($selected['hostport']??3306)
            !==(int)($local['hostport']??3306)) {
        throw new RuntimeException('Wrong MySQL dialect/port');
    }
    $open=static function() use ($local): PDO {
        return new PDO('mysql:host='.$local['hostname'].';port='.
            (int)($local['hostport']??3306).';dbname='.$local['database']
            .';charset=utf8mb4',(string)$local['username'],
            (string)$local['password'],[
                PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_EMULATE_PREPARES=>false,
                PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
                PDO::ATTR_TIMEOUT=>8,
            ]);
    };
    $db=$open();
    if (strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')!==0) {
        throw new RuntimeException('Not code-local MySQL5.6');
    }
    $count=static function(PDO $conn,string $sql,array $args=[]): int {
        $stmt=$conn->prepare($sql);
        $stmt->execute($args);
        return (int)$stmt->fetchColumn();
    };
    $schema=(string)$local['database'];
    $phase='columns-permission';
    $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,IS_NULLABLE,COLUMN_DEFAULT'
        .' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME=?');
    foreach ($required as $table=>$names) {
        $columns->execute([$schema,$table]);
        $fields=[];
        foreach ($columns->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $fields[strtolower((string)$row['COLUMN_NAME'])]=$row;
        }
        if (array_diff($names,array_keys($fields))) {
            throw new RuntimeException('Bill-more table columns 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 ($fields as $name=>$column) {
                if ($name!=='id' && $column['IS_NULLABLE']==='NO'
                    && $column['COLUMN_DEFAULT']===null
                    && !in_array($name,$inserted,true)) {
                    throw new RuntimeException('Permission insert omits required field');
                }
            }
            if ($count($db,'SELECT COUNT(*) FROM information_schema.TRIGGERS'
                .' WHERE TRIGGER_SCHEMA=? AND EVENT_OBJECT_TABLE=?',
                [$schema,$table])!==0
                || $count($db,'SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE'
                    .' WHERE TABLE_SCHEMA=? AND TABLE_NAME=?'
                    .' AND REFERENCED_TABLE_NAME IS NOT NULL',
                    [$schema,$table])!==0) {
                throw new RuntimeException('Permission trigger/FK gate failed');
            }
        }
    }
    $index=$db->prepare('SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME'
        .' FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=?'
        .' AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX');
    $index->execute([$schema,'ydy_user_data']);
    $indexes=[];
    foreach ($index->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $name=(string)$row['INDEX_NAME'];
        $indexes[$name]['unique']=(int)$row['NON_UNIQUE']===0;
        $indexes[$name]['columns'][]=strtolower((string)$row['COLUMN_NAME']);
    }
    $hasUnique=false;
    foreach ($indexes as $item) {
        if ($item['unique']
            && $item['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 LIMIT 300';
    $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)==='5e9e078c00ec'
            && substr(hash('sha256',(string)$row['f_id']),0,12)==='df56bc061e91'
            && substr(hash('sha256',(string)$row['d_name']),0,12)==='0feb1c7373e3'
            && substr(hash('sha256',(string)$row['f_name']),0,12)==='096dc845ec98'
            && substr(hash('sha256',substr((string)$row['menu_date'],0,10)),0,12)
                ==='f00c125bd8e1'
            && substr(hash('sha256',(string)$row['restaurant_uuid']),0,12)
                ==='67851cd5df6c'
            && (int)$row['d_category']===1
            && (int)$row['meal_times']===2
            && 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)!=='f00c125bd8e1'
        || (int)$target['d_category']!==1
        || (int)$target['meal_times']!==2) {
        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']!==86 || $before['anomaly_count']!==6) {
        throw new RuntimeException('Approved natural source counts changed');
    }
    $result['candidate']=[
        'dish_uuid_sha12'=>'5e9e078c00ec',
        'food_id_sha12'=>'df56bc061e91',
        'date_sha12'=>'f00c125bd8e1',
        'category'=>1,'meal_times'=>2,
        'recipe_count'=>$before['recipe_count'],
        'anomaly_count'=>$before['anomaly_count'],
        'source_hash_sha12'=>substr($before['hash'],0,12),
    ];

    $phase='fixture-fresh-connection';
    $refreshAt=microtime(true);
    $db=$open();
    $health=$db->prepare('SELECT 1');
    $health->execute();
    if ((int)$health->fetchColumn()!==1) {
        throw new RuntimeException('Fresh fixture PDO SELECT 1 failed');
    }
    $result['fixture_fresh_connection']=[
        'select1_passed'=>true,
        'elapsed_ms'=>(int)round((microtime(true)-$refreshAt)*1000),
    ];

    $phase='private-manifest';
    if (!is_dir($manifestDir)) {
        if (!mkdir($manifestDir,0700)) {
            throw new RuntimeException('Private manifest directory create failed');
        }
    }
    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'=>$lane,'schema'=>'code-local-mysql56','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)
        use ($runtime): 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:'.$runtime['port'].$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;
        }
        $sameAsA=$response['body_sha256']===
            '64873b3b915df3f2678735df205862fd90e3cfda7a857e10dcbcc6539f62a877';
        $good=$response['http_status']===200
            && $response['transport']==='json'
            && is_array($json) && ($json['code']??null)===0
            && $fixedTwo && $weightMatches && $sameAsA;
        $evidence['weight_fixed_two_string']=$fixedTwo;
        $evidence['one_dish_weight_matches_source']=$weightMatches;
        $evidence['full_response_sha_matches_a_original']=$sameAsA;
        $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:'.$runtime['port'].' ')===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:'.$runtime['port'].'/__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);
