mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 03:54:00 +00:00
* ci: guard gateway protocol event coverage for iOS/Android clients (#100198) Adds scripts/check-protocol-event-coverage.mjs, which derives the server->client event catalog from GATEWAY_EVENTS in src/gateway/server-methods-list.ts, extracts the events each mobile app handles from Swift/Kotlin dispatch sites, and fails on gateway events no client handles unless allowlisted with a reason in scripts/protocol-event-coverage.allowlist.json. Wired as pnpm check:protocol-coverage in the CI guards shard. * fix(ci): scope Kotlin event extraction to handle*Event dispatch functions (#100198) Bare event == "..." literals in predicate helpers outside the dispatch path (gatewayEventInvalidatesNodesDevices in NodeRuntime.kt, which has no production caller) counted as Android coverage, silently masking that node.pair.requested/resolved have no live handler. Kotlin extraction now only reads when(event) labels and event comparisons inside fun handle*Event(...) bodies; node.pair.* moved to the Android allowlist with a truthful reason. Swift extraction stays tree-wide because consumption there always reads .event off a received EventFrame. * fix(android): remove dead node pairing event helper * fix(ci): preserve protocol allowlist parse errors * test(ci): align tooling import plan
44 lines
4.1 KiB
JSON
44 lines
4.1 KiB
JSON
{
|
|
"$comment": "Gateway events each mobile client intentionally does not handle yet, with a one-line reason. Consumed by scripts/check-protocol-event-coverage.mjs (pnpm check:protocol-coverage). Adding a gateway event without a client handler requires either handling it or adding an entry here; the check also fails when an entry goes stale (event removed or now handled).",
|
|
"ios": {
|
|
"session.operation": "Chat UI derives run state from chat/agent events; no session.operation consumer yet.",
|
|
"session.tool": "Session tool stream is not rendered by the iOS chat surface yet.",
|
|
"sessions.changed": "iOS refreshes session lists via explicit sessions.* requests instead of this push event.",
|
|
"presence": "Presence roster is a control-UI (web/desktop) surface; iOS does not render it.",
|
|
"shutdown": "iOS relies on socket close plus reconnect/backoff instead of the shutdown notice.",
|
|
"heartbeat": "iOS liveness uses tick and WebSocket-level ping; heartbeat is unused.",
|
|
"cron": "Cron run activity is not surfaced in the iOS app.",
|
|
"node.pair.requested": "Node pairing state is fetched on demand; no push consumer on iOS yet.",
|
|
"node.pair.resolved": "Node pairing state is fetched on demand; no push consumer on iOS yet.",
|
|
"device.pair.requested": "Device pairing flows poll via device.pair.* methods on iOS.",
|
|
"device.pair.resolved": "Device pairing flows poll via device.pair.* methods on iOS.",
|
|
"voicewake.routing.changed": "iOS only consumes voicewake.changed trigger updates; routing changes are not surfaced.",
|
|
"exec.approval.requested": "Handled in NodeAppModel via ExecApprovalNotificationBridge constants; the literal-only extractor cannot see constant case labels.",
|
|
"exec.approval.resolved": "Handled in NodeAppModel via ExecApprovalNotificationBridge constants; the literal-only extractor cannot see constant case labels.",
|
|
"plugin.approval.requested": "Plugin approval prompts are not implemented on iOS.",
|
|
"plugin.approval.resolved": "Plugin approval prompts are not implemented on iOS.",
|
|
"terminal.data": "Embedded terminal is a web/desktop surface; iOS has no terminal client.",
|
|
"terminal.exit": "Embedded terminal is a web/desktop surface; iOS has no terminal client.",
|
|
"update.available": "Gateway self-update notices do not apply to iOS; app updates ship via the App Store."
|
|
},
|
|
"android": {
|
|
"session.operation": "Chat UI derives run state from chat/agent events; no session.operation consumer yet.",
|
|
"session.tool": "Session tool stream is not rendered by the Android chat surface yet.",
|
|
"presence": "Presence roster is a control-UI (web/desktop) surface; Android does not render it.",
|
|
"talk.mode": "Android toggles talk mode locally; gateway talk.mode sync is not consumed.",
|
|
"shutdown": "Android relies on socket close plus reconnect/backoff instead of the shutdown notice.",
|
|
"heartbeat": "Android liveness uses tick and WebSocket-level ping; heartbeat is unused.",
|
|
"cron": "Cron run activity is not surfaced in the Android app.",
|
|
"node.pair.requested": "Android's bounded operator session lacks operator.pairing; onboarding refreshes node approval with explicit node.list requests.",
|
|
"node.pair.resolved": "Android's bounded operator session lacks operator.pairing; onboarding refreshes node approval with explicit node.list requests.",
|
|
"device.pair.requested": "Device pairing flows poll via device.pair.* methods on Android.",
|
|
"device.pair.resolved": "Device pairing flows poll via device.pair.* methods on Android.",
|
|
"voicewake.changed": "Android reads voicewake state on demand via voicewake.get; no push consumer yet.",
|
|
"voicewake.routing.changed": "Android reads voicewake state on demand via voicewake.get; no push consumer yet.",
|
|
"plugin.approval.requested": "Plugin approval prompts are not implemented on Android.",
|
|
"plugin.approval.resolved": "Plugin approval prompts are not implemented on Android.",
|
|
"terminal.data": "Embedded terminal is a web/desktop surface; Android has no terminal client.",
|
|
"terminal.exit": "Embedded terminal is a web/desktop surface; Android has no terminal client."
|
|
}
|
|
}
|