<?php

declare(strict_types=1);

// C draft: metadata/COUNT by default; DML/HTTP only with POC_APPROVED_N3_WRITE=1.
set_exception_handler(static function (Throwable $error): void {
    fwrite(STDERR, 'AI_N3_PREFLIGHT_FAILED ' . get_class($error) . PHP_EOL);
    exit(2);
});
$root = '/tmp/zhct-ai-http-20260929.3XDj3w';
$base = 'http://127.0.0.1:18102';
$env = [];
foreach (explode("\0", (string)@file_get_contents('/proc/53772/environ')) as $item) {
    $parts = explode('=', $item, 2);
    if (count($parts) === 2) $env[$parts[0]] = $parts[1];
}
if (($env['POC_TARGET_ROOT'] ?? '') !== $root
    || ($env['POC_BASE_URL'] ?? '') !== $base
    || ($env['POC_DIALECT'] ?? '') !== 'dm'
    || ($env['POC_AI_HOST'] ?? '') !== '127.0.0.1'
    || ($env['POC_AI_PORT'] ?? '') !== '5238'
    || ($env['POC_AI_SCHEMA'] ?? '') !== 'AIZHCT_APP'
    || ($env['POC_AI_USER'] ?? '') !== 'AIZHCT_APP') {
    throw new RuntimeException('Unapproved C AI boundary');
}
$boundaryRaw = @file_get_contents($base . '/__poc_boundary', false,
    stream_context_create(['http' => ['timeout' => 5]]));
$boundary = is_string($boundaryRaw) ? json_decode($boundaryRaw, true) : null;
unset($boundaryRaw);
if (!is_array($boundary) || empty($boundary['external_stubs'])) {
    throw new RuntimeException('C external isolation absent');
}
$db = new PDO('dm:host=' . $env['POC_AI_HOST'] . ';port=' . $env['POC_AI_PORT']
    . ';schema=' . $env['POC_AI_SCHEMA'], $env['POC_AI_USER'],
    $env['POC_AI_PASSWORD'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_CASE => PDO::CASE_LOWER]);
if ((string)$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")
    ->fetchColumn() !== 'AIZHCT_APP') {
    throw new RuntimeException('C actual schema mismatch');
}
$count = static function (string $sql, array $args = []) use ($db): int {
    $stmt = $db->prepare($sql);
    $stmt->execute($args);
    return (int)$stmt->fetchColumn();
};
$needed = [
    'store' => ['STORE_ID'],
    'store_user' => ['STORE_USER_ID', 'USER_NAME', 'PASSWORD', 'IS_SUPER',
        'STORE_ID', 'IS_DELETE'],
    'store_user_role' => ['ID', 'STORE_USER_ID'],
    'store_api' => ['API_ID', 'URL'],
    'staff' => ['ID', 'NAME', 'STORE_ID', 'IS_DELETE'],
    'staff_weight' => ['ID', 'STAFF_ID', 'SET_DATE', 'HEIGHT', 'WEIGHT',
        'STORE_ID', 'IS_DELETE', 'CREATE_BY'],
    'meal' => ['ID', 'STAFF_ID', 'MEAL_DATE', 'MEAL_TIMES', 'STORE_ID',
        'IS_DELETE', 'CREATE_BY'],
    'meal_infos' => ['ID', 'MEAL_ID', 'STAFF_ID', 'MEAL_DATE', 'MEAL_TIMES',
        'DISHES_ID', 'DISHES_WEIGHT', 'CATEGORY', 'STORE_ID', 'IS_DELETE'],
    'meal_recommend' => ['ID', 'STAFF_ID', 'MEAL_DATE'],
    'dishes' => ['ID', 'NAME', 'CATEGORY', 'WEIGHT', 'ENERGY',
        'CARBOHYDRATE', 'PROTEIN', 'FAT', 'STORE_ID', 'IS_DELETE'],
    'dishes_cate' => ['ID', 'PID'],
];
$tableOk = [];
$triggerCounts = [];
foreach ($needed as $short => $columns) {
    $table = 'YOSHOP_' . strtoupper($short);
    $exists = $count('SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME=?', [$table]) === 1;
    $columnOk = false;
    $triggerCounts[$short] = null;
    if ($exists) {
        $stmt = $db->prepare('SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME=?');
        $stmt->execute([$table]);
        $actual = array_map('strtoupper', $stmt->fetchAll(PDO::FETCH_COLUMN));
        $columnOk = count(array_diff($columns, $actual)) === 0;
        $triggerCounts[$short] = $count('SELECT COUNT(*) FROM USER_TRIGGERS'
            . " WHERE TABLE_NAME=? AND STATUS='ENABLED'", [$table]);
    }
    $tableOk[$short] = $exists && $columnOk;
}
$routes = ['weight.staff_weight/list', 'weight.staff_weight/echartsList',
    'meal.meals/mealsInfo'];
$acl = [];
if ($tableOk['store_api']) {
    foreach ($routes as $route) {
        $acl[$route] = $count('SELECT COUNT(*) FROM YOSHOP_STORE_API WHERE URL=?',
            ['/' . $route]);
    }
}
$marker = 'CDXPARNUN3' . strtoupper(bin2hex(random_bytes(4)));
$markerZero = [];
foreach (['store_user' => 'USER_NAME', 'staff' => 'NAME',
    'dishes' => 'NAME'] as $short => $field) {
    $markerZero[$short] = $tableOk[$short]
        ? $count('SELECT COUNT(*) FROM YOSHOP_' . strtoupper($short)
            . ' WHERE ' . $field . '=?', [$marker]) === 0 : null;
}
$catalog = [
    'store_10001' => $tableOk['store']
        ? $count('SELECT COUNT(*) FROM YOSHOP_STORE WHERE STORE_ID=?', [10001]) : null,
    'dishes_top_category_count' => $tableOk['dishes_cate']
        ? $count('SELECT COUNT(*) FROM YOSHOP_DISHES_CATE WHERE PID=0') : null,
];
$dishCandidate = null;
$dishId = 0;
$dishHashBefore = '';
$dishCandidateUnique = false;
if ($tableOk['dishes'] && $tableOk['dishes_cate']) {
    $candidateSql = 'SELECT d.* FROM YOSHOP_DISHES d'
        . ' JOIN YOSHOP_DISHES_CATE c ON c.ID=d.CATEGORY'
        . ' WHERE d.STORE_ID=10001 AND d.IS_DELETE=0 AND d.ENERGY>0 AND d.WEIGHT>0'
        . ' AND c.PID=0 ORDER BY d.ID ASC'
        . ' FETCH FIRST 1 ROWS ONLY';
    $candidateStmt = $db->query($candidateSql);
    $dishCandidate = $candidateStmt->fetch(PDO::FETCH_ASSOC) ?: null;
    if (is_array($dishCandidate)) {
        $dishId = (int)($dishCandidate['id'] ?? 0);
        ksort($dishCandidate);
        $encoded = json_encode($dishCandidate,
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        $dishHashBefore = is_string($encoded) ? hash('sha256', $encoded) : '';
        $dishCandidateUnique = $dishId > 0 && $dishHashBefore !== ''
            && $count('SELECT COUNT(*)'
            . ' FROM YOSHOP_DISHES d JOIN YOSHOP_DISHES_CATE c ON c.ID=d.CATEGORY'
            . ' WHERE d.ID=? AND d.STORE_ID=10001 AND d.IS_DELETE=0'
            . ' AND d.ENERGY>0 AND d.WEIGHT>0 AND c.PID=0',
            [$dishId]) === 1;
    }
}
$pass = !in_array(false, $tableOk, true)
    && !in_array(false, $markerZero, true)
    && $catalog['store_10001'] === 1
    && (int)$catalog['dishes_top_category_count'] > 0
    && array_sum(array_map('intval', $triggerCounts)) === 0
    && $dishCandidateUnique;
$pass = $pass && array_sum($acl) === 0;
if (!$pass || (string)getenv('POC_APPROVED_N3_WRITE') !== '1') {
    echo json_encode(['suite' => 'ai-store-n3-C', 'mode' => 'read-only-preflight',
    'tables_and_columns' => $tableOk, 'enabled_trigger_counts' => $triggerCounts,
    'acl_api_rows' => $acl, 'catalog_counts' => $catalog,
    'readonly_dish_candidate' => ['id' => $dishId,
        'row_sha256' => $dishHashBefore, 'unique_valid' => $dishCandidateUnique],
    'fresh_marker_zero' => $markerZero, 'external_stubs' => true],
    JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit($pass ? 0 : 1);
}

define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require $root . '/vendor/autoload.php';
(new \think\App($root))->setEnvName('poc')->initialize();
$rows = static function (string $sql, array $args = []) use ($db): array {
    $stmt = $db->prepare($sql);
    $stmt->execute($args);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
};
$assert = static function (bool $ok, string $message): void {
    if (!$ok) throw new RuntimeException($message);
};
$token = $marker . 'TOKEN' . strtoupper(bin2hex(random_bytes(8)));
$testDate = date('Y-m-d');
$mealTime = $testDate . ' 12:00:00';
$operatorId = 0;
$staffId = 0;
$dishId = (int)($dishCandidate['id'] ?? 0);
$categoryId = (int)($dishCandidate['category'] ?? 0);
$weightId = 0;
$mealId = 0;
$mealInfoId = 0;
$unsettledRequest = false;
$results = [];
$cleanup = [];
$failure = '';
$tokenPayload = null;
$request = static function (string $route, array $data) use ($base, $token): array {
    $context = stream_context_create(['http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json;charset=utf-8\r\n"
            . 'Access-Token: ' . $token . "\r\n",
        'content' => json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        'timeout' => 60, 'ignore_errors' => true,
    ]]);
    $started = microtime(true);
    $raw = @file_get_contents($base . '/index.php?s=/store/' . $route, false, $context);
    preg_match('/HTTP\/\S+\s+(\d+)/', $http_response_header[0] ?? '', $match);
    $json = is_string($raw) ? json_decode($raw, true) : null;
    unset($raw);
    return ['http' => (int)($match[1] ?? 0), 'complete' => is_array($json),
        'status' => is_array($json) ? (int)($json['status'] ?? -1) : -1,
        'data' => is_array($json) ? ($json['data'] ?? null) : null,
        'elapsed_ms' => (int)round((microtime(true) - $started) * 1000)];
};
try {
    $assert($dishId > 0 && $categoryId > 0 && $dishHashBefore !== '',
        'Read-only existing dish candidate absent');

    $db->prepare('INSERT INTO YOSHOP_STORE_USER'
        . ' (USER_NAME,PASSWORD,REAL_NAME,IS_SUPER,IS_DELETE,STORE_ID,CREATE_BY,CREATE_TIME,UPDATE_TIME)'
        . ' VALUES (?,?,?,1,0,10001,?,?,?)')
        ->execute([$marker, '!disabled-' . strtoupper(bin2hex(random_bytes(12))),
            $marker, $marker, time(), time()]);
    $owned = $rows('SELECT STORE_USER_ID FROM YOSHOP_STORE_USER WHERE USER_NAME=?', [$marker]);
    $assert(count($owned) === 1, 'Synthetic super operator missing/ambiguous');
    $operatorId = (int)$owned[0]['store_user_id'];
    $assert($operatorId > 0, 'Synthetic super operator ID invalid');
    $tokenPayload = ['user' => ['store_user_id' => $operatorId,
        'store_id' => 10001, 'user_name' => $marker,
        'real_name' => $marker, 'is_super' => 1],
        'store_id' => 10001, 'is_login' => true];

    $db->prepare('INSERT INTO YOSHOP_STAFF'
        . ' (NAME,STORE_ID,HEIGHT,WEIGHT,GENDER,BIRTHDAY,PHONE,IS_DELETE)'
        . " VALUES (?,10001,170,60,1,'1990-01-01','',0)")
        ->execute([$marker]);
    $owned = $rows('SELECT ID FROM YOSHOP_STAFF WHERE NAME=?', [$marker]);
    $assert(count($owned) === 1, 'Synthetic staff missing/ambiguous');
    $staffId = (int)$owned[0]['id'];
    $assert($count('SELECT COUNT(*) FROM YOSHOP_MEAL_RECOMMEND'
        . ' WHERE STAFF_ID=? AND MEAL_DATE=?', [$staffId, $testDate]) === 0,
        'Synthetic staff already has recommendation');

    $db->prepare('INSERT INTO YOSHOP_STAFF_WEIGHT'
        . ' (STAFF_ID,HEIGHT,WEIGHT,BODY_FAT_RATE,BMI,SET_DATE,STORE_ID,IS_DELETE,CREATE_BY)'
        . ' VALUES (?,170.00,60.00,20.00,20.76,?,10001,0,?)')
        ->execute([$staffId, $testDate, $marker]);
    $owned = $rows('SELECT ID FROM YOSHOP_STAFF_WEIGHT'
        . ' WHERE STAFF_ID=? AND SET_DATE=? AND CREATE_BY=?',
        [$staffId, $testDate, $marker]);
    $assert(count($owned) === 1, 'Synthetic weight row missing/ambiguous');
    $weightId = (int)$owned[0]['id'];

    $db->prepare('INSERT INTO YOSHOP_MEAL'
        . ' (STAFF_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,STORE_ID,IS_DELETE,CREATE_BY)'
        . ' VALUES (?,?,1,?,10001,0,?)')
        ->execute([$staffId, $testDate, $mealTime, $marker]);
    $owned = $rows('SELECT ID FROM YOSHOP_MEAL'
        . ' WHERE STAFF_ID=? AND MEAL_DATE=? AND CREATE_BY=?',
        [$staffId, $testDate, $marker]);
    $assert(count($owned) === 1, 'Synthetic meal missing/ambiguous');
    $mealId = (int)$owned[0]['id'];
    $db->prepare('INSERT INTO YOSHOP_MEAL_INFOS'
        . ' (MEAL_ID,STAFF_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,DISHES_ID,DISHES_WEIGHT,'
        . ' CATEGORY,ENERGY,CARBOHYDRATE,PROTEIN,FAT,STORE_ID,IS_DELETE,CREATE_BY)'
        . ' VALUES (?,?,?,1,?,?,?,?,?,?,?,?,10001,0,?)')
        ->execute([$mealId, $staffId, $testDate, $mealTime,
            $dishId, $dishCandidate['weight'], $categoryId,
            $dishCandidate['energy'], $dishCandidate['carbohydrate'],
            $dishCandidate['protein'], $dishCandidate['fat'], $marker]);
    $owned = $rows('SELECT ID FROM YOSHOP_MEAL_INFOS'
        . ' WHERE MEAL_ID=? AND STAFF_ID=? AND DISHES_ID=? AND CREATE_BY=?',
        [$mealId, $staffId, $dishId, $marker]);
    $assert(count($owned) === 1, 'Synthetic meal item missing/ambiguous');
    $mealInfoId = (int)$owned[0]['id'];
    $assert($count('SELECT COUNT(*) FROM YOSHOP_STAFF_WEIGHT'
        . ' WHERE STAFF_ID=? AND SET_DATE=? AND CREATE_BY=?',
        [$staffId, $testDate, $marker]) === 1
        && $count('SELECT COUNT(*) FROM YOSHOP_MEAL_INFOS'
            . ' WHERE MEAL_ID=? AND STAFF_ID=? AND DISHES_ID=? AND CREATE_BY=?',
            [$mealId, $staffId, $dishId, $marker]) === 1,
        'N3 original-table fixture incomplete');
    $results['fixture_weight_meal_one_each_existing_dish'] = true;
    $results['readonly_dish_id'] = $dishId;
    $results['readonly_dish_row_sha256'] = $dishHashBefore;

    $cases = [
        'weight.StaffWeight/list' => ['staff_id' => $staffId,
            'start_date' => $testDate, 'end_date' => $testDate,
            'page_size' => 10, 'page' => 1],
        'weight.StaffWeight/echartsList' => ['staff_id' => $staffId,
            'start_date' => $testDate, 'end_date' => $testDate],
        'meal.Meals/mealsInfo' => ['staff_id' => $staffId,
            'meal_date' => $testDate],
    ];
    foreach ($cases as $route => $params) {
        // Short-lived super token is refreshed only immediately before this one read.
        $assert(\think\facade\Cache::set($token, $tokenPayload, 45)
            && \think\facade\Cache::has($token),
            'Synthetic super token refresh failed');
        $response = $request($route, $params);
        if (!$response['complete']) {
            $unsettledRequest = true;
            throw new RuntimeException('N3 read outcome unsettled');
        }
        $assert($response['http'] === 200 && $response['status'] === 200
            && $response['elapsed_ms'] <= 60000,
            'N3 read response status or client budget mismatch');
        $data = $response['data'];
        if ($route === 'weight.StaffWeight/list') {
            $list = is_array($data) ? ($data['list']['data'] ?? null) : null;
            $row = is_array($list) ? ($list[0] ?? null) : null;
            $assert(is_array($list) && count($list) === 1
                && (int)($row['staff_id'] ?? 0) === $staffId
                && abs((float)($row['weight'] ?? -1) - 60.0) < 0.001,
                'N3 weight list/original row mismatch');
            $results['weight_list_one'] = true;
            $results['weight_list_type'] = gettype($row['weight'] ?? null);
        } elseif ($route === 'weight.StaffWeight/echartsList') {
            $list = is_array($data) ? ($data['list'] ?? null) : null;
            $row = is_array($list) ? ($list[0] ?? null) : null;
            $assert(is_array($list) && count($list) === 1
                && abs((float)($row['weight'] ?? -1) - 60.0) < 0.001,
                'N3 weight curve/original row mismatch');
            $results['weight_curve_one'] = true;
            $results['weight_curve_type'] = gettype($row['weight'] ?? null);
        } else {
            $meals = is_array($data) ? ($data['list'] ?? null) : null;
            $found = 0;
            if (is_array($meals)) {
                foreach ($meals as $mealGroup) {
                    foreach ((array)($mealGroup['data'] ?? []) as $categoryGroup) {
                        foreach ((array)($categoryGroup['dishes'] ?? []) as $dish) {
                            if ((int)($dish['dishes_id'] ?? 0) === $dishId) $found++;
                        }
                    }
                }
            }
            $assert($found === 1, 'N3 mealsInfo synthetic dish missing/duplicate');
            $results['meals_info_one_dish'] = true;
        }
    }
} catch (Throwable $error) {
    $failure = get_class($error) . ':' . hash('sha256', $error->getMessage());
} finally {
    try {
        $cacheAbsent = false;
        try {
            \think\facade\Cache::delete($token);
            $cacheAbsent = !\think\facade\Cache::has($token);
        } catch (Throwable $cacheError) {
            $cleanup['cache_error_class'] = get_class($cacheError);
        }
        $cleanup['cache_absent'] = $cacheAbsent;
        $barrierComplete = true;
        if ($unsettledRequest) {
            $raw = @file_get_contents($base . '/__poc_boundary', false,
                stream_context_create(['http' => [
                    'method' => 'GET', 'header' => "Connection: close\r\n",
                    'timeout' => 30, 'ignore_errors' => true,
                ]]));
            $barrier = is_string($raw) ? json_decode($raw, true) : null;
            unset($raw);
            preg_match('/HTTP\/\S+\s+(\d+)/', $http_response_header[0] ?? '', $httpMatch);
            $cmdline = str_replace("\0", ' ',
                (string)@file_get_contents('/proc/53772/cmdline'));
            $oneWorker = !isset($env['PHP_CLI_SERVER_WORKERS'])
                || (int)$env['PHP_CLI_SERVER_WORKERS'] <= 1;
            $barrierComplete = is_array($barrier)
                && !empty($barrier['external_stubs'])
                && (int)($httpMatch[1] ?? 0) === 200
                && strpos($cmdline, '-S 127.0.0.1:18102') !== false
                && $oneWorker;
            $cleanup['single_worker_barrier_complete'] = $barrierComplete;
        }
        if (!$cacheAbsent || !$barrierComplete) {
            $cleanup['deferred_actor_and_business_cleanup'] = true;
        } else {
            if ($operatorId <= 0) {
                $owned = $rows('SELECT STORE_USER_ID FROM YOSHOP_STORE_USER WHERE USER_NAME=?', [$marker]);
                $assert(count($owned) <= 1, 'Synthetic operator ambiguous; refusing cleanup');
                if ($owned) $operatorId = (int)$owned[0]['store_user_id'];
            }
            if ($staffId <= 0) {
                $owned = $rows('SELECT ID FROM YOSHOP_STAFF WHERE NAME=?', [$marker]);
                $assert(count($owned) <= 1, 'Synthetic staff ambiguous; refusing cleanup');
                if ($owned) $staffId = (int)$owned[0]['id'];
            }
            if ($mealId <= 0 && $staffId > 0) {
                $owned = $rows('SELECT ID FROM YOSHOP_MEAL WHERE STAFF_ID=?'
                    . ' AND MEAL_DATE=? AND CREATE_BY=?', [$staffId, $testDate, $marker]);
                $assert(count($owned) <= 1, 'Synthetic meal ambiguous; refusing cleanup');
                if ($owned) $mealId = (int)$owned[0]['id'];
            }
            if ($weightId <= 0 && $staffId > 0) {
                $owned = $rows('SELECT ID FROM YOSHOP_STAFF_WEIGHT'
                    . ' WHERE STAFF_ID=? AND SET_DATE=? AND CREATE_BY=?',
                    [$staffId, $testDate, $marker]);
                $assert(count($owned) <= 1, 'Synthetic weight row ambiguous; refusing cleanup');
                if ($owned) $weightId = (int)$owned[0]['id'];
            }
            if ($mealInfoId <= 0 && $staffId > 0) {
                $owned = $rows('SELECT ID FROM YOSHOP_MEAL_INFOS'
                    . ' WHERE STAFF_ID=? AND MEAL_ID=? AND DISHES_ID=? AND CREATE_BY=?',
                    [$staffId, $mealId, $dishId, $marker]);
                $assert(count($owned) <= 1, 'Synthetic meal item ambiguous; refusing cleanup');
                if ($owned) $mealInfoId = (int)$owned[0]['id'];
            }
            if ($staffId > 0) {
                $infos = $rows('SELECT ID,MEAL_ID,DISHES_ID,CREATE_BY FROM YOSHOP_MEAL_INFOS'
                    . ' WHERE STAFF_ID=?', [$staffId]);
                $weights = $rows('SELECT ID,SET_DATE,CREATE_BY FROM YOSHOP_STAFF_WEIGHT'
                    . ' WHERE STAFF_ID=?', [$staffId]);
                $meals = $rows('SELECT ID,CREATE_BY FROM YOSHOP_MEAL WHERE STAFF_ID=?', [$staffId]);
                $assert(count($infos) <= 1 && (!$infos
                    || ((int)$infos[0]['id'] === $mealInfoId
                        && (int)$infos[0]['meal_id'] === $mealId
                        && (int)$infos[0]['dishes_id'] === $dishId
                        && (string)$infos[0]['create_by'] === $marker))
                    && count($weights) <= 1 && (!$weights
                        || ((int)$weights[0]['id'] === $weightId
                            && (string)$weights[0]['create_by'] === $marker))
                    && count($meals) <= 1 && (!$meals
                        || ((int)$meals[0]['id'] === $mealId
                            && (string)$meals[0]['create_by'] === $marker))
                    && $count('SELECT COUNT(*) FROM YOSHOP_MEAL_RECOMMEND WHERE STAFF_ID=?',
                        [$staffId]) === 0,
                    'Unexpected synthetic staff children; refusing cleanup');
                if ($mealInfoId > 0) {
                    $db->prepare('DELETE FROM YOSHOP_MEAL_INFOS'
                        . ' WHERE ID=? AND STAFF_ID=? AND MEAL_ID=? AND DISHES_ID=? AND CREATE_BY=?')
                        ->execute([$mealInfoId, $staffId, $mealId, $dishId, $marker]);
                }
            }
            if ($mealId > 0) {
                $db->prepare('DELETE FROM YOSHOP_MEAL WHERE ID=? AND STAFF_ID=? AND CREATE_BY=?')
                    ->execute([$mealId, $staffId, $marker]);
            }
            if ($weightId > 0) {
                $db->prepare('DELETE FROM YOSHOP_STAFF_WEIGHT'
                    . ' WHERE ID=? AND STAFF_ID=? AND CREATE_BY=?')
                    ->execute([$weightId, $staffId, $marker]);
            }
            if ($staffId > 0) {
                $db->prepare('DELETE FROM YOSHOP_STAFF WHERE ID=? AND NAME=?')
                    ->execute([$staffId, $marker]);
            }
            if ($operatorId > 0) {
                $assert($count('SELECT COUNT(*) FROM YOSHOP_STORE_USER_ROLE'
                    . ' WHERE STORE_USER_ID=?', [$operatorId]) === 0,
                    'Unexpected synthetic super role relation; refusing cleanup');
                $db->prepare('DELETE FROM YOSHOP_STORE_USER WHERE STORE_USER_ID=? AND USER_NAME=?')
                    ->execute([$operatorId, $marker]);
            }
            $dishAfter = $rows('SELECT * FROM YOSHOP_DISHES WHERE ID=?', [$dishId]);
            $dishUnchanged = count($dishAfter) === 1;
            if ($dishUnchanged) {
                ksort($dishAfter[0]);
                $encodedAfter = json_encode($dishAfter[0],
                    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                $dishUnchanged = is_string($encodedAfter)
                    && hash('sha256', $encodedAfter) === $dishHashBefore;
            }
            $cleanup = array_merge($cleanup, [
                'operator_zero' => $count('SELECT COUNT(*) FROM YOSHOP_STORE_USER WHERE USER_NAME=?', [$marker]) === 0,
                'staff_zero' => $count('SELECT COUNT(*) FROM YOSHOP_STAFF WHERE NAME=?', [$marker]) === 0,
                'readonly_dish_unchanged' => $dishUnchanged,
                'weight_zero' => $staffId <= 0 || $count('SELECT COUNT(*) FROM YOSHOP_STAFF_WEIGHT WHERE STAFF_ID=?', [$staffId]) === 0,
                'meal_zero' => $staffId <= 0 || $count('SELECT COUNT(*) FROM YOSHOP_MEAL WHERE STAFF_ID=?', [$staffId]) === 0,
                'meal_infos_zero' => $staffId <= 0 || $count('SELECT COUNT(*) FROM YOSHOP_MEAL_INFOS WHERE STAFF_ID=?', [$staffId]) === 0,
                'recommend_zero' => $staffId <= 0 || $count('SELECT COUNT(*) FROM YOSHOP_MEAL_RECOMMEND WHERE STAFF_ID=?', [$staffId]) === 0,
            ]);
        }
    } catch (Throwable $error) {
        $cleanup['error_class'] = get_class($error);
        $cleanup['error_sha256'] = hash('sha256', $error->getMessage());
    }
}
$clean = !in_array(false, $cleanup, true)
    && !isset($cleanup['error_class']) && !isset($cleanup['cache_error_class'])
    && empty($cleanup['deferred_actor_and_business_cleanup']);
echo json_encode(['suite' => 'ai-store-n3-C', 'marker' => $marker,
    'results' => $results, 'failure' => $failure, 'cleanup' => $cleanup],
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
exit($failure === '' && $clean ? 0 : 1);
