From f2e2b9a8f4701e67d3cb14d5ef7c5a216127beaa Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Mon, 27 Apr 2026 16:02:36 +0200 Subject: [PATCH] Update relay-handling logic and test assertions for device binding and local IP resolution - Correct test cases to ensure proper relay IDs are switched. - Add robust local IP resolution for relay-device bindings, including caching and inventory backfill. - Introduce fast-path options for relay status and switch dispatch. - Validate PHP extensions (`curl`, `sqlite3`) in edge agent images. --- services/edge-agent/Dockerfile.test-gateway | 4 +- services/edge-agent/dist/agent.mjs | 76 ++++- services/edge-agent/test/agent.test.mjs | 17 + services/edge-broker/server.mjs | 81 ++++- services/edge-broker/test/broker.test.mjs | 136 +++++++- .../nginx/app/.phpunit.cache/test-results | 2 +- .../app/classes/gateway_shelly_transport.php | 25 +- .../app/classes/shelly_relay_inventory.php | 40 +++ .../app/classes/shelly_transport_resolver.php | 16 +- .../classes/edge_gateway_manager.php | 322 ++++++++++++++++-- .../selfserve_lane_port_controller_t.php | 8 +- .../selfserve_lane_relay_controller_t.php | 31 +- .../Dockerfile.auto-updater | 3 +- .../edge-gateway-agent/Dockerfile.edge-agent | 3 + .../edge-gateway-agent/Dockerfile.lan-worker | 3 + .../truckwash-edge-agent.service | 16 +- .../nginx/app/routes/moduleSelfServeRoute.php | 57 ++++ .../EdgeGatewayManagerCommandQueueTest.php | 16 + .../EdgeGatewayManagerHeartbeatStatusTest.php | 41 +++ .../EdgeGatewayUpdateLifecycleTest.php | 13 +- .../Selfserve/GatewayShellyTransportTest.php | 57 ++++ .../SelfserveLanePortControllerTest.php | 8 +- .../Selfserve/SelfserveRouteWiringTest.php | 2 + .../Selfserve/ShellyRelayInventoryTest.php | 13 + .../Selfserve/ShellyTransportResolverTest.php | 29 ++ 25 files changed, 938 insertions(+), 81 deletions(-) diff --git a/services/edge-agent/Dockerfile.test-gateway b/services/edge-agent/Dockerfile.test-gateway index fef5aa55..af691a1e 100644 --- a/services/edge-agent/Dockerfile.test-gateway +++ b/services/edge-agent/Dockerfile.test-gateway @@ -3,9 +3,7 @@ FROM php:8.2-cli WORKDIR /opt/truckwash-edge-agent RUN set -eux; \ - apt-get update; \ - apt-get install -y --no-install-recommends ca-certificates; \ - rm -rf /var/lib/apt/lists/* + php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }' COPY services/nginx/app/resources/edge-gateway-agent/ ./ diff --git a/services/edge-agent/dist/agent.mjs b/services/edge-agent/dist/agent.mjs index 2ecece90..4c2e8963 100644 --- a/services/edge-agent/dist/agent.mjs +++ b/services/edge-agent/dist/agent.mjs @@ -17,6 +17,7 @@ const DEFAULT_UPDATE_VERIFICATION_TIMEOUT_SECONDS = 45; const DEFAULT_UPDATE_VERIFY_INTERVAL_MS = 500; const DEFAULT_UPDATE_RESTART_GRACE_MS = 150; const DEFAULT_BROKER_RECONNECT_DELAY_MS = 1500; +const DEFAULT_SHELLY_LOCAL_HTTP_TIMEOUT_MS = 1200; const UPDATE_VERIFY_COMMAND = "post-update-verify"; const execFile = promisify(execFileCallback); @@ -426,8 +427,55 @@ export async function claimIfNeeded(config, configPath, fetchImpl = fetch) { return nextConfig; } -async function fetchJson(url, fetchImpl = fetch) { - const response = await fetchImpl(url); +function makeHttpTimeoutError(timeoutMs) { + const error = new Error(`HTTP request timed out after ${timeoutMs}ms`); + error.code = "EDGE_AGENT_HTTP_TIMEOUT"; + return error; +} + +function isHttpTimeoutError(error) { + return error?.code === "EDGE_AGENT_HTTP_TIMEOUT"; +} + +function resolveShellyLocalHttpTimeoutMs(options = {}) { + const configured = Number(options.timeoutMs ?? process.env.EDGE_SHELLY_LOCAL_HTTP_TIMEOUT_MS); + if (Number.isFinite(configured) && configured > 0) { + return Math.max(50, Math.floor(configured)); + } + + return DEFAULT_SHELLY_LOCAL_HTTP_TIMEOUT_MS; +} + +async function fetchJson(url, fetchImpl = fetch, options = {}) { + const timeoutMs = Number(options.timeoutMs || 0); + let timeout = null; + let controller = null; + const requestOptions = {}; + if (timeoutMs > 0 && typeof AbortController !== "undefined") { + controller = new AbortController(); + requestOptions.signal = controller.signal; + } + + let response; + try { + const fetchPromise = Promise.resolve().then(() => fetchImpl(url, requestOptions)); + response = timeoutMs > 0 + ? await Promise.race([ + fetchPromise, + new Promise((_, reject) => { + timeout = setTimeout(() => { + controller?.abort(); + reject(makeHttpTimeoutError(timeoutMs)); + }, timeoutMs); + }), + ]) + : await fetchPromise; + } finally { + if (timeout !== null) { + clearTimeout(timeout); + } + } + if (!response.ok) { throw new Error(`HTTP ${response.status}`); } @@ -458,7 +506,9 @@ export async function discoverShellyDevices(options = {}, fetchImpl = fetch) { await Promise.all(candidateIps.map(async (ip) => { try { - const identity = await fetchJson(`http://${ip}/shelly`, fetchImpl); + const identity = await fetchJson(`http://${ip}/shelly`, fetchImpl, { + timeoutMs: resolveShellyLocalHttpTimeoutMs(options), + }); discovered.push({ id: identity.mac || identity.id || ip, device_id: identity.mac || identity.id || ip, @@ -482,19 +532,23 @@ export async function discoverShellyDevices(options = {}, fetchImpl = fetch) { export async function getRelayStatus(payload, fetchImpl = fetch) { const ip = payload.localIp || payload.local_ip || payload.ip; const channel = Number.isInteger(payload.channel) ? payload.channel : 0; + const timeoutMs = resolveShellyLocalHttpTimeoutMs(payload); if (!ip) { throw new Error("Missing relay local IP"); } try { - const rpc = await fetchJson(`http://${ip}/rpc/Switch.GetStatus?id=${channel}`, fetchImpl); + const rpc = await fetchJson(`http://${ip}/rpc/Switch.GetStatus?id=${channel}`, fetchImpl, { timeoutMs }); return { online: true, on: Boolean(rpc.output), raw: rpc, }; - } catch { - const legacy = await fetchJson(`http://${ip}/relay/${channel}`, fetchImpl); + } catch (error) { + if (isHttpTimeoutError(error)) { + throw error; + } + const legacy = await fetchJson(`http://${ip}/relay/${channel}`, fetchImpl, { timeoutMs }); return { online: true, on: Boolean(legacy.ison ?? legacy.output), @@ -507,19 +561,23 @@ export async function setRelayState(payload, fetchImpl = fetch) { const ip = payload.localIp || payload.local_ip || payload.ip; const channel = Number.isInteger(payload.channel) ? payload.channel : 0; const on = Boolean(payload.on); + const timeoutMs = resolveShellyLocalHttpTimeoutMs(payload); if (!ip) { throw new Error("Missing relay local IP"); } try { - const rpc = await fetchJson(`http://${ip}/rpc/Switch.Set?id=${channel}&on=${on ? "true" : "false"}`, fetchImpl); + const rpc = await fetchJson(`http://${ip}/rpc/Switch.Set?id=${channel}&on=${on ? "true" : "false"}`, fetchImpl, { timeoutMs }); return { online: true, on: Boolean(rpc.output ?? on), raw: rpc, }; - } catch { - const legacy = await fetchJson(`http://${ip}/relay/${channel}?turn=${on ? "on" : "off"}`, fetchImpl); + } catch (error) { + if (isHttpTimeoutError(error)) { + throw error; + } + const legacy = await fetchJson(`http://${ip}/relay/${channel}?turn=${on ? "on" : "off"}`, fetchImpl, { timeoutMs }); return { online: true, on: Boolean(legacy.ison ?? legacy.output ?? on), diff --git a/services/edge-agent/test/agent.test.mjs b/services/edge-agent/test/agent.test.mjs index 4e8dd7bc..637bf028 100644 --- a/services/edge-agent/test/agent.test.mjs +++ b/services/edge-agent/test/agent.test.mjs @@ -120,6 +120,23 @@ test("relay status and switch commands support both Shelly RPC and legacy endpoi assert.equal(switched.on, false); }); +test("relay switch commands fail quickly when the local Shelly request stalls", async () => { + let calls = 0; + const hangingFetch = async () => { + calls += 1; + return new Promise(() => {}); + }; + const startedAt = Date.now(); + + await assert.rejects( + () => setRelayState({ localIp: "10.1.0.31", channel: 0, on: true, timeoutMs: 50 }, hangingFetch), + /HTTP request timed out after 50ms/ + ); + + assert.equal(calls, 1); + assert.ok(Date.now() - startedAt < 500); +}); + test("runUpdate stages a pending verification restart after installing new artifacts", async () => { const tempDir = await mkdtemp(path.join(os.tmpdir(), "edge-agent-update-")); const configPath = path.join(tempDir, "config.json"); diff --git a/services/edge-broker/server.mjs b/services/edge-broker/server.mjs index 7bd16008..b9a02b7f 100644 --- a/services/edge-broker/server.mjs +++ b/services/edge-broker/server.mjs @@ -106,6 +106,19 @@ function sendJson(ws, payload) { return true; } +function currentTimestamp() { + return new Date().toISOString(); +} + +function normalizeErrorMessage(error, fallback = "Connection step failed") { + if (error instanceof Error && error.message) { + return error.message; + } + + const message = String(error || "").trim(); + return message || fallback; +} + export function createBrokerServer(options = {}) { const sharedSecret = options.sharedSecret ?? process.env.EDGE_BROKER_SHARED_SECRET ?? ""; const managerUrl = resolveManagerUrl(options); @@ -331,6 +344,44 @@ export function createBrokerServer(options = {}) { return syncPromise; }; + const sendAgentWelcome = (ws) => + sendJson(ws, { + type: "WELCOME", + target: "edge-agent", + gatewayId: String(ws.gatewayId || ""), + connectionId: ws.connectionId || null, + agentInstanceId: ws.agentInstanceId || null, + serverTime: currentTimestamp(), + broker: { + authMode, + }, + }); + + const sendAgentConnectionProgress = (ws, stage, status, message, details = {}) => + sendJson(ws, { + type: "CONNECTION_PROGRESS", + gatewayId: String(ws.gatewayId || ""), + connectionId: ws.connectionId || null, + stage, + status, + message, + ...details, + serverTime: currentTimestamp(), + }); + + const sendAgentConnectionError = (ws, stage, error, details = {}) => + sendJson(ws, { + type: "CONNECTION_ERROR", + gatewayId: String(ws.gatewayId || ""), + connectionId: ws.connectionId || null, + stage, + status: "failed", + message: normalizeErrorMessage(error), + error: normalizeErrorMessage(error), + ...details, + serverTime: currentTimestamp(), + }); + const server = http.createServer(async (req, res) => { try { const url = new URL(req.url, "http://localhost"); @@ -421,6 +472,9 @@ export function createBrokerServer(options = {}) { ws.agentInstanceId = agentInstanceId || null; ws.connectionId = randomUUID(); agents.set(gatewayId, ws); + wss.emit("connection", ws, req); + sendAgentWelcome(ws); + sendAgentConnectionProgress(ws, "presence", "started", "Reporting broker presence to the edge manager."); reportGatewayPresence(gatewayId, { status: "connected", connectionId: ws.connectionId, @@ -428,15 +482,30 @@ export function createBrokerServer(options = {}) { remote_address: req.socket.remoteAddress || null, agent_instance_id: ws.agentInstanceId, }, - }).catch(() => {}); + }) + .then(() => { + sendAgentConnectionProgress(ws, "presence", "succeeded", "Broker presence was reported."); + }) + .catch((error) => { + sendAgentConnectionError(ws, "presence", error); + }); broadcastGatewayEvent(gatewayId, { type: "presence.changed", gatewayId, status: "connected", connectionId: ws.connectionId, }); - syncGatewayBacklog(gatewayId, ws).catch(() => {}); - wss.emit("connection", ws, req); + sendAgentConnectionProgress(ws, "backlog", "started", "Synchronizing queued gateway work."); + syncGatewayBacklog(gatewayId, ws) + .then((result) => { + sendAgentConnectionProgress(ws, "backlog", "succeeded", "Queued gateway work was synchronized.", { + queued: Boolean(result?.queued), + dispatchCount: Array.isArray(result?.dispatch) ? result.dispatch.length : 0, + }); + }) + .catch((error) => { + sendAgentConnectionError(ws, "backlog", error); + }); }); return; } @@ -549,7 +618,11 @@ export function createBrokerServer(options = {}) { } if (message.type === "TELEMETRY") { - const payload = message.payload || {}; + const payload = { + ...(message.payload || {}), + broker_connection_id: ws.connectionId || null, + broker_agent_instance_id: ws.agentInstanceId || null, + }; let ingested = null; let ingestError = null; try { diff --git a/services/edge-broker/test/broker.test.mjs b/services/edge-broker/test/broker.test.mjs index 78bb7e05..909baece 100644 --- a/services/edge-broker/test/broker.test.mjs +++ b/services/edge-broker/test/broker.test.mjs @@ -4,12 +4,6 @@ import WebSocket from "ws"; import { createBrokerServer } from "../server.mjs"; -function waitForMessage(socket) { - return new Promise((resolve) => { - socket.once("message", (raw) => resolve(JSON.parse(raw.toString()))); - }); -} - function collectMessages(socket) { const messages = []; socket.on("message", (raw) => { @@ -132,7 +126,10 @@ test("broker forwards browser shell input, resize, and close events to the agent const agentMessages = collectMessages(agent); const browser = new WebSocket(`ws://127.0.0.1:${port}/ws/browser-shell?token=session-token`); await new Promise((resolve) => browser.once("open", resolve)); - await waitForMessage(agent); + await waitFor( + () => agentMessages.some((message) => message.type === "OPEN_ROOT_SHELL" && message.payload.sessionId === "shell-2"), + { description: "agent shell open request" } + ); browser.send(JSON.stringify({ type: "input", data: "ls\r" })); browser.send(JSON.stringify({ type: "resize", cols: 140, rows: 44 })); @@ -214,7 +211,10 @@ test("broker closes browser shell sessions when the agent disconnects before she const browser = new WebSocket(`ws://127.0.0.1:${port}/ws/browser-shell?token=session-token`); const browserMessages = collectMessages(browser); await new Promise((resolve) => browser.once("open", resolve)); - await waitForMessage(agent); + await waitFor( + () => agentMessages.some((message) => message.type === "OPEN_ROOT_SHELL" && message.payload.sessionId === "shell-4"), + { description: "agent shell open request before disconnect" } + ); agent.terminate(); await waitForClose(browser); @@ -227,6 +227,119 @@ test("broker closes browser shell sessions when the agent disconnects before she await broker.close(); }); +test("broker sends an agent welcome before connection progress and backlog dispatch", async () => { + const broker = createBrokerServer({ + authMode: "stub", + reportGatewayPresence: async () => ({}), + requestGatewayBacklog: async () => ({ + dispatch: [ + { + type: "TASK_DISPATCH", + taskType: "OPERATION", + operation: { + id: 91, + type: "DISCOVERY", + request: {}, + }, + }, + ], + }), + }); + const address = await broker.listen(0); + const port = address.port; + + const agent = new WebSocket(`ws://127.0.0.1:${port}/ws/agent?gatewayId=701&token=agent-token`); + const messages = collectMessages(agent); + await new Promise((resolve) => agent.once("open", resolve)); + + await waitFor( + () => messages.some((message) => message.type === "TASK_DISPATCH" && message.operation?.id === 91), + { description: "backlog dispatch after connection welcome" } + ); + + assert.equal(messages[0].type, "WELCOME"); + assert.equal(messages[0].gatewayId, "701"); + assert.equal(typeof messages[0].connectionId, "string"); + assert.ok(messages[0].connectionId.length > 0); + + const firstProgressIndex = messages.findIndex((message) => message.type === "CONNECTION_PROGRESS"); + const dispatchIndex = messages.findIndex((message) => message.type === "TASK_DISPATCH"); + assert.ok(firstProgressIndex > 0); + assert.ok(dispatchIndex > firstProgressIndex); + assert.ok( + messages.some( + (message) => + message.type === "CONNECTION_PROGRESS" && + message.stage === "presence" && + message.status === "started" + ) + ); + assert.ok( + messages.some( + (message) => + message.type === "CONNECTION_PROGRESS" && + message.stage === "backlog" && + message.status === "started" + ) + ); + assert.ok( + messages.some( + (message) => + message.type === "CONNECTION_PROGRESS" && + message.stage === "backlog" && + message.status === "succeeded" && + message.dispatchCount === 1 + ) + ); + + agent.terminate(); + await broker.close(); +}); + +test("broker sends connection errors to agents after the welcome message", async () => { + const broker = createBrokerServer({ + authMode: "stub", + reportGatewayPresence: async () => { + throw new Error("presence callback unavailable"); + }, + requestGatewayBacklog: async () => { + throw new Error("backlog sync unavailable"); + }, + }); + const address = await broker.listen(0); + const port = address.port; + + const agent = new WebSocket(`ws://127.0.0.1:${port}/ws/agent?gatewayId=701&token=agent-token`); + const messages = collectMessages(agent); + await new Promise((resolve) => agent.once("open", resolve)); + + await waitFor( + () => messages.filter((message) => message.type === "CONNECTION_ERROR").length >= 2, + { description: "agent connection error notifications" } + ); + + assert.equal(messages[0].type, "WELCOME"); + assert.ok( + messages.some( + (message) => + message.type === "CONNECTION_ERROR" && + message.stage === "presence" && + message.error === "presence callback unavailable" + ) + ); + assert.ok( + messages.some( + (message) => + message.type === "CONNECTION_ERROR" && + message.stage === "backlog" && + message.error === "backlog sync unavailable" + ) + ); + + agent.terminate(); + await broker.close(); +}); + test("broker syncs queued gateway backlog on agent connect and manual sync", async () => { const backlogRequests = []; const broker = createBrokerServer({ @@ -285,6 +398,7 @@ test("broker syncs queued gateway backlog on agent connect and manual sync", asy }); test("broker fans out telemetry, task, log, and presence updates to browser gateway streams", async () => { + const telemetryPayloads = []; const broker = createBrokerServer({ authMode: "stub", validateAgent: async () => ({ id: "701", gateway_id: "701", label: "CPH Edge 01" }), @@ -293,7 +407,10 @@ test("broker fans out telemetry, task, log, and presence updates to browser gate gateway_id: "701", scopes: ["overview", "tasks", "logs", "statistics"], }), - ingestTelemetry: async (_gatewayId, payload) => ({ gateway: { id: 701, metadata: payload.metadata || {} } }), + ingestTelemetry: async (_gatewayId, payload) => { + telemetryPayloads.push(payload); + return { gateway: { id: 701, metadata: payload.metadata || {} } }; + }, ingestTaskEvent: async (_gatewayId, operationId, payload) => ({ id: operationId, status: "IN_PROGRESS", @@ -356,6 +473,7 @@ test("broker fans out telemetry, task, log, and presence updates to browser gate assert.ok(browserMessages.some((message) => message.type === "stats.updated")); assert.ok(browserMessages.some((message) => message.type === "task.updated" && message.operationId === 41)); assert.ok(browserMessages.some((message) => message.type === "log.append" && /heartbeat/.test(message.entry?.message))); + assert.equal(telemetryPayloads[0]?.broker_connection_id?.length > 0, true); browser.terminate(); agent.terminate(); diff --git a/services/nginx/app/.phpunit.cache/test-results b/services/nginx/app/.phpunit.cache/test-results index 9d7098c8..14270f76 100644 --- a/services/nginx/app/.phpunit.cache/test-results +++ b/services/nginx/app/.phpunit.cache/test-results @@ -1 +1 @@ -{"version":"pest_3.8.6","defects":{"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":1,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":7,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":7,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":8,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":1,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":1,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":1,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":1,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":7,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":8,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":1,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":1,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":8,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":1,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":1,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":8,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":7,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":7,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":7,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":7,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":8,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":7,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":1,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":1,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":1,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":1,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":1,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":1,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":1,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":1,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":7,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":7,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":7,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":1,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":7,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":7,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":7,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":1},"times":{"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_a_64_char_auth_token_for_an_existing_user":0.11,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_throws_a_clear_exception_when_customer_user_is_missing":0.017,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_passkey_challenge_legacy_script_green_during_migration":0.028,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_register_CVR_legacy_script_green_during_migration":0.029,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_and_caps_to_9_options":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_department_ids_by_selected_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_gate_type_digit_to_entrance_or_exit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_stores__loads_and_clears_ivr_state_with_ttl":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_validates_state_caller_fingerprint_matching":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_and_gate_prompts":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_creates_permission_nodes_linked_to_subuser_permission_keys":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_rejects_empty_permission_definitions":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_button_arrays__json_and_csv_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_button_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_vehicle_type_values_and_null_semantics":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_vehicle_type_values":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_non_numeric_vehicle_type_strings":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_keeps_lane_service_enum_contract_for_MACHINE":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_booking_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_selfserve_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubusersRoutePermissionLinkTest::__pest_evaluable_it_keeps_subusers_route_list_permission_linked_to_SUBUSERS__LIST_node":0.005,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_keeps_route_and_service_entity_type_registries_in_sync_with_expanded_coverage":0,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":0.009,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_wires_local_e_conomic_customer_index_into_customer_related_search_entities":0.003,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_registers_cron_tasks_that_keep_the_e_conomic_search_index_refreshed":0.003,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_generic_db_object_mutation_flows":0.004,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_object_property_mutations":0.003,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_when_module_config_values_change":0.002,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_registers_cron_maintenance_task_for_system_search_cache":0.002,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_redacts_obvious_sensitive_fragments_before_sending_query_to_intent_parser":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_builds_payload_with_redacted_query_and_parses_strict_JSON_output":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_falls_back_safely_when_OpenAI_is_disabled":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_handles_malformed_OpenAI_response_payloads_without_throwing":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_uses_parser_cache_for_identical_query_and_allowed_type_combinations":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_caps_alias_and_hint_payloads_from_OpenAI_and_filters_hints_to_allowed_types":0.006,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":0.007,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":0.007,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":0.005,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_normalizes_type_lists_from_csv_json_and_arrays":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_parses_booleans_and_clamps_integers_using_route_defaults":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_exposes_expected_searchable_entity_types":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_system_wide_search_GET_and_POST_endpoints_with_intent_debug_support":0.003,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_superuser_cache_clear_and_rebuild_endpoints_for_system_search":0.003,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_passes_permission_and_own_scope_context_into_system_search_service":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_invoke_intent_parser_when_lexical_confidence_is_already_high":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_on_low_confidence_lexical_results_and_applies_hints_only_boosts":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_lets_parser_entity_hints_override_explicit_include_filters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_returns_fallback_parser_metadata_when_parser_fails_gracefully":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_scopes_query_cache_by_permission_context_to_avoid_cross_user_cache_leakage":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_caps_AI_driven_expanded_terms_to_prevent_query_amplification":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_expands_danish_discount_wording_into_lexical_discount_synonyms":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_for_intent_driven_natural_language_queries_even_when_lexical_score_is_high":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_association_hints_to_pull_related_customer_records_from_non_customer_matches":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_prefers_newer_records_when_relevance_scores_are_comparable":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_keeps_explicit_identifier_matches_ahead_of_newer_but_weaker_records":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_promotes_invoices_orders_order_bookings_and_customers_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_prioritizes_cancelled_bookings_over_active_bookings":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_heavily_demotes_configured_low_priority_entity_types_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_tokenizes_unicode_names_without_stripping_non_ascii_letters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_treat_explicit_identifier_queries_as_intent_driven":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_requires_broader_term_coverage_for_multi_word_scoring":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_enriches_object_attachment_results_with_associated_customer_context":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_includes_the_economic_customer_index_in_cache_dependencies_for_customer_scoped_results":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_falls_back_to_invoice_date_ranges_when_invoice_names_are_missing":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_derives_xlvask_customer_numbers_only_from_digits_only_extern_ids":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_replaces_unnamed_user_titles_with_the_customer_context_name":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_the_goal_criteria_label_for_department_goal_titles":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_reuses_parser_cache_entries_for_repeated_natural_language_intent_requests":0.106,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_clears_parser_cache_namespace_via_clearAll_to_force_a_fresh_parse":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_bumps_per_table_cache_versions_when_a_dirty_table_marker_is_registered":0.081,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_registers_economic_v2_backfill_command_in_cli_dispatcher":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_provides_a_backfill_cron_script_entrypoint":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_exact__match_when_totals_lines_and_departments_are_identical":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_total__mismatch_when_only_totals_differ":0.015,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_line_level_mismatches_for_quantity_and_price":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_departmental_distribution_mismatches":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_missing__target_when_draft_or_booked_target_is_unavailable":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_draft_invoice_lines_including_departmental_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_marks_text_only_zero_value_lines_as_non_billable_and_keeps_deterministic_key":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_booked_invoices_and_computes_net_total_delta_from_lines":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_contains_internal_normalization_path_with_departmental_metadata_support":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_supports_barred_filtering_when_listing_e_conomic_customers":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_implements_a_dedicated_v2_e_conomic_revenue_statistics_service_and_route":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_all_collected_invoice_economic_v2_routes_with_explicit_permissions":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_version_aware_distribution_and_pricing_history_v2_routes":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_caches_v2_distribution_responses_with_a_configurable_redis_ttl":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_fixed_pricing_versions_from_create_and_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_vehicle_subscription_versions_for_create_update_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_discount_override_versions_from_superuser_discounts_route":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_keeps_legacy_compare_endpoint_path_for_backward_compatibility":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_implements_effective_range_lifecycle_methods_for_all_versioned_entities":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_closes_previous_active_interval_before_inserting_a_new_version":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_includes_best_effort_backfill_with_provenance_and_confidence_metadata":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_anchors_historical_resolution_on_order_created__at_timestamps_in_distribution_service":0.004,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_order_ids_in_net_amount_calculation":0.007,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_customer_arrays_in_date_range_transaction_fetches":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_uses_centralized_duplicate_filtering_for_possible_duplicate_detection":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_per_scope_and_date_range":0.007,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_requires_superuser_permission_for_invoicing_period_distribution_all_endpoint":0.017,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_shared_date_range_normalization_across_invoicing_period_endpoints":0.032,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_normalizes_a_valid_invoicing_date_range_to_full_day_timestamps":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_invalid_date_formats":0.012,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_descending_date_ranges":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_finds_duplicate_orders_regardless_of_original_input_order":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_runs_best_effort_backfill_when_fixed_pricing_version_history_is_empty":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_self_serve_conditions_with_combined_AND_and_OR_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_prefers_condition_results_over_question_answers_when_evaluating_task_gates":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":0.01,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_machine_types__eligibility__summaries__and_machine_start_webhook_routes":0.014,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_machine_type_support_wired_into_lanes__tasks__and_conditions_routes":0.018,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_normalizes_webhook_methods_and_falls_back_to_POST_for_unsupported_verbs":0,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_n8n_query_keys":0,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_workflow_lifecycle_endpoints_for_the_n8n_module":0.002,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_execution_and_webhook_trigger_endpoints_for_the_n8n_module":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_encodes_raw_filter_query_values_that_include_timestamps":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_avoids_double_encoding_query_values_that_are_already_escaped":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":0,"P\\Tests\\Unit\\Bookings\\OrderBookingRouteIdempotencyGuardTest::__pest_evaluable_it_guards_order_booking_creation_with_redis_backed_idempotency":0.24,"P\\Tests\\Unit\\DynamicImages\\DynamicImagePreRenderCronWiringTest::__pest_evaluable_it_registers_dynamic_image_pre_render_cron_task_and_related_helpers":0.005,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":0.226,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":0.017,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":0.014,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":0.011,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":0.016,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":0.013,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_both_own_and_elevated_permissions_when_both_are_missing":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_only_elevated_permission_when_own_permission_exists_but_own_context_fails":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_allows_elevated_permission_path_without_forbidden_and_validates_department_access":0,"P\\Tests\\Unit\\Permissions\\ForbiddenResponseWiringTest::__pest_evaluable_it_routes_and_trait_use_forbidden_responses_for_permission_and_ownership_denials":0.018,"P\\Tests\\Unit\\Permissions\\GroupPermissionSessionInvalidationWiringTest::__pest_evaluable_it_invalidates_related_user_permission_and_auth_session_caches_when_group_permissions_change":0.004,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_snake__case_fields":0.066,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_camelCase_aliases":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_normalizes_ENTIRE__DURATION_to_ignore_target__duration__every":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_defaults_recurring_target__duration__every_to_1_when_omitted":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_keeps_strict_legacy_mode_when_target__duration_is_invalid":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_computes_weekly_target_using_touched_ISO_weeks_for_March_2026":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_applies_target__duration__every_for_weekly_cadence":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_prorates_ENTIRE__DURATION_target_by_overlap_days":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_splits_advanced_target_by_override_weights_per_department":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_preserves_legacy_target_behavior_when_target__duration_is_missing":0,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_monthly_renderer_script_green":0.147,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_department_daily_renderer_script_green":0.147,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":0.007,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_uses_company_scoped_workfeed_endpoints_and_raw_Authorization_header":0.003,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_normalizes_documented_shift_query_parameters":0.001,"P\\Tests\\Unit\\Workfeed\\WorkfeedConfigRouteWiringTest::__pest_evaluable_it_registers_module_config_endpoints_for_workfeed":0.004,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_workfeed_query_keys":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_employee_and_department_endpoints_for_the_workfeed_module":0.004,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_shift_endpoints_for_the_workfeed_module":0.002,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_for_the_hour_slot_based_on_overlap":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_department_id_from_supported_workfeed_shift_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_wrapped_workfeed_collections_from_common_response_keys":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_includes_a_date_key_in_department_weather_timeline_entries":0.003,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_from_start_of_yesterday_to_end_of_today":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_an_explicit_selected_date_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_across_multiple_departments_for_one_hour_slot":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_department_id_input_from_scalar_csv_and_nested_array_values":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_explicit_date__from_and_date__to_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_resolves_forecast_day_count_for_a_given_timeline_range_with_sane_limits":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_resolves_weather_coordinates_from_valid_coordinates_only":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_null_weather_coordinates_when_all_department_locations_are_invalid":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_classifies_weatherapi_no_matching_location_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_does_not_classify_non_location_weatherapi_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_an_empty_forecast_fallback_when_coordinates_are_unavailable":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_for_department_sets_and_timeline_ranges":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_order_insensitive_cache_keys_for_equivalent_department_id_sets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_marks_non_started_slots_as_unknown_regardless_of_wash_hour_ratio":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_preloading_for_department_weather_cache":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_stale_ttl_defaults_and_clamps_stale_ttl_below_fresh_ttl":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_hot_activity_ttl_defaults_and_clamps_to_a_positive_value":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_fresh_cached_payloads_without_invoking_the_resolver":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_stale_cached_payloads_and_enqueues_a_refresh_signal":0.01,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_recomputes_and_rewrites_cache_payloads_when_stale_window_is_exceeded":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_records_hot_keys_order_insensitively_and_applies_preload_target_caps":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_batched_wash_count_rows_into_hourly_slot_totals":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_wires_department_weather_route_to_use_batched_wash_aggregation":0.007,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":0,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_ensures_economic_module_rows_in_one_sanitized_batch":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_returns_id_keyed_economic_module_payload_with_null_defaults":0,"P\\Tests\\Unit\\Orders\\OrdersRouteListBatchingWiringTest::__pest_evaluable_it_wires_GET__orders_through_batched_enrichment_and_stripe_snapshot_caching":0.006,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_cashier_names_from_cache_and_fetches_missing_ones_in_batch":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_deterministic_map_for_duplicate_and_unsorted_cashier_ids":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_implements_batched_cashier_name_lookup_with_cache_first_fallback_behavior":0.006,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_sanitizes_and_deduplicates_cashier_ids_before_batch_lookup":0.003,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_shift_carries_an_extended_approval_end_timestamp":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_treat_late_unapproved_administrative_edits_as_overtime":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_changes_weather_timeline_cache_key_when_department_weather_targets_change":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_evaluates_healthy_degraded_and_unhealthy_statuses_from_configured_department_targets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_configured_targets_are_missing_for_department_status_evaluation":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":0.046,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_target_routes_with_explicit_read_and_manage_permissions":0.004,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_persists_department_weather_targets_using_canonical_department_variable_keys":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_relay_status_get_and_set_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_batches_sequential_machine_relay_status_requests_into_a_single_Shelly_get_call":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_retries_missing_Shelly_status_payloads_until_relay_status_becomes_ready":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_times_out_with_a_clear_Shelly_readiness_error_when_payload_remains_missing":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_direct_set_switch_and_seeds_cache_so_immediate_status_read_does_not_call_Shelly_get":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_lane_gate_open_endpoint":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_in_progress_self_serve_wash_details_endpoint":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":0.132,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":0.001,"P\\Tests\\Unit\\Selfserve\\DepartmentSelfServeEnabledRelaySyncWiringTest::__pest_evaluable_it_syncs_lane_relay_states_when_department_self_serve_enabled_flag_changes":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_supports_hard_relay_set_even_when_lane_status_is_CLOSED":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_enables_cleaner_relay_on_wash_start_command_and_webhook_flow":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_relay_off_when_a_self_serve_wash_session_is_completed":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_typed_task_gates_with_strict_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_typed_task_gates_for_known_references":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_typed_task_gates_reference_unknown_entities":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_config_draft_publish_rollback_lifecycle_endpoints":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_legacy_self_serve_CRUD_routes_syncing_canonical_drafts":0.013,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_keeps_cleaner_relay_enable_wired_into_machine_relay_start_paths":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":0.277,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_encodes_config_json_payloads_with_apostrophes_before_persistence":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_and_cleaner_relays_off_when_a_self_serve_wash_session_is_completed":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_vehicle_type_override_into_self_serve_preview_and_synchronization_routes":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_local_demo_responses_and_skips_Shelly_cloud_calls_for_demo_relay_ids":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_default_OFF_status_for_demo_relay_ids_without_Shelly_lookups":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_excludes_demo_relay_ids_from_Shelly_status_batch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_keeps_demo_relay_gate_open_queued_but_skips_Shelly_switch_calls":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_allowed_services_route_through_machine_relay_visibility_sync":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enables_MACHINE_relay_when_MACHINE_is_visible_in_allowed_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_turns_MACHINE_relay_off_immediately_when_MACHINE_is_not_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_does_not_enable_MACHINE_relay_when_allowEnable_is_false_even_if_MACHINE_is_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_is_a_safe_no_op_when_MACHINE_relay_is_not_configured":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_synchronizes_machine_relay_from_visible_services_during_session_synchronization":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_adds_explicit_relay_disable_session_helper_for_visibility_driven_OFF_transitions":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_property_gate_command_permissions":0.008,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneCommandEnumTest::__pest_evaluable_it_parses_property_gate_lane_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_entrance_gate_for_OPEN__PROPERTY__ACCESS__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_exit_gate_for_OPEN__PROPERTY__EXIT__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_blocks_property_gate_commands_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_throws_a_clear_error_when_entrance_gate_is_missing_for_property_access_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_access_command_failures":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_reads_machine_allowed_state_from_session_summary_payload_safely":0.005,"P\\Tests\\Unit\\Selfserve\\DbObjectPaginationLegacyColumnCompatibilityTest::__pest_evaluable_it_guards_pagination_against_searchable_fields_missing_from_legacy_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_dynamic__images__vehicle__type_column_for_legacy_selfserve_wash_session_task_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_billable_minutes_when_elapsed_minutes_exceed_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_elapsed_minutes_equal_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_included_minutes_exceed_elapsed_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_handles_zero_and_low_elapsed_wash_time_edge_cases":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_wash_included_minutes_into_self_serve_module_config":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_blocks_explicit_relay_writes_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_disabled_no_op_from_machine_relay_visibility_sync_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":0.019,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":0.072,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":0.013,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_exit_command_failures":0.002,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_caller_id_is_not_confirmed":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_voice_call_facade_methods_to_documented_endpoints_and_methods":0.039,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_recordings_insights_log_and_flash_methods_to_documented_resources":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_encodes_path_segments_before_building_outbound_endpoints":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_serializes_query_parameters_for_GET_transport_requests":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_4xx_and_5xx_transport_failures_into_informative_exceptions":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":0.005,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":0.004,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_accepts_valid_payloads_for_create_and_nested_call_flow_commands":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_rejects_unknown_fields_and_invalid_enum_values_in_strict_schemas":0.014,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_supports_CSV_normalization_in_schema_validation_for_log_filters":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_validates_flash_hangup_payloads_for_both_supported_request_shapes":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_fails_before_forward_step_when_strict_validation_fails_and_forwards_when_valid":0,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_full_Bird_voice_call_route_surface_with_strict_validation_and_permissions":0.005,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_flash_hangup_endpoint_and_keeps_end_alias_wired_as_compatibility_path":0.004,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":0.006,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":0.005,"P\\Tests\\Unit\\Selfserve\\DepartmentGatesRelaysRouteWiringTest::__pest_evaluable_it_validates_department_gate_config_on_both_create_and_update_routes":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_wash__started__at_column_for_legacy_selfserve_wash_session_schemas":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_stores_wash__started__at_in_self_serve_wash_sessions_when_machine_start_is_triggered":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_passes_lane_wash_start_time_into_the_session_machine_start_marker":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_resolves_in_progress_wash__started__at_from_session_with_compatibility_fallbacks":0.003,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_say_payload_and_applies_hangup_default":0.019,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_log_query_csv_and_integer_fields":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_nested_create_call_payload_sections_and_drops_unknown_keys":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_keeps_gather_nested_say_payload_unchanged_when_hangup_is_omitted":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_supports_no_body_and_flash_hangup_payload_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_2_second_Shelly_gate_for_back_to_back_requests":0.023,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enforces_a_2_second_gap_between_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_keeps_back_to_back_get_switch_requests_ordered_through_the_relay_controller":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_executes_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_does_not_print_Shelly_switch_responses_to_output":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_enforces_a_global_2_second_Shelly_gate_in_sendPostRequest":0.004,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_uses_Redis_NX_PX_semantics_for_cross_request_Shelly_rate_limiting":0.003,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_enforces_the_2_second_Shelly_gate_across_separate_request_contexts":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_does_not_delay_when_the_Shelly_gate_is_already_expired":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":0.201,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_relay_is_offline_and_only_disables_configured_relays":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_bills_manual_self_serve_stop_using_full_elapsed_minutes_without_included_minute_reduction":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_keeps_included_minute_reduction_for_automatic_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_on_first_dtmf_input_captured_within_the_300_second_window":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_send_Slack_when_dtmf_input_repeats_without_change":0.008,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_again_when_dtmf_input_changes_within_the_window":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_gathering_and_does_not_hang_up_before_300_seconds_have_elapsed":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_announces_timeout_waits_10_seconds_and_sends_hangup_once_at_or_after_300_seconds":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_polling_until_terminal_status_and_only_then_finalizes":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_finalizes_immediately_when_webhook_payload_is_already_terminal_before_timeout_logic":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_duplicate_timeout_or_hangup_actions_across_retries_and_lock_contention":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_state_when_polling_fails_so_completion_is_not_falsely_reported":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_dtmf_input_repeats_without_change":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_answers_immediately_once_and_does_not_re_answer_on_subsequent_webhook_retries":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_with_retry_loop_semantics_until_input_is_entered":0.004,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_result_provides_keys_field_instead_of_dtmf":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_conditions_variable_keys_carries_the_entered_value":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_to_check_every_2_seconds_with_retry_loop_semantics_until_input_is_entered":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_ignores_non_numeric_customer__number_values_from_request":0.042,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_casts_numeric_customer__number_strings_to_int_before_lookup":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_prefers_user__id_when_both_user__id_and_customer__number_are_valid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_falls_back_to_customer__number_when_user__id_is_invalid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_normalizes_request_identifiers_before_user_lookups":0.004,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_rejects_non_positive_and_non_digit_request_values":0.003,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_pagination_results_when_present":0.006,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_collection_count_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_returns_zero_when_neither_pagination_nor_collection_is_available":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_counts_object_based_collections_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_uses_collection_when_present":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_falls_back_to_paymentTerms_when_collection_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_supports_top_level_array_payloads":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_returns_an_empty_array_when_no_known_collection_shape_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_economic__endpoint__t_when_explicitly_requested_and_configured":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_economic__endpoint__t_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_economic__endpoint__t":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_economic__endpoint__t":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_legacy_economic__m_when_available":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_legacy_economic__m_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_legacy_economic__m":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_legacy_economic__m":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_unfiltered_total_when_no_customer_filters_are_active":0.004,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_search_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_barred_filter_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_treats__null__search_and_barred_values_as_no_filter":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_filtered_total_when_unfiltered_total_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_maps_e_conomic_integration_failures_in_customer_listing_to_explicit_502_responses":0.014,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_logs_LIST__CUSTOMERS_success_only_after_pagination_and_customer_mapping_are_completed":0.009,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_guards_against_malformed_customer_list_payloads_before_calling_paginate":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_endpoint_trait_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_legacy_economic__m_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_returns_raw_payload_unchanged_on_successful_HTTP_statuses":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_accepts_valid_list_payloads_that_include_collection_and_pagination_results":0.02,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_pagination_is_missing_from_the_response_payload":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_upstream_responds_with_an_error_shaped_payload":0,"P\\Tests\\Unit\\Router\\RouterThrowableHandlingTest::__pest_evaluable_it_catches_throwables_during_auto_route_loading_and_maps_them_to_internal_server_errors":0.003,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_does_not_request_e_conomic_customer_data_when_customer_number_is_zero":0.101,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_short_circuits_e_conomic_customer_lookup_for_non_positive_customer_numbers":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_queued_economic_invoice_endpoints_in_economicInvoiceRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_defines_economic_transfer_queue_jobs_schema_bootstrap_table_and_tracking_columns":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_provides_queue_processor_class_constants_and_processing_entrypoint":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_registers_economic_transfer_queue_cron_task_and_handler":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_paths_in_openapi":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_schemas_in_openapi":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_quantity_for_e_conomic_export":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_price_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_keeps_positive_quantity_and_price_items_billable_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicInvoiceDraftZeroItemSkipWiringTest::__pest_evaluable_it_skips_zero_cost_and_zero_quantity_items_in_legacy_economic_draft_helper":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_malformed_order_item_payloads_for_e_conomic_export_safety":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueHardeningTest::__pest_evaluable_it_hardens_transfer_queue_with_type_validation_retry_caps_and_stale_lock_recovery":0.004,"P\\Tests\\Unit\\Router\\AutoloadRedisCacheValidationTest::__pest_evaluable_it_validates_cached_autoload_paths_before_returning_and_clears_stale_cache_entries":0.003,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_applies_created__at_bounds_directly_in_SQL_when_filtering_orders_by_registration_number":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_rejects_an_inverted_date_range_for_registration_lookups":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_returns_early_when_registration_number_is_blank":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_wires_queue_worker_class_loading_for_CLI_queue_action":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_economic_invoice_queue_endpoints_before_constructing_queue_service":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_collected_invoice_queue_endpoints_before_constructing_queue_service":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_gracefully_handles_unavailable_queue_dependencies_on_collected_invoice_queue_endpoints":0.005,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_the_queue_job_id_in_POST__collected_invoices_economic_enqueue_response":0.204,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_requires_id_and_at_least_one_mutable_field_for_PUT__collected_invoices_in_user_route":0.004,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":0.175,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_queued_contract_for_POST__collected_invoices_stripe_book":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_order_draft_export_route_queue_only":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_collected_invoice_draft_producing_routes_queue_only_in_orderInvoicesRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_collected_invoice_and_stripe_draft_producing_endpoints_before_constructing_queue_service":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_unavailable_queue_dependency_responses_for_async_economic_transfer_endpoints":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_order_payloads_to_strict_positive_integer_ids":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_collected_invoice_payload_booleans_to_strict_bool_values":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_rejects_invalid_transfer_payloads_before_enqueue_write_attempts":0.036,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":0.284,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":0.012,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":0.011,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_guards_on_economic_invoice_queue_status_and_retry_routes":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_queue_status_lifecycle_endpoints":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_order_draft_export_route":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_collected_invoice_draft_producing_routes":0.004,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_economic":0.236,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_stripe_book":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_200_fallback_plus_202_queue_contracts_for_export_endpoints_and_keeps_503_on_queue_lifecycle_endpoints":0.009,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":0.014,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":0.195,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":0.003,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":0.003,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":0.009,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_marks_queued_transactions_and_clears_requires__action_when_all_actionable_work_is_already_queued":0.826,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_keeps_requires__action_true_when_a_customer_still_has_unqueued_actionable_transactions":0.045,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_or_subscription_customers_with_no_transactions_when_a_relevant_queue_job_exists":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_queues_admin_commands__exposes_agent_poll_result_handlers__and_keeps_heartbeats_from_mutating_discovery_state":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_defines_the_dispatchable_gateway_guard_on_the_loaded_manager_class":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"recent heartbeat stays online\"\"":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"late heartbeat degrades after one minute\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"stale heartbeat goes offline after five minutes\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"explicit offline reports stay offline even when heartbeat is fresh\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"missing heartbeat is treated as offline\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_marks_ready_discovery_as_stale_when_the_gateway_heartbeat_has_expired":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_edge_gateway_management_REST_endpoints":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_public_installer__claim__heartbeat__command_polling__and_internal_broker_auth_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_uses_the_same_default_broker_url_and_shared_secret_fallback_as_the_docker_stack":0.267,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_forwarded_https_scheme_when_proxied":0.336,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_infers_https_for_the_staging_api_host_when_only_the_https_port_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":0.2,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https_and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_localhost_broker_overrides_on_plain_http_and_ws_for_local_development":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_includes_node_pty_build_prerequisites_in_the_generated_install_script":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured_and_derives_the_broker_from_the_api_origin":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https__strips_paths__and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_merges_incoming_heartbeat_metadata_with_existing_gateway_metadata":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_PHP_edge_agent_routes_for_operations_and_legacy_relay_command_polling":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":0.005,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":0.011,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_keeps_relay_dispatch_and_discovery_queueing_on_the_edge_gateway_manager":0.08,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_loads_relay_command_helpers_on_the_manager_and_gateway_operations_on_the_dedicated_service":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":0.445,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_includes_the_container_mounted_artifact_directory_as_a_candidate":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_reads_install_artifacts_through_the_shared_locator":0.016,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_builds_update_payloads_with_checksums_from_resolved_artifact_paths":0.232,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_a_supported_runtime_layout":0.225,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_PHP_agent_artifacts_and_forwarded_https_scheme":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_explains_the_legacy_dist_mount_mismatch_when_php_artifacts_are_unavailable":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":0.022,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_falls_back_to_baked_in_artifacts_when_the_mount_path_is_absent":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":0.026,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":1.109,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":2.935,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":1.375,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":0.982,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":3.423,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":1.13,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":1.615,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":5.592,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":1.29,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":1.517,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":4.136,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":0.512,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":0.965,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":1.045,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":1.64,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":3.683,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":3.194,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayOperationLegacySchemaCompatibilityTest::__pest_evaluable_it_keeps_the_legacy_operation__type_column_compatible_with_v2_operation_queueing":0.017,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_contexts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_stores_and_retrieves_full_order_bookings_payloads":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_ignores_malformed_cached_payloads_and_clears_order_bookings_list_caches":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsRouteCacheWiringTest::__pest_evaluable_it_caches_the_paginated_order_bookings_list_response_and_invalidates_it_on_booking_changes":0.008,"P\\Tests\\Unit\\Bookings\\VehicleSearchBookedMetadataRouteContractTest::__pest_evaluable_it_keeps_booked_vehicle_search_metadata_aligned_with_filtered_pending_order_bookings":0.005,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0.012,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_count_contexts":0.012,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_stores_and_retrieves_normalized_booking_counts":0.014,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_ignores_malformed_payloads_and_clears_order_bookings_count_caches":0.078,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsRouteWiringTest::__pest_evaluable_it_adds_a_cached_order_bookings_counts_endpoint_and_invalidates_it_on_booking_changes":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_summarizes_fleet_usage_statistics_for_the_dashboard_landing_view":0,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":0.271,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":0.097,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8.099,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":4.515,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":1.271,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":0.888,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":1.349,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":0.698,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":1.365,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":1.932,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":0.393,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":0.788,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":0.732,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":0.692,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":1.515,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":1.719,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":0.587,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":0.419,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":1.048,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":0.378,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":0.59,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":1.554,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":0.788,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":1.552,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":1.006,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":1.191,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":0.947,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":3.28,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":0.86,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":1.127,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":0.888,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":0.877,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":1.281,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":5.434,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":4.756,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":3.943,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":3.746,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":4.131,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":0.726,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":1.326,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":1.159,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_parses_cached_economic_customer_payloads_that_use_snake__case_customer__number":0.246,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_leaves_the_economic_customer_model_empty_when_no_valid_customer_number_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_derives_fleet_usage_directly_from_cached_gateway_row_summaries":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":0.547,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_adds_a_gateway_metadata_update_endpoint_with_label_and_primary_assignment_fields":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_reassigns_department_primary_gateways_through_dedicated_manager_helpers":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayShellPollingTransportTest::__pest_evaluable_it_removes_shell_access_from_the_edge_gateway_HTTP_contracts":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":0.052,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_deterministic_cache_keys":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_stores_and_retrieves_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_removes_deleted_gateways_from_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":0.014,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_module_scoped_edge_gateway_operator_routes":0.016,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_module_config_endpoints":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_config_endpoints_from_the_module_route_directory":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":0.014,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_caps_install_session_diagnostics_and_events_while_preserving_the_first_start_timestamp":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_clears_terminal_failure_details_after_a_successful_claim_update":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_marks_expired_non_terminal_install_sessions_as_terminal_when_read_back":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":0,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_validates_relay_gate_configs_and_keeps_relay_specific_fields_in_the_payload":0.016,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_rejects_relay_gate_configs_without_a_logical_relay_id":0.011,"P\\Tests\\Unit\\Bird\\DepartmentGatesRelayOpenTest::__pest_evaluable_it_dispatches_relay_backed_gates_through_the_edge_gateway_relay_manager":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayDepartmentWorkspaceContractTest::__pest_evaluable_it_defines_the_department_hardware_workspace_service_payload_surface":0.005,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_adds_lane_aware_scanner_management_and_a_dedicated_rotate_key_action":0.005,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_uses_the_scanner_default_lane_before_requiring_an_explicit_lane__id_in_machine_button_webhooks":0.003,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_status_responses_into_the_Shelly_cloud_payload_shape":0.015,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_switch_responses_into_the_Shelly_cloud_payload_shape":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_requires_a_valid_department_id_for_gateway_transport_requests":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_rejects_unsupported_gateway_transport_endpoints":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_binding_lookup_failures_while_resolving_relay_state_through_the_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_offline_gateway_failures_while_dispatching_relay_switch_commands":0,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":21.835,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":7.837,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_normalizes_owned_Shelly_devices_into_relay_select_options":0.179,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_fails_fast_when_Shelly_inventory_does_not_include_owned_devices_status":0.018,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayOptionsRouteWiringTest::__pest_evaluable_it_registers_a_department_lane_relay_options_endpoint_backed_by_Shelly_inventory":0.094,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayNullificationRouteWiringTest::__pest_evaluable_it_nullifies_department_lane_relay_fields_when_blank_select_values_are_submitted":0.005,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":109.487,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":229.768,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":12.815,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":198.915,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":192.229,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":7.59,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":52.202,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":143.121,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":17.564,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":51.102,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":226.202,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_imports_a_matching_e_conomic_customer_into_the_local_system_when_no_local_record_exists":0.282,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_reports_when_the_local_customer_already_has_a_login_account":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_a_new_e_conomic_customer_and_returns_a_created_result_for_new_rows":0.012,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_the_economic_record_for_an_existing_local_account_when_no_matching_upstream_customer_exists":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_rejects_CVR_conflicts_when_the_upstream_customer_number_does_not_match_the_submitted_phone_number":0.02,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_registers_the_customer_import_route_and_wires_it_through_the_mass_import_service":0.099,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_builds_customer_name_cache_payloads_from_economic_data_or_display_name_fallbacks":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_guards_bulk_customer_name_cache_writes_behind_a_resolved_payload_check":0.001,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":16.516}} \ No newline at end of file +{"version":"pest_3.8.6","defects":{"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":1,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":7,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":7,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":8,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":1,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":1,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":1,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":1,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":7,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":8,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":1,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":1,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":8,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":1,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":1,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":8,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":7,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":7,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":7,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":7,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":8,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":7,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":1,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":1,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":1,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":1,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":7,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":1,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":1,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":7,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":1,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":7,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":7,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":1,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":7,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":7,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":7,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":1,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":7,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":7,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":7,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":1},"times":{"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_a_64_char_auth_token_for_an_existing_user":0.11,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_throws_a_clear_exception_when_customer_user_is_missing":0.017,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_passkey_challenge_legacy_script_green_during_migration":0.028,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_register_CVR_legacy_script_green_during_migration":0.029,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_and_caps_to_9_options":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_department_ids_by_selected_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_gate_type_digit_to_entrance_or_exit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_stores__loads_and_clears_ivr_state_with_ttl":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_validates_state_caller_fingerprint_matching":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_and_gate_prompts":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_creates_permission_nodes_linked_to_subuser_permission_keys":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_rejects_empty_permission_definitions":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_button_arrays__json_and_csv_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_button_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_vehicle_type_values_and_null_semantics":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_vehicle_type_values":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_non_numeric_vehicle_type_strings":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_keeps_lane_service_enum_contract_for_MACHINE":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_booking_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_selfserve_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubusersRoutePermissionLinkTest::__pest_evaluable_it_keeps_subusers_route_list_permission_linked_to_SUBUSERS__LIST_node":0.005,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_keeps_route_and_service_entity_type_registries_in_sync_with_expanded_coverage":0,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":0.009,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_wires_local_e_conomic_customer_index_into_customer_related_search_entities":0.003,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_registers_cron_tasks_that_keep_the_e_conomic_search_index_refreshed":0.003,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_generic_db_object_mutation_flows":0.004,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_object_property_mutations":0.003,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_when_module_config_values_change":0.002,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_registers_cron_maintenance_task_for_system_search_cache":0.002,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_redacts_obvious_sensitive_fragments_before_sending_query_to_intent_parser":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_builds_payload_with_redacted_query_and_parses_strict_JSON_output":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_falls_back_safely_when_OpenAI_is_disabled":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_handles_malformed_OpenAI_response_payloads_without_throwing":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_uses_parser_cache_for_identical_query_and_allowed_type_combinations":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_caps_alias_and_hint_payloads_from_OpenAI_and_filters_hints_to_allowed_types":0.006,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":0.007,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":0.007,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":0.005,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_normalizes_type_lists_from_csv_json_and_arrays":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_parses_booleans_and_clamps_integers_using_route_defaults":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_exposes_expected_searchable_entity_types":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_system_wide_search_GET_and_POST_endpoints_with_intent_debug_support":0.003,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_superuser_cache_clear_and_rebuild_endpoints_for_system_search":0.003,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_passes_permission_and_own_scope_context_into_system_search_service":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_invoke_intent_parser_when_lexical_confidence_is_already_high":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_on_low_confidence_lexical_results_and_applies_hints_only_boosts":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_lets_parser_entity_hints_override_explicit_include_filters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_returns_fallback_parser_metadata_when_parser_fails_gracefully":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_scopes_query_cache_by_permission_context_to_avoid_cross_user_cache_leakage":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_caps_AI_driven_expanded_terms_to_prevent_query_amplification":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_expands_danish_discount_wording_into_lexical_discount_synonyms":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_for_intent_driven_natural_language_queries_even_when_lexical_score_is_high":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_association_hints_to_pull_related_customer_records_from_non_customer_matches":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_prefers_newer_records_when_relevance_scores_are_comparable":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_keeps_explicit_identifier_matches_ahead_of_newer_but_weaker_records":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_promotes_invoices_orders_order_bookings_and_customers_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_prioritizes_cancelled_bookings_over_active_bookings":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_heavily_demotes_configured_low_priority_entity_types_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_tokenizes_unicode_names_without_stripping_non_ascii_letters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_treat_explicit_identifier_queries_as_intent_driven":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_requires_broader_term_coverage_for_multi_word_scoring":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_enriches_object_attachment_results_with_associated_customer_context":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_includes_the_economic_customer_index_in_cache_dependencies_for_customer_scoped_results":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_falls_back_to_invoice_date_ranges_when_invoice_names_are_missing":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_derives_xlvask_customer_numbers_only_from_digits_only_extern_ids":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_replaces_unnamed_user_titles_with_the_customer_context_name":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_the_goal_criteria_label_for_department_goal_titles":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_reuses_parser_cache_entries_for_repeated_natural_language_intent_requests":0.106,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_clears_parser_cache_namespace_via_clearAll_to_force_a_fresh_parse":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_bumps_per_table_cache_versions_when_a_dirty_table_marker_is_registered":0.081,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_registers_economic_v2_backfill_command_in_cli_dispatcher":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_provides_a_backfill_cron_script_entrypoint":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_exact__match_when_totals_lines_and_departments_are_identical":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_total__mismatch_when_only_totals_differ":0.015,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_line_level_mismatches_for_quantity_and_price":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_departmental_distribution_mismatches":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_missing__target_when_draft_or_booked_target_is_unavailable":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_draft_invoice_lines_including_departmental_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_marks_text_only_zero_value_lines_as_non_billable_and_keeps_deterministic_key":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_booked_invoices_and_computes_net_total_delta_from_lines":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_contains_internal_normalization_path_with_departmental_metadata_support":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_supports_barred_filtering_when_listing_e_conomic_customers":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_implements_a_dedicated_v2_e_conomic_revenue_statistics_service_and_route":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_all_collected_invoice_economic_v2_routes_with_explicit_permissions":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_version_aware_distribution_and_pricing_history_v2_routes":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_caches_v2_distribution_responses_with_a_configurable_redis_ttl":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_fixed_pricing_versions_from_create_and_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_vehicle_subscription_versions_for_create_update_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_discount_override_versions_from_superuser_discounts_route":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_keeps_legacy_compare_endpoint_path_for_backward_compatibility":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_implements_effective_range_lifecycle_methods_for_all_versioned_entities":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_closes_previous_active_interval_before_inserting_a_new_version":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_includes_best_effort_backfill_with_provenance_and_confidence_metadata":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_anchors_historical_resolution_on_order_created__at_timestamps_in_distribution_service":0.004,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_order_ids_in_net_amount_calculation":0.007,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_customer_arrays_in_date_range_transaction_fetches":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_uses_centralized_duplicate_filtering_for_possible_duplicate_detection":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_per_scope_and_date_range":0.007,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_requires_superuser_permission_for_invoicing_period_distribution_all_endpoint":0.017,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_shared_date_range_normalization_across_invoicing_period_endpoints":0.032,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_normalizes_a_valid_invoicing_date_range_to_full_day_timestamps":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_invalid_date_formats":0.012,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_descending_date_ranges":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_finds_duplicate_orders_regardless_of_original_input_order":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_runs_best_effort_backfill_when_fixed_pricing_version_history_is_empty":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_self_serve_conditions_with_combined_AND_and_OR_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_prefers_condition_results_over_question_answers_when_evaluating_task_gates":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":0.01,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_machine_types__eligibility__summaries__and_machine_start_webhook_routes":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_machine_type_support_wired_into_lanes__tasks__and_conditions_routes":0.013,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_normalizes_webhook_methods_and_falls_back_to_POST_for_unsupported_verbs":0,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_n8n_query_keys":0,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_workflow_lifecycle_endpoints_for_the_n8n_module":0.002,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_execution_and_webhook_trigger_endpoints_for_the_n8n_module":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_encodes_raw_filter_query_values_that_include_timestamps":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_avoids_double_encoding_query_values_that_are_already_escaped":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":0,"P\\Tests\\Unit\\Bookings\\OrderBookingRouteIdempotencyGuardTest::__pest_evaluable_it_guards_order_booking_creation_with_redis_backed_idempotency":0.24,"P\\Tests\\Unit\\DynamicImages\\DynamicImagePreRenderCronWiringTest::__pest_evaluable_it_registers_dynamic_image_pre_render_cron_task_and_related_helpers":0.005,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":0.226,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":0.017,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":0.014,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":0.011,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":0.016,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":0.013,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_both_own_and_elevated_permissions_when_both_are_missing":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_only_elevated_permission_when_own_permission_exists_but_own_context_fails":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_allows_elevated_permission_path_without_forbidden_and_validates_department_access":0,"P\\Tests\\Unit\\Permissions\\ForbiddenResponseWiringTest::__pest_evaluable_it_routes_and_trait_use_forbidden_responses_for_permission_and_ownership_denials":0.018,"P\\Tests\\Unit\\Permissions\\GroupPermissionSessionInvalidationWiringTest::__pest_evaluable_it_invalidates_related_user_permission_and_auth_session_caches_when_group_permissions_change":0.004,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_snake__case_fields":0.066,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_camelCase_aliases":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_normalizes_ENTIRE__DURATION_to_ignore_target__duration__every":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_defaults_recurring_target__duration__every_to_1_when_omitted":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_keeps_strict_legacy_mode_when_target__duration_is_invalid":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_computes_weekly_target_using_touched_ISO_weeks_for_March_2026":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_applies_target__duration__every_for_weekly_cadence":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_prorates_ENTIRE__DURATION_target_by_overlap_days":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_splits_advanced_target_by_override_weights_per_department":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_preserves_legacy_target_behavior_when_target__duration_is_missing":0,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_monthly_renderer_script_green":0.147,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_department_daily_renderer_script_green":0.147,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":0.007,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_uses_company_scoped_workfeed_endpoints_and_raw_Authorization_header":0.003,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_normalizes_documented_shift_query_parameters":0.001,"P\\Tests\\Unit\\Workfeed\\WorkfeedConfigRouteWiringTest::__pest_evaluable_it_registers_module_config_endpoints_for_workfeed":0.004,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_workfeed_query_keys":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_employee_and_department_endpoints_for_the_workfeed_module":0.004,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_shift_endpoints_for_the_workfeed_module":0.002,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_for_the_hour_slot_based_on_overlap":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_department_id_from_supported_workfeed_shift_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_wrapped_workfeed_collections_from_common_response_keys":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_includes_a_date_key_in_department_weather_timeline_entries":0.003,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_from_start_of_yesterday_to_end_of_today":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_an_explicit_selected_date_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_across_multiple_departments_for_one_hour_slot":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_department_id_input_from_scalar_csv_and_nested_array_values":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_explicit_date__from_and_date__to_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_resolves_forecast_day_count_for_a_given_timeline_range_with_sane_limits":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_resolves_weather_coordinates_from_valid_coordinates_only":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_null_weather_coordinates_when_all_department_locations_are_invalid":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_classifies_weatherapi_no_matching_location_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_does_not_classify_non_location_weatherapi_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_an_empty_forecast_fallback_when_coordinates_are_unavailable":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_for_department_sets_and_timeline_ranges":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_order_insensitive_cache_keys_for_equivalent_department_id_sets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_marks_non_started_slots_as_unknown_regardless_of_wash_hour_ratio":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_preloading_for_department_weather_cache":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_stale_ttl_defaults_and_clamps_stale_ttl_below_fresh_ttl":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_hot_activity_ttl_defaults_and_clamps_to_a_positive_value":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_fresh_cached_payloads_without_invoking_the_resolver":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_stale_cached_payloads_and_enqueues_a_refresh_signal":0.01,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_recomputes_and_rewrites_cache_payloads_when_stale_window_is_exceeded":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_records_hot_keys_order_insensitively_and_applies_preload_target_caps":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_batched_wash_count_rows_into_hourly_slot_totals":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_wires_department_weather_route_to_use_batched_wash_aggregation":0.007,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":0,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_ensures_economic_module_rows_in_one_sanitized_batch":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_returns_id_keyed_economic_module_payload_with_null_defaults":0,"P\\Tests\\Unit\\Orders\\OrdersRouteListBatchingWiringTest::__pest_evaluable_it_wires_GET__orders_through_batched_enrichment_and_stripe_snapshot_caching":0.006,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_cashier_names_from_cache_and_fetches_missing_ones_in_batch":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_deterministic_map_for_duplicate_and_unsorted_cashier_ids":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_implements_batched_cashier_name_lookup_with_cache_first_fallback_behavior":0.006,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_sanitizes_and_deduplicates_cashier_ids_before_batch_lookup":0.003,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_shift_carries_an_extended_approval_end_timestamp":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_treat_late_unapproved_administrative_edits_as_overtime":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_changes_weather_timeline_cache_key_when_department_weather_targets_change":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_evaluates_healthy_degraded_and_unhealthy_statuses_from_configured_department_targets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_configured_targets_are_missing_for_department_status_evaluation":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":0.046,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_target_routes_with_explicit_read_and_manage_permissions":0.004,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_persists_department_weather_targets_using_canonical_department_variable_keys":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_relay_status_get_and_set_endpoints":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_batches_sequential_machine_relay_status_requests_into_a_single_Shelly_get_call":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_retries_missing_Shelly_status_payloads_until_relay_status_becomes_ready":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_times_out_with_a_clear_Shelly_readiness_error_when_payload_remains_missing":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_direct_set_switch_and_seeds_cache_so_immediate_status_read_does_not_call_Shelly_get":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_lane_gate_open_endpoint":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_in_progress_self_serve_wash_details_endpoint":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":0.132,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":0.001,"P\\Tests\\Unit\\Selfserve\\DepartmentSelfServeEnabledRelaySyncWiringTest::__pest_evaluable_it_syncs_lane_relay_states_when_department_self_serve_enabled_flag_changes":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_supports_hard_relay_set_even_when_lane_status_is_CLOSED":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_enables_cleaner_relay_on_wash_start_command_and_webhook_flow":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_relay_off_when_a_self_serve_wash_session_is_completed":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_typed_task_gates_with_strict_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_typed_task_gates_for_known_references":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_typed_task_gates_reference_unknown_entities":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_config_draft_publish_rollback_lifecycle_endpoints":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_legacy_self_serve_CRUD_routes_syncing_canonical_drafts":0.014,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_keeps_cleaner_relay_enable_wired_into_machine_relay_start_paths":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":0.277,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_encodes_config_json_payloads_with_apostrophes_before_persistence":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_and_cleaner_relays_off_when_a_self_serve_wash_session_is_completed":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_vehicle_type_override_into_self_serve_preview_and_synchronization_routes":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_local_demo_responses_and_skips_Shelly_cloud_calls_for_demo_relay_ids":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_default_OFF_status_for_demo_relay_ids_without_Shelly_lookups":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_excludes_demo_relay_ids_from_Shelly_status_batch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_keeps_demo_relay_gate_open_queued_but_skips_Shelly_switch_calls":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_allowed_services_route_through_machine_relay_visibility_sync":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enables_MACHINE_relay_when_MACHINE_is_visible_in_allowed_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_turns_MACHINE_relay_off_immediately_when_MACHINE_is_not_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_does_not_enable_MACHINE_relay_when_allowEnable_is_false_even_if_MACHINE_is_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_is_a_safe_no_op_when_MACHINE_relay_is_not_configured":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_synchronizes_machine_relay_from_visible_services_during_session_synchronization":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_adds_explicit_relay_disable_session_helper_for_visibility_driven_OFF_transitions":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_property_gate_command_permissions":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneCommandEnumTest::__pest_evaluable_it_parses_property_gate_lane_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_entrance_gate_for_OPEN__PROPERTY__ACCESS__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_exit_gate_for_OPEN__PROPERTY__EXIT__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_blocks_property_gate_commands_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_throws_a_clear_error_when_entrance_gate_is_missing_for_property_access_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_access_command_failures":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_reads_machine_allowed_state_from_session_summary_payload_safely":0.005,"P\\Tests\\Unit\\Selfserve\\DbObjectPaginationLegacyColumnCompatibilityTest::__pest_evaluable_it_guards_pagination_against_searchable_fields_missing_from_legacy_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_dynamic__images__vehicle__type_column_for_legacy_selfserve_wash_session_task_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_billable_minutes_when_elapsed_minutes_exceed_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_elapsed_minutes_equal_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_included_minutes_exceed_elapsed_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_handles_zero_and_low_elapsed_wash_time_edge_cases":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_wash_included_minutes_into_self_serve_module_config":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_blocks_explicit_relay_writes_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_disabled_no_op_from_machine_relay_visibility_sync_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":0.019,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":0.072,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":0.013,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_exit_command_failures":0.002,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_caller_id_is_not_confirmed":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_voice_call_facade_methods_to_documented_endpoints_and_methods":0.039,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_recordings_insights_log_and_flash_methods_to_documented_resources":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_encodes_path_segments_before_building_outbound_endpoints":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_serializes_query_parameters_for_GET_transport_requests":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_4xx_and_5xx_transport_failures_into_informative_exceptions":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":0.005,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":0.004,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_accepts_valid_payloads_for_create_and_nested_call_flow_commands":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_rejects_unknown_fields_and_invalid_enum_values_in_strict_schemas":0.014,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_supports_CSV_normalization_in_schema_validation_for_log_filters":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_validates_flash_hangup_payloads_for_both_supported_request_shapes":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_fails_before_forward_step_when_strict_validation_fails_and_forwards_when_valid":0,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_full_Bird_voice_call_route_surface_with_strict_validation_and_permissions":0.005,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_flash_hangup_endpoint_and_keeps_end_alias_wired_as_compatibility_path":0.004,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":0.006,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":0.005,"P\\Tests\\Unit\\Selfserve\\DepartmentGatesRelaysRouteWiringTest::__pest_evaluable_it_validates_department_gate_config_on_both_create_and_update_routes":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_wash__started__at_column_for_legacy_selfserve_wash_session_schemas":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_stores_wash__started__at_in_self_serve_wash_sessions_when_machine_start_is_triggered":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_passes_lane_wash_start_time_into_the_session_machine_start_marker":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_resolves_in_progress_wash__started__at_from_session_with_compatibility_fallbacks":0.003,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_say_payload_and_applies_hangup_default":0.019,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_log_query_csv_and_integer_fields":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_nested_create_call_payload_sections_and_drops_unknown_keys":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_keeps_gather_nested_say_payload_unchanged_when_hangup_is_omitted":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_supports_no_body_and_flash_hangup_payload_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_2_second_Shelly_gate_for_back_to_back_requests":0.023,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enforces_a_2_second_gap_between_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_keeps_back_to_back_get_switch_requests_ordered_through_the_relay_controller":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_executes_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_does_not_print_Shelly_switch_responses_to_output":0.015,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_enforces_a_global_2_second_Shelly_gate_in_sendPostRequest":0.004,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_uses_Redis_NX_PX_semantics_for_cross_request_Shelly_rate_limiting":0.003,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_enforces_the_2_second_Shelly_gate_across_separate_request_contexts":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_does_not_delay_when_the_Shelly_gate_is_already_expired":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":0.201,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_relay_is_offline_and_only_disables_configured_relays":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_bills_manual_self_serve_stop_using_full_elapsed_minutes_without_included_minute_reduction":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_keeps_included_minute_reduction_for_automatic_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_on_first_dtmf_input_captured_within_the_300_second_window":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_send_Slack_when_dtmf_input_repeats_without_change":0.008,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_again_when_dtmf_input_changes_within_the_window":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_gathering_and_does_not_hang_up_before_300_seconds_have_elapsed":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_announces_timeout_waits_10_seconds_and_sends_hangup_once_at_or_after_300_seconds":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_polling_until_terminal_status_and_only_then_finalizes":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_finalizes_immediately_when_webhook_payload_is_already_terminal_before_timeout_logic":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_duplicate_timeout_or_hangup_actions_across_retries_and_lock_contention":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_state_when_polling_fails_so_completion_is_not_falsely_reported":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_dtmf_input_repeats_without_change":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_answers_immediately_once_and_does_not_re_answer_on_subsequent_webhook_retries":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_with_retry_loop_semantics_until_input_is_entered":0.004,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_result_provides_keys_field_instead_of_dtmf":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_conditions_variable_keys_carries_the_entered_value":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_to_check_every_2_seconds_with_retry_loop_semantics_until_input_is_entered":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_ignores_non_numeric_customer__number_values_from_request":0.042,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_casts_numeric_customer__number_strings_to_int_before_lookup":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_prefers_user__id_when_both_user__id_and_customer__number_are_valid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_falls_back_to_customer__number_when_user__id_is_invalid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_normalizes_request_identifiers_before_user_lookups":0.004,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_rejects_non_positive_and_non_digit_request_values":0.003,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_pagination_results_when_present":0.006,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_collection_count_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_returns_zero_when_neither_pagination_nor_collection_is_available":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_counts_object_based_collections_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_uses_collection_when_present":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_falls_back_to_paymentTerms_when_collection_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_supports_top_level_array_payloads":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_returns_an_empty_array_when_no_known_collection_shape_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_economic__endpoint__t_when_explicitly_requested_and_configured":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_economic__endpoint__t_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_economic__endpoint__t":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_economic__endpoint__t":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_legacy_economic__m_when_available":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_legacy_economic__m_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_legacy_economic__m":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_legacy_economic__m":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_unfiltered_total_when_no_customer_filters_are_active":0.004,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_search_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_barred_filter_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_treats__null__search_and_barred_values_as_no_filter":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_filtered_total_when_unfiltered_total_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_maps_e_conomic_integration_failures_in_customer_listing_to_explicit_502_responses":0.014,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_logs_LIST__CUSTOMERS_success_only_after_pagination_and_customer_mapping_are_completed":0.009,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_guards_against_malformed_customer_list_payloads_before_calling_paginate":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_endpoint_trait_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_legacy_economic__m_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_returns_raw_payload_unchanged_on_successful_HTTP_statuses":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_accepts_valid_list_payloads_that_include_collection_and_pagination_results":0.02,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_pagination_is_missing_from_the_response_payload":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_upstream_responds_with_an_error_shaped_payload":0,"P\\Tests\\Unit\\Router\\RouterThrowableHandlingTest::__pest_evaluable_it_catches_throwables_during_auto_route_loading_and_maps_them_to_internal_server_errors":0.003,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_does_not_request_e_conomic_customer_data_when_customer_number_is_zero":0.101,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_short_circuits_e_conomic_customer_lookup_for_non_positive_customer_numbers":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_queued_economic_invoice_endpoints_in_economicInvoiceRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_defines_economic_transfer_queue_jobs_schema_bootstrap_table_and_tracking_columns":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_provides_queue_processor_class_constants_and_processing_entrypoint":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_registers_economic_transfer_queue_cron_task_and_handler":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_paths_in_openapi":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_schemas_in_openapi":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_quantity_for_e_conomic_export":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_price_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_keeps_positive_quantity_and_price_items_billable_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicInvoiceDraftZeroItemSkipWiringTest::__pest_evaluable_it_skips_zero_cost_and_zero_quantity_items_in_legacy_economic_draft_helper":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_malformed_order_item_payloads_for_e_conomic_export_safety":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueHardeningTest::__pest_evaluable_it_hardens_transfer_queue_with_type_validation_retry_caps_and_stale_lock_recovery":0.004,"P\\Tests\\Unit\\Router\\AutoloadRedisCacheValidationTest::__pest_evaluable_it_validates_cached_autoload_paths_before_returning_and_clears_stale_cache_entries":0.003,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_applies_created__at_bounds_directly_in_SQL_when_filtering_orders_by_registration_number":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_rejects_an_inverted_date_range_for_registration_lookups":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_returns_early_when_registration_number_is_blank":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_wires_queue_worker_class_loading_for_CLI_queue_action":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_economic_invoice_queue_endpoints_before_constructing_queue_service":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_collected_invoice_queue_endpoints_before_constructing_queue_service":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_gracefully_handles_unavailable_queue_dependencies_on_collected_invoice_queue_endpoints":0.005,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_the_queue_job_id_in_POST__collected_invoices_economic_enqueue_response":0.204,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_requires_id_and_at_least_one_mutable_field_for_PUT__collected_invoices_in_user_route":0.004,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":0.175,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_queued_contract_for_POST__collected_invoices_stripe_book":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_order_draft_export_route_queue_only":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_collected_invoice_draft_producing_routes_queue_only_in_orderInvoicesRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_collected_invoice_and_stripe_draft_producing_endpoints_before_constructing_queue_service":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_unavailable_queue_dependency_responses_for_async_economic_transfer_endpoints":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_order_payloads_to_strict_positive_integer_ids":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_collected_invoice_payload_booleans_to_strict_bool_values":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_rejects_invalid_transfer_payloads_before_enqueue_write_attempts":0.036,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":0.284,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":0.012,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":0.011,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_guards_on_economic_invoice_queue_status_and_retry_routes":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_queue_status_lifecycle_endpoints":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_order_draft_export_route":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_collected_invoice_draft_producing_routes":0.004,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_economic":0.236,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_stripe_book":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_200_fallback_plus_202_queue_contracts_for_export_endpoints_and_keeps_503_on_queue_lifecycle_endpoints":0.009,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":0.014,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":0.195,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":0.003,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":0.003,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":0.009,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_marks_queued_transactions_and_clears_requires__action_when_all_actionable_work_is_already_queued":0.826,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_keeps_requires__action_true_when_a_customer_still_has_unqueued_actionable_transactions":0.045,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_or_subscription_customers_with_no_transactions_when_a_relevant_queue_job_exists":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_queues_admin_commands__exposes_agent_poll_result_handlers__and_keeps_heartbeats_from_mutating_discovery_state":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_defines_the_dispatchable_gateway_guard_on_the_loaded_manager_class":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"recent heartbeat stays online\"\"":0.032,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"late heartbeat degrades after one minute\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"stale heartbeat goes offline after five minutes\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"explicit offline reports stay offline even when heartbeat is fresh\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"missing heartbeat is treated as offline\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_marks_ready_discovery_as_stale_when_the_gateway_heartbeat_has_expired":0.499,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_edge_gateway_management_REST_endpoints":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_public_installer__claim__heartbeat__command_polling__and_internal_broker_auth_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_uses_the_same_default_broker_url_and_shared_secret_fallback_as_the_docker_stack":0.267,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_forwarded_https_scheme_when_proxied":0.336,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_infers_https_for_the_staging_api_host_when_only_the_https_port_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":0.2,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https_and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_localhost_broker_overrides_on_plain_http_and_ws_for_local_development":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_includes_node_pty_build_prerequisites_in_the_generated_install_script":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured_and_derives_the_broker_from_the_api_origin":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https__strips_paths__and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_merges_incoming_heartbeat_metadata_with_existing_gateway_metadata":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_PHP_edge_agent_routes_for_operations_and_legacy_relay_command_polling":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":0.005,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":0.011,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_keeps_relay_dispatch_and_discovery_queueing_on_the_edge_gateway_manager":0.167,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_loads_relay_command_helpers_on_the_manager_and_gateway_operations_on_the_dedicated_service":0.01,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":0.359,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":0.445,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_includes_the_container_mounted_artifact_directory_as_a_candidate":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_reads_install_artifacts_through_the_shared_locator":0.016,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_builds_update_payloads_with_checksums_from_resolved_artifact_paths":0.232,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_a_supported_runtime_layout":0.225,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_PHP_agent_artifacts_and_forwarded_https_scheme":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_explains_the_legacy_dist_mount_mismatch_when_php_artifacts_are_unavailable":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":0.022,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_falls_back_to_baked_in_artifacts_when_the_mount_path_is_absent":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":0.026,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":1.109,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":2.935,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":1.375,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":0.982,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":3.423,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":1.13,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":1.615,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":5.592,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":1.29,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":1.517,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":4.136,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":0.512,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":0.965,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":1.045,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":1.64,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":3.683,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":3.194,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayOperationLegacySchemaCompatibilityTest::__pest_evaluable_it_keeps_the_legacy_operation__type_column_compatible_with_v2_operation_queueing":0.017,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_contexts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_stores_and_retrieves_full_order_bookings_payloads":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_ignores_malformed_cached_payloads_and_clears_order_bookings_list_caches":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsRouteCacheWiringTest::__pest_evaluable_it_caches_the_paginated_order_bookings_list_response_and_invalidates_it_on_booking_changes":0.008,"P\\Tests\\Unit\\Bookings\\VehicleSearchBookedMetadataRouteContractTest::__pest_evaluable_it_keeps_booked_vehicle_search_metadata_aligned_with_filtered_pending_order_bookings":0.005,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0.012,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_count_contexts":0.012,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_stores_and_retrieves_normalized_booking_counts":0.014,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_ignores_malformed_payloads_and_clears_order_bookings_count_caches":0.078,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsRouteWiringTest::__pest_evaluable_it_adds_a_cached_order_bookings_counts_endpoint_and_invalidates_it_on_booking_changes":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_summarizes_fleet_usage_statistics_for_the_dashboard_landing_view":0.01,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":0.271,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":0.097,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8.099,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":4.515,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":1.271,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":0.888,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":1.349,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":0.698,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":1.365,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":1.932,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":0.393,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":0.788,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":0.732,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":0.692,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":1.515,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":1.719,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":0.587,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":0.419,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":1.048,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":0.378,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":0.59,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":1.554,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":0.788,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":1.552,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":1.006,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":1.191,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":0.947,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":3.28,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":0.86,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":1.127,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":0.888,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":0.877,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":1.281,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":5.434,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":4.756,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":3.943,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":3.746,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":4.131,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":0.726,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":1.326,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":1.159,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_parses_cached_economic_customer_payloads_that_use_snake__case_customer__number":0.246,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_leaves_the_economic_customer_model_empty_when_no_valid_customer_number_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_derives_fleet_usage_directly_from_cached_gateway_row_summaries":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":0.547,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_adds_a_gateway_metadata_update_endpoint_with_label_and_primary_assignment_fields":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_reassigns_department_primary_gateways_through_dedicated_manager_helpers":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayShellPollingTransportTest::__pest_evaluable_it_removes_shell_access_from_the_edge_gateway_HTTP_contracts":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":0.196,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_deterministic_cache_keys":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_stores_and_retrieves_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_removes_deleted_gateways_from_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":0.014,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_module_scoped_edge_gateway_operator_routes":0.016,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_module_config_endpoints":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_config_endpoints_from_the_module_route_directory":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":0.014,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_caps_install_session_diagnostics_and_events_while_preserving_the_first_start_timestamp":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_clears_terminal_failure_details_after_a_successful_claim_update":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_marks_expired_non_terminal_install_sessions_as_terminal_when_read_back":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":0,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_validates_relay_gate_configs_and_keeps_relay_specific_fields_in_the_payload":0.016,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_rejects_relay_gate_configs_without_a_logical_relay_id":0.011,"P\\Tests\\Unit\\Bird\\DepartmentGatesRelayOpenTest::__pest_evaluable_it_dispatches_relay_backed_gates_through_the_edge_gateway_relay_manager":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayDepartmentWorkspaceContractTest::__pest_evaluable_it_defines_the_department_hardware_workspace_service_payload_surface":0.005,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_adds_lane_aware_scanner_management_and_a_dedicated_rotate_key_action":0.005,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_uses_the_scanner_default_lane_before_requiring_an_explicit_lane__id_in_machine_button_webhooks":0.003,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_status_responses_into_the_Shelly_cloud_payload_shape":0.026,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_switch_responses_into_the_Shelly_cloud_payload_shape":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_requires_a_valid_department_id_for_gateway_transport_requests":0.015,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_rejects_unsupported_gateway_transport_endpoints":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_binding_lookup_failures_while_resolving_relay_state_through_the_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_offline_gateway_failures_while_dispatching_relay_switch_commands":0,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":21.835,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":7.837,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_normalizes_owned_Shelly_devices_into_relay_select_options":0.144,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_fails_fast_when_Shelly_inventory_does_not_include_owned_devices_status":0.013,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayOptionsRouteWiringTest::__pest_evaluable_it_registers_a_department_lane_relay_options_endpoint_backed_by_Shelly_inventory":0.208,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayNullificationRouteWiringTest::__pest_evaluable_it_nullifies_department_lane_relay_fields_when_blank_select_values_are_submitted":0.005,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":109.487,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":229.768,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":12.815,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":198.915,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":192.229,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":7.59,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":52.202,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":143.121,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":17.564,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":51.102,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":226.202,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_imports_a_matching_e_conomic_customer_into_the_local_system_when_no_local_record_exists":0.282,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_reports_when_the_local_customer_already_has_a_login_account":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_a_new_e_conomic_customer_and_returns_a_created_result_for_new_rows":0.012,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_the_economic_record_for_an_existing_local_account_when_no_matching_upstream_customer_exists":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_rejects_CVR_conflicts_when_the_upstream_customer_number_does_not_match_the_submitted_phone_number":0.02,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_registers_the_customer_import_route_and_wires_it_through_the_mass_import_service":0.099,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_builds_customer_name_cache_payloads_from_economic_data_or_display_name_fallbacks":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_guards_bulk_customer_name_cache_writes_behind_a_resolved_payload_check":0.001,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":16.516,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_only_trusts_broker_presence_while_the_broker_heartbeat_is_fresh":0.667,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_refreshes_broker_presence_from_broker_telemetry_heartbeats":0.005,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_gateway_transport_when_a_department_is_in_gateway_mode":0.169,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_cloud_transport_when_a_department_is_in_cloud_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_lets_relay_tests_override_the_department_transport_without_changing_department_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_falls_back_to_local_device_and_control_names_when_Shelly_cloud_list_metadata_is_unavailable":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_uses_local_only_gateway_dispatch_for_explicit_local_transport_overrides":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_marks_non_injected_local_overrides_as_local_only_gateway_transport":0.02,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__in__id_on":0}} \ No newline at end of file diff --git a/services/nginx/app/classes/gateway_shelly_transport.php b/services/nginx/app/classes/gateway_shelly_transport.php index 2b864f51..5b8d2421 100644 --- a/services/nginx/app/classes/gateway_shelly_transport.php +++ b/services/nginx/app/classes/gateway_shelly_transport.php @@ -9,7 +9,10 @@ use interfaces\shelly_transport_i; class gateway_shelly_transport implements shelly_transport_i { - public function __construct(private readonly ?edge_gateway_manager $manager = null) + public function __construct( + private readonly ?edge_gateway_manager $manager = null, + private readonly bool $localOnly = false + ) { } @@ -52,7 +55,9 @@ class gateway_shelly_transport implements shelly_transport_i $result = []; foreach ($ids as $logicalRelayId) { - $status = $this->manager()->dispatchRelayStatus($departmentId, $logicalRelayId); + $status = $this->localOnly + ? $this->manager()->dispatchRelayStatusLocalOnly($departmentId, $logicalRelayId) + : $this->manager()->dispatchRelayStatus($departmentId, $logicalRelayId); $result[] = $this->normalizeRelayPayload($logicalRelayId, $status); } @@ -69,11 +74,17 @@ class gateway_shelly_transport implements shelly_transport_i throw new Exception('Shelly gateway switch requests require an id'); } - $status = $this->manager()->dispatchRelaySwitch( - $departmentId, - $logicalRelayId, - (bool)($data['on'] ?? false) - ); + $status = $this->localOnly + ? $this->manager()->dispatchRelaySwitchLocalOnly( + $departmentId, + $logicalRelayId, + (bool)($data['on'] ?? false) + ) + : $this->manager()->dispatchRelaySwitch( + $departmentId, + $logicalRelayId, + (bool)($data['on'] ?? false) + ); return [$this->normalizeRelayPayload($logicalRelayId, $status)]; } diff --git a/services/nginx/app/classes/shelly_relay_inventory.php b/services/nginx/app/classes/shelly_relay_inventory.php index 4e9add12..9a70d4b4 100644 --- a/services/nginx/app/classes/shelly_relay_inventory.php +++ b/services/nginx/app/classes/shelly_relay_inventory.php @@ -198,6 +198,7 @@ class shelly_relay_inventory $online = $this->normalizeBoolean($catalog_entry['cloud_online'] ?? null); } $status_color = $this->extractStatusColor($online); + $local_ip = $this->extractLocalIp($device, $catalog_entry); return [ 'id' => $device_id, @@ -215,6 +216,7 @@ class shelly_relay_inventory 'code' => $device_code !== '' ? $device_code : null, 'control_type' => $control_type, 'control_name' => $control_name !== '' ? $control_name : null, + 'local_ip' => $local_ip, 'status_color' => $status_color, 'online' => $online, ]; @@ -352,6 +354,44 @@ class shelly_relay_inventory ]); } + /** + * @param array $device + * @param array|null $catalog_entry + */ + private function extractLocalIp(array $device, ?array $catalog_entry = null): ?string + { + $candidates = [ + $device['local_ip'] ?? null, + $device['localIp'] ?? null, + $device['ip'] ?? null, + $device['_dev_info']['local_ip'] ?? null, + $device['_dev_info']['localIp'] ?? null, + $device['_dev_info']['ip'] ?? null, + $device['wifi_sta']['ip'] ?? null, + $device['wifi']['ip'] ?? null, + $device['eth']['ip'] ?? null, + $device['status']['wifi_sta']['ip'] ?? null, + $device['status']['wifi']['ip'] ?? null, + $device['status']['eth']['ip'] ?? null, + $device['status']['sta_ip'] ?? null, + $device['settings']['wifi_sta']['ip'] ?? null, + $device['settings']['wifi']['ip'] ?? null, + $device['settings']['eth']['ip'] ?? null, + $catalog_entry['local_ip'] ?? null, + $catalog_entry['localIp'] ?? null, + $catalog_entry['ip'] ?? null, + ]; + + foreach ($candidates as $candidate) { + $normalized = trim((string)($candidate ?? '')); + if ($normalized !== '' && filter_var($normalized, FILTER_VALIDATE_IP) !== false) { + return $normalized; + } + } + + return null; + } + private function buildRelayLabel( ?string $device_type, string $cloud_name, diff --git a/services/nginx/app/classes/shelly_transport_resolver.php b/services/nginx/app/classes/shelly_transport_resolver.php index e8f65d79..a876ab27 100644 --- a/services/nginx/app/classes/shelly_transport_resolver.php +++ b/services/nginx/app/classes/shelly_transport_resolver.php @@ -17,8 +17,22 @@ class shelly_transport_resolver ) { } - public function resolveForDepartment(int $departmentId): shelly_transport_i + public function resolveForDepartment(int $departmentId, ?string $transportOverride = null): shelly_transport_i { + $override = strtolower(trim((string)$transportOverride)); + $explicitLocalOverride = $override === 'local'; + if ($override === 'local') { + $override = edge_gateway_manager::TRANSPORT_MODE_GATEWAY; + } + + if ($override === edge_gateway_manager::TRANSPORT_MODE_GATEWAY) { + return $this->gatewayTransport ?? new gateway_shelly_transport($this->manager(), $explicitLocalOverride); + } + + if ($override === edge_gateway_manager::TRANSPORT_MODE_CLOUD) { + return $this->cloudTransport ?? new cloud_shelly_transport(); + } + $mode = $this->manager()->getDepartmentTransportMode($departmentId); if ($mode === edge_gateway_manager::TRANSPORT_MODE_GATEWAY) { return $this->gatewayTransport ?? new gateway_shelly_transport($this->manager()); diff --git a/services/nginx/app/modules/edgegateway/classes/edge_gateway_manager.php b/services/nginx/app/modules/edgegateway/classes/edge_gateway_manager.php index c2cd07ae..429ee3c4 100644 --- a/services/nginx/app/modules/edgegateway/classes/edge_gateway_manager.php +++ b/services/nginx/app/modules/edgegateway/classes/edge_gateway_manager.php @@ -74,6 +74,8 @@ class edge_gateway_manager public const SHELL_SESSION_TTL_SECONDS = 900; public const DEVICE_FRESHNESS_DEGRADED_AFTER_SECONDS = 180; public const CREDENTIAL_FRESH_AFTER_SECONDS = 2592000; + /** @var array>|null */ + private ?array $shellyRelayOptionsCache = null; public function __construct() { @@ -621,8 +623,15 @@ class edge_gateway_manager if ($existing !== []) { $bindingObject = (new edge_gateway_relay_bindings_o())->select((int)$existing[0]['id']); + $existingDeviceId = trim((string)$bindingObject->device_id->value()); + $localIp = $this->resolveRelayBindingLocalIp( + $gatewayId, + $binding, + $deviceId, + $existingDeviceId === $deviceId ? $bindingObject->local_ip->value() : null + ); $bindingObject->device_id->set($deviceId); - $bindingObject->local_ip->set($binding['local_ip'] ?? null); + $bindingObject->local_ip->set($localIp); $bindingObject->channel->set((int)($binding['channel'] ?? 0)); $bindingObject->binding_source->set((string)($binding['binding_source'] ?? 'MANUAL')); $bindingObject->approved_by->set($userId); @@ -631,12 +640,13 @@ class edge_gateway_manager continue; } + $localIp = $this->resolveRelayBindingLocalIp($gatewayId, $binding, $deviceId); (new edge_gateway_relay_bindings_o())->add_object([ 'gateway_id' => $gatewayId, 'department_id' => $departmentId, 'relay_id' => $relayId, 'device_id' => $deviceId, - 'local_ip' => $binding['local_ip'] ?? null, + 'local_ip' => $localIp, 'channel' => (int)($binding['channel'] ?? 0), 'binding_source' => (string)($binding['binding_source'] ?? 'MANUAL'), 'approved_by' => $userId, @@ -837,10 +847,33 @@ class edge_gateway_manager * @throws Exception */ public function dispatchRelayStatus(int $departmentId, string $logicalRelayId): array + { + return $this->dispatchRelayStatusWithOptions($departmentId, $logicalRelayId); + } + + /** + * @throws Exception + */ + public function dispatchRelayStatusLocalOnly(int $departmentId, string $logicalRelayId): array + { + return $this->dispatchRelayStatusWithOptions($departmentId, $logicalRelayId, true); + } + + /** + * @throws Exception + */ + private function dispatchRelayStatusWithOptions( + int $departmentId, + string $logicalRelayId, + bool $requireFastLocalPath = false + ): array { $binding = $this->resolveRelayBinding($departmentId, $logicalRelayId); $gateway = $this->requireGateway((int)$binding['gateway_id']); $resolution = $this->resolveRelayExecutionPlan($gateway, $binding, $logicalRelayId); + if ($requireFastLocalPath) { + $resolution = $this->forceLocalRelayExecutionPlan($resolution); + } if (($resolution['execution_path'] ?? 'local') === 'cloud') { return $this->dispatchRelayThroughCloud($departmentId, $logicalRelayId, null, $binding, $resolution); @@ -854,6 +887,7 @@ class edge_gateway_manager ], null, [ 'preferred_channel' => (string)($resolution['preferred_channel'] ?? self::DELIVERY_CHANNEL_API), 'fallback_reason' => $resolution['reason'] ?? null, + 'require_fast_path' => $requireFastLocalPath, ]); try { @@ -875,10 +909,34 @@ class edge_gateway_manager * @throws Exception */ public function dispatchRelaySwitch(int $departmentId, string $logicalRelayId, bool $on): array + { + return $this->dispatchRelaySwitchWithOptions($departmentId, $logicalRelayId, $on); + } + + /** + * @throws Exception + */ + public function dispatchRelaySwitchLocalOnly(int $departmentId, string $logicalRelayId, bool $on): array + { + return $this->dispatchRelaySwitchWithOptions($departmentId, $logicalRelayId, $on, true); + } + + /** + * @throws Exception + */ + private function dispatchRelaySwitchWithOptions( + int $departmentId, + string $logicalRelayId, + bool $on, + bool $requireFastLocalPath = false + ): array { $binding = $this->resolveRelayBinding($departmentId, $logicalRelayId); $gateway = $this->requireGateway((int)$binding['gateway_id']); $resolution = $this->resolveRelayExecutionPlan($gateway, $binding, $logicalRelayId); + if ($requireFastLocalPath) { + $resolution = $this->forceLocalRelayExecutionPlan($resolution); + } if (($resolution['execution_path'] ?? 'local') === 'cloud') { return $this->dispatchRelayThroughCloud($departmentId, $logicalRelayId, $on, $binding, $resolution); @@ -893,6 +951,7 @@ class edge_gateway_manager ], null, [ 'preferred_channel' => (string)($resolution['preferred_channel'] ?? self::DELIVERY_CHANNEL_API), 'fallback_reason' => $resolution['reason'] ?? null, + 'require_fast_path' => $requireFastLocalPath, ]); try { @@ -1870,16 +1929,43 @@ BASH; public function recordTelemetryFromBroker(int $gatewayId, array $payload): array { $gateway = $this->requireGateway($gatewayId); + $now = $this->now(); $metadata = array_merge( (array)($gateway->metadata_json->value() ?? []), isset($payload['metadata']) && is_array($payload['metadata']) ? (array)$payload['metadata'] : [] ); + $existingPresence = isset($metadata['broker_presence']) && is_array($metadata['broker_presence']) + ? (array)$metadata['broker_presence'] + : []; + $presenceMetadata = isset($existingPresence['metadata']) && is_array($existingPresence['metadata']) + ? (array)$existingPresence['metadata'] + : []; + $payloadMetadata = isset($payload['metadata']) && is_array($payload['metadata']) ? (array)$payload['metadata'] : []; + $connectionId = trim((string)($payload['broker_connection_id'] ?? $existingPresence['connection_id'] ?? '')); + $presence = [ + 'gateway_id' => $gatewayId, + 'connected' => true, + 'connection_id' => $connectionId !== '' ? $connectionId : null, + 'last_seen_at' => $now, + 'disconnect_reason' => null, + 'last_error' => null, + 'metadata' => array_merge($presenceMetadata, array_filter([ + 'agent_instance_id' => $payload['broker_agent_instance_id'] + ?? $payloadMetadata['agent_instance_id'] + ?? null, + ], static fn(mixed $value): bool => $value !== null && $value !== '')), + ]; + $metadata['broker_presence'] = $presence; + $metadata['broker_connected'] = true; + $metadata['broker_connected_at'] = $now; + $metadata['broker_last_error'] = null; + $this->writeBrokerPresence($gatewayId, $presence); $gateway->status->set((string)($payload['status'] ?? self::STATUS_ONLINE)); $gateway->hostname->set($payload['hostname'] ?? $gateway->hostname->value()); $gateway->installed_version->set($payload['installed_version'] ?? $gateway->installed_version->value()); $gateway->target_version->set($payload['target_version'] ?? $gateway->target_version->value()); - $gateway->last_heartbeat_at->set($this->now()); + $gateway->last_heartbeat_at->set($now); $gateway->metadata_json->set($metadata); if (isset($payload['inventory']) && is_array($payload['inventory'])) { @@ -2834,6 +2920,145 @@ BASH; } } + private function resolveRelayBindingLocalIp( + int $gatewayId, + array $binding, + string $deviceId, + mixed $existingLocalIp = null + ): ?string { + $incomingLocalIp = $this->normalizeLocalIp( + $binding['local_ip'] + ?? $binding['localIp'] + ?? $binding['ip'] + ?? $binding['metadata']['local_ip'] + ?? null + ); + if ($incomingLocalIp !== null) { + return $incomingLocalIp; + } + + $preservedLocalIp = $this->normalizeLocalIp($existingLocalIp); + if ($preservedLocalIp !== null) { + return $preservedLocalIp; + } + + $inventoryLocalIp = $this->findInventoryLocalIp($gatewayId, $deviceId); + if ($inventoryLocalIp !== null) { + return $inventoryLocalIp; + } + + return $this->findShellyCloudRelayLocalIp( + $deviceId, + trim((string)($binding['relay_id'] ?? '')) + ); + } + + private function findInventoryLocalIp(int $gatewayId, string $deviceId): ?string + { + $rows = (new edge_gateway_device_inventory_o())->getFieldsWhere([ + 'gateway_id' => $gatewayId, + 'device_id' => $deviceId, + 'deleted_at' => null, + ], ['id']); + + if ($rows === []) { + return null; + } + + $inventoryObject = (new edge_gateway_device_inventory_o())->select((int)$rows[0]['id']); + return $this->normalizeLocalIp($inventoryObject->local_ip->value()); + } + + private function findShellyCloudRelayLocalIp(string $deviceId, string $relayId): ?string + { + foreach ($this->listShellyRelayOptionsForLocalIpLookup() as $option) { + $optionDeviceId = trim((string)($option['device_id'] ?? '')); + $optionRelayId = trim((string)($option['id'] ?? '')); + if ($optionDeviceId !== $deviceId && $optionRelayId !== $relayId && $optionRelayId !== $deviceId) { + continue; + } + + $localIp = $this->normalizeLocalIp( + $option['local_ip'] + ?? $option['localIp'] + ?? $option['ip'] + ?? null + ); + if ($localIp !== null) { + return $localIp; + } + } + + return null; + } + + /** + * @return array> + */ + private function listShellyRelayOptionsForLocalIpLookup(): array + { + if (is_array($this->shellyRelayOptionsCache)) { + return $this->shellyRelayOptionsCache; + } + + try { + $this->shellyRelayOptionsCache = (new shelly_relay_inventory())->listRelayOptions(); + } catch (\Throwable) { + $this->shellyRelayOptionsCache = []; + } + + return $this->shellyRelayOptionsCache; + } + + private function normalizeLocalIp(mixed $value): ?string + { + $localIp = trim((string)($value ?? '')); + if ($localIp === '') { + return null; + } + + return filter_var($localIp, FILTER_VALIDATE_IP) !== false ? $localIp : null; + } + + /** + * @param array $device + */ + private function extractDeviceLocalIp(array $device): ?string + { + return $this->normalizeLocalIp( + $device['local_ip'] + ?? $device['localIp'] + ?? $device['ip'] + ?? $device['metadata']['local_ip'] + ?? $device['metadata']['localIp'] + ?? $device['metadata']['ip'] + ?? null + ); + } + + private function backfillRelayBindingLocalIpFromInventory(int $gatewayId, string $deviceId, ?string $localIp): void + { + $localIp = $this->normalizeLocalIp($localIp); + if ($localIp === null) { + return; + } + + $rows = (new edge_gateway_relay_bindings_o())->getFieldsWhere([ + 'gateway_id' => $gatewayId, + 'device_id' => $deviceId, + 'deleted_at' => null, + ], ['id']); + + foreach ($rows as $row) { + $bindingObject = (new edge_gateway_relay_bindings_o())->select((int)$row['id']); + if ($this->normalizeLocalIp($bindingObject->local_ip->value()) !== null) { + continue; + } + + $bindingObject->local_ip->set($localIp); + } + } + /** * @param array> $inventory */ @@ -2845,6 +3070,7 @@ BASH; continue; } + $localIp = $this->extractDeviceLocalIp($device); $rows = (new edge_gateway_device_inventory_o())->getFieldsWhere([ 'gateway_id' => $gatewayId, 'device_id' => $deviceId, @@ -2855,7 +3081,7 @@ BASH; (new edge_gateway_device_inventory_o())->add_object([ 'gateway_id' => $gatewayId, 'device_id' => $deviceId, - 'local_ip' => $device['local_ip'] ?? $device['ip'] ?? null, + 'local_ip' => $localIp, 'model' => $device['model'] ?? null, 'channel_count' => (int)($device['channel_count'] ?? $device['channels'] ?? 1), 'capabilities_json' => (array)($device['capabilities'] ?? []), @@ -2863,17 +3089,21 @@ BASH; 'last_seen_at' => $this->now(), 'metadata_json' => (array)($device['metadata'] ?? []), ]); + $this->backfillRelayBindingLocalIpFromInventory($gatewayId, $deviceId, $localIp); continue; } $inventoryObject = (new edge_gateway_device_inventory_o())->select((int)$rows[0]['id']); - $inventoryObject->local_ip->set($device['local_ip'] ?? $device['ip'] ?? null); + if ($localIp !== null) { + $inventoryObject->local_ip->set($localIp); + } $inventoryObject->model->set($device['model'] ?? null); $inventoryObject->channel_count->set((int)($device['channel_count'] ?? $device['channels'] ?? 1)); $inventoryObject->capabilities_json->set((array)($device['capabilities'] ?? [])); $inventoryObject->online->set((bool)($device['online'] ?? true)); $inventoryObject->last_seen_at->set($this->now()); $inventoryObject->metadata_json->set((array)($device['metadata'] ?? [])); + $this->backfillRelayBindingLocalIpFromInventory($gatewayId, $deviceId, $localIp); } } @@ -2931,7 +3161,7 @@ BASH; $gateway = $this->requireGateway($gatewayId); $normalizedStatus = trim(strtolower($status)); $connected = $normalizedStatus === 'connected'; - $presence = array_filter([ + $presence = [ 'gateway_id' => $gatewayId, 'connected' => $connected, 'connection_id' => $connectionId, @@ -2939,7 +3169,7 @@ BASH; 'disconnect_reason' => $connected ? null : $reason, 'last_error' => !$connected && $reason !== null && trim($reason) !== '' ? trim($reason) : null, 'metadata' => $metadata, - ], static fn(mixed $value): bool => $value !== null); + ]; $this->writeBrokerPresence($gatewayId, $presence); @@ -3142,7 +3372,7 @@ BASH; } $presence = $this->readBrokerPresence($gatewayId); - return !empty($presence['connected']) ? self::DELIVERY_CHANNEL_BROKER : self::DELIVERY_CHANNEL_API; + return self::isBrokerPresenceConnected($presence) ? self::DELIVERY_CHANNEL_BROKER : self::DELIVERY_CHANNEL_API; } public function validateBrokerSharedSecret(?string $secret): bool @@ -3301,33 +3531,66 @@ BASH; ]); } + private function forceLocalRelayExecutionPlan(array $resolution): array + { + $wasCloud = (string)($resolution['execution_path'] ?? 'local') === 'cloud'; + $recoveryActions = array_values(array_filter(array_unique(array_merge( + (array)($resolution['recovery_actions'] ?? []), + ['retry_local_command'] + )))); + + return array_merge($resolution, [ + 'execution_path' => 'local', + 'preferred_channel' => self::DELIVERY_CHANNEL_BROKER, + 'fallback_mode' => self::RELAY_FALLBACK_LOCAL_ONLY, + 'reason' => $wasCloud ? 'local_transport_override' : ($resolution['reason'] ?? null), + 'recommended_action' => $resolution['recommended_action'] ?? 'retry_local_command', + 'recovery_actions' => $recoveryActions, + ]); + } + /** * @throws Exception */ private function dispatchGatewayCommand(edge_gateways_o $gateway, edge_gateway_command_jobs_o $job): array { + $delivery = (array)($job->delivery_json->value() ?? []); + $preferredChannel = (string)($delivery['preferred_channel'] ?? self::DELIVERY_CHANNEL_API); + $requireFastPath = !empty($delivery['require_fast_path']); + $effectiveStatus = self::resolveGatewayStatus( $gateway->status->value() === null ? null : (string)$gateway->status->value(), $gateway->last_heartbeat_at->value() === null ? null : (string)$gateway->last_heartbeat_at->value() ); - if (!in_array($effectiveStatus, [self::STATUS_ONLINE, self::STATUS_DEGRADED], true)) { + if (!$requireFastPath && !in_array($effectiveStatus, [self::STATUS_ONLINE, self::STATUS_DEGRADED], true)) { throw new Exception('Gateway agent is offline'); } - $delivery = (array)($job->delivery_json->value() ?? []); - $preferredChannel = (string)($delivery['preferred_channel'] ?? self::DELIVERY_CHANNEL_API); - - if ($preferredChannel === self::DELIVERY_CHANNEL_BROKER && $this->buildBrokerInternalUrl() !== null) { - try { - $this->markCommandJobDispatching($job, self::DELIVERY_CHANNEL_BROKER); - $payload = $this->dispatchBrokerCommand($gateway, $job); - $this->finalizeCommandJob($job, true, $payload, null, $gateway); - return $payload; - } catch (Exception $exception) { - $this->markCommandDeliveryFailure($job, self::DELIVERY_CHANNEL_BROKER, $exception->getMessage(), 'broker_dispatch_failed'); + if ($preferredChannel === self::DELIVERY_CHANNEL_BROKER) { + if ($this->buildBrokerInternalUrl() === null) { + $this->markCommandDeliveryFailure($job, self::DELIVERY_CHANNEL_BROKER, 'Edge broker is not configured', 'broker_not_configured'); + if ($requireFastPath) { + throw new Exception('Edge broker is not configured'); + } + } else { + try { + $this->markCommandJobDispatching($job, self::DELIVERY_CHANNEL_BROKER); + $payload = $this->dispatchBrokerCommand($gateway, $job); + $this->finalizeCommandJob($job, true, $payload, null, $gateway); + return $payload; + } catch (Exception $exception) { + $this->markCommandDeliveryFailure($job, self::DELIVERY_CHANNEL_BROKER, $exception->getMessage(), 'broker_dispatch_failed'); + if ($requireFastPath) { + throw $exception; + } + } } } + if ($requireFastPath) { + throw new Exception('Edge broker fast path is unavailable'); + } + return $this->waitForCommandResult((int)$job->id); } @@ -3386,11 +3649,6 @@ BASH; throw new Exception('Edge broker is not configured'); } - $presence = $this->readBrokerPresence((int)$gateway->id); - if (empty($presence['connected'])) { - throw new Exception('Edge broker fast path is unavailable'); - } - $result = $this->httpJsonRequest( $brokerUrl . '/api/gateways/' . (int)$gateway->id . '/commands', [ @@ -4101,9 +4359,9 @@ BASH; $brokerPresence = isset($metadata['broker_presence']) && is_array($metadata['broker_presence']) ? (array)$metadata['broker_presence'] : []; - $brokerConnected = !empty($brokerPresence['connected']); $brokerLastSeenAt = isset($brokerPresence['last_seen_at']) ? (string)$brokerPresence['last_seen_at'] : null; $brokerAgeSeconds = self::heartbeatAgeSeconds($brokerLastSeenAt, $now); + $brokerConnected = self::isBrokerPresenceConnected($brokerPresence, $now); $brokerHealthy = $brokerConnected && $brokerAgeSeconds !== null && $brokerAgeSeconds < self::BROKER_CONNECTIVITY_DEGRADED_AFTER_SECONDS; @@ -4132,6 +4390,18 @@ BASH; ]; } + private static function isBrokerPresenceConnected(array $presence, ?int $now = null): bool + { + if (empty($presence['connected'])) { + return false; + } + + $lastSeenAt = isset($presence['last_seen_at']) ? (string)$presence['last_seen_at'] : null; + $ageSeconds = self::heartbeatAgeSeconds($lastSeenAt, $now); + + return $ageSeconds !== null && $ageSeconds < self::BROKER_PRESENCE_TTL_SECONDS; + } + private static function buildRelayHealth(array $gateway, string $effectiveStatus, ?int $now = null): array { $bindings = is_array($gateway['bindings'] ?? null) ? (array)$gateway['bindings'] : []; diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php index e947866c..f9d53adf 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_port_controller_t.php @@ -32,8 +32,8 @@ trait selfserve_lane_port_controller_t if ($this->getLaneStatus()->equals(selfserve_lane_status::FAULT)) throw new \Exception("Cannot open port on FAULT lane"); // Get the relay ID based on the port $relay_id = match ($port) { - selfserve_lane_port::ENTRANCE => $this->department_lane->relay_out_id->value(), - selfserve_lane_port::EXIT => $this->department_lane->relay_in_id->value(), + selfserve_lane_port::ENTRANCE => $this->department_lane->relay_in_id->value(), + selfserve_lane_port::EXIT => $this->department_lane->relay_out_id->value(), default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"), }; // Make sure relay ID is valid @@ -63,8 +63,8 @@ trait selfserve_lane_port_controller_t { // Queue the relay switch command to be executed asynchronously $relay_id = match ($port) { - selfserve_lane_port::ENTRANCE => $this->department_lane->relay_out_id->value(), - selfserve_lane_port::EXIT => $this->department_lane->relay_in_id->value(), + selfserve_lane_port::ENTRANCE => $this->department_lane->relay_in_id->value(), + selfserve_lane_port::EXIT => $this->department_lane->relay_out_id->value(), default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"), }; // If the relay ID indicates a demo port, skip the Shelly switch call but keep the logging and state changes diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_relay_controller_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_relay_controller_t.php index 855caef2..093073d2 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_relay_controller_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_relay_controller_t.php @@ -21,6 +21,27 @@ trait selfserve_lane_relay_controller_t private const SHELLY_DEFAULT_CHANNEL = 0; private const DEMO_RELAY_ID_PREFIX = 'demo-'; + protected ?string $shelly_transport_override = null; + + /** + * @throws \Exception + */ + public function setShellyTransportOverride(?string $transport): self + { + $normalized = strtolower(trim((string)$transport)); + if ($normalized === '') { + $this->shelly_transport_override = null; + return $this; + } + + if (!in_array($normalized, ['cloud', 'gateway', 'local'], true)) { + throw new \Exception('Invalid Shelly transport override. Expected local or cloud.'); + } + + $this->shelly_transport_override = $normalized; + return $this; + } + /** * Get current MACHINE relay status from Shelly. * @return array{relay_id: string, online: bool, on: bool} @@ -622,7 +643,10 @@ trait selfserve_lane_relay_controller_t private function getLaneShellyStatusSnapshotCacheKey(): string { - return self::SHELLY_STATUS_SNAPSHOT_KEY_PREFIX . (int)$this->id; + $transport = strtolower(trim((string)$this->shelly_transport_override)); + $safeTransport = $transport !== '' ? (preg_replace('/[^a-z0-9_-]+/', '_', $transport) ?: $transport) : ''; + $transportSuffix = $safeTransport !== '' ? '_' . $safeTransport : ''; + return self::SHELLY_STATUS_SNAPSHOT_KEY_PREFIX . (int)$this->id . $transportSuffix; } /** @@ -695,7 +719,10 @@ trait selfserve_lane_relay_controller_t protected function createShellyTransport(): shelly_transport_i { - return (new shelly_transport_resolver())->resolveForDepartment($this->resolveShellyTransportDepartmentId()); + return (new shelly_transport_resolver())->resolveForDepartment( + $this->resolveShellyTransportDepartmentId(), + $this->shelly_transport_override + ); } /** diff --git a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.auto-updater b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.auto-updater index d6096f78..47bbd462 100644 --- a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.auto-updater +++ b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.auto-updater @@ -4,7 +4,8 @@ FROM ${BASE_IMAGE} RUN set -eux; \ apt-get update; \ apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose; \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/*; \ + php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }' COPY auto-updater.php /usr/local/bin/auto-updater.php diff --git a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.edge-agent b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.edge-agent index 0e23e555..a888a98d 100644 --- a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.edge-agent +++ b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.edge-agent @@ -1,6 +1,9 @@ ARG BASE_IMAGE=php:8.2-cli-bookworm FROM ${BASE_IMAGE} +RUN set -eux; \ + php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }' + WORKDIR /opt/truckwash-edge-agent COPY agent.php /opt/truckwash-edge-agent/agent.php diff --git a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.lan-worker b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.lan-worker index d6029bfa..5721d482 100644 --- a/services/nginx/app/resources/edge-gateway-agent/Dockerfile.lan-worker +++ b/services/nginx/app/resources/edge-gateway-agent/Dockerfile.lan-worker @@ -1,6 +1,9 @@ ARG BASE_IMAGE=php:8.2-cli-bookworm FROM ${BASE_IMAGE} +RUN set -eux; \ + php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }' + WORKDIR /opt/truckwash-edge-agent COPY lan-worker.php /opt/truckwash-edge-agent/lan-worker.php diff --git a/services/nginx/app/resources/edge-gateway-agent/truckwash-edge-agent.service b/services/nginx/app/resources/edge-gateway-agent/truckwash-edge-agent.service index f09efba8..5a6bdaa3 100644 --- a/services/nginx/app/resources/edge-gateway-agent/truckwash-edge-agent.service +++ b/services/nginx/app/resources/edge-gateway-agent/truckwash-edge-agent.service @@ -1,14 +1,16 @@ [Unit] -Description=TruckWash Edge Agent -After=network.target +Description=TruckWash Edge Agent Compatibility Unit +After=network-online.target docker.service +Wants=network-online.target docker.service [Service] -Type=simple +Type=oneshot +RemainAfterExit=yes WorkingDirectory=/opt/truckwash-edge-agent -ExecStart=/usr/bin/php /opt/truckwash-edge-agent/agent.php --config /opt/truckwash-edge-agent/config.json -Restart=always -RestartSec=5 -User=root +ExecStart=/opt/truckwash-edge-agent/gateway-launcher.sh up +ExecReload=/opt/truckwash-edge-agent/gateway-launcher.sh reconcile +ExecStop=/opt/truckwash-edge-agent/gateway-launcher.sh down +TimeoutStartSec=900 [Install] WantedBy=multi-user.target diff --git a/services/nginx/app/routes/moduleSelfServeRoute.php b/services/nginx/app/routes/moduleSelfServeRoute.php index 014fde68..7c7bc5a2 100644 --- a/services/nginx/app/routes/moduleSelfServeRoute.php +++ b/services/nginx/app/routes/moduleSelfServeRoute.php @@ -441,12 +441,14 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $lane->open($gate); $response->success([ 'lane_id' => $lane_id, 'gate' => $gate->name, 'opened' => true, 'state' => $lane->getLaneState()->name, + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { error_log('Failed to open self-serve lane gate ' . $gate->name . ' for lane ' . $lane_id . ': ' . $e->getMessage()); @@ -468,6 +470,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $status = $lane->getMachineProgramPickerRelayStatus(); $response->success([ 'lane_id' => $lane_id, @@ -475,6 +478,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to get MACHINE_PROGRAM_PICKER relay status: ' . $e->getMessage(), 400); @@ -501,6 +505,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $lane->setMachineProgramPickerRelayStatus((bool)$on); $status = $lane->getMachineProgramPickerRelayStatus(); $response->success([ @@ -510,6 +515,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to set MACHINE_PROGRAM_PICKER relay status: ' . $e->getMessage(), 400); @@ -530,6 +536,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $status = $lane->getMachineCleanerRelayStatus(); $response->success([ 'lane_id' => $lane_id, @@ -537,6 +544,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to get MACHINE_CLEANER relay status: ' . $e->getMessage(), 400); @@ -563,6 +571,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $lane->setMachineCleanerRelayStatus((bool)$on); $status = $lane->getMachineCleanerRelayStatus(); $response->success([ @@ -572,6 +581,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to set MACHINE_CLEANER relay status: ' . $e->getMessage(), 400); @@ -592,6 +602,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $status = $lane->getMachineRelayStatus(); $response->success([ 'lane_id' => $lane_id, @@ -599,6 +610,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to get MACHINE relay status: ' . $e->getMessage(), 400); @@ -625,6 +637,7 @@ class moduleSelfServeRoute $lane = $selfserve->lane($lane_id); try { + $this->applyShellyTransportOverride($lane); $lane->setMachineRelayStatus((bool)$on); // Keep lane cache state aligned with the latest explicit relay action try { @@ -651,6 +664,7 @@ class moduleSelfServeRoute 'relay_id' => (string)$status['relay_id'], 'online' => (bool)$status['online'], 'on' => (bool)$status['on'], + 'transport' => $this->requestedShellyTransportOverride(), ]); } catch (\Exception $e) { $response->error('Failed to set MACHINE relay status: ' . $e->getMessage(), 400); @@ -984,4 +998,47 @@ class moduleSelfServeRoute 'modules_selfserve_lane_force_machine_disable' => 'Force disable MACHINE relay but keep lane as in-wash (superusers only)' ]); } + + /** + * @throws \Exception + */ + private function applyShellyTransportOverride(object $lane): void + { + $transport = $this->requestedShellyTransportOverride(); + if ($transport === null) { + return; + } + + if (!method_exists($lane, 'setShellyTransportOverride')) { + throw new \Exception('This lane does not support Shelly transport overrides.'); + } + + $lane->setShellyTransportOverride($transport); + } + + private function requestedShellyTransportOverride(): ?string + { + $transport = null; + foreach (['transport', 'test_transport', 'transport_mode'] as $parameter) { + if (self::isParametersSet([$parameter])) { + $transport = self::getParameter($parameter); + break; + } + } + + $normalized = strtolower(trim((string)$transport)); + if ($normalized === '') { + return null; + } + + if ($normalized === 'gateway') { + return 'local'; + } + + if (!in_array($normalized, ['local', 'cloud'], true)) { + throw new \InvalidArgumentException('Invalid transport. Expected local or cloud.'); + } + + return $normalized; + } } diff --git a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerCommandQueueTest.php b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerCommandQueueTest.php index 30fc50c3..5512bd83 100644 --- a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerCommandQueueTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerCommandQueueTest.php @@ -11,8 +11,18 @@ it('keeps relay dispatch and discovery queueing on the edge gateway manager', fu expect($managerSource)->not->toBeFalse(); expect($managerSource)->toContain('public function queueDiscovery'); expect($managerSource)->toContain('public function dispatchRelayStatus'); + expect($managerSource)->toContain('public function dispatchRelayStatusLocalOnly'); expect($managerSource)->toContain('public function dispatchRelaySwitch'); + expect($managerSource)->toContain('public function dispatchRelaySwitchLocalOnly'); expect($managerSource)->toContain('private function createCommandJob'); + expect($managerSource)->toContain("'require_fast_path' => \$requireFastLocalPath"); + expect($managerSource)->toContain('local_transport_override'); + expect($managerSource)->toContain('private function resolveRelayBindingLocalIp'); + expect($managerSource)->toContain('private function findShellyCloudRelayLocalIp'); + expect($managerSource)->toContain('private function backfillRelayBindingLocalIpFromInventory'); + expect($managerSource)->toContain('$bindingObject->local_ip->set($localIp);'); + expect($managerSource)->toContain("'local_ip' => \$localIp"); + expect($managerSource)->toContain('(new shelly_relay_inventory())->listRelayOptions()'); expect($managerSource)->toContain('public function buildUpdateOperationRequest'); expect($managerSource)->toContain('public function rotateGatewayCredentials'); expect($operationServiceSource)->toContain('public function queueOperation'); @@ -38,11 +48,17 @@ it('loads relay command helpers on the manager and gateway operations on the ded expect($reflection->hasMethod('pollCommand'))->toBeTrue(); expect($reflection->hasMethod('submitCommandResult'))->toBeTrue(); expect($reflection->hasMethod('dispatchRelayStatus'))->toBeTrue(); + expect($reflection->hasMethod('dispatchRelayStatusLocalOnly'))->toBeTrue(); expect($reflection->hasMethod('dispatchRelaySwitch'))->toBeTrue(); + expect($reflection->hasMethod('dispatchRelaySwitchLocalOnly'))->toBeTrue(); expect($reflection->hasMethod('claimNextCommandJob'))->toBeTrue(); expect($reflection->getMethod('claimNextCommandJob')->isPrivate())->toBeTrue(); expect($reflection->hasMethod('syncDeviceInventory'))->toBeTrue(); expect($reflection->getMethod('syncDeviceInventory')->isPrivate())->toBeTrue(); + expect($reflection->hasMethod('resolveRelayBindingLocalIp'))->toBeTrue(); + expect($reflection->getMethod('resolveRelayBindingLocalIp')->isPrivate())->toBeTrue(); + expect($reflection->hasMethod('backfillRelayBindingLocalIpFromInventory'))->toBeTrue(); + expect($reflection->getMethod('backfillRelayBindingLocalIpFromInventory')->isPrivate())->toBeTrue(); expect($reflection->hasMethod('syncGatewayInventory'))->toBeTrue(); expect($operationServiceReflection->hasMethod('queueOperation'))->toBeTrue(); expect($operationServiceReflection->hasMethod('cancelOperation'))->toBeTrue(); diff --git a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php index 700014d6..0ee352be 100644 --- a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php @@ -72,6 +72,38 @@ it('marks ready discovery as stale when the gateway heartbeat has expired', func expect($gateway['discovery_status'])->toBe('STALE'); }); +it('only trusts broker presence while the broker heartbeat is fresh', function (): void { + $recent = edge_gateway_manager::deriveGatewayRuntimeState([ + 'status' => edge_gateway_manager::STATUS_ONLINE, + 'last_heartbeat_at' => '2026-04-08 10:04:50', + 'metadata' => [ + 'broker_presence' => [ + 'connected' => true, + 'last_seen_at' => '2026-04-08 10:04:30', + ], + ], + ], edge_gateway_heartbeat_test_now('2026-04-08 10:05:00')); + + expect($recent['channel_status']['broker']['connected'])->toBeTrue(); + expect($recent['channel_status']['broker']['state'])->toBe(edge_gateway_manager::STATUS_ONLINE); + expect($recent['channel_status']['command']['preferred'])->toBe(edge_gateway_manager::DELIVERY_CHANNEL_BROKER); + + $stale = edge_gateway_manager::deriveGatewayRuntimeState([ + 'status' => edge_gateway_manager::STATUS_ONLINE, + 'last_heartbeat_at' => '2026-04-08 10:04:50', + 'metadata' => [ + 'broker_presence' => [ + 'connected' => true, + 'last_seen_at' => '2026-04-08 10:03:00', + ], + ], + ], edge_gateway_heartbeat_test_now('2026-04-08 10:05:00')); + + expect($stale['channel_status']['broker']['connected'])->toBeFalse(); + expect($stale['channel_status']['broker']['state'])->toBe(edge_gateway_manager::STATUS_OFFLINE); + expect($stale['channel_status']['command']['preferred'])->toBe(edge_gateway_manager::DELIVERY_CHANNEL_API); +}); + it('merges incoming heartbeat metadata with existing gateway metadata', function (): void { $source = file_get_contents(app_path('classes/edge_gateway_manager.php')); @@ -79,6 +111,15 @@ it('merges incoming heartbeat metadata with existing gateway metadata', function expect($source)->toContain("\$gateway->metadata_json->set(array_merge(\$existingMetadata, (array)(\$payload['metadata'] ?? [])));"); }); +it('refreshes broker presence from broker telemetry heartbeats', function (): void { + $source = file_get_contents(app_path('classes/edge_gateway_manager.php')); + + expect($source)->toContain('public function recordTelemetryFromBroker'); + expect($source)->toContain("'broker_connection_id'"); + expect($source)->toContain('$this->writeBrokerPresence($gatewayId, $presence);'); + expect($source)->toContain('private static function isBrokerPresenceConnected'); +}); + it('derives relay fallback and transport health details without shell or update runtime state', function (): void { $gateway = edge_gateway_manager::deriveGatewayRuntimeState([ 'status' => edge_gateway_manager::STATUS_ONLINE, diff --git a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayUpdateLifecycleTest.php b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayUpdateLifecycleTest.php index 333b7a5c..10edcd06 100644 --- a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayUpdateLifecycleTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayUpdateLifecycleTest.php @@ -50,7 +50,11 @@ it('builds the installer around the compose stack artifacts and management polli expect($managerSource)->toContain('journalctl -u truckwash-edge-gateway-stack.service -n 60 --no-pager || true'); expect($managerSource)->not->toContain('agent.mjs'); expect($managerSource)->toContain("'brokerUrl' => \$this->buildBrokerPublicUrl()"); - expect($serviceSource)->toContain('ExecStart=/usr/bin/php /opt/truckwash-edge-agent/agent.php --config /opt/truckwash-edge-agent/config.json'); + expect($serviceSource)->toContain('Description=TruckWash Edge Agent Compatibility Unit'); + expect($serviceSource)->toContain('ExecStart=/opt/truckwash-edge-agent/gateway-launcher.sh up'); + expect($serviceSource)->toContain('ExecReload=/opt/truckwash-edge-agent/gateway-launcher.sh reconcile'); + expect($serviceSource)->toContain('ExecStop=/opt/truckwash-edge-agent/gateway-launcher.sh down'); + expect($serviceSource)->not->toContain('/usr/bin/php /opt/truckwash-edge-agent/agent.php'); expect($stackServiceSource)->toContain('ExecStart=/opt/truckwash-edge-agent/gateway-launcher.sh up'); expect($stackServiceSource)->toContain('TimeoutStartSec=900'); expect($launcherSource)->toContain('STACK_HEALTHCHECK_TIMEOUT_SECONDS="${STACK_HEALTHCHECK_TIMEOUT_SECONDS:-300}"'); @@ -92,14 +96,17 @@ it('builds the installer around the compose stack artifacts and management polli expect($agentSource)->toContain("'last_transport_error'"); expect($agentSource)->toContain('private function recordTransportFailure(string $context, Throwable $throwable): void'); expect($edgeDockerfileSource)->toContain('FROM ${BASE_IMAGE}'); + expect($edgeDockerfileSource)->toContain('extension_loaded($extension)'); + expect($edgeDockerfileSource)->toContain('Missing PHP extension: {$extension}'); expect($edgeDockerfileSource)->toContain('COPY agent.php /opt/truckwash-edge-agent/agent.php'); - expect($edgeDockerfileSource)->not->toContain('docker-php-ext-install'); expect($workerDockerfileSource)->toContain('FROM ${BASE_IMAGE}'); + expect($workerDockerfileSource)->toContain('extension_loaded($extension)'); + expect($workerDockerfileSource)->toContain('Missing PHP extension: {$extension}'); expect($workerDockerfileSource)->toContain('COPY lan-worker.php /opt/truckwash-edge-agent/lan-worker.php'); - expect($workerDockerfileSource)->not->toContain('docker-php-ext-install'); expect($autoUpdaterSource)->toContain("'/bin/bash ' . escapeshellarg(\$launcherPath) . ' reconcile 2>&1'"); expect($autoUpdaterDockerfileSource)->toContain('COPY auto-updater.php /usr/local/bin/auto-updater.php'); expect($autoUpdaterDockerfileSource)->toContain('apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose;'); + expect($autoUpdaterDockerfileSource)->toContain('extension_loaded($extension)'); expect($serviceSource)->not->toContain('node /opt/truckwash-edge-agent/agent.mjs'); }); diff --git a/services/nginx/app/tests/Unit/Selfserve/GatewayShellyTransportTest.php b/services/nginx/app/tests/Unit/Selfserve/GatewayShellyTransportTest.php index 6a4b857c..daff7d0a 100644 --- a/services/nginx/app/tests/Unit/Selfserve/GatewayShellyTransportTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/GatewayShellyTransportTest.php @@ -12,6 +12,10 @@ class GatewayShellyTransportManagerFake extends edge_gateway_manager public array $statusCalls = []; /** @var array> */ public array $switchCalls = []; + /** @var array> */ + public array $localOnlyStatusCalls = []; + /** @var array> */ + public array $localOnlySwitchCalls = []; public ?Exception $statusException = null; public ?Exception $switchException = null; @@ -55,6 +59,35 @@ class GatewayShellyTransportManagerFake extends edge_gateway_manager 'raw' => ['source' => 'switch'], ]; } + + public function dispatchRelayStatusLocalOnly(int $departmentId, string $logicalRelayId): array + { + $this->localOnlyStatusCalls[] = [ + 'department_id' => $departmentId, + 'relay_id' => $logicalRelayId, + ]; + + return [ + 'online' => true, + 'on' => true, + 'raw' => ['source' => 'local-status'], + ]; + } + + public function dispatchRelaySwitchLocalOnly(int $departmentId, string $logicalRelayId, bool $on): array + { + $this->localOnlySwitchCalls[] = [ + 'department_id' => $departmentId, + 'relay_id' => $logicalRelayId, + 'on' => $on, + ]; + + return [ + 'online' => true, + 'on' => $on, + 'raw' => ['source' => 'local-switch'], + ]; + } } it('maps gateway relay status responses into the Shelly cloud payload shape', function (): void { @@ -92,6 +125,30 @@ it('maps gateway relay switch responses into the Shelly cloud payload shape', fu expect($result[0]['status']['switch:0']['output'])->toBeFalse(); }); +it('uses local-only gateway dispatch for explicit local transport overrides', function (): void { + $manager = new GatewayShellyTransportManagerFake(); + $transport = new gateway_shelly_transport($manager, true); + + $status = $transport->sendPostRequest('/v2/devices/api/get', [ + 'ids' => ['relay-entry'], + ], 17); + $switch = $transport->sendPostRequest('/v2/devices/api/set/switch', [ + 'id' => 'relay-entry', + 'on' => true, + ], 17); + + expect($manager->localOnlyStatusCalls)->toBe([ + ['department_id' => 17, 'relay_id' => 'relay-entry'], + ]); + expect($manager->localOnlySwitchCalls)->toBe([ + ['department_id' => 17, 'relay_id' => 'relay-entry', 'on' => true], + ]); + expect($manager->statusCalls)->toBe([]); + expect($manager->switchCalls)->toBe([]); + expect($status[0]['raw']['source'])->toBe('local-status'); + expect($switch[0]['raw']['source'])->toBe('local-switch'); +}); + it('requires a valid department id for gateway transport requests', function (): void { $transport = new gateway_shelly_transport(new GatewayShellyTransportManagerFake()); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveLanePortControllerTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveLanePortControllerTest.php index 40d39ee8..da680f1b 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveLanePortControllerTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveLanePortControllerTest.php @@ -97,7 +97,7 @@ class SelfserveLanePortControllerHarness public function logLaneAction(...$args): void {} } -it('opens exit port by switching relay_in_id on', function (): void { +it('opens exit port by switching relay_out_id on', function (): void { $lane = new SelfserveLanePortControllerHarness( relayInId: 'relay-in-123', relayOutId: 'relay-out-123' @@ -108,13 +108,13 @@ it('opens exit port by switching relay_in_id on', function (): void { expect($result)->toBeTrue(); expect($lane->switchFake->switchCalls)->toBe([ [ - 'id' => 'relay-in-123', + 'id' => 'relay-out-123', 'on' => true, ], ]); }); -it('opens entrance port by switching relay_out_id on', function (): void { +it('opens entrance port by switching relay_in_id on', function (): void { $lane = new SelfserveLanePortControllerHarness( relayInId: 'relay-in-123', relayOutId: 'relay-out-123' @@ -125,7 +125,7 @@ it('opens entrance port by switching relay_out_id on', function (): void { expect($result)->toBeTrue(); expect($lane->switchFake->switchCalls)->toBe([ [ - 'id' => 'relay-out-123', + 'id' => 'relay-in-123', 'on' => true, ], ]); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php index 68ea2674..19e1021b 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php @@ -84,6 +84,8 @@ it('wires machine relay status get and set endpoints', function (): void { expect($moduleSelfServeRoute)->toContain('getMachineCleanerRelayStatus'); expect($moduleSelfServeRoute)->toContain('setMachineCleanerRelayStatus'); expect($moduleSelfServeRoute)->toContain('setMachineCleanerRelayStatusHard(true)'); + expect($moduleSelfServeRoute)->toContain('applyShellyTransportOverride($lane)'); + expect($moduleSelfServeRoute)->toContain("'transport' => \$this->requestedShellyTransportOverride()"); }); it('wires allowed services route through machine relay visibility sync', function (): void { diff --git a/services/nginx/app/tests/Unit/Selfserve/ShellyRelayInventoryTest.php b/services/nginx/app/tests/Unit/Selfserve/ShellyRelayInventoryTest.php index 6cb7be00..966f91c1 100644 --- a/services/nginx/app/tests/Unit/Selfserve/ShellyRelayInventoryTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/ShellyRelayInventoryTest.php @@ -19,6 +19,9 @@ it('normalizes owned Shelly devices into relay select options', function (): voi 'online' => 1, ], 'name' => 'Entry Gate', + 'wifi_sta' => [ + 'ip' => '10.32.0.11', + ], 'status' => [ 'switch:0' => [ 'output' => false, @@ -33,6 +36,11 @@ it('normalizes owned Shelly devices into relay select options', function (): voi 'model' => 'Shelly Pro 2PM', ], 'name' => 'Machine Cabinet', + 'status' => [ + 'eth' => [ + 'ip' => '10.32.0.12', + ], + ], 'relays' => [ ['ison' => false, 'name' => 'Program Picker'], ], @@ -96,6 +104,7 @@ it('normalizes owned Shelly devices into relay select options', function (): voi 'code' => 'SPSW-001PE16EU', 'control_type' => 'Switch', 'control_name' => 'Entrance Relay', + 'local_ip' => '10.32.0.11', 'status_color' => 'Green', 'online' => true, ], @@ -109,6 +118,7 @@ it('normalizes owned Shelly devices into relay select options', function (): voi 'code' => 'SPSW-201XE16EU', 'control_type' => 'Relay', 'control_name' => 'Program Picker', + 'local_ip' => '10.32.0.12', 'status_color' => 'Red', 'online' => false, ], @@ -122,6 +132,7 @@ it('normalizes owned Shelly devices into relay select options', function (): voi 'code' => 'SHSW-1', 'control_type' => 'Relay', 'control_name' => null, + 'local_ip' => null, 'status_color' => 'Red', 'online' => false, ], @@ -142,6 +153,7 @@ it('falls back to local device and control names when Shelly cloud list metadata 'model' => 'Shelly Plus 1PM', 'online' => 1, ], + 'ip' => '10.32.0.21', 'name' => 'Entry Gate', 'status' => [ 'switch:0' => [ @@ -174,6 +186,7 @@ it('falls back to local device and control names when Shelly cloud list metadata 'code' => 'SPSW-001PE16EU', 'control_type' => 'Switch', 'control_name' => 'Entrance Relay', + 'local_ip' => '10.32.0.21', 'status_color' => 'Green', 'online' => true, ], diff --git a/services/nginx/app/tests/Unit/Selfserve/ShellyTransportResolverTest.php b/services/nginx/app/tests/Unit/Selfserve/ShellyTransportResolverTest.php index b32c7173..48b6535f 100644 --- a/services/nginx/app/tests/Unit/Selfserve/ShellyTransportResolverTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/ShellyTransportResolverTest.php @@ -4,6 +4,7 @@ app_require('classes/edge_gateway_manager.php'); app_require('classes/shelly_transport_resolver.php'); use classes\edge_gateway_manager; +use classes\gateway_shelly_transport; use classes\shelly_transport_resolver; use interfaces\shelly_transport_i; @@ -75,3 +76,31 @@ it('resolves the injected cloud transport when a department is in cloud mode', f expect($resolver->resolveForDepartment(22))->toBe($cloudTransport); expect($manager->calls)->toBe([22]); }); + +it('lets relay tests override the department transport without changing department mode', function (): void { + $manager = new ShellyTransportResolverManagerFake(); + $manager->modesByDepartment[17] = edge_gateway_manager::TRANSPORT_MODE_CLOUD; + + $cloudTransport = new ShellyTransportResolverTransportFake('cloud'); + $gatewayTransport = new ShellyTransportResolverTransportFake('gateway'); + + $resolver = new shelly_transport_resolver($manager, $cloudTransport, $gatewayTransport); + + expect($resolver->resolveForDepartment(17, 'local'))->toBe($gatewayTransport); + expect($resolver->resolveForDepartment(17, 'gateway'))->toBe($gatewayTransport); + expect($resolver->resolveForDepartment(17, 'cloud'))->toBe($cloudTransport); + expect($manager->calls)->toBe([]); +}); + +it('marks non-injected local overrides as local-only gateway transport', function (): void { + $manager = new ShellyTransportResolverManagerFake(); + $resolver = new shelly_transport_resolver($manager); + + $transport = $resolver->resolveForDepartment(17, 'local'); + $localOnly = new ReflectionProperty($transport, 'localOnly'); + $localOnly->setAccessible(true); + + expect($transport)->toBeInstanceOf(gateway_shelly_transport::class); + expect($localOnly->getValue($transport))->toBeTrue(); + expect($manager->calls)->toBe([]); +});