openclaw/scripts/protocol-event-coverage.allowlist.json
Ayaan Zaidi 7753ffb475
fix(ui): publish initial model catalog on connect (#145927)
## What Problem This Solves

The first web model picker open could wait seven seconds for a catalog reply. A late initial snapshot could also restore an old saved account after the user changed it.

## Why This Change Was Made

Publish the existing catalog during connection setup through the authenticated request dispatcher. Initial and ordinary replies use the same cache publication checks, so delayed work cannot replace a newer session selection.

## User Impact

Published choices appear on first open and reconnect while discovery continues. Warm reopen stays fast, without an extra catalog request from opening the picker.

## Evidence

With catalog replies held for seven seconds, the original picker had no usable choices until the reply. The corrected New Session and active-chat pickers showed rows within 100 ms; warm reopen took 8–12 ms. Neither open added a request.

Real browser/Gateway tests cover reconnect and a saved-account change before snapshot completion. Sixteen valid configuration fixtures start; an invalid legacy fixture rejects as expected. Previous-version source builds connect in both directions; installed-release upgrades were not tested. Full consumer analysis: `consumers.md`.

## Compatibility

The new connect field is sent only after server advertisement. Clients without opt-in receive no snapshot. No protocol-version bump, configuration key, database change, or migration.

## Consumers

- New Session picker: uses published rows before its ordinary catalog reply.
- Active-chat picker: receives the saved session's model/account projection and retains newer selections.
- Mounted browser shell: preserves initial publication across reconnect.

## Invalidation

Connection, identity, configuration, session metadata, session mutations, and explicit refresh retire stale reads. Expiry and eviction retain publication ordering; delayed results cannot refill invalidated state.

## Contention

Snapshot publication adds no lock, transaction, or await. The existing dispatcher owns catalog reads; the common cache owner admits results synchronously.

## Tests

Browser picker tests exercise fresh, saved-session, refresh, and reconnect flows. Gateway tests enter connect, `models.list`, and `sessions.patch`. Handshake, cache, metadata, and sibling checks pass. The shared test partition guard passes with the server grouping from #146212. Full automated validation is still required.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-12 23:39:39 +05:30

89 lines
10 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": {
"controlUi.sessionPullRequests.changed": "Sidebar PR indicators are a Control UI surface; native apps do not render session PR chips.",
"cron": "Cron run activity is not surfaced in the iOS app.",
"device.pair.changed": "Device label projection refresh is a Control UI surface; iOS does not render the Gateway Devices page.",
"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.",
"device.pair.setup.completed": "Generated setup lifecycle is a Control UI surface; iOS direct Watch setup completes through Watch connectivity.",
"device.pair.setup.deliveryUncertain": "Generated setup recovery is a Control UI surface; native clients receive the handoff response directly.",
"gateway.suspension": "Gateway suspension account-footer presentation is a Control UI surface; iOS does not render this footer.",
"heartbeat": "iOS liveness uses tick and WebSocket-level ping; heartbeat is unused.",
"mentions.changed": "Personal Inbox invalidation is a Control UI surface; iOS does not expose the temporary mentions Inbox.",
"models.snapshot": "Initial catalog snapshots are sent only to the requesting Control UI connection.",
"node.hostStats": "Host resource meters are a Control UI surface; iOS does not render them.",
"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.",
"node.presence": "Node activity is reported by macOS nodes and consumed by gateway routing; iOS has no presence reporter yet.",
"node.runnerInventory.changed": "Session-host placement refresh is a Control UI surface; iOS does not offer device runner placement yet.",
"openclaw.approval.requested": "OpenClaw system-agent config approvals are a web/desktop operator surface; iOS has no operator-approval prompt.",
"openclaw.approval.resolved": "OpenClaw system-agent config approvals are a web/desktop operator surface; iOS has no operator-approval prompt.",
"plugin.approval.requested": "Plugin approval prompts are not implemented on iOS.",
"plugin.approval.resolved": "Plugin approval prompts are not implemented on iOS.",
"plugins.changed": "Plugin inventory and UI descriptors are Control UI surfaces; iOS has no plugin manager and refreshes chat catalogs through chat.metadata.changed.",
"plugins.controlUi.changed": "Plugin browser-module catalog changes are consumed by the web Control UI; iOS does not load those modules.",
"portal.changed": "Control-UI-only surface; native apps have no portal viewer yet.",
"presence": "Presence roster is a control-UI (web/desktop) surface; iOS does not render it.",
"session.approval": "Native approval review uses exec.approval push/nudge delivery; the session-scoped approval stream is a Control UI chat surface.",
"session.operation": "Chat UI derives run state from chat/agent events; no session.operation consumer yet.",
"session.sharing": "Session visibility/membership management is a Control UI operator surface; iOS reads visibility/sharingRole from session rows and has no sharing editor.",
"session.sharing.evidence": "Principal-less sharing evidence is a Control UI operator surface; iOS refreshes canonical session rows through sessions.changed.",
"session.suggestion": "The suggestion queue is a Control UI collaboration surface; iOS does not render or resolve session suggestions.",
"session.tool": "Session tool stream is not rendered by the iOS chat surface yet.",
"session.typing": "Collaborative typing state is a Control UI-only ephemeral indicator; iOS does not render it.",
"shutdown": "iOS relies on socket close plus reconnect/backoff instead of the shutdown notice.",
"skills.changed": "Skills settings is a macOS operator surface; iOS does not expose skill management yet.",
"task.suggestion": "Task suggestion cards are a Control UI-only surface; iOS does not render them.",
"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.",
"ui.command": "Web Control UI-only layout commands; iOS does not consume them.",
"update.available": "Gateway self-update notices do not apply to iOS; app updates ship via the App Store.",
"update.run.changed": "Gateway update-run progress is an operator surface; iOS has no update-run history view.",
"voicewake.routing.changed": "iOS only consumes voicewake.changed trigger updates; routing changes are not surfaced."
},
"android": {
"controlUi.sessionPullRequests.changed": "Sidebar PR indicators are a Control UI surface; native apps do not render session PR chips.",
"cron": "Cron run activity is not surfaced in the Android app.",
"device.pair.changed": "Device label projection refresh is a Control UI surface; Android does not render the Gateway Devices page.",
"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.",
"device.pair.setup.completed": "Generated setup lifecycle is a Control UI surface; Android consumes setup codes but does not issue or track them.",
"device.pair.setup.deliveryUncertain": "Generated setup recovery is a Control UI surface; Android consumes setup codes but does not issue or track them.",
"gateway.suspension": "Gateway suspension account-footer presentation is a Control UI surface; Android does not render this footer.",
"heartbeat": "Android liveness uses tick and WebSocket-level ping; heartbeat is unused.",
"mentions.changed": "Personal Inbox invalidation is a Control UI surface; Android does not expose the temporary mentions Inbox.",
"models.snapshot": "Initial catalog snapshots are sent only to the requesting Control UI connection.",
"node.hostStats": "Host resource meters are a Control UI surface; Android does not render them.",
"node.invoke.cancel": "Cancel targets streaming agent.cli.claude.run.v1 invokes; app nodes never advertise agent runs, so no cancel can address them.",
"node.invoke.input": "Carries terminal keystrokes/resize to a node PTY relay invoke; the relay runs on gateway/CLI node hosts and app nodes never host it, so Android has no consumer.",
"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.",
"node.presence": "Node activity is reported by macOS nodes and consumed by gateway routing; Android has no presence reporter yet.",
"node.runnerInventory.changed": "Session-host placement refresh is a Control UI surface; Android does not offer device runner placement yet.",
"openclaw.approval.requested": "OpenClaw system-agent config approvals are a web/desktop operator surface; Android has no operator-approval prompt.",
"openclaw.approval.resolved": "OpenClaw system-agent config approvals are a web/desktop operator surface; Android has no operator-approval prompt.",
"plugin.approval.requested": "Plugin approval prompts are not implemented on Android.",
"plugin.approval.resolved": "Plugin approval prompts are not implemented on Android.",
"plugins.changed": "Plugin inventory and UI descriptors are Control UI surfaces; Android has no plugin manager and refreshes chat catalogs through chat.metadata.changed.",
"plugins.controlUi.changed": "Plugin browser-module catalog changes are consumed by the web Control UI; Android does not load those modules.",
"portal.changed": "Control-UI-only surface; native apps have no portal viewer yet.",
"presence": "Presence roster is a control-UI (web/desktop) surface; Android does not render it.",
"session.approval": "Native approval review uses exec.approval push/nudge delivery; the session-scoped approval stream is a Control UI chat surface.",
"session.operation": "Chat UI derives run state from chat/agent events; no session.operation consumer yet.",
"session.sharing": "Session visibility/membership management is a Control UI operator surface; Android reads visibility/sharingRole from session rows and has no sharing editor.",
"session.sharing.evidence": "Principal-less sharing evidence is a Control UI operator surface; Android refreshes canonical session rows through sessions.changed.",
"session.suggestion": "The suggestion queue is a Control UI collaboration surface; Android does not render or resolve session suggestions.",
"session.tool": "Session tool stream is not rendered by the Android chat surface yet.",
"session.typing": "Collaborative typing state is a Control UI-only ephemeral indicator; Android does not render it.",
"shutdown": "Android relies on socket close plus reconnect/backoff instead of the shutdown notice.",
"skills.changed": "Skills settings is a macOS operator surface; Android does not expose skill management yet.",
"talk.mode": "Android toggles talk mode locally; gateway talk.mode sync is not consumed.",
"task.suggestion": "Task suggestion cards are a Control UI-only surface; Android does not render them.",
"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.",
"ui.command": "Web Control UI-only layout commands; Android does not consume them.",
"update.run.changed": "Gateway update-run progress is an operator surface; Android has no update-run history view.",
"voicewake.routing.changed": "Android reads voicewake state on demand via voicewake.get; no push consumer yet."
}
}