<?php
declare(strict_types=1);

// Nonproduction C lane; one self-owned unpaid order only.
if (getenv('CDX_CASHIER_C_RUN') !== 'APPROVED_ONE_OWNED_ORDER_20261008'
    || getenv('CDX_CASHIER_C_SHA') !== hash_file('sha256', __FILE__)) {
    echo "DENIED business_http=0 business_dml=0\n";
    exit(78);
}
function requireC(bool $ok, string $why): void {
    if (!$ok) throw new RuntimeException($why);
}
function oneC(PDO $db, string $sql, array $args = []): array {
    $s = $db->prepare($sql); $s->execute($args);
    $r = $s->fetch(PDO::FETCH_ASSOC);
    return is_array($r) ? array_change_key_case($r, CASE_LOWER) : [];
}
function countC(PDO $db, string $sql, array $args = []): int {
    $s = $db->prepare($sql); $s->execute($args);
    return (int)$s->fetchColumn();
}
function typesC($value) {
    if (!is_array($value)) return gettype($value);
    $out = [];
    foreach ($value as $key => $item) $out[$key] = typesC($item);
    return $out;
}
function centsC($value): int {
    $text = (string)$value;
    requireC(preg_match('/^(0|[1-9][0-9]*)(?:\.([0-9]{1,2}))?$/D', $text, $m) === 1,
        'C unexpected money format');
    return (int)$m[1] * 100 + (int)str_pad($m[2] ?? '', 2, '0');
}
const ROOT_C = '/tmp/zhct-ai-http-20260929.3XDj3w';
const ACTOR_C = 'CDXPARMOB9411C2CB';
const AI_ID_C = 1836;
const STORE_USER_C = 2642;
const STORE_STAFF_C = 2182;
const OLD_ORDER_C = 23625;
requireC(getenv('POC_DIALECT') === 'dm' && getenv('POC_AI_SCHEMA') === 'AIZHCT_APP'
    && getenv('POC_SCHEMA') === 'ZHCT_APP' && getenv('POC_EXTERNAL_STUBS') === '1'
    && getenv('POC_TARGET_ROOT') === ROOT_C
    && getenv('POC_BASE_URL') === 'http://127.0.0.1:18102', 'C worker identity drift');
foreach ([
    'app/api/controller/Cashier.php' => 'a25c6b142e0010333d4f8aab14f2b911e11394922df063b0c9ae2482a09189e3',
    'app/api/service/Cashier.php' => '61dcb786c12eab1b1ecaec2aff0189169f8c86f4071119c7f63d3b3da04d2c6f',
    'app/api/service/cashier/MealPayment.php' => 'e18ab87f23d748df78564b0be4433c76268d69079029adb40bb9b6fcc6e47b65',
    'config/cache.php' => 'ccf1c56eb4178f3eaad8775e26a27742b2cacf662b46fb058cbb91d23783b8c6',
] as $file => $sha) {
    requireC(hash_equals($sha, (string)hash_file('sha256', ROOT_C . '/' . $file)),
        'C source/cache drift ' . $file);
}
$boundary = file_get_contents('http://127.0.0.1:18102/__poc_boundary');
requireC(is_string($boundary) && json_decode($boundary, true) === ['external_stubs' => true],
    'C external boundary absent');
$connect = static function (string $schema, int $port, string $userKey, string $passwordKey): PDO {
    $db = new PDO("dm:host=127.0.0.1;port=$port;schema=$schema",
        getenv($userKey), getenv($passwordKey),
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    requireC($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()
        === $schema, 'C connected wrong schema');
    return $db;
};
$ai = $connect('AIZHCT_APP', 5238, 'POC_AI_USER', 'POC_AI_PASSWORD');
$store = $connect('ZHCT_APP', 5237, 'POC_USER', 'POC_PASSWORD');
$actor = oneC($ai, 'SELECT USER_ID,STORE_ID,IS_DELETE,BALANCE,GIFT_BALANCE,SUBSIDY_BALANCE'
    . ' FROM YOSHOP_USER WHERE USER_ID=? AND NICK_NAME=?', [AI_ID_C, ACTOR_C]);
$staff = oneC($store, 'SELECT ID,AI_USER_ID,IS_SHOW FROM YDY_STAFF WHERE ID=? AND NAME=?',
    [STORE_STAFF_C, ACTOR_C]);
$storeUser = oneC($store, 'SELECT ID,AI_USER_ID,IS_DELETE FROM YDY_USER WHERE ID=? AND ACCOUNT=?',
    [STORE_USER_C, ACTOR_C]);
$oldOrder = oneC($store, 'SELECT ID,USER_ID,SOURCE,PAY_STATUS,ORDER_STATUS,RESTAURANT_ID,MEAL_TIMES'
    . ' FROM YDY_MEAL_ORDER WHERE ID=? AND REMARK=?', [OLD_ORDER_C, ACTOR_C]);
requireC((int)($actor['user_id'] ?? 0) === AI_ID_C && (int)($actor['store_id'] ?? 0) === 10001
    && (int)($actor['is_delete'] ?? 1) === 0
    && (int)($staff['id'] ?? 0) === STORE_STAFF_C && (int)($staff['ai_user_id'] ?? 0) === AI_ID_C
    && (int)($storeUser['id'] ?? 0) === STORE_USER_C
    && (int)($storeUser['ai_user_id'] ?? 0) === AI_ID_C
    && (int)($oldOrder['id'] ?? 0) === OLD_ORDER_C
    && (int)($oldOrder['user_id'] ?? 0) === STORE_USER_C
    && (int)($oldOrder['source'] ?? 0) === 4 && (int)($oldOrder['pay_status'] ?? 0) === 20
    && (int)($oldOrder['restaurant_id'] ?? 0) > 0
    && (int)($oldOrder['meal_times'] ?? 0) > 0, 'C synthetic actor/order drift');
requireC(countC($store, 'SELECT COUNT(*) FROM YDY_MEAL_ORDER WHERE USER_ID=?'
    . ' AND PAY_STATUS=10 AND ORDER_STATUS=10 AND IS_DELETE=0', [STORE_USER_C]) === 0,
    'C actor already has unpaid order');
$ledgerTables = ['YOSHOP_ACCOUNT_SETTLEMENT', 'YOSHOP_USER_BALANCE_LOG',
    'YOSHOP_USER_SUBSIDY_LOG'];
$ledgerBefore = [];
foreach ($ledgerTables as $table) {
    $ledgerBefore[$table] = countC($ai, "SELECT COUNT(*) FROM $table WHERE USER_ID=?", [AI_ID_C]);
}
$actorSha = hash('sha256', serialize([$actor, $staff, $storeUser, $oldOrder]));
define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require ROOT_C . '/vendor/autoload.php';
(new \think\App(ROOT_C))->setEnvName('poc')->initialize();
requireC(config('cache.default') === 'file', 'C cache is not isolated File');
$marker = 'CDXCOI' . strtoupper(bin2hex(random_bytes(5)));
$token = $marker . 'T' . strtoupper(bin2hex(random_bytes(12)));
$journal = '/tmp/' . $marker . '.cashier-c-journal';
umask(0077);
$writeJournal = static function (array $item) use ($journal): void {
    $handle = fopen($journal, is_file($journal) ? 'ab' : 'xb');
    requireC(is_resource($handle), 'private journal open failed');
    fwrite($handle, json_encode($item, JSON_UNESCAPED_SLASHES) . "\n");
    fclose($handle);
};
$writeJournal(['phase' => 'prepared', 'marker' => $marker, 'token' => $token,
    'actor' => AI_ID_C, 'store_user' => STORE_USER_C, 'order_id' => 0]);
$orderId = 0; $requestComplete = false;
try {
    requireC(countC($store, 'SELECT COUNT(*) FROM YDY_MEAL_ORDER WHERE ORDER_NO=? OR REMARK=?',
        [$marker, $marker]) === 0, 'C marker collision');
    $insert = $store->prepare('INSERT INTO YDY_MEAL_ORDER (ORDER_NO,USER_ID,RESTAURANT_ID,'
        . 'MEAL_DATE,MEAL_TIMES,BIND_TIME,SOURCE,PAY_STATUS,ORDER_STATUS,TOTAL_PRICE,'
        . 'ORI_TOTAL_PRICE,ORDER_PRICE,PAY_PRICE,MARKETING_STRATEGY_ID,REMARK,MSGID,IS_DELETE)'
        . ' VALUES (?,?,?,?,?,?,4,10,10,0.80,0.80,0.80,0.80,0,?,?,0)');
    $insert->execute([$marker, STORE_USER_C, (int)$oldOrder['restaurant_id'],
        date('Y-m-d'), (int)$oldOrder['meal_times'], date('Y-m-d H:i:s'), $marker, $marker]);
    $orderId = (int)$store->lastInsertId();
    requireC($orderId > 0, 'C insert lacked ID');
    $writeJournal(['phase' => 'inserted', 'marker' => $marker, 'order_id' => $orderId]);
    $before = oneC($store, 'SELECT * FROM YDY_MEAL_ORDER WHERE ID=?', [$orderId]);
    requireC((int)($before['user_id'] ?? 0) === STORE_USER_C
        && (int)($before['pay_status'] ?? 0) === 10
        && (int)($before['order_status'] ?? 0) === 10
        && (string)($before['order_no'] ?? '') === $marker
        && (string)($before['remark'] ?? '') === $marker, 'C inserted order mismatch');
    requireC(\think\facade\Cache::set($token,
        ['user' => ['user_id' => AI_ID_C], 'password_version' => 0,
            'login_type' => 'thirdparty'], 300) !== false, 'C token creation failed');
    $url = 'http://127.0.0.1:18102/api/cashier/orderInfo?storeId=10001&orderId='
        . $orderId . '&client=H5';
    $context = stream_context_create(['http' => ['method' => 'GET',
        'header' => "platform: H5\r\nAccess-Token: $token\r\n",
        'ignore_errors' => true, 'timeout' => 15, 'follow_location' => 0]]);
    $handle = @fopen($url, 'rb', false, $context);
    requireC(is_resource($handle), 'C HTTP open failed');
    $raw = stream_get_contents($handle, 1048577); fclose($handle);
    requireC(is_string($raw) && strlen($raw) <= 1048576, 'C HTTP size invalid');
    $http = preg_match('/^HTTP\/\S+ 200/', $http_response_header[0] ?? '') === 1;
    $json = json_decode($raw, true);
    $requestComplete = is_array($json);
    $writeJournal(['phase' => 'http_returned', 'marker' => $marker,
        'order_id' => $orderId, 'http200' => $http,
        'business_status' => $json['status'] ?? null]);
    requireC($http && $requestComplete && (int)($json['status'] ?? 0) === 200,
        'C HTTP/business error');
    $data = $json['data'] ?? null;
    requireC(is_array($data)
        && array_keys($data) === ['order', 'personal', 'paymentMethods', 'deductionPreview']
        && (int)($data['order']['orderId'] ?? 0) === $orderId
        && (int)($data['order']['pay_status'] ?? 0) === 10, 'C response contract mismatch');
    $mealUrl = 'http://127.0.0.1:18102/api/mealCashier/orderInfo?orderId='
        . $orderId . '&client=H5';
    $mealHandle = @fopen($mealUrl, 'rb', false, $context);
    requireC(is_resource($mealHandle), 'C shared MealCashier HTTP open failed');
    $mealRaw = stream_get_contents($mealHandle, 1048577); fclose($mealHandle);
    $mealJson = is_string($mealRaw) && strlen($mealRaw) <= 1048576
        ? json_decode($mealRaw, true) : null;
    $mealData = $mealJson['data'] ?? null;
    requireC(is_array($mealJson) && (int)($mealJson['status'] ?? 0) === 200
        && is_array($mealData) && is_array($mealData['order'] ?? null)
        && (int)($mealData['order']['orderId'] ?? 0) === $orderId,
        'C shared MealCashier route regression failed');
    foreach (['total_price', 'order_price', 'pay_price',
        'discount_amount', 'management_fee'] as $moneyField) {
        requireC(is_string($mealData['order'][$moneyField] ?? null),
            'C shared MealCashier money type differs: ' . $moneyField);
    }
    $after = oneC($store, 'SELECT * FROM YDY_MEAL_ORDER WHERE ID=?', [$orderId]);
    requireC((int)($after['pay_status'] ?? 0) === 10
        && (int)($after['order_status'] ?? 0) === 10
        && (string)($after['order_no'] ?? '') === $marker
        && (string)($after['remark'] ?? '') === $marker
        && centsC($data['order']['pay_price'] ?? null)
            === centsC($after['pay_price'] ?? null),
        'C order readback mismatch');
    $allowed = ['order_price','pay_price','management_fee','discount_amount',
        'marketing_strategy_id','marketing_strategy_time_range_id','time_range_mode',
        'strategy_time_range_text','actual_strategy_type','actual_strategy_value','update_time'];
    foreach ($before as $key => $value) {
        if ($value !== ($after[$key] ?? null)) requireC(in_array($key, $allowed, true),
            'C unexpected order field changed');
    }
    $actorNow = [oneC($ai, 'SELECT USER_ID,STORE_ID,IS_DELETE,BALANCE,GIFT_BALANCE,SUBSIDY_BALANCE'
            . ' FROM YOSHOP_USER WHERE USER_ID=? AND NICK_NAME=?', [AI_ID_C, ACTOR_C]),
        oneC($store, 'SELECT ID,AI_USER_ID,IS_SHOW FROM YDY_STAFF WHERE ID=? AND NAME=?',
            [STORE_STAFF_C, ACTOR_C]),
        oneC($store, 'SELECT ID,AI_USER_ID,IS_DELETE FROM YDY_USER WHERE ID=? AND ACCOUNT=?',
            [STORE_USER_C, ACTOR_C]),
        oneC($store, 'SELECT ID,USER_ID,SOURCE,PAY_STATUS,ORDER_STATUS,RESTAURANT_ID,MEAL_TIMES'
            . ' FROM YDY_MEAL_ORDER WHERE ID=? AND REMARK=?', [OLD_ORDER_C, ACTOR_C])];
    requireC(hash_equals($actorSha, hash('sha256', serialize($actorNow))),
        'C prior actor/order changed');
    foreach ($ledgerTables as $table) requireC(countC($ai,
        "SELECT COUNT(*) FROM $table WHERE USER_ID=?", [AI_ID_C]) === $ledgerBefore[$table],
        'C ledger changed');
    requireC(countC($store, 'SELECT COUNT(*) FROM YDY_INITIAL_MENU WHERE MEAL_ORDER_ID=?',
        [$orderId]) === 0, 'C order acquired menu child');
    $delete = $store->prepare('DELETE FROM YDY_MEAL_ORDER WHERE ID=? AND ORDER_NO=? AND REMARK=?'
        . ' AND USER_ID=? AND PAY_STATUS=10 AND ORDER_STATUS=10 AND ACCOUNT_SETTLEMENT_ID=0');
    $delete->execute([$orderId, $marker, $marker, STORE_USER_C]);
    requireC($delete->rowCount() === 1, 'C exact cleanup did not delete one order');
    $writeJournal(['phase' => 'deleted', 'marker' => $marker, 'order_id' => $orderId]);
    $postContext = stream_context_create(['http' => ['method' => 'POST',
        'header' => "platform: H5\r\nAccess-Token: $token\r\nContent-Type: application/json\r\n",
        'content' => '{}', 'ignore_errors' => true, 'timeout' => 15,
        'follow_location' => 0]]);
    $zhctHandle = @fopen('http://127.0.0.1:18102/api/User/zhctInfo', 'rb', false, $postContext);
    requireC(is_resource($zhctHandle), 'C User/zhctInfo HTTP open failed');
    $zhctRaw = stream_get_contents($zhctHandle, 1048577); fclose($zhctHandle);
    $zhctJson = is_string($zhctRaw) && strlen($zhctRaw) <= 1048576
        ? json_decode($zhctRaw, true) : null;
    $zhctBalance = $zhctJson['data']['balance'] ?? null;
    $storeBalance = oneC($store, 'SELECT BALANCE FROM YDY_USER WHERE ID=? AND ACCOUNT=?',
        [STORE_USER_C, ACTOR_C]);
    requireC(is_array($zhctJson) && (int)($zhctJson['status'] ?? 0) === 200
        && array_key_exists('balance', $zhctJson['data'] ?? [])
        && centsC($zhctBalance) === centsC($storeBalance['balance'] ?? null),
        'C User/zhctInfo original balance mismatch');
    $getJson = static function (string $path, string $method = 'GET')
        use ($context, $postContext): array {
        requireC(in_array($method, ['GET', 'POST'], true), 'C test method invalid');
        $requestContext = $method === 'POST' ? $postContext : $context;
        $h = @fopen('http://127.0.0.1:18102' . $path, 'rb', false, $requestContext);
        requireC(is_resource($h), 'C extra User route open failed');
        $raw = stream_get_contents($h, 1048577); fclose($h);
        requireC(is_string($raw) && strlen($raw) <= 1048576,
            'C extra User route response size invalid');
        $body = json_decode($raw, true);
        fwrite(STDERR, 'extra_route_diag=' . json_encode(['path' => $path,
            'status' => is_array($body) ? ($body['status'] ?? null) : null,
            'message' => is_array($body) ? ($body['message'] ?? null) : null]) . PHP_EOL);
        requireC(is_array($body), 'C extra User route non-JSON');
        return $body;
    };
    $assetsBody = $getJson('/api/User/assets');
    $assets = $assetsBody['data']['assets'] ?? null;
    requireC((int)($assetsBody['status'] ?? 0) === 200
        && is_array($assets) && array_key_exists('balance', $assets)
        && array_key_exists('subsidy', $assets)
        && array_key_exists('total_balance', $assets), 'C User/assets data missing');
    fwrite(STDERR, 'assets_diag=' . json_encode(['balance_type' => gettype($assets['balance']),
        'cash_cents' => centsC($assets['balance'])]) . PHP_EOL);
    $cashoutBody = $getJson('/api/Cashout/read', 'POST');
    $cashoutMoney = $cashoutBody['data']['money'] ?? null;
    requireC((int)($cashoutBody['status'] ?? 0) === 200
        && array_key_exists('money', $cashoutBody['data'] ?? [])
        && centsC($cashoutMoney) === 0,
        'C Cashout/read zero-refundable branch differs');
    $rechargeMarker = 'CR' . $marker;
    $rechargeNow = time();
    requireC(countC($ai, 'SELECT COUNT(*) FROM YOSHOP_RECHARGE_ORDER'
        . ' WHERE ORDER_NO=? OR NOTE=?', [$rechargeMarker, $rechargeMarker]) === 0,
        'C owned recharge marker collision');
    $rechargeInsert = $ai->prepare('INSERT INTO YOSHOP_RECHARGE_ORDER'
        . ' (ORDER_NO,USER_ID,PAY_PRICE,ACTUAL_MONEY,PAY_METHOD,PAY_STATUS,'
        . ' PAY_TIME,REFUNDABLE_MONEY,RECHARGE_DATE,NOTE,CREATE_BY,STORE_ID,'
        . ' PLATFORM,CREATE_TIME,UPDATE_TIME)'
        . " VALUES (?,?,0.80,0.80,'wechat',20,?,0.80,?,?,?,10001,'H5',?,?)");
    $rechargeInsert->execute([$rechargeMarker, AI_ID_C, $rechargeNow,
        date('Y-m-d'), $rechargeMarker, $rechargeMarker,
        $rechargeNow, $rechargeNow]);
    $rechargeId = (int)$ai->lastInsertId();
    requireC($rechargeId > 0, 'C owned recharge ID missing');
    $writeJournal(['phase' => 'recharge_inserted', 'marker' => $marker,
        'recharge_id' => $rechargeId, 'recharge_marker' => $rechargeMarker]);
    $rechargeRow = oneC($ai, 'SELECT ORDER_ID,ORDER_NO,USER_ID,PAY_METHOD,PAY_STATUS,'
        . ' REFUNDABLE_MONEY,NOTE FROM YOSHOP_RECHARGE_ORDER WHERE ORDER_ID=?',
        [$rechargeId]);
    requireC((int)($rechargeRow['user_id'] ?? 0) === AI_ID_C
        && ($rechargeRow['order_no'] ?? '') === $rechargeMarker
        && ($rechargeRow['note'] ?? '') === $rechargeMarker
        && ($rechargeRow['pay_method'] ?? '') === 'wechat'
        && (int)($rechargeRow['pay_status'] ?? 0) === 20
        && centsC($rechargeRow['refundable_money'] ?? null) === 80,
        'C owned recharge original row mismatch');
    try {
        $cashoutPositiveBody = $getJson('/api/Cashout/read', 'POST');
        $cashoutPositiveMoney = $cashoutPositiveBody['data']['money'] ?? null;
        requireC((int)($cashoutPositiveBody['status'] ?? 0) === 200
            && centsC($cashoutPositiveMoney) === 80,
            'C Cashout/read positive amount differs from owned recharge');
    } finally {
        // read() has no business DML: exact cleanup is safe even if HTTP times out.
            requireC(countC($ai, 'SELECT COUNT(*) FROM YOSHOP_CASHOUT_ORDER_DETAIL'
                . ' WHERE RECHARGE_ORDER_ID=?', [$rechargeId]) === 0,
                'C owned recharge acquired cashout detail');
            $deleteRecharge = $ai->prepare('DELETE FROM YOSHOP_RECHARGE_ORDER'
                . ' WHERE ORDER_ID=? AND ORDER_NO=? AND NOTE=? AND USER_ID=?'
                . " AND PAY_METHOD='wechat' AND PAY_STATUS=20"
                . ' AND REFUNDABLE_MONEY=0.80 AND STORE_ID=10001');
            $deleteRecharge->execute([$rechargeId, $rechargeMarker,
                $rechargeMarker, AI_ID_C]);
            requireC($deleteRecharge->rowCount() === 1,
                'C exact owned recharge cleanup not one row');
            $writeJournal(['phase' => 'recharge_deleted', 'marker' => $marker,
                'recharge_id' => $rechargeId]);
            $afterCashoutUser = oneC($ai, 'SELECT BALANCE FROM YOSHOP_USER WHERE USER_ID=?',
                [AI_ID_C]);
            requireC(centsC($afterCashoutUser['balance'] ?? null)
                === centsC($actor['balance']), 'C user balance changed by preview');
            foreach ($ledgerTables as $table) requireC(countC($ai,
                "SELECT COUNT(*) FROM $table WHERE USER_ID=?", [AI_ID_C])
                    === $ledgerBefore[$table], 'C ledger changed by preview');
    }
    $staffMarker = $marker . 'STAFF';
    requireC(countC($ai, 'SELECT COUNT(*) FROM YOSHOP_STAFF WHERE USER_ID=? AND IS_DELETE=0',
        [AI_ID_C]) === 0
        && countC($ai, 'SELECT COUNT(*) FROM YOSHOP_STAFF WHERE NAME=?',
            [$staffMarker]) === 0, 'C AI staff fixture collision');
    $staffInsert = $ai->prepare('INSERT INTO YOSHOP_STAFF'
        . ' (USER_ID,NAME,STORE_ID,HEIGHT,WEIGHT,GENDER,BIRTHDAY,PHONE,IS_DELETE)'
        . " VALUES (?,?,10001,170,60,1,'1990-01-01','',0)");
    $staffInsert->execute([AI_ID_C, $staffMarker]);
    $aiStaffId = (int)$ai->lastInsertId();
    requireC($aiStaffId > 0, 'C AI staff fixture ID missing');
    $aiStaffRow = oneC($ai, 'SELECT ID,USER_ID,NAME,HEIGHT,WEIGHT FROM YOSHOP_STAFF WHERE ID=?',
        [$aiStaffId]);
    requireC((int)($aiStaffRow['user_id'] ?? 0) === AI_ID_C
        && ($aiStaffRow['name'] ?? '') === $staffMarker
        && (int)($aiStaffRow['height'] ?? 0) === 170
        && (int)($aiStaffRow['weight'] ?? 0) === 60
        && countC($ai, 'SELECT COUNT(*) FROM YOSHOP_MEAL WHERE STAFF_ID=?',
            [$aiStaffId]) === 0, 'C AI staff fixture original readback mismatch');
    $writeJournal(['phase' => 'ai_staff_inserted', 'marker' => $marker,
        'ai_staff_id' => $aiStaffId, 'staff_marker' => $staffMarker]);
    $dataReturned = false;
    try {
        $dataBody = $getJson('/api/User/data', 'POST');
        $dataReturned = true;
        $coursePost = $getJson('/api/drill.course/all', 'POST');
        $courseGet = $getJson('/api/drill.course/all', 'GET');
        $courseList = $coursePost['data']['list'] ?? null;
        requireC((int)($coursePost['status'] ?? 0) === 200
            && (int)($courseGet['status'] ?? 0) === 200
            && is_array($courseList) && count($courseList) > 0
            && $courseList === ($courseGet['data']['list'] ?? null),
            'C drill.course/all POST differs from proven GET route');
    } finally {
        if ($dataReturned) {
            foreach (['YOSHOP_MEAL', 'YOSHOP_HABIT', 'YOSHOP_HABIT_RPE',
                'YOSHOP_STAFF_WEIGHT'] as $table) {
                requireC(countC($ai, 'SELECT COUNT(*) FROM ' . $table . ' WHERE STAFF_ID=?',
                    [$aiStaffId]) === 0, 'C AI staff acquired child: ' . $table);
            }
            $staffDelete = $ai->prepare('DELETE FROM YOSHOP_STAFF WHERE ID=? AND USER_ID=?'
                . ' AND NAME=? AND STORE_ID=10001 AND IS_DELETE=0');
            $staffDelete->execute([$aiStaffId, AI_ID_C, $staffMarker]);
            requireC($staffDelete->rowCount() === 1, 'C AI staff exact cleanup failed');
            $writeJournal(['phase' => 'ai_staff_deleted', 'marker' => $marker,
                'ai_staff_id' => $aiStaffId]);
        }
    }
    $userData = $dataBody['data'] ?? null;
    requireC((int)($dataBody['status'] ?? 0) === 200
        && is_array($userData) && is_string($userData['baseData'] ?? null)
        && is_array($userData['diningData'] ?? null), 'C User/data shape missing');
    echo json_encode(['status' => 'C_LIMITED_PASS', 'http' => 200,
        'order_key_type_sha' => hash('sha256', json_encode(typesC($data['order']))),
        'full_data_type_sha' => hash('sha256', json_encode(typesC($data))),
        'order_types' => typesC($data['order']),
        'data_types' => typesC($data),
        'response_keys' => array_keys($data),
        'shared_meal_cashier_http' => 200,
        'zhct_info' => ['http' => 200, 'balance_type' => gettype($zhctBalance),
            'balance_cents' => centsC($zhctBalance)],
        'assets' => ['http' => 200, 'balance_type' => gettype($assets['balance']),
            'cash_cents' => centsC($assets['balance']),
            'subsidy_type' => gettype($assets['subsidy']),
            'total_type' => gettype($assets['total_balance'])],
        'cashout_read' => ['http' => 200,
            'money_type' => gettype($cashoutMoney), 'money_cents' => 0],
        'cashout_read_positive' => ['http' => 200,
            'money_type' => gettype($cashoutPositiveMoney),
            'money_cents' => centsC($cashoutPositiveMoney),
            'owned_recharge_deleted' => true],
        'drill_course_all' => ['post_http' => 200,
            'get_http' => 200, 'count' => count($courseList),
            'same_lane_methods_equal' => true],
        'user_data' => ['http' => 200,
            'base_nonempty' => $userData['baseData'] !== '',
            'dining_count' => count($userData['diningData']),
            'content_sha' => hash('sha256', json_encode($userData, JSON_UNESCAPED_UNICODE)),
            'base_text' => $userData['baseData'],
            'first_dining' => $userData['diningData'][0] ?? null,
            'last_dining' => $userData['diningData'][89] ?? null],
        'marketing_refresh_on_owned_row' => $before !== $after,
        'source_order_cleaned' => true,
        'external_payment_invoked' => false], JSON_UNESCAPED_SLASHES), PHP_EOL;
} catch (Throwable $error) {
    fwrite(STDERR, 'STOP ' . $error->getMessage() . ' order_id=' . $orderId
        . ' complete=' . ($requestComplete ? '1' : '0') . ' journal=' . $journal . PHP_EOL);
    throw $error;
} finally {
    \think\facade\Cache::delete($token);
    $tokenZero = !\think\facade\Cache::has($token);
    $writeJournal(['phase' => 'token_cleanup', 'marker' => $marker, 'order_id' => $orderId,
        'token_zero' => $tokenZero]);
    fwrite(STDERR, 'token_zero=' . ($tokenZero ? '1' : '0') . ' journal=' . $journal . PHP_EOL);
}
