# Multi-engine routing

WebX treats a browser engine as replaceable execution infrastructure. The
control plane chooses the lowest-cost **compatible** backend while preserving
WebX policy, evidence, lifecycle, identity, quota, and human-control semantics.

This is intentionally different from treating every CDP-speaking product as
Chromium. Agent-first engines such as Kitesurf, Lightpanda, and Obscura can be
excellent for bounded extraction, but their CDP and Web Platform surfaces are
not interchangeable with full Chrome.

## Safety contract

1. The primary engine is used when a request declares no requirements and its
   launch configuration implies none. This preserves existing behavior.
2. Explicit `required_caps` are merged with requirements inferred from the
   authoritative launch configuration. Callers cannot omit capabilities to
   make WebX ignore a proxy, persistent profile, extension, custom binary, or
   high-assurance isolation request.
3. Only failures classified as pre-execution `capacity` or `unavailable` may
   try the next compatible engine.
4. Unknown and incompatible provisioning failures stop immediately.
5. WebX never replays an already-started browser task on another engine. That
   would duplicate side effects. A future runtime escalation feature must use
   checkpoints/effect contracts and explicit operator policy.
6. Engines that fail the startup live-conformance probe are not registered or
   advertised by `GET /api/engines`.

Every successful allocation exposes the selected engine, routing reason, and
redacted attempts in session metadata and the API response. WebX also emits an
`webx.engine-selection.v1` operational evidence event with
`runtimeFallbackAllowed: false` when the configured evidence store accepts it.

## Capability model

The engine profile separates one-shot rendering from full-browser behavior:

- DOM/WebMCP/accessibility/pixel perception modes;
- live screencast, screenshot, and PDF;
- proxy and authenticated `Fetch` interception;
- persistent contexts and long sessions;
- extensions and Selenium;
- WebGL, media, and downloads;
- launch-flag control and high-assurance isolation;
- real-browser fingerprint fidelity.

New fields deserialize to `false`. Older capability JSON therefore remains
readable and fails closed instead of receiving newly introduced powers.

Full Chromium enables the complete profile. A Kitesurf-class profile enables
one-shot DOM, screenshot, and PDF work but not persistent auth, Selenium,
extensions, media/WebGL, bot-sensitive fingerprint fidelity, or long sessions.
Live probes verify `Fetch.enable`, `Page.startScreencast`,
`Page.captureScreenshot`, and `Page.printToPDF`; unprobeable capabilities stay
bound to the known engine family.

## Registering engines

External unauthenticated DevTools discovery endpoints use:

```bash
WEBX_ENGINES="extract-a=http://10.0.0.21:9222;extract-b=http://10.0.0.22:9222"
```

Each direct endpoint is single-tenant because WebX does not control its process
or browser contexts. Register one endpoint per desired concurrent session.
Launch-time configuration is rejected on direct endpoints rather than ignored.

Cloudflare Browser Run/Kitesurf currently requires a provider-specific
authenticated CDP transport. Do not place credentials in `WEBX_ENGINES`. Add a
credential-vault-backed adapter, region policy, and tenant opt-in before using
it for customer traffic. Kitesurf is also beta; Chromium must remain the
full-fidelity route.

## API

`POST /api/sessions` accepts `required_caps`. Example one-shot screenshot:

```json
{
  "required_caps": {
    "screenshot": true
  }
}
```

The response reports what actually happened:

```json
{
  "engine": "extract-a",
  "routing_reason": "safe_allocation_fallback",
  "routing_attempts": [
    {"engine":"extract-b","outcome":"capacity"},
    {"engine":"extract-a","outcome":"selected"}
  ]
}
```

Browserbase-compatible responses expose the same fields under `webx`. The
engine label is operator configuration, while metrics normalize it to a bounded
family so arbitrary labels cannot create unbounded Prometheus cardinality.

## Observability

- `GET /api/engines` — registered, live-probed capability profiles.
- `webx_engine_selection_total{engine_family,reason}` — selected engines.
- `webx_engine_allocation_retry_total{engine_family,outcome}` — safe
  pre-execution capacity/unavailability retries.
- Evidence kind `engine_selection` — per-session operational explanation;
  session metadata remains the authoritative routing record.
- Admin Console → Engines — stateful/stateless posture and important
  capabilities.

## Production rollout

1. Keep Chromium primary.
2. Register a lightweight canary engine with isolated capacity.
3. Send only explicit DOM/screenshot/PDF workloads to it.
4. Compare success, wall time, cost, and fallback rate against Chromium using
   the scenario lab.
5. Maintain per-domain compatibility data. Do not infer universal
   compatibility from Web Platform Test counts.
6. Expand traffic only after the same verification contracts pass on both
   engines.
