load(); \support\App::loadAllConfig(['route']); date_default_timezone_set('Asia/Shanghai'); use app\miniapi\auth\Principal; use app\miniapi\auth\SessionVerifier; use app\miniapi\model\MiniUser; use app\miniapi\model\MiniSession; use app\miniapi\model\MiniGrant; use app\miniapi\model\MiniCheckout; use app\miniapi\model\MiniEnterpriseBalance; use app\miniapi\model\MiniCommand; use app\miniapi\model\MiniAudit; use app\miniapi\model\MiniTaskRecord; use app\miniapi\model\MiniPhoto; use app\miniapi\service\Access; use app\miniapi\service\AuthService; use app\miniapi\service\Catalog; use app\miniapi\service\EnterpriseQuery; use app\miniapi\service\EnterpriseCommands; use app\miniapi\service\CheckoutService; use app\miniapi\service\DriverService; use app\miniapi\service\AgentQuery; use app\miniapi\service\IdentityManagement; use app\miniapi\exception\ApiException; use app\miniapi\controller\CheckoutController; use app\miniapi\controller\PhotoController; use plugin\saiadmin\app\model\water\WaterEnterprise; use plugin\saiadmin\app\model\water\WaterSku; use plugin\saiadmin\app\model\water\WaterAccount; use plugin\saiadmin\app\model\water\WaterOrder; use plugin\saiadmin\app\model\water\WaterDelivery; use plugin\saiadmin\app\model\water\WaterContent; use plugin\saiadmin\app\service\WaterBusiness; use plugin\saiadmin\app\service\WaterDispatch; use support\Request; use app\miniapi\support\PhoneNumber; use app\miniapi\http\Fields; $checks = 0; $contract = new MiniApiContract(); function check(bool $ok, string $label): void { global $checks; $checks++; if (!$ok) { throw new RuntimeException($label); } } function reject(callable $fn, int $code, string $label): void { try { $fn(); } catch (ApiException $e) { check($e->getCode() === $code, $label . ' actual ' . $e->getCode()); return; }throw new RuntimeException('Missing rejection: ' . $label); } function inputRequest(string $path, array $data, Principal $actor): Request { $body = json_encode($data); $r = new Request("POST $path HTTP/1.1\r\nHost: localhost\r\nContent-Type: application/json\r\nContent-Length: " . strlen($body) . "\r\n\r\n" . $body); $r->miniPrincipal = $actor; return $r; } foreach ([ '138-1234-5678' => ['13812345678', '138****5678'], '+86 138 1234 5678' => ['+8613812345678', '+861******5678'], '(010) 1234-5678' => ['01012345678', '010****5678'], '1234567' => ['1234567', '12***67'], ] as $input => [$normalized, $masked]) { check(PhoneNumber::normalize((string) $input) === $normalized, 'phone normalization'); check(PhoneNumber::mask((string) $input) === $masked, 'formatted phone masked'); } foreach (['------', '++++++', '()()()', '(01012345678', '138****5678', '123456', '+0123456789', '0000000', '1234567890123456'] as $phone) { reject(fn () => Fields::phone(['phone' => $phone]), 42201, 'invalid phone rejected'); check(PhoneNumber::mask($phone) === '****', 'invalid legacy phone never exposed'); } check(PhoneNumber::mask('') === '', 'missing phone stays empty'); $models = [ MiniUser::class, MiniSession::class, MiniGrant::class, MiniCheckout::class, MiniEnterpriseBalance::class, MiniCommand::class, MiniAudit::class, MiniTaskRecord::class, MiniPhoto::class, WaterEnterprise::class, WaterSku::class, WaterAccount::class, WaterOrder::class, WaterDelivery::class, ]; $before = []; foreach ($models as $m) { $before[$m] = $m::query()->count(); } $db = (new MiniUser())->getConnection(); $db->beginTransaction(); $tag = 'MINI-TEST-' . bin2hex(random_bytes(6)); try { $business = new WaterBusiness(); $auth = new AuthService(); $manager = new IdentityManagement(); $session = $auth->issue([ 'appid' => 'test-' . $tag, 'openid' => 'u1', ]); $actor = (new SessionVerifier())->verify($session['access_token']); $other = $auth->issue([ 'appid' => 'test-' . $tag, 'openid' => 'u2', ]); $otherActor = (new SessionVerifier())->verify($other['access_token']); check($session['identities'] === [], 'new login has no inherited authority'); $provider = new class ('test-' . $tag) implements \app\miniapi\auth\IdentityProvider { public function __construct(private readonly string $appid) { } public function exchange(string $code): array { if ($code !== 'verified-test-code') { throw new ApiException(40102, 'invalid code', 401); } return ['appid' => $this->appid, 'openid' => 'u1']; } }; $loginService = new AuthService($provider); check($loginService->login(['code' => 'verified-test-code'])['user_id'] === $session['user_id'], 'login service depends on identity adapter contract'); reject(fn () => $loginService->login(['code' => 'verified-test-code', 'user_id' => 'forged']), 42201, 'client cannot supply provider identity'); check(MiniSession::query()->where('user_id', $actor->userId)->value('token_hash') !== $session['access_token'], 'token hash only'); reject(fn () => (new SessionVerifier())->verify('admin.jwt.token'), 40101, 'admin JWT not accepted'); $enterprise = $business->save('enterprise', [ 'name' => $tag, 'contact' => '?????????', 'phone' => '13812345678', 'address' => '????????????', 'region' => '?????????', 'employee_count' => 30, ], 1)['id']; $enterprise2 = $business->save('enterprise', [ 'name' => $tag . '-other', 'contact' => '???', 'phone' => '13912345678', 'address' => '????????????', ], 1)['id']; $sku = $business->save('sku', [ 'name' => $tag, 'liters' => 18.9, ], 1)['id']; $package = $business->save('package', [ 'name' => $tag, 'sku_id' => $sku, 'buckets' => 30, 'price_cents' => 69900, ], 1)['id']; $business->purchase([ 'enterprise_id' => $enterprise, 'package_id' => $package, 'reference' => $tag . '-receipt', ], 1); $business->stock([ 'sku_id' => $sku, 'mode' => 'inbound', 'quantity' => 60, 'reference' => $tag . '-stock', 'note' => 'test', ], 1); $manager->grant(1, [ 'user_id' => (int) $actor->userId, 'role' => 'enterprise_admin', 'resource_id' => $enterprise, ]); $manager->grant(1, [ 'user_id' => (int) $otherActor->userId, 'role' => 'enterprise_member', 'resource_id' => $enterprise, ]); reject(fn () => $manager->grant(2, [ 'user_id' => (int) $actor->userId, 'role' => 'enterprise_admin', 'resource_id' => $enterprise2, ]), 40301, 'only admin can bind identity'); $access = new Access($actor); $query = new EnterpriseQuery($access); $commands = new EnterpriseCommands($access); $checkout = new CheckoutService($access); check(count($access->identities()) === 1, 'identity returned after explicit grant'); reject(fn () => $access->enterprise($enterprise2), 40301, 'cross enterprise read forbidden'); reject(fn () => (new Access($otherActor))->enterprise($enterprise, true), 40301, 'member cannot write'); check($query->addresses()['items'][0]['phone'] === '138****5678', 'phone masking'); check(count($query->addresses()['items']) === 1, 'addresses scoped'); $rights = $query->rights($enterprise); check($rights['summary']['available'] === 30, 'real purchased rights'); check($rights['items'][0]['expires_at'] === null && !$rights['capabilities']['individual_package_cards'], 'no fictitious expiry or separate cards'); $catalog = (new Catalog())->detail($package); check($catalog['price_cents'] === 69900, 'catalog integer cents'); WaterSku::query()->where('id', $sku)->update(['status' => 2]); reject(fn () => (new Catalog())->detail($package), 40401, 'disabled SKU hides package'); WaterSku::query()->where('id', $sku)->update(['status' => 1]); $item = ['items' => [[ 'package_id' => $package, 'quantity' => 2, ]]]; $quote = $checkout->quote($enterprise, $item); check($quote['amount_cents'] === 139800 && $quote['discount_cents'] === 0, 'server quote does not copy mock discount'); reject(fn () => $checkout->quote($enterprise, ['items' => [[ 'package_id' => $package, 'quantity' => 1, ], [ 'package_id' => $package, 'quantity' => 2, ]]]), 42201, 'duplicate package rejected'); reject(fn () => $checkout->quote($enterprise, ['items' => [[ 'package_id' => $package, 'quantity' => 1, 'price_cents' => 1, ]]]), 42201, 'client price rejected'); $create = $item + [ 'request_key' => $tag . '-checkout', 'expected_amount_cents' => 139800, 'agreement_accepted' => true, ]; reject(fn () => $checkout->create($enterprise, array_replace($create, ['expected_amount_cents' => 1])), 40904, 'changed quote rejected'); $order = $checkout->create($enterprise, $create); check($order['status'] === 'pending', 'checkout stored pending'); check($checkout->create($enterprise, $create)['id'] === $order['id'], 'checkout retry reuses order'); reject(fn () => $checkout->create($enterprise, array_replace($create, ['expected_amount_cents' => 1])), 40901, 'different replay rejected'); check($query->rights($enterprise)['summary']['available'] === 30, 'pending order never credits rights'); check(WaterOrder::query()->where('enterprise_id', $enterprise)->count() === 1, 'pending order never appears in receipts'); $controller = new CheckoutController(); $quoteResponse = $controller->quote(inputRequest('/api/mini/v1/test', $item, $actor), (string) $enterprise); check(json_decode($quoteResponse->rawBody(), true)['data']['amount_cents'] === 139800, 'nested JSON items work through HTTP controller'); MiniEnterpriseBalance::query()->create([ 'enterprise_id' => $enterprise, 'balance_cents' => 200000, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]); $payKey = $tag . '-pay'; $payResponse = $controller->pay(inputRequest('/api/mini/v1/test', [ 'request_key' => $payKey, 'payment_method' => 'balance', ], $actor), (string) $enterprise, (string) $order['id']); $payBody = json_decode($payResponse->rawBody(), true); check($payBody['data']['status'] === 'paid', 'balance payment marks checkout paid'); check((int) MiniEnterpriseBalance::query()->where('enterprise_id', $enterprise)->value('balance_cents') === 60200, 'balance payment deducts cents'); check($query->rights($enterprise)['summary']['available'] === 90, 'balance payment grants purchased rights'); check(WaterOrder::query()->where('enterprise_id', $enterprise)->count() === 3, 'balance payment creates receipts'); check($checkout->pay($enterprise, $order['id'], [ 'request_key' => $payKey, 'payment_method' => 'balance', ])['replayed'] === true, 'balance payment retry replays safely'); reject(fn () => $controller->pay(inputRequest('/api/mini/v1/test', [ 'request_key' => $tag . '-wechat', 'payment_method' => 'wechat', ], $actor), (string) $enterprise, (string) $order['id']), 50303, 'wechat payment remains reserved'); check($checkout->detail($enterprise, $order['id'])['address']['phone'] === '138****5678', 'checkout address masked'); check($query->orders($enterprise, ['kind' => 'checkouts'])['total'] === 1, 'checkout list real'); $cancelOrder = $checkout->create($enterprise, array_replace($create, ['request_key' => $tag . '-cancel-create'])); check($checkout->cancel($enterprise, $cancelOrder['id'], ['request_key' => $tag . '-cancel-order'])['status'] === 'cancelled', 'checkout cancellation'); $address = $query->addresses()['items'][0]; check($query->addressDetail($enterprise)['phone'] === '13812345678', 'enterprise admin can edit actual contact'); reject(fn () => (new EnterpriseQuery(new Access($otherActor)))->addressDetail($enterprise), 40301, 'member cannot read editable contact'); $changed = $commands->address($enterprise, [ 'request_key' => $tag . '-address', 'revision' => $address['revision'], 'address' => '???????????????', 'contact' => '???', 'phone' => '138-1234-5678', ]); check(WaterEnterprise::query()->find($enterprise)->phone === '13812345678', 'address stores normalized phone'); check(WaterEnterprise::query()->find($enterprise)->address === '???????????????', 'address update works'); reject(fn () => $commands->address($enterprise, [ 'request_key' => $tag . '-stale-address', 'revision' => $address['revision'], 'address' => '???????????????', 'contact' => '???', 'phone' => '13812345678', ]), 40901, 'stale address revision rejected even within same second'); $booking = [ 'sku_id' => $sku, 'quantity' => 8, 'request_key' => $tag . '-book', ]; $task = $commands->book($enterprise, $booking)['id']; check($commands->book($enterprise, $booking)['id'] === $task, 'booking retry no duplicate'); check($query->rights($enterprise)['summary']['frozen'] === 8, 'booking freezes existing rights'); reject(fn () => $commands->book($enterprise, array_replace($booking, ['request_key' => $tag . '-book-other'])), 40902, 'second active booking rejected'); reject(fn () => $commands->address($enterprise, [ 'request_key' => $tag . '-address-active', 'revision' => $changed['revision'], 'address' => '??????', 'contact' => '???', 'phone' => '13812345678', ]), 40902, 'active task prevents moving address'); check($commands->cancel($enterprise, $task, ['request_key' => $tag . '-cancel-task'])['status'] === 'cancelled', 'cancel pending task'); check($query->rights($enterprise)['summary']['frozen'] === 0, 'cancel releases rights'); $task = $commands->book($enterprise, array_replace($booking, ['request_key' => $tag . '-book-2']))['id']; $dispatch = new WaterDispatch(); $driver = $dispatch->saveDriver([ 'name' => $tag, 'phone' => $tag, 'region' => '?????????', 'vehicle' => 'test', 'capacity' => 100, ], 1)['id']; $dispatch->shift([ 'driver_id' => $driver, 'date' => date('Y-m-d'), 'state' => 'on', ], 1); $dispatch->commit([ 'date' => date('Y-m-d'), 'request_key' => $tag . '-route', 'routes' => [[ 'driver_id' => $driver, 'task_ids' => [$task], ]], ], 1); $manager->grant(1, [ 'user_id' => (int) $actor->userId, 'role' => 'driver', 'resource_id' => $driver, ]); $driverService = new DriverService($access); check($driverService->tasks($driver, [])['total'] === 1, 'driver sees only assigned task'); check($driverService->detail($driver, $task)['contact_phone'] === '13812345678', 'assigned driver can call customer'); reject(fn () => (new DriverService(new Access($otherActor)))->detail($driver, $task), 40301, 'unbound driver forbidden'); reject(fn () => $commands->cancel($enterprise, $task, ['request_key' => $tag . '-cancel-assigned']), 40902, 'customer cannot cancel assigned task'); check($driverService->command($driver, $task, 'start', ['request_key' => $tag . '-depart'])['status'] === 'transit', 'driver departure uses stock transaction'); check($driverService->command($driver, $task, 'start', ['request_key' => $tag . '-depart'])['replayed'], 'departure replay'); $driverService->command($driver, $task, 'checkin', [ 'request_key' => $tag . '-checkin', 'latitude' => 22.52, 'longitude' => 113.92, ]); reject(fn () => $driverService->command($driver, $task, 'checkin', [ 'request_key' => $tag . '-bad-location', 'latitude' => 100, 'longitude' => 113.92, ]), 42201, 'latitude range checked'); $driverService->command($driver, $task, 'exception', [ 'request_key' => $tag . '-exception', 'reason' => '??????????????????', ]); check(WaterDelivery::query()->find($task)->status === 'transit', 'exception report does not invent completion'); $finish = [ 'request_key' => $tag . '-complete', 'accepted_qty' => 8, 'empty_returned' => 0, 'receiver' => '???', 'confirmed' => true, 'photo_ids' => [], ]; reject(fn () => $driverService->command($driver, $task, 'complete', $finish), 42201, 'completion requires photo'); $img = imagecreatetruecolor(640, 100); ob_start(); imagepng($img); $base64 = base64_encode(ob_get_clean()); imagedestroy($img); $photoInput = [ 'request_key' => $tag . '-photo', 'image_base64' => $base64, 'latitude' => 22.52, 'longitude' => 113.92, ]; $photo = $driverService->photo($driver, $task, $photoInput); check($driverService->photo($driver, $task, $photoInput)['id'] === $photo['id'], 'photo upload idempotent'); check(MiniPhoto::query()->find($photo['id'])->mime === 'image/jpeg', 'photos reencoded and watermarked'); reject(fn () => $driverService->photo($driver, $task, array_replace($photoInput, [ 'request_key' => $tag . '-bad-photo', 'image_base64' => base64_encode(''), ])), 42201, 'non image rejected'); $draft = array_replace($finish, [ 'request_key' => $tag . '-draft', 'photo_ids' => [$photo['id']], ]); check($driverService->command($driver, $task, 'draft', $draft)['saved'], 'draft saved without settlement'); check($query->rights($enterprise)['summary']['remaining'] === 90, 'draft never consumes rights'); $finish['photo_ids'] = [$photo['id']]; check($driverService->command($driver, $task, 'complete', $finish)['status'] === 'completed', 'driver completes assigned task'); check($driverService->command($driver, $task, 'complete', $finish)['replayed'], 'completion retry does not settle twice'); check($driverService->detail($driver, $task)['contact_phone'] === null, 'completed task no longer exposes call number'); $rights = $query->rights($enterprise); check($rights['summary']['remaining'] === 82 && $rights['summary']['frozen'] === 0, 'exactly eight rights consumed'); check($rights['summary']['full_qty'] === 8, 'site inventory received'); check($query->tracking($enterprise, $task)['photos'][0]['id'] == $photo['id'], 'customer sees own fulfillment evidence'); reject(fn () => $query->tracking($enterprise2, $task), 40301, 'tracking cannot cross enterprise'); $pr = new Request('GET /api/mini/v1/photos/' . $photo['id'] . '?scope=enterprise&resource_id=' . $enterprise . " HTTP/1.1\r\nHost: localhost\r\n\r\n"); $pr->miniPrincipal = $actor; check((new PhotoController())->photo($pr, (string) $photo['id'])->getHeader('Content-Type') === 'image/jpeg', 'private photo authorized'); $pr2 = new Request('GET /api/mini/v1/photos/' . $photo['id'] . '?scope=enterprise&resource_id=' . $enterprise2 . " HTTP/1.1\r\nHost: localhost\r\n\r\n"); $pr2->miniPrincipal = $otherActor; reject(fn () => (new PhotoController())->photo($pr2, (string) $photo['id']), 40301, 'photo ownership enforced'); $device = $business->save('device', [ 'name' => $tag, 'sn' => $tag, 'enterprise_id' => $enterprise, 'sku_id' => $sku, ], 1)['id']; check($query->deviceDetail($enterprise, $device)['today_liters'] === null, 'unknown telemetry stays null'); check(count($query->deviceDetail($enterprise, $device)['trend']) === 7, 'seven day trend'); check(!$driverService->deviceCheck($driver, $task, $tag)['online'], 'device registration does not mean online'); $now = date('Y-m-d H:i:s'); WaterContent::query()->insert([ 'title' => $tag, 'image_url' => 'https://example.test/a.png', 'target_url' => 'https://example.test/', 'audience' => 'purchased', 'region' => '?????????', 'sort' => 999999, 'status' => 1, 'created_at' => $now, 'updated_at' => $now, ]); $home = $query->home($enterprise); check(in_array($tag, array_column($home['banners'], 'title'), true), 'home derives actual paid audience'); check($home['unread_messages'] === null, 'no fake unread message count'); check($driverService->dashboard($driver)['summary']['completed_today'] === 1, 'driver dashboard completion'); check(count($driverService->routes($driver)) === 1, 'assigned routes returned'); $agent = $business->save('agent', [ 'name' => $tag, 'contact' => '??????', 'phone' => $tag, 'region' => '?????????', 'address' => '??????', ], 1)['id']; WaterEnterprise::query()->where('id', $enterprise)->update(['agent_id' => $agent]); $manager->grant(1, [ 'user_id' => (int) $actor->userId, 'role' => 'agent', 'resource_id' => $agent, ]); $aq = new AgentQuery($access); check($aq->customers($agent, [])['total'] === 1, 'agent customers scoped'); check($aq->orders($agent, [])['total'] === 3, 'paid checkout receipts enter agent turnover'); check($aq->dashboard($agent)['summary']['month_amount_cents'] === 209700, 'agent real receipt turnover'); check($aq->commissions($agent)['withdrawable_cents'] === 0 && $aq->commissions($agent)['pending_cents'] === 0, 'unsettled commission account starts at zero'); $customer = $aq->customers($agent, [])['items'][0]; check($customer['amount_cents'] === 209700 && $customer['has_purchased'] && $customer['device_count'] === 1, 'customer aggregates preserve paid and device totals'); check($customer['last_purchase_at'] !== null, 'customer last receipt timestamp'); WaterEnterprise::query()->where('id', $enterprise2)->update(['agent_id' => $agent, 'phone' => '+86 138 1234 5678']); $futureReceipt = WaterOrder::query()->where('enterprise_id', $enterprise)->first()->replicate(); $futureReceipt->fill([ 'enterprise_id' => $enterprise2, 'reference' => $tag . '-future', 'created_at' => date('Y-m-d H:i:s', time() + 86400), ])->save(); $db->enableQueryLog(); try { $db->flushQueryLog(); $aq->customers($agent, ['page_size' => 1]); $singleCount = count($db->getQueryLog()); $db->flushQueryLog(); $customers = $aq->customers($agent, ['page_size' => 100]); check(count($db->getQueryLog()) === $singleCount, 'customer query count does not grow per row'); check(count($customers['items']) === 2, 'query-count regression covers multiple customers'); } finally { $db->disableQueryLog(); $db->flushQueryLog(); } $unpaid = $customers['items'][0]; check($unpaid['id'] === $enterprise2 && $unpaid['amount_cents'] === 0 && !$unpaid['has_purchased'], 'future receipt excluded from customer purchase totals'); check($unpaid['last_purchase_at'] === null && $unpaid['device_count'] === 0, 'empty aggregates return null timestamp and zero count'); check($unpaid['phone'] === '+861******5678', 'agent list masks legacy international phone'); check($aq->customers($agent, ['filter' => 'unpaid'])['total'] === 1, 'unpaid filter agrees with aggregates'); foreach ([ 'Login' => $session, 'Config' => (new \app\miniapi\service\SystemService())->configuration(), 'Health' => (new \app\miniapi\service\SystemService())->status(), 'Profile' => $query->profile($enterprise), 'Addresses' => $query->addresses(), 'EditableAddress' => $query->addressDetail($enterprise), 'Home' => $home, 'Package' => $catalog, 'PackagePage' => (new Catalog())->listing(['keyword' => $tag]), 'Rights' => $rights, 'LedgerPage' => $query->ledger($enterprise, []), 'EnterpriseOrderPage' => $query->orders($enterprise, []), 'Tracking' => $query->tracking($enterprise, $task), 'DevicePage' => $query->devices($enterprise, []), 'DeviceDetail' => $query->deviceDetail($enterprise, $device), 'Rewards' => $query->rewards($enterprise), 'Quote' => $quote, 'Checkout' => $order, 'CheckoutDetail' => $checkout->detail($enterprise, $order['id']), 'AddressResult' => $changed, 'DriverDashboard' => $driverService->dashboard($driver), 'TaskPage' => $driverService->tasks($driver, []), 'TaskDetail' => $driverService->detail($driver, $task), 'Route' => $driverService->routes($driver)[0], 'DeviceCheck' => $driverService->deviceCheck($driver, $task, $tag), 'PhotoResult' => $photo, 'AgentDashboard' => $aq->dashboard($agent), 'CustomerPage' => $customers, 'AgentOrderPage' => $aq->orders($agent, []), 'Commissions' => $aq->commissions($agent), ] as $schema => $result) { check($contract->data($schema, $result), 'actual response matches OpenAPI: ' . $schema); } foreach (['purchases', 'checkouts'] as $kind) { check($contract->data('EnterpriseOrderPage', $query->orders($enterprise, ['kind' => $kind])), 'order variant matches OpenAPI: ' . $kind); } reject(fn () => (new AgentQuery(new Access($otherActor)))->dashboard($agent), 40301, 'agent identity enforced'); $manager->grant(1, [ 'user_id' => (int) $actor->userId, 'role' => 'enterprise_admin', 'resource_id' => $enterprise, 'status' => 0, ]); reject(fn () => $query->rights($enterprise), 40301, 'revocation effective immediately'); reject(fn () => $checkout->create($enterprise, $create), 40301, 'revoked user cannot replay old checkout result'); $auth->logout($session['access_token']); reject(fn () => (new SessionVerifier())->verify($session['access_token']), 40101, 'logout invalidates token'); MiniSession::query()->where('user_id', $otherActor->userId)->update(['expires_at' => date('Y-m-d H:i:s', time() - 1)]); reject(fn () => (new SessionVerifier())->verify($other['access_token']), 40101, 'expired token rejected'); check(MiniAudit::query()->where('actor_type', 'mini')->where('actor_id', $actor->userId)->count() > 0, 'mini actor audit separate from admin'); check(WaterDelivery::query()->find($task)->created_by === 0, 'mini IDs not impersonating admin IDs'); } finally { $db->rollBack(); } foreach ($models as $m) { check($m::query()->count() === $before[$m], $m . ' fixtures rolled back'); } echo "PASS: $checks mini water API checks; no persistent business changes.\n";