From 7882355b136f4b9fa6e47a78dd091daa4711bd6b Mon Sep 17 00:00:00 2001 From: robertjamesprior <83608739+robertjamesprior@users.noreply.github.com> Date: Fri, 25 Sep 2026 19:02:44 +0000 Subject: [PATCH 1/2] Document the KERNEL_CONNECTION_FAILED live view event The live view client posts KERNEL_CONNECTION_FAILED to the parent frame once it has given up starting the viewer. Add it to the parent-frame events table, version-gate it, handle it in the detection sample, and document that the client retries transient failures internally so an embedder does not remount on top of a retry the client is already running. --- browsers/live-view.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/browsers/live-view.mdx b/browsers/live-view.mdx index 62862928..f481b755 100644 --- a/browsers/live-view.mdx +++ b/browsers/live-view.mdx @@ -100,6 +100,7 @@ When the live view is embedded in an iframe, the client posts messages to the pa | `KERNEL_PLAYING` | `playing: true` | Video frames are rendering. | | `KERNEL_PAUSED` | `playing: false` | Playback has stopped. | | `KERNEL_CONNECTION_TIMEOUT` | `reason`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The client's connection watchdog expired. Useful for diagnostics. | +| `KERNEL_CONNECTION_FAILED` | `reason`, `attempts`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The client has given up starting the viewer and will not try again until the iframe reloads. | | `KERNEL_READ_ONLY_CHANGED` | `readOnly`, `requestId` | Acknowledges a `KERNEL_SET_READ_ONLY` request. | ### Accepted from the parent @@ -111,6 +112,8 @@ When the live view is embedded in an iframe, the client posts messages to the pa `KERNEL_CONNECTION_TIMEOUT`, `KERNEL_READ_ONLY_CHANGED` and `KERNEL_SET_READ_ONLY` require a recent browser image. `KERNEL_CONNECTED`, `KERNEL_PLAYING` and `KERNEL_PAUSED` are available on all current images, but `capabilities` is sent only by recent ones — older images post `{ type: 'KERNEL_CONNECTED', connected: true }`, so treat a missing `capabilities` as unknown rather than unsupported. + `KERNEL_CONNECTION_FAILED` requires a browser image that includes the connect-failure fix. On images without it the client fails silently instead, so treat a missing `KERNEL_CONNECTION_FAILED` as unknown rather than as a successful start, and keep gating on `KERNEL_PLAYING`. + Messages are exchanged with the parent origin derived from `document.referrer`. If the referrer is unavailable — for example under a restrictive `Referrer-Policy` — the client cannot resolve your origin and will reject `KERNEL_SET_READ_ONLY`. @@ -140,6 +143,7 @@ window.addEventListener('message', (event) => { if (event.origin !== liveViewOrigin) return; if (event.data?.type === 'KERNEL_PLAYING') clearTimeout(watchdog); if (event.data?.type === 'KERNEL_PAUSED') arm(); + if (event.data?.type === 'KERNEL_CONNECTION_FAILED') showFallback(event.data); }); arm(); @@ -147,6 +151,10 @@ arm(); Do not gate on `KERNEL_CONNECTION_TIMEOUT` alone. The watchdog behind it is cleared once negotiation begins, so a connection that stalls after that point never emits it. Log it alongside `KERNEL_PLAYING` to capture the connection state at the moment things stalled. +`KERNEL_CONNECTION_FAILED` is the terminal signal. It means the client has exhausted its attempts, or hit a failure it will not retry, and nothing further will happen until the iframe reloads. Surface a persistent message on it rather than remounting automatically: the failure is often a property of the browser environment, so a remount repeats it. `attempts` reports how many attempts were made before giving up. + +The client retries transient failures itself, up to three attempts one second apart. Internal retries are not reported to the parent, so `KERNEL_CONNECTION_TIMEOUT` is only posted on the final attempt, and a remount on that event duplicates a retry the client is already doing. + ## Kiosk mode Kiosk mode provides a fullscreen live view experience without browser UI elements like the address bar and tabs. You can enable kiosk mode when creating a browser by setting the `kiosk_mode` parameter to `true`. From cc978cb2175082a69a55e8827ad123266fa874ca Mon Sep 17 00:00:00 2001 From: robertjamesprior <83608739+robertjamesprior@users.noreply.github.com> Date: Fri, 25 Sep 2026 21:23:35 +0000 Subject: [PATCH 2/2] Document the KERNEL_CONNECTION_FAILED live view event The client reports a failed connect to the parent frame as a single terminal event, and both terminal events now carry a machine-readable reason instead of prose. - add KERNEL_CONNECTION_FAILED to the parent-frame events table - document the shared reason set -- transport, signaling, media, peer, unsupported, server -- so an embedder can branch on it without matching message text - note that a failed connect posts one of the two terminal events, never both, and that the client does not retry a connect itself - treat KERNEL_CONNECTION_TIMEOUT as terminal alongside it, and record the older reason string on images that predate the fix Version-gated on the browser image carrying kernel/kernel-images#417. --- browsers/live-view.mdx | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/browsers/live-view.mdx b/browsers/live-view.mdx index f481b755..db72d22b 100644 --- a/browsers/live-view.mdx +++ b/browsers/live-view.mdx @@ -99,10 +99,21 @@ When the live view is embedded in an iframe, the client posts messages to the pa | `KERNEL_CONNECTED` | `connected`, `capabilities` (recent images only) | Signaling is established. Frames are not necessarily rendering yet. | | `KERNEL_PLAYING` | `playing: true` | Video frames are rendering. | | `KERNEL_PAUSED` | `playing: false` | Playback has stopped. | -| `KERNEL_CONNECTION_TIMEOUT` | `reason`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The client's connection watchdog expired. Useful for diagnostics. | -| `KERNEL_CONNECTION_FAILED` | `reason`, `attempts`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The client has given up starting the viewer and will not try again until the iframe reloads. | +| `KERNEL_CONNECTION_TIMEOUT` | `reason`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | A connect stage ran out its bound without completing. `reason` names the stage. | +| `KERNEL_CONNECTION_FAILED` | `reason`, `iceConnectionState`, `connectionState`, `signalingState`, `socketOpen` | The connect failed outright. `reason` says why. Nothing further happens until the iframe reloads. | | `KERNEL_READ_ONLY_CHANGED` | `readOnly`, `requestId` | Acknowledges a `KERNEL_SET_READ_ONLY` request. | +Both terminal events carry the same `reason`, so branch on it instead of matching message text: + +| `reason` | Meaning | +| --- | --- | +| `transport` | the socket never opened inside its bound, or closed before signaling | +| `signaling` | the socket opened but no offer arrived inside its bound | +| `media` | a peer exists but ICE never reached `checking` inside its bound | +| `peer` | peer construction or the remote offer threw | +| `unsupported` | the browser has no `RTCPeerConnection` | +| `server` | the server closed the connect | + ### Accepted from the parent | Event | Payload | Effect | @@ -112,14 +123,14 @@ When the live view is embedded in an iframe, the client posts messages to the pa `KERNEL_CONNECTION_TIMEOUT`, `KERNEL_READ_ONLY_CHANGED` and `KERNEL_SET_READ_ONLY` require a recent browser image. `KERNEL_CONNECTED`, `KERNEL_PLAYING` and `KERNEL_PAUSED` are available on all current images, but `capabilities` is sent only by recent ones — older images post `{ type: 'KERNEL_CONNECTED', connected: true }`, so treat a missing `capabilities` as unknown rather than unsupported. - `KERNEL_CONNECTION_FAILED` requires a browser image that includes the connect-failure fix. On images without it the client fails silently instead, so treat a missing `KERNEL_CONNECTION_FAILED` as unknown rather than as a successful start, and keep gating on `KERNEL_PLAYING`. + `KERNEL_CONNECTION_FAILED` requires a browser image that includes the connect-failure fix. On images without it the client fails silently instead, so treat a missing `KERNEL_CONNECTION_FAILED` as unknown rather than as a successful start, and keep gating on `KERNEL_PLAYING`. On images before that fix, `KERNEL_CONNECTION_TIMEOUT` carries `reason: 'connection timeout'` rather than a stage name. Messages are exchanged with the parent origin derived from `document.referrer`. If the referrer is unavailable — for example under a restrictive `Referrer-Policy` — the client cannot resolve your origin and will reject `KERNEL_SET_READ_ONLY`. ### Detecting a viewer that never starts -Gate on `KERNEL_PLAYING`. It fires only once frames actually arrive, so it is the one signal that distinguishes a working viewer from one that is still connecting or has silently failed. Start a timer when you mount the iframe and remount if `KERNEL_PLAYING` has not arrived: +Gate on `KERNEL_PLAYING`. It fires only once frames actually arrive, so it is the signal that distinguishes a working viewer from one that is still connecting or has silently failed. The terminal events below tell you when the client has stopped trying. Start a timer when you mount the iframe and remount if `KERNEL_PLAYING` has not arrived: ```typescript Typescript/Javascript const iframe = document.querySelector('#kernel-live-view'); @@ -144,6 +155,7 @@ window.addEventListener('message', (event) => { if (event.data?.type === 'KERNEL_PLAYING') clearTimeout(watchdog); if (event.data?.type === 'KERNEL_PAUSED') arm(); if (event.data?.type === 'KERNEL_CONNECTION_FAILED') showFallback(event.data); + if (event.data?.type === 'KERNEL_CONNECTION_TIMEOUT') showFallback(event.data); }); arm(); @@ -151,9 +163,9 @@ arm(); Do not gate on `KERNEL_CONNECTION_TIMEOUT` alone. The watchdog behind it is cleared once negotiation begins, so a connection that stalls after that point never emits it. Log it alongside `KERNEL_PLAYING` to capture the connection state at the moment things stalled. -`KERNEL_CONNECTION_FAILED` is the terminal signal. It means the client has exhausted its attempts, or hit a failure it will not retry, and nothing further will happen until the iframe reloads. Surface a persistent message on it rather than remounting automatically: the failure is often a property of the browser environment, so a remount repeats it. `attempts` reports how many attempts were made before giving up. +`KERNEL_CONNECTION_FAILED` and `KERNEL_CONNECTION_TIMEOUT` are both terminal, and a failed connect posts one of them, never both. Whichever arrives, nothing further happens until the iframe reloads. Surface a persistent message rather than remounting blindly: a `peer` or `unsupported` reason is a property of the browser environment, so a remount repeats it, while a `transport` reason is worth one retry. -The client retries transient failures itself, up to three attempts one second apart. Internal retries are not reported to the parent, so `KERNEL_CONNECTION_TIMEOUT` is only posted on the final attempt, and a remount on that event duplicates a retry the client is already doing. +The client does not retry a connect itself, so whatever `reason` you get is the first failure, and whether to try again is your call. ## Kiosk mode