Takeover retention and runtime health

Wait strategies and readiness retain their existing meanings; see readiness. This change governs tab ownership and takeover availability, independently of whether a wait returned successfully.

When a takeover tab is reclaimed

--takeover reclaims its tab only after affirmative mechanical capture evidence: a 2xx main response, a nonempty rendered document and visible text, no recognized challenge, no failed/empty requested capture, and, when scoped readiness was measured, a satisfied wait with ready target content. This is not validation of business fields. Use selector-stable:<css> to identify required content and inspect those fields in the returned artifacts.

HTTP 403 (including an unrecognized denial), missing/unknown content, failed captures and readiness timeouts retain the tab. A short “Hang tight! We are checking your browser” document is recognized without requiring a provider marker. Unknown content gets takeover_content_unverified and a human_takeover action without inventing a page_kind. A successfully loaded HTTP error page is not successful takeover completion.

The result preserves status, artifacts, readiness signals, warnings and tab_id. If minting a panel URL fails, the result keeps its review action, tab and artifacts, adds the actual handoff error as a warning, and leaves takeover_url_secret absent. Do not assume that every review action contains a usable panel URL. Fetch errors report trace.retained_tab_id when a target was retained; those failures do not become successful fetches.

A plain fetch with --tab retains the caller’s tab. A successful takeover re-fetch may recycle that tab. Driver cleanup and the idle reaper ensure a dedicated inert about:blank#afhttp-window-anchor exists before closing a page, so concurrent cleanup cannot close the host’s final browser window. If that guard fails, cleanup retains the original tab and reports the failure. Raw CDP Target.closeTarget is an explicit low-level command and has no such automatic protection.

Configuration support and actual availability

/capabilities.takeover still describes configured backend/provider support. Authenticated /health adds build and takeover:

FieldMeaning
configuredTakeover is enabled with a display provider.
browser_runningSupervised browser process has not exited; null if not supervised.
cdp_connectedA fresh CDP connection answered Target.getTargets.
display_connectedProvider process and X/web connections are usable; test adapters check their web connection.
readyConfigured, browser has not exited, CDP and display probes passed.
reasonWhy takeover is unavailable; omitted when ready.

container status.running describes the container process. It can be true while takeover is unavailable. Status adds host_build, backend_connected, takeover_configured and takeover_health; takeover_ready reflects live checks, not configured capability. A degraded health response keeps the profile identity and provides the backend error.

New hosts check before issuing or exchanging a handoff, renewing a UI lease, loading the panel document, and accepting its WebSocket connection. Panel HTML polls an authenticated status endpoint and shows a connection-loss banner after repeated failures. These checks do not restart a browser, switch profiles, or remove cookies. Diagnose the host before an operator restarts it. Health is a bounded observation at a point in time, not a guarantee against a process exiting immediately afterwards.

Metadata durability and recovery

While holding the profile lock, the host writes metadata to a uniquely named temporary file in the same directory, retries short/interrupted system writes, syncs the completed file, atomically replaces afhttp-profile.json, then syncs the parent directory on Unix. ENOSPC or another failure before replacement leaves the previous file byte-identical. An interruption before replacement can leave an unused temporary file; it cannot truncate the old metadata. A directory-sync failure after replacement leaves complete new metadata but reports that crash durability could not be confirmed.

An EOF or schema/name/backend error concerns afhttp-profile.json, not proof of corrupt browser data. Back up the profile directory, recover or repair its metadata using its actual name/backend, and preserve the browser files. Do not delete/recreate an entire profile to repair a metadata parse error. Free disk space separately before retrying. These changes do not identify the cause of disk exhaustion.

Compatibility

There is no protocol envelope/schema or version-number change. The optional health/status/trace fields are additive and old responses still deserialize. takeover_content_unverified is a new warning code: consumers with exhaustive warning enums must handle it. Rust callers constructing public health/trace struct literals must initialize the added fields; exhaustive error-code matches need the new variant. More takeover results retain tabs and request review, and a failed URL mint now yields captured results plus a warning.

For an older host, the new driver checks its existing backend.connected before minting a handoff/UI lease (or probes CDP directly if /health is disabled). It cannot attest to old-host display liveness: status omits takeover_ready when unknown and emits a warning, while still reporting configuration and CDP state. Browser metadata durability, host-side checks, the panel banner and reaper protection require a rebuilt host. Building a driver does not update an already-running host or a system installation. Browser fetch cleanup protection runs in the new driver even when connecting to an older host.

The driver cannot validate the browser behind a standalone previously issued handoff URL on an older host; that host still controls the exchange and panel. Use the authenticated host health check or mint a fresh handoff with the new driver before opening it.