# Wall-E Session History Hydration

## Problem

Wall-E session history is chat transcript data, not terminal scrollback. CTM used to hydrate visible Wall-E tabs through the same `attach` and `snapshot` restore path used by xterm-backed Codex/Claude sessions. That made a Wall-E tab vulnerable to terminal lifecycle races:

- restart creates deferred startup placeholders;
- hidden terminal snapshot prewarm can ask the server to auto-start a deferred session;
- if that happens for a Wall-E placeholder with no visible browser client, the runtime can be marked restored while no `walle-history` payload is delivered;
- the browser can then sit in `requested && !loaded` state and keep showing "Rehydrating Wall-E session history".

The history read itself is normally cheap. The product boundary was wrong.

## Architecture

Wall-E history now has its own request/response lane:

1. Browser activation calls `WalleSession.requestHistory(...)`.
2. The client sends `walle-history-request` over the existing CTM WebSocket.
3. The server resolves the Wall-E transcript source from live session metadata, CTM DB identity, or startup task metadata.
4. The server replies with `walle-history` from the durable conversation cache or local Wall-E transcript history.
5. Terminal `snapshot`, `reflow`, and hidden prewarm paths are not allowed to auto-start Wall-E deferred sessions.

This keeps chat history hydration independent from PTY restore. Existing `attach` remains compatible for older clients, but it is no longer the normal browser path for loading a Wall-E conversation.

## Browser Surface Reconciliation

The browser must treat server session type as authoritative after reconnect.
A tab can exist locally before the latest `list` payload arrives, and that local
tab may still have a stale terminal container from a previous runtime shape.
Native Wall-E sessions are not xterm sessions, so reusing that terminal surface
can leave a `snapshot-loading-overlay` on screen even though the server has
already reported the session as idle.

On every `sessions-list` refresh:

- if the server reports `type: "walle"` or a native Wall-E marker, the client
  converts the local session to a Wall-E surface;
- conversion disposes terminal renderers, timers, xterm instances, stale
  containers, and loading overlays before rendering the Wall-E transcript view;
- if an existing Wall-E-shaped local tab is later reported as terminal-backed,
  the client recreates a terminal stub instead of mutating the Wall-E DOM in
  place;
- `server-ready` and restart overlays do not wait for terminal scrollback when
  the active tab is a native Wall-E session. They request Wall-E history and
  dismiss the global restore overlay.

This mirrors the boundary used by OpenCode/Claude-style transcript views:
conversation history is hydrated by a transcript/message lane, while terminal
snapshot restore is reserved for live terminal sessions.

## Hidden Snapshot Prewarm Policy

Hidden snapshot prewarm is only for hidden sessions that have live terminal
control. It must not auto-start a deferred provider session just to serialize a
background snapshot.

Rules:

- skip native Wall-E sessions;
- skip exited sessions;
- skip restore-deferred sessions that do not expose terminal input/control;
- if a legacy/in-flight hidden prewarm receives `session-restore-deferred` with
  `starting: false`, settle the prewarm immediately instead of waiting for the
  timeout.

This prevents restart from turning into a serialized background resume storm,
which was the main reason some tabs appeared to restore slowly or never clear
their loading state.

## State Contract

The browser treats history loading as an idempotent state machine:

- `idle`: no history request has been made;
- `loading(requestId)`: a request is in flight;
- `loaded(requestId)`: history arrived, even if the transcript is empty;
- `error(requestId)`: the server rejected the request.

If a visible tab is stuck in `requested && !loaded`, activation retries after the retry window instead of assuming the old request will complete. Server responses echo `historyRequestId`, so stale replies cannot overwrite a newer load.

## Server Rules

- `walle-history-request` may read cache/transcript history without starting a deferred runtime.
- `snapshot` for a Wall-E session is redirected to history hydration and returns a non-terminal snapshot no-op.
- `_maybeAutoStartDeferredRestore` blocks Wall-E auto-start from snapshot/reflow/prewarm sources.
- `/api/session/messages` uses the local Wall-E cache/history fast path before falling back to generic JSONL parsing.

## Testing

Regression coverage lives in `tests/walle-history-hydration.test.js`:

- Wall-E deferred sessions do not auto-start from terminal snapshot prewarm.
- Terminal sessions keep their existing auto-start behavior.
- requested-but-not-loaded Wall-E history retries after the retry window.

Browser regression coverage:

- `tests/rendering/scenarios/walle-session-default-model.spec.js` verifies that
  a native Wall-E `sessions-list` update replaces a stale terminal restore
  surface and requests Wall-E history.
- `tests/rendering/scenarios/reconnect.spec.js` verifies that hidden deferred
  tabs are skipped by background snapshot prewarm and that deferred prewarm
  responses settle immediately.

Run:

```bash
npm --prefix claude-task-manager test -- --test-name-pattern=walle-history-hydration
node --check claude-task-manager/server.js
node --check claude-task-manager/public/js/walle-session.js
npm --prefix claude-task-manager run test:render -- scenarios/walle-session-default-model.spec.js -g "type transition" --retries=0
npm --prefix claude-task-manager run test:render -- scenarios/reconnect.spec.js -g "hidden deferred tabs" --retries=0
```
