# CTM App Update Refresh Protocol

## Problem

CTM is a long-lived browser app. A user can keep several CTM tabs open while
`create-walle update` replaces CTM and Wall-E code, restarts the server, and
serves newer HTML, CSS, and JavaScript. Existing browser tabs may reconnect to
the new server while still executing the old client bundle.

That is unsafe in both directions:

- silently keeping old code leaves users on stale UX after an update;
- blindly reloading every tab can destroy active terminal input, queue drafts,
  screenshot edits, or mobile composer text.

## Design

The server is the source of truth for the installed application identity. Each
WebSocket `hello` includes an app identity:

- `version`: the installed create-walle version;
- `components`: CTM and Wall-E package versions;
- `buildId`: a stable hash of key shipped files and package versions.

`buildId` is recomputed from file stats when version info is requested. It must
not be process-cached because update installers can replace static assets before
or during a server restart.

The client records the first app identity it sees for the current document. On
later WebSocket reconnects, if the server identity changes, the page is running
old code and must refresh before continuing normal operation.

## UX Contract

When a changed app identity is detected:

1. Broadcast `reload-required` to same-origin CTM tabs using `BroadcastChannel`.
2. If the current tab is idle, reload immediately.
3. If the current tab has active user work, show a sticky reload-required banner
   and do not steal focus.
4. The banner remains until the user clicks **Reload now** or the page is
   refreshed.

Active user work includes focused xterm.js terminals, editable inputs,
contenteditable composers, open modals, open queue panel, and screenshot editor
state.

## Mobile/PWA

The mobile service worker already uses a network-first shell strategy and
activates new workers. That only updates future navigations; a currently open
mobile document still needs the same runtime identity handshake. Mobile uses the
same `hello` comparison and shows a compact refresh banner when a composer or
detail view is active.

## Non-Goals

- No hard reload while a user is typing.
- No reload prompt for ordinary CTM restarts when the app identity is unchanged.
- No dependency on service workers for desktop refresh behavior.

## Verification

Focused render tests should cover:

- an idle desktop tab auto-refreshes on server identity change;
- a focused terminal desktop tab shows the reload banner without losing focus;
- another open tab receives the reload-required event through `BroadcastChannel`;
- mobile shows the refresh banner instead of silently keeping stale code.
