<?php

declare(strict_types=1);

// Store PC activity read routes. Default is SELECT-only; no business HTTP/DML
// is reachable without explicit reviewed SHA and both DB identity approvals.
set_exception_handler(static function (Throwable $e): void {
    fwrite(STDERR, 'Activity read3 preflight failed ' . get_class($e) . ':'
        . hash('sha256', $e->getMessage()) . PHP_EOL);
    exit(1);
});
$lane = (string)getenv('CDX_ACT3_LANE');
$action = (string)($argv[1] ?? '');
$targets = [
    'A' => ['/tmp/zhct-http-store-a.l5omH8', 'http://127.0.0.1:18097', 21023,
        'mysql', '5f0bc855dc205360896f7a08a5d66f3904a39a607cc463f6a70a6add04a55e7e',
        '95ce9bcee0f908ace8c86c1978ed9e41791e56a3ab53d53de17972d12e908341',
        16, 'f4c9424e2867', 14, 2],
    'B' => ['/tmp/zhct-http-store-mysql.dQTTBP', 'http://127.0.0.1:18081', 10001,
        'mysql', '1ff0e49451950d671498ad5e1f7380f60448d2f7a39041d4b53370abd6e6d78f',
        '8953e4be37bb3a1f6adf40c9da9b19de5e3eb2f61d595812b080a66bec10b7c2',
        16, 'f4c9424e2867', 14, 2],
    'C' => ['/tmp/zhct-dm-poc-20260928.fcpiiN/store', 'http://127.0.0.1:18080', 112175,
        'dm', '1ff0e49451950d671498ad5e1f7380f60448d2f7a39041d4b53370abd6e6d78f',
        '8953e4be37bb3a1f6adf40c9da9b19de5e3eb2f61d595812b080a66bec10b7c2',
        8, '71138ce0bc8f', 3, 3],
];
if (!isset($targets[$lane]) || !in_array($action, ['--preflight', '--execute'], true)
    || ($action === '--execute'
        && ((string)getenv('CDX_ACT3_EXECUTE') !== 'ROOT_APPROVED_ACT3_V1'
            || (string)getenv('CDX_ACT3_SHA') !== hash_file('sha256', __FILE__)))) {
    fwrite(STDERR, "Activity read3 business HTTP and fixture DML disabled\n");
    exit(78);
}
[$root, $base, $pid, $dialect, $commonSha, $userSha,
    $candidateId, $candidateUuidSha12, $expectedActivityTotal,
    $expectedRegistrationTotal] = $targets[$lane];
if ((string)getenv('POC_APP_ROOT') !== $root
    || (string)getenv('POC_BASE_URL') !== $base
    || (string)getenv('POC_DIALECT') !== $dialect || is_link($root)
    || hash_file('sha256', $root . '/application/p/controller/Activity.php')
        !== '33ac5799f82a12cce57d35fa6af7b1d9f0960eb7b3cc6b3442956e5ed802ffda'
    || hash_file('sha256', $root . '/application/p/logic/Activity.php')
        !== '4b190a081cf1e1a30e24973e709733c1d20089f6e098e07c1d3b9ef9e871ac84'
    || hash_file('sha256', $root . '/application/base/AdminController.php')
        !== '7565b36fa4dda2c21cc4fa3b37753dbffb7c3a464bb8c11ea0f17ca00bececa5'
    || hash_file('sha256', $root . '/application/common.php') !== $commonSha
    || hash_file('sha256', $root . '/application/model/User.php') !== $userSha
    || hash_file('sha256', $root . '/application/model/File.php')
        !== '1d9a5a9c62ae27b3d95c24d0031826d0b9f43f9fb6d72ec916ba9b2c5ed2cae6'
    || hash_file('sha256', $root . '/application/route.php')
        !== '081b0186b7f40f0bdd237cecb3e2d678fc9344c656932c0d3b3052404e4f1510') {
    throw new RuntimeException('Activity read3 approved source/runtime drift');
}
$runtimeReady = static function () use ($root, $base, $pid): bool {
    $cmdline = (string)@file_get_contents('/proc/' . $pid . '/cmdline');
    $environment = (string)@file_get_contents('/proc/' . $pid . '/environ');
    $children = (string)@file_get_contents('/proc/' . $pid . '/task/' . $pid . '/children');
    $boundary = json_decode((string)@file_get_contents($base . '/__poc_boundary'), true);
    $port = (int)parse_url($base, PHP_URL_PORT);
    $hex = strtoupper(str_pad(dechex($port), 4, '0', STR_PAD_LEFT));
    $inode = '';
    foreach (@file('/proc/net/tcp', FILE_IGNORE_NEW_LINES) ?: [] as $line) {
        $part = preg_split('/\s+/', trim($line));
        if (($part[1] ?? '') === '0100007F:' . $hex && ($part[3] ?? '') === '0A') {
            $inode = (string)($part[9] ?? '');
            break;
        }
    }
    $owns = false;
    if ($inode !== '') foreach (@scandir('/proc/' . $pid . '/fd') ?: [] as $fd) {
        if ($fd !== '.' && $fd !== '..'
            && @readlink('/proc/' . $pid . '/fd/' . $fd) === 'socket:[' . $inode . ']') {
            $owns = true;
            break;
        }
    }
    $multiWorker = preg_match('/(?:^|\x00)PHP_CLI_SERVER_WORKERS=(\d+)(?:\x00|$)/',
        $environment, $match) && (int)$match[1] > 1;
    return strpos($cmdline, '127.0.0.1:' . $port) !== false
        && strpos($cmdline, $root . '/public') !== false
        && $environment !== '' && trim($children) === '' && !$multiWorker
        && $owns && is_array($boundary) && !empty($boundary['external_stubs'])
        && !empty($boundary['redis_isolated']) && empty($boundary['real_queue']);
};
if (!$runtimeReady()) throw new RuntimeException('Activity read3 isolated worker absent');
$runtime = require $root . '/application/database.php';
if (!is_array($runtime) || (string)($runtime['prefix'] ?? '') !== 'ydy_') {
    throw new RuntimeException('Activity read3 Store DB config invalid');
}
$aiRuntime = $runtime['ai_zhct'] ?? null;
if (!is_array($aiRuntime) || (string)($aiRuntime['prefix'] ?? '') !== 'yoshop_') {
    throw new RuntimeException('Activity read3 AI config missing; fallback forbidden');
}
$storeApproved = $dialect === 'dm'
    ? 'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194'
    : '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401';
$aiApproved = $dialect === 'dm'
    ? '628c12663da929e593de74c9c58e5bcfab0530fbfbcb1d90a9ed7b736a45fd5e'
    : '210f925e093f71e26a8c8923f0f626e3be0a15ccff3d386bba21feef695c8a5b';
if ($dialect === 'mysql') {
    $local = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
    if (!is_array($local) || (string)($runtime['type'] ?? '') !== 'mysql'
        || !in_array((string)($runtime['charset'] ?? ''), ['utf8', 'utf8mb4'], true)
        || (string)($aiRuntime['prefix'] ?? '')
            !== (string)($local['ai_zhct']['prefix'] ?? '')) {
        throw new RuntimeException('Activity read3 code-local MySQL required');
    }
    foreach (['hostname', 'database', 'username', 'password'] as $key) {
        if (($runtime[$key] ?? null) !== ($local[$key] ?? null)
            || ($aiRuntime[$key] ?? null) !== (($local['ai_zhct'] ?? [])[$key] ?? null)) {
            throw new RuntimeException('Activity read3 Store/AI differs from code local');
        }
    }
    if ((int)($runtime['hostport'] ?? 3306) !== (int)($local['hostport'] ?? 3306)
        || (int)($aiRuntime['hostport'] ?? 3306)
            !== (int)($local['ai_zhct']['hostport'] ?? $local['hostport'] ?? 3306)) {
        throw new RuntimeException('Activity read3 MySQL port mismatch');
    }
    $storeDsn = 'mysql:host=' . $runtime['hostname'] . ';port='
        . (int)($runtime['hostport'] ?? 3306) . ';dbname=' . $runtime['database']
        . ';charset=' . $runtime['charset'];
    $aiDsn = 'mysql:host=' . $aiRuntime['hostname'] . ';port='
        . (int)($aiRuntime['hostport'] ?? 3306) . ';dbname=' . $aiRuntime['database']
        . ';charset=' . $runtime['charset'];
    $hostFingerprint = null;
} else {
    if ((string)($runtime['type'] ?? '') !== 'app\\cores\\database\\Dm'
        || (string)getenv('POC_HOST') !== '127.0.0.1'
        || (string)getenv('POC_PORT') !== '5237'
        || strtoupper((string)getenv('POC_SCHEMA')) !== 'ZHCT_APP'
        || strtoupper((string)getenv('POC_USER')) !== 'ZHCT_APP'
        || (string)getenv('POC_AI_HOST') !== '127.0.0.1'
        || (string)getenv('POC_AI_PORT') !== '5238'
        || strtoupper((string)getenv('POC_AI_SCHEMA')) !== 'AIZHCT_APP'
        || strtoupper((string)getenv('POC_AI_USER')) !== 'AIZHCT_APP') {
        throw new RuntimeException('Activity read3 nonproduction DM pair drift');
    }
    foreach (['hostname' => 'POC_HOST', 'hostport' => 'POC_PORT',
        'database' => 'POC_SCHEMA', 'username' => 'POC_USER',
        'password' => 'POC_PASSWORD'] as $key => $env) {
        if ((string)($runtime[$key] ?? '') !== (string)getenv($env)) {
            throw new RuntimeException('Activity read3 Store worker config drift');
        }
    }
    foreach (['hostname' => 'POC_AI_HOST', 'hostport' => 'POC_AI_PORT',
        'database' => 'POC_AI_SCHEMA', 'username' => 'POC_AI_USER',
        'password' => 'POC_AI_PASSWORD'] as $key => $env) {
        if ((string)($aiRuntime[$key] ?? '') !== (string)getenv($env)) {
            throw new RuntimeException('Activity read3 AI worker config drift');
        }
    }
    $machine = trim((string)@file_get_contents('/etc/machine-id'));
    if ($machine === '' || gethostname() === false) {
        throw new RuntimeException('Activity read3 DM host unknown');
    }
    $hostFingerprint = hash('sha256', gethostname() . '|' . $machine);
    if ($hostFingerprint !== 'd56d81988bb0f106946cce91c608fdd0ef1116e5150b23376ea87e086eace4b9') {
        throw new RuntimeException('Activity read3 DM host mismatch');
    }
    $listeners = [];
    $listenerExit = 0;
    @exec('/usr/sbin/ss -ltnp 2>/dev/null', $listeners, $listenerExit);
    $ports = [];
    if ($listenerExit === 0) foreach ($listeners as $line) {
        if (preg_match('/\*:(5237|5238)\s+.*users:\(\("dmserver",pid=(\d+),/',
            $line, $match)) {
            $exe = @readlink('/proc/' . $match[2] . '/exe');
            if (is_string($exe) && basename($exe) === 'dmserver') $ports[$match[1]] = true;
        }
    }
    if (count($ports) !== 2) throw new RuntimeException('Activity read3 DM pair not local');
    $storeDsn = 'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
    $aiDsn = 'dm:host=127.0.0.1;port=5238;schema=AIZHCT_APP';
}
$connect = static function (string $dsn, array $config): PDO {
    return new PDO($dsn, (string)$config['username'], (string)$config['password'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
};
try {
    $storeDb = $connect($storeDsn, $runtime);
    $aiDb = $connect($aiDsn, $aiRuntime);
} catch (Throwable $e) {
    fwrite(STDERR, 'Activity read3 approved DB pair unavailable: '
        . get_class($e) . PHP_EOL);
    exit(75);
}
$identity = static function (PDO $db, string $which) use ($dialect): string {
    if ($dialect === 'mysql') {
        return (string)$db->query(
            "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())")
            ->fetchColumn();
    }
    $schema = (string)$db->query(
        "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn();
    return ($which === 'store' ? 'ZHCT_APP|5237|' : 'AIZHCT_APP|5238|') . $schema;
};
if (!hash_equals($storeApproved, hash('sha256', $identity($storeDb, 'store')))
    || !hash_equals($aiApproved, hash('sha256', $identity($aiDb, 'ai')))) {
    throw new RuntimeException('Activity read3 Store/AI DB identity mismatch');
}
if ($action === '--execute'
    && ((string)getenv('CDX_ACT3_STORE_SHA') !== $storeApproved
        || (string)getenv('CDX_ACT3_AI_SHA') !== $aiApproved
        || ($dialect === 'dm'
            && (string)getenv('CDX_ACT3_HOST_SHA') !== $hostFingerprint))) {
    throw new RuntimeException('Activity read3 explicit DB/host confirmation absent');
}
$s = $dialect === 'dm' ? 'YDY_' : 'ydy_';
$a = $dialect === 'dm' ? 'YOSHOP_' : 'yoshop_';
$read = static function (PDO $db, string $sql, array $args = []): array {
    $stmt = $db->prepare($sql);
    $stmt->execute($args);
    $out = [];
    foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $item = [];
        foreach (array_change_key_case($row, CASE_LOWER) as $key => $value) {
            $item[$key] = is_resource($value) ? stream_get_contents($value) : $value;
        }
        $out[] = $item;
    }
    return $out;
};
$count = static function (PDO $db, string $sql, array $args = []): int {
    $stmt = $db->prepare($sql);
    $stmt->execute($args);
    return (int)$stmt->fetchColumn();
};
$allTotal = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a . 'activity');
$otherStores = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a
    . 'activity WHERE STORE_ID IS NULL OR STORE_ID<>10001');
if ($allTotal !== $expectedActivityTotal || $otherStores !== 0 || $allTotal > 20) {
    throw new RuntimeException('Activity read3 shared tenant/activity boundary changed');
}
$allActivities = $read($aiDb, 'SELECT * FROM ' . $a . 'activity ORDER BY ID DESC'
    . ($dialect === 'dm' ? ' FETCH FIRST 11 ROWS ONLY' : ' LIMIT 11'));
$listRows = array_slice($allActivities, 0, 10);
if (count($allActivities) !== min(11, $allTotal)
    || count($listRows) !== min(10, $allTotal)
    || strlen(serialize($listRows)) > 128 * 1024) {
    throw new RuntimeException('Activity read3 list source/page bound changed');
}
$candidateRows = $read($aiDb, 'SELECT * FROM ' . $a . 'activity'
    . ' WHERE ID=? AND STORE_ID=10001', [$candidateId]);
$candidate = $candidateRows[0] ?? null;
if (count($candidateRows) !== 1 || !is_array($candidate)
    || substr(hash('sha256', (string)$candidate['uuid']), 0, 12)
        !== $candidateUuidSha12
    || !in_array($candidateId, array_map(static function (array $x): int {
        return (int)$x['id'];
    }, $listRows), true)) {
    throw new RuntimeException('Activity read3 registered candidate drift');
}
$safeBoundary = static function (array $row): bool {
    foreach (['start_time', 'end_time'] as $field) {
        $t = strtotime((string)($row[$field] ?? ''));
        if ($t !== false && abs($t - time()) < 120) return false;
    }
    return true;
};
foreach ($listRows as $row) if (!$safeBoundary($row)) {
    throw new RuntimeException('Activity read3 status changes during test window');
}
$regTotal = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a . 'activity_register'
    . ' WHERE ACTIVITY_ID=? AND STORE_ID=10001', [$candidateId]);
$regRows = $read($aiDb, 'SELECT ar.ID,ar.USER_ID,ar.CREATE_TIME,u.NICK_NAME'
    . ' FROM ' . $a . 'activity_register ar LEFT JOIN ' . $a . 'user u'
    . ' ON u.USER_ID=ar.USER_ID WHERE ar.ACTIVITY_ID=? AND ar.STORE_ID=10001'
    . ' ORDER BY ar.ID DESC'
    . ($dialect === 'dm' ? ' FETCH FIRST 11 ROWS ONLY' : ' LIMIT 11'),
    [$candidateId]);
if ($regTotal !== $expectedRegistrationTotal || $regTotal < 1 || $regTotal > 10
    || count($regRows) !== $regTotal) {
    throw new RuntimeException('Activity read3 registration/source bound changed');
}
foreach ($regRows as $row) if (!array_key_exists('nick_name', $row)
    || $row['nick_name'] === null) {
    throw new RuntimeException('Activity read3 joined user source absent');
}
$source = ['activities' => $listRows, 'candidate' => $candidate,
    'registrations' => $regRows, 'activity_total' => $allTotal,
    'registration_total' => $regTotal];
$sourceSha = hash('sha256', serialize($source));
$aiActivityRows = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a . 'activity');
$aiRegisterRows = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a . 'activity_register');
$aiUserRows = $count($aiDb, 'SELECT COUNT(*) FROM ' . $a . 'user');
$storeUserRows = $count($storeDb, 'SELECT COUNT(*) FROM ' . $s . 'user');
$stale = $count($storeDb, 'SELECT COUNT(*) FROM ' . $s . 'user'
    . " WHERE ACCOUNT LIKE 'CDXACT3%'");
if ($stale !== 0) throw new RuntimeException('Activity read3 prior actor residue');
if ($dialect === 'dm') {
    $stmt = $storeDb->prepare('CALL SP_TABLEDEF(?, ?)');
    $stmt->execute(['ZHCT_APP', 'YDY_USER']);
    $definition = $stmt->fetchColumn();
    if (is_resource($definition)) $definition = stream_get_contents($definition);
    $identityUser = preg_match('/"ID"\s+[A-Z0-9]+\s+AUTO_INCREMENT\s+NOT\s+NULL/i',
        (string)$definition) === 1;
    $userTriggers = $count($storeDb,
        'SELECT COUNT(*) FROM USER_TRIGGERS WHERE TABLE_NAME=?', ['YDY_USER']);
    $userFk = $count($storeDb,
        "SELECT COUNT(*) FROM USER_CONSTRAINTS WHERE TABLE_NAME=? AND CONSTRAINT_TYPE='R'",
        ['YDY_USER'])
        + $count($storeDb, 'SELECT COUNT(*) FROM ALL_CONSTRAINTS c'
            . ' JOIN ALL_CONSTRAINTS parent'
            . ' ON c.R_OWNER=parent.OWNER AND c.R_CONSTRAINT_NAME=parent.CONSTRAINT_NAME'
            . " WHERE c.CONSTRAINT_TYPE='R' AND parent.OWNER='ZHCT_APP'"
            . ' AND parent.TABLE_NAME=?', ['YDY_USER']);
} else {
    $identityUser = $count($storeDb, 'SELECT COUNT(*) FROM information_schema.COLUMNS'
        . ' WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?'
        . " AND EXTRA LIKE '%auto_increment%'", ['ydy_user', 'id']) === 1;
    $userTriggers = $count($storeDb, 'SELECT COUNT(*) FROM information_schema.TRIGGERS'
        . ' WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?', ['ydy_user']);
    $userFk = $count($storeDb, 'SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE'
        . ' WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?'
        . ' AND REFERENCED_TABLE_NAME IS NOT NULL', ['ydy_user'])
        + $count($storeDb, 'SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE'
            . ' WHERE REFERENCED_TABLE_SCHEMA=DATABASE()'
            . ' AND REFERENCED_TABLE_NAME=?', ['ydy_user']);
}
if (!$identityUser || $userTriggers !== 0 || $userFk !== 0) {
    throw new RuntimeException('Activity read3 Store actor table boundary drift');
}
$preflightTypes = static function (array $row): array {
    $out = array_map('gettype', $row);
    ksort($out);
    return $out;
};
$pre = ['lane' => $lane, 'mode' => 'select-only-preflight',
    'store_db_identity_approved' => true, 'ai_db_identity_approved' => true,
    'dm_host_and_pair_local' => $dialect === 'dm' ? true : null,
    'activity_total' => $allTotal, 'other_store_activity_rows' => $otherStores,
    'list_page_rows' => count($listRows),
    'selected_activity_id' => $candidateId,
    'selected_uuid_sha12' => $candidateUuidSha12,
    'selected_registration_rows' => $regTotal,
    'source_sha' => $sourceSha,
    'candidate_activity_field_types' => $preflightTypes($candidate),
    'first_registration_field_types' => $preflightTypes($regRows[0]),
    'ai_table_counts' => [$aiActivityRows, $aiRegisterRows, $aiUserRows],
    'store_user_count' => $storeUserRows,
    'store_actor_id_autogenerated_fk0_triggers0' => true,
    'old_actor_rows' => $stale,
    'lists_missing_store_filter_existing_business_risk' => true,
    'business_http_executed' => false, 'dml_executed' => false];
if ($action === '--preflight') {
    echo json_encode($pre, JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(0);
}

// This branch is inaccessible without the reviewed execute marker and hashes.
$marker = 'CDXACT3' . strtoupper(bin2hex(random_bytes(6)));
$collision = $count($storeDb, 'SELECT COUNT(*) FROM ' . $s . 'user'
    . ' WHERE UUID=? OR ACCOUNT=?', [$marker, $marker]);
if ($collision !== 0) throw new RuntimeException('Activity read3 marker collision');
$privateDir = sys_get_temp_dir() . '/zhct-activity-read3-' . $marker;
if (file_exists($privateDir) || !mkdir($privateDir, 0700)) {
    throw new RuntimeException('Activity read3 private recovery directory unavailable');
}
chmod($privateDir, 0700);
$journalPath = $privateDir . '/recovery.json';
$journal = ['lane' => $lane, 'marker' => $marker,
    'activity_id' => $candidateId, 'source_sha' => $sourceSha,
    'state' => 'prepared'];
$saveJournal = static function () use (&$journal, $privateDir, $journalPath): void {
    $next = $privateDir . '/recovery.next';
    if (file_put_contents($next, json_encode($journal, JSON_UNESCAPED_SLASHES)) === false) {
        throw new RuntimeException('Activity read3 journal write failed');
    }
    chmod($next, 0600);
    if (!rename($next, $journalPath)) throw new RuntimeException('Activity read3 journal rename failed');
};
$saveJournal();
$actorId = 0;
$httpSent = false;
$httpConfirmed = true;
$results = [];
$sourceUnchanged = false;
$cleaned = false;
$privateCleared = false;
$failure = '';
$types = static function (array $row): array {
    $out = array_map('gettype', $row);
    ksort($out);
    return $out;
};
$http = static function (string $path, array $form, string $token) use ($base, $root,
    $pid, $runtimeReady, &$httpSent, &$httpConfirmed): array {
    if (!$runtimeReady()) throw new RuntimeException('Activity read3 HTTP runtime drift');
    $header = "Content-Type: application/x-www-form-urlencoded\r\n";
    if ($token !== '') $header .= 'token: ' . $token . "\r\n";
    $context = stream_context_create(['http' => ['method' => 'POST',
        'header' => $header,
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'timeout' => 20, 'ignore_errors' => true]]);
    $httpConfirmed = false;
    $httpSent = true;
    $stream = @fopen($base . '/p/activity/' . $path, 'rb', false, $context);
    $body = is_resource($stream) ? stream_get_contents($stream, 262145) : false;
    $meta = is_resource($stream) ? stream_get_meta_data($stream) : [];
    if (is_resource($stream)) fclose($stream);
    if (!is_string($body) || !empty($meta['timed_out']) || strlen($body) > 262144) {
        throw new RuntimeException('Activity read3 HTTP outcome incomplete or oversized');
    }
    $httpConfirmed = true;
    $headers = $http_response_header ?? [];
    if (strpos((string)($headers[0] ?? ''), ' 200 ') === false) {
        throw new RuntimeException('Activity read3 HTTP status mismatch');
    }
    $json = json_decode($body, true);
    if (!is_array($json) || !array_key_exists('code', $json)) {
        throw new RuntimeException('Activity read3 response envelope invalid');
    }
    return $json;
};
$expectedStatus = static function (array $row): string {
    $start = strtotime((string)($row['start_time'] ?? ''));
    $end = strtotime((string)($row['end_time'] ?? ''));
    if (!$start || !$end) return '';
    if (time() < $start) return '未开始';
    if (time() > $end) return '已结束';
    return '进行中';
};
$imageMatches = static function ($actual, $source): bool {
    $suffix = str_replace('\\', '/', (string)($source ?? ''));
    $value = (string)($actual ?? '');
    return $suffix === '' ? $value === ''
        : ($value !== '' && substr($value, -strlen($suffix)) === $suffix);
};
$matchesActivity = static function (array $actual, array $expected,
    bool $detail) use ($expectedStatus, $imageMatches, $regTotal): bool {
    foreach ($expected as $key => $value) {
        if (!array_key_exists($key, $actual)) return false;
        if ($key === 'img' || $key === 'detail_img') {
            if (!$imageMatches($actual[$key], $value)) return false;
        } elseif ((string)($actual[$key] ?? '') !== (string)($value ?? '')) {
            return false;
        }
    }
    if ((string)($actual['activity_status'] ?? '') !== $expectedStatus($expected)) return false;
    if ($detail && (!is_int($actual['participants'] ?? null)
        || $actual['participants'] !== $regTotal)) return false;
    return true;
};
try {
    $noToken = $http('lists', ['page' => '1'], '');
    if (($noToken['code'] ?? null) !== 100) {
        throw new RuntimeException('Activity read3 missing-auth contract mismatch');
    }
    $results['missing_auth_rejected'] = true;
    $stmt = $storeDb->prepare('INSERT INTO ' . $s . 'user'
        . ' (UUID,ACCOUNT,PWD,SALT,NAME,TYPE,CREATE_TIME,CREATE_BY,IS_DELETE)'
        . ' VALUES (?,?,?,?,?,?,?,?,?)');
    $stmt->execute([$marker, $marker, 'DISABLED', strtoupper(bin2hex(random_bytes(8))),
        $marker, 0, date('Y-m-d H:i:s'), 'CODEX', 0]);
    if ($stmt->rowCount() !== 1) throw new RuntimeException('Activity read3 actor insert count');
    $stmt = $storeDb->prepare('SELECT ID FROM ' . $s . 'user'
        . ' WHERE UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
    $stmt->execute([$marker, $marker, 'CODEX']);
    $actorId = (int)$stmt->fetchColumn();
    if ($actorId <= 0) throw new RuntimeException('Activity read3 actor ID absent');
    $journal['actor_id'] = $actorId;
    $journal['state'] = 'actor_committed';
    $saveJournal();
    require_once $root . '/application/base/Security.php';
    $token = \app\base\Security::encrypt(implode("\t",
        [(string)$actorId, $marker, $marker, '0', '', '', $marker]));
    if (!is_string($token) || $token === '') {
        throw new RuntimeException('Activity read3 synthetic token unavailable');
    }
    $requests = [
        'lists' => ['page' => '1'],
        'info' => ['uuid' => (string)$candidate['uuid']],
        'registerLists' => ['uuid' => (string)$candidate['uuid'], 'page' => '1'],
    ];
    $successMessages = ['lists' => '请求成功', 'info' => '信息获取成功',
        'registerLists' => '获取成功'];
    foreach ($requests as $route => $form) {
        $json = $http($route, $form, $token);
        if (($json['code'] ?? null) !== 0
            || ($json['message'] ?? null) !== $successMessages[$route]
            || !is_array($json['data'] ?? null)) {
            throw new RuntimeException('Activity read3 positive response failed');
        }
        $data = $json['data'];
        if ($route === 'lists') {
            $rows = $data['rows'] ?? null;
            if (!is_array($rows) || count($rows) !== count($listRows)
                || (int)($data['total'] ?? -1) !== $allTotal) {
                throw new RuntimeException('Activity read3 list pagination/source mismatch');
            }
            foreach ($listRows as $i => $expected) {
                if (!is_array($rows[$i] ?? null)
                    || !$matchesActivity($rows[$i], $expected, false)) {
                    throw new RuntimeException('Activity read3 list row mismatch');
                }
            }
            $rowTypes = count($rows) ? $types($rows[0]) : [];
            $rowCount = count($rows);
        } elseif ($route === 'info') {
            if (!$matchesActivity($data, $candidate, true)) {
                throw new RuntimeException('Activity read3 detail row mismatch');
            }
            $rowTypes = $types($data);
            $rowCount = 1;
        } else {
            $rows = $data['rows'] ?? null;
            if (!is_array($rows) || count($rows) !== $regTotal
                || (int)($data['total'] ?? -1) !== $regTotal) {
                throw new RuntimeException('Activity read3 register pagination/source mismatch');
            }
            foreach ($regRows as $i => $expected) {
                $row = $rows[$i] ?? null;
                if (!is_array($row)
                    || (string)($row['id'] ?? '') !== (string)$expected['id']
                    || (string)($row['nickname'] ?? '') !== (string)$expected['nick_name']
                    || (string)($row['create_time'] ?? '')
                        !== (string)$expected['create_time']) {
                    throw new RuntimeException('Activity read3 register row mismatch');
                }
            }
            $rowTypes = count($rows) ? $types($rows[0]) : [];
            $rowCount = count($rows);
        }
        $results[$route] = ['positive' => true, 'rows' => $rowCount,
            'top_types' => $types($json), 'data_types' => $types($data),
            'first_row_types' => $rowTypes,
            'response_sha' => hash('sha256', json_encode($json,
                JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))];
    }
    $missingInfo = $http('info', [], $token);
    $missingRegister = $http('registerLists', [], $token);
    if (($missingInfo['code'] ?? null) !== 1
        || ($missingRegister['code'] ?? null) !== 1) {
        throw new RuntimeException('Activity read3 required UUID rejection mismatch');
    }
    $results['missing_uuid_rejected'] = true;
    $freshAi = $connect($aiDsn, $aiRuntime);
    if (!hash_equals($aiApproved, hash('sha256', $identity($freshAi, 'ai')))) {
        throw new RuntimeException('Activity read3 AI source recheck identity drift');
    }
    $freshPage = $read($freshAi, 'SELECT * FROM ' . $a . 'activity ORDER BY ID DESC'
        . ($dialect === 'dm' ? ' FETCH FIRST 11 ROWS ONLY' : ' LIMIT 11'));
    $freshCandidate = $read($freshAi, 'SELECT * FROM ' . $a . 'activity'
        . ' WHERE ID=? AND STORE_ID=10001', [$candidateId]);
    $freshRegs = $read($freshAi, 'SELECT ar.ID,ar.USER_ID,ar.CREATE_TIME,u.NICK_NAME'
        . ' FROM ' . $a . 'activity_register ar LEFT JOIN ' . $a . 'user u'
        . ' ON u.USER_ID=ar.USER_ID WHERE ar.ACTIVITY_ID=? AND ar.STORE_ID=10001'
        . ' ORDER BY ar.ID DESC'
        . ($dialect === 'dm' ? ' FETCH FIRST 11 ROWS ONLY' : ' LIMIT 11'),
        [$candidateId]);
    $after = ['activities' => array_slice($freshPage, 0, 10),
        'candidate' => $freshCandidate[0] ?? null, 'registrations' => $freshRegs,
        'activity_total' => $count($freshAi, 'SELECT COUNT(*) FROM ' . $a . 'activity'),
        'registration_total' => $count($freshAi, 'SELECT COUNT(*) FROM '
            . $a . 'activity_register WHERE ACTIVITY_ID=? AND STORE_ID=10001',
            [$candidateId])];
    $sourceUnchanged = hash('sha256', serialize($after)) === $sourceSha
        && $count($freshAi, 'SELECT COUNT(*) FROM ' . $a . 'activity_register')
            === $aiRegisterRows
        && $count($freshAi, 'SELECT COUNT(*) FROM ' . $a . 'user') === $aiUserRows;
    if (!$sourceUnchanged) throw new RuntimeException('Activity read3 AI source changed');
} catch (Throwable $e) {
    $failure = get_class($e) . ':' . hash('sha256', $e->getMessage());
} finally {
    $workerStopped = !is_dir('/proc/' . $pid);
    $runtimeSafe = $workerStopped || $runtimeReady();
    $cleanupSafe = $runtimeSafe && ($workerStopped || !$httpSent || $httpConfirmed);
    if ($cleanupSafe) {
        try {
            $cleanupDb = $connect($storeDsn, $runtime);
            if (!hash_equals($storeApproved,
                hash('sha256', $identity($cleanupDb, 'store')))) {
                throw new RuntimeException('Activity read3 cleanup DB identity drift');
            }
            $rows = $read($cleanupDb, 'SELECT ID,UUID,ACCOUNT,NAME,TYPE,CREATE_BY'
                . ' FROM ' . $s . 'user WHERE UUID=? OR ACCOUNT=?', [$marker, $marker]);
            if (count($rows) > 1) throw new RuntimeException('Activity read3 extra actor row');
            foreach ($rows as $row) {
                if ((string)$row['uuid'] !== $marker
                    || (string)$row['account'] !== $marker
                    || (string)$row['name'] !== $marker
                    || (int)$row['type'] !== 0
                    || (string)$row['create_by'] !== 'CODEX'
                    || ($actorId > 0 && (int)$row['id'] !== $actorId)) {
                    throw new RuntimeException('Activity read3 actor ownership drift');
                }
                $stmt = $cleanupDb->prepare('DELETE FROM ' . $s . 'user'
                    . ' WHERE ID=? AND UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
                $stmt->execute([(int)$row['id'], $marker, $marker, 'CODEX']);
                if ($stmt->rowCount() !== 1) {
                    throw new RuntimeException('Activity read3 exact cleanup affected rows mismatch');
                }
            }
            $verify = $connect($storeDsn, $runtime);
            if (!hash_equals($storeApproved, hash('sha256', $identity($verify, 'store')))
                || $count($verify, 'SELECT COUNT(*) FROM ' . $s . 'user'
                    . ' WHERE UUID=? OR ACCOUNT=?', [$marker, $marker]) !== 0) {
                throw new RuntimeException('Activity read3 independent actor zero failed');
            }
            $cleaned = true;
        } catch (Throwable $e) {
            $failure .= ($failure === '' ? '' : ';') . 'cleanup:'
                . get_class($e) . ':' . hash('sha256', $e->getMessage());
        }
    } else {
        $failure .= ($failure === '' ? '' : ';')
            . ($httpSent && !$httpConfirmed && !$workerStopped
                ? 'cleanup:uncertain_http_outcome' : 'cleanup:runtime_drift');
    }
    if ($cleaned) {
        if (is_file($journalPath)) @unlink($journalPath);
        if (is_file($privateDir . '/recovery.next')) @unlink($privateDir . '/recovery.next');
        $privateCleared = @rmdir($privateDir);
        if (!$privateCleared) $failure .= ';private_journal_not_removed';
    } else {
        $journal['state'] = 'requires_manual_recovery';
        try { $saveJournal(); } catch (Throwable $e) { /* retain old journal */ }
    }
}
$result = ['lane' => $lane, 'marker' => $marker,
    'results' => $results, 'ai_source_unchanged' => $sourceUnchanged,
    'store_actor_independent_zero' => $cleaned,
    'private_journal_removed' => $privateCleared,
    'private_recovery_pointer' => $cleaned ? null : $privateDir,
    'failure' => $failure];
echo json_encode($result, JSON_UNESCAPED_SLASHES), PHP_EOL;
if ($failure !== '' || !$sourceUnchanged || !$cleaned || !$privateCleared
    || empty($results['missing_auth_rejected'])
    || empty($results['missing_uuid_rejected'])
    || !isset($results['lists'], $results['info'], $results['registerLists'])) exit(1);
