# Session Identity Platform — WebX

**Document type:** Architecture + Product Intent + Implementation Record + Operational Runbook + Decision History  
**Status:** In Development (identity/network coherence platform landed on branch `codex/session-identity-platform`; default policy remains backward-compatible)  
**Engineering owner:** WebX platform / browser runtime team  
**Product owner:** WebX product (verified browser automation)  
**Repository:** `rust_mono_browser` (workspace members under `crates/`)  
**Production:** `https://webx.agentslab.host` (live data plane; identity policy env-gated)  
**Last materially reviewed:** 2026-08-10  
**Consumer portal:** `/docs/session-identity` (guide) · `/docs/session-identity-system-record` (this record) · catalog `/docs`  
**Schema versions:** `webx.session-identity.v1`, `webx.fingerprint.v1`, policy version `coherent-v1`  
**Canonical code:**  
- `crates/webx-server/src/session_identity.rs`  
- `crates/webx-server/src/proxy_manager.rs`  
- `crates/webx-server/src/contexts.rs`  
- `crates/webx-server/src/run_launch.rs`  
- `crates/webx-browser/src/stealth.rs`  
**Acceptance IDs:** UAT-047 … UAT-054 (`uat/manifest/v1/uat-manifest.json`)

---

## 0. Executive Summary

### What did we build?

A **Session Identity Platform** that composes browser fingerprint, managed proxy lease, geography, DNS mode, Chrome build, and persistence policy into one authoritative `SessionIdentity` document per session. Launch paths derive user-agent, locale, timezone, and egress from that structure instead of inventing independent facts. Persistent browser contexts store a **secret-free** `webx-network-identity.json` so cookie reuse also rebinds a compatible network family. Failover prefers minimum identity distance and **fails closed** when no safe route exists.

### Why does it exist?

Logged-in portal automation fails trust and reliability when the browser “looks like” one place (UA, timezone, locale) while traffic exits another (proxy country), or when a retained login context silently continues over a different egress IP family. Sites treat that as fraud or bot risk; operators cannot prove what identity was actually used. The platform makes identity **coherent, sticky, observable, and fail-closed** under opt-in policy.

### Who benefits?

| Actor | Benefit |
|---|---|
| **Primary — automation integrators** | Stable geo + fingerprint contracts for Playwright/Browserbase-compatible sessions and agent tasks |
| **Secondary — ops specialists running logged-in portals** | Sticky login contexts keep network identity beside cookies |
| **Operators** | Metrics, quarantine, drift detection without DB surgery |
| **Downstream trust layer** | Identity digests bound into run manifests / receipts |

### What changed?

**Before**  
Fingerprint patches, proxy leases, and persistent contexts were loosely coupled. Callers could request US proxy with a DE timezone; sticky contexts could reuse cookies while picking a different egress; failover could jump countries; receipts could not prove a coherent identity.

**After**  
`SessionIdentity::compose` is the single composition point. `WEBX_IDENTITY_POLICY=permissive|coherent|strict` controls fail-closed behavior (default **permissive** for backward compatibility). Managed proxy acquisition honors `preferred_lease_hash` and identity distance (`MAX_SAFE_IDENTITY_DISTANCE = 50`; country change costs 100 → always unsafe). Context reuse under coherent/strict requires a compatible managed lease when prior network identity is concrete. Post-egress observation re-validates without fabricating exit country.

### Current state

| Dimension | Status |
|---|---|
| Product maturity | **Beta** (platform primitives + UAT contracts; not a claim of anti-bot immunity) |
| Production usage | Live WebX deployment; identity policy env-gated; managed proxies opt-in via pool inventory |
| Reliability | Fail-closed on coherent/strict; permissive default preserves existing callers |
| Security review | Identity contracts forbid credential logging; secret-free provenance; no JA3 spoof / “undetectable” claims |
| Operational ownership | WebX platform team |
| Major known limitation | Probabilistic fingerprint simulation intentionally out of scope; external residential vendor adapters and full portable context v2 (object-store CAS) remain infrastructure-dependent |
| Next major decision | Default production policy: keep `permissive` vs promote `coherent` for high-assurance tenants |

### One-sentence architecture

**Client / agent task** → `run_launch` / Browserbase session create → **`SessionIdentity` compose + `ProxyManager.acquire`** → Chrome launch (fingerprint + profile dir) + egress lease → **observation / drift / provenance on run manifest** → durable logs & receipts.

---

## 1. Product Intent

Engineering decisions start with the outcome being created, not the technology selected.

### 1.1 Problem statement

**User problem**  
Operators running logged-in third-party portals (invoices, compliance, supplier systems without APIs) need a browser session that **stays the same person** across steps and restarts: same cookies, same geography, same browser surface — and honest failure when that cannot be guaranteed.

**Business problem**  
Without coherent identity, automation flunks anti-fraud checks, causes support load, and weakens WebX’s differentiator (verified, auditable runs). Competitors sell “browser infra”; WebX must sell **trustable identity + evidence**.

**Technical problem**  
Historically independent knobs (UA spoof, proxy pool, Chrome profile dir, DNS mode) could contradict each other. Failover and context reuse could silently change network identity. Secrets risked leaking into logs/receipts if identity snapshots were naïve.

**Why now?**  
Production authority hardening (2026-08-09), Browserbase-compatible session plane, managed proxy receipts, and multi-session persistent contexts made incoherent identity an unacceptable integrity hole before GA claims.

### 1.2 Target users / actors

| Actor | Goal | Pain today (without platform) | Expected value |
|---|---|---|---|
| **Aisha — API Integrator** | Create geo-pinned sessions via `/v1/sessions` with stable contracts | Contradictory UA vs proxy; silent geo downgrade | Fail-closed errors; proxy receipt; identity digests |
| **Maya — Accounts Payable Specialist** (via automation) | Complete portal workflows while logged in | Session “looks different” mid-run; forced re-login | Sticky context + network continuity |
| **Jordan — Platform Operator** | Detect bad egress / quarantine / drift without DB surgery | Opaque proxy failures; no identity metrics | Bounded Prometheus metrics; quarantine; fail-closed acquire |
| **Sam — Security / Compliance Reviewer** | Prove what identity a run used | No secret-free identity block on receipts | `provenance_block()` digests on run manifests |
| **Riley — Release Engineer** | Gate releases on identity invariants | Soft claims without tests | UAT-047..054 + cargo unit proofs |

---

## 2. Outcomes and Success Criteria

### 2.1 Product outcomes

| Outcome | Metric | Baseline | Target | Measurement source |
|---|---|---|---|---|
| Coherent sessions admit cleanly | Identity validation failure rate under `coherent` | Unmeasured (pre-platform) | Near-zero for correctly configured profiles | `webx_identity_validation_failures_total` |
| No silent geo downgrade | Managed lease rejects when inventory cannot satisfy geo | Silent wrong-country possible | 100% reject with `managed_proxy_unavailable` / fail-closed | Unit + UAT-048 |
| Sticky context continuity | Context reuse keeps compatible network family | Cookies only | Cookies + `webx-network-identity.json` rebinding | UAT-049, `contexts` tests |
| Operator-visible health | Proxy quarantine & acquire outcomes | Ad-hoc logs | Metric coverage without IP cardinality | `webx_proxy_*`, `webx_identity_*` |
| Release confidence | UAT-047..054 pass under local-deterministic / production profiles | Not in suite | Mandatory gates as tagged | `uat/manifest/v1/uat-manifest.json` |

### 2.2 Engineering outcomes

| Outcome | Measure | Target |
|---|---|---|
| Availability (identity path) | Composition + acquire on session create | Fail closed; do not admit contradictory identity under coherent/strict |
| Latency | Identity compose + local pool acquire | Negligible vs Chrome cold start (~2.5s); geo check is optional external RTT |
| Correctness | No fabricated `observedCountry` | Unverified → `null` / unevaluable |
| Recoverability | Identity-preserving failover | Prefer min `identity_distance`; country change never silent |
| Data durability | Context network identity on disk | Survive process restart for process-tier profiles |
| Deployment safety | Unknown `WEBX_IDENTITY_POLICY` | Admission fails closed via `try_from_env` |
| Cost efficiency | Network budget without price | `PricingUnevaluable` — no silent free ride |

### 2.3 Non-goals

- **NG-01** — Probabilistic fingerprint simulation, JA3/TLS stack spoofing, or “undetectable browser” marketing claims.  
- **NG-02** — Guaranteeing bypass of Cloudflare / reCAPTCHA / commercial bot-management (captcha path is separate).  
- **NG-03** — Portable persistent-context v2 (object storage, immutable CAS heads, cross-worker materialization) — listed as infrastructure-dependent.  
- **NG-04** — Replacing the verified-execution stack (`webx-verify`); identity is composition + evidence, not membrane.  
- **NG-05** — Inventing exit geography when geo-check is unconfigured or fails.  
- **NG-06** — Changing default policy to `coherent` for all existing tenants without an explicit product decision.

Non-goals prevent accidental architecture expansion.

---

## 3. Constraints

### Hard constraints

| Constraint | Source | Consequence |
|---|---|---|
| Backward-compatible default policy | Product / existing API clients | Default `IdentityPolicy::Permissive` |
| No second persistent datastore for identity MVP | Platform simplicity | Network identity lives beside context profile on disk (`webx-network-identity.json`); durable session catalogue remains SQLite/Postgres |
| Secrets never in receipts/logs/identity docs | Security | Only lease hashes, digests, sanitized network facts |
| Must work with existing auth (`x-api-key` / Bearer / Browserbase `X-BB-API-Key`) | Platform | Identity does not introduce a new auth plane |
| Must integrate with process-tier Chrome profiles | Orchestrator | Contexts meaningful under process orchestrator; shared-context tier accepts id without persistence effect |
| Production public bind policy | Runtime profiles | Production/high_assurance invariants still apply at process level |
| Metric label cardinality bounds | Ops | Exit IP and free-form domain must not appear as Prometheus labels |
| Fail closed on unknown identity policy in admission | Production safety | `IdentityPolicy::try_from_env` errors on unknown nonempty values |

### Soft constraints

- Prefer existing platform primitives (CDP stealth, proxy pool, context store, run manifests).  
- Prefer operational simplicity over theoretical multi-hop identity graphs.  
- Avoid a second fingerprint framework beside `FingerprintProfile`.  
- Prefer reversible decisions when evidence is incomplete (policy remains env-gated).  
- Prefer honest `null` / error over fabricated coherence.

---

## 4. System Invariants

| ID | Invariant | Enforcement |
|---|---|---|
| **INV-01** | Downstream launch paths must derive browser/network attributes from composed `SessionIdentity` (or explicit honest omission), not invent independent UA/geo/proxy facts | `session_identity` module contract; `run_launch` / `browserbase_compat` acquire path |
| **INV-02** | Fingerprint profiles must be internally coherent (`webx.fingerprint.v1`) before launch | `FingerprintProfile::validate`; invalid → no session |
| **INV-03** | Under coherent/strict, high-value contradictions fail closed (timezone vs country, locale vs country, mobile proxy + desktop UA, requested vs observed country) | `IdentityValidator` |
| **INV-04** | Observed exit country is never fabricated | Geo check unset/fail → `null`; qualification unevaluable |
| **INV-05** | Retrying/sticky acquire with `preferred_lease_hash` must not silently switch to an identity-distant route when fail-closed distance is required | `ProxyManager` + `MAX_SAFE_IDENTITY_DISTANCE` |
| **INV-06** | Country-changing failover is never silent under identity-preserving mode | Distance cost 100 > 50 threshold → `NoSafeFailover` |
| **INV-07** | Persistent context with concrete prior network identity cannot silently continue on direct/external/none egress under coherent/strict | `IdentityError::IdentityContinuity` |
| **INV-08** | Identity snapshots are secret-free (no proxy passwords, no credential-bearing URLs) | Type design + `bind_network_identity` refuse heuristic |
| **INV-09** | Prior context may inform preference/validation but must not copy `last_lease_hash` into a claim of an active lease on a new direct session | `SessionIdentity::compose` comments + logic |
| **INV-10** | Prometheus metrics omit exit IP and free-form domain labels | `metrics.rs` + UAT identity contracts |
| **INV-11** | Documentation / UAT IDs for identity cases remain UAT-047..054 | Manifest + `test_identity_network_contracts.py` |
| **INV-12** | Chrome major from live `Browser.getVersion` must match fingerprint major when both known and policy fail-closed | `validate_browser_product_against_profile` / stealth path |

When implementation changes, these invariants should survive.

---

## 5. Scope and System Boundary

### 5.1 In scope

- Composition and validation of `SessionIdentity`  
- Fingerprint profile schema and CDP application (UA, UA-CH, platform, locale, timezone, viewport, hardware, WebGL)  
- Managed proxy inventory, lease, sticky key, health quarantine, identity-distance failover  
- Post-egress observation and drift detection  
- Persistent context network identity bind/load  
- Provenance digests on run launch / run manifest  
- Metrics and UAT contracts for the above  
- Integration with agent task launch and Browserbase-compatible session create  

### 5.2 Out of scope

- LLM ODEV loop internals (owned by `webx-agent`)  
- Membrane / confirmation / receipts crypto (owned by `webx-verify` / receipt signing)  
- Full multi-region control plane topology (see `docs/MULTI_REGION.md`)  
- Captcha solving product claims (see `docs/CAPTCHA.md`)  
- Residential ISP vendor commercial SLAs  
- WebDriver BiDi completeness  
- Tenant SSO lifecycle (OIDC/SAML/SCIM) beyond using existing project API keys  

### 5.3 Context diagram

```
                 ┌──────────────────────────┐
                 │ Integrator / Agent task  │
                 └────────────┬─────────────┘
                              │ REST / WS / MCP
                              ▼
              ┌───────────────────────────────┐
              │        webx-server            │
              │  Auth → run_launch / BB API   │
              │                               │
              │  ┌─────────────────────────┐  │
              │  │ Session Identity        │  │
              │  │ Platform boundary       │  │
              │  │  compose / validate     │  │
              │  │  ProxyManager.acquire   │  │
              │  │  ContextStore bind/load │  │
              │  └───────────┬─────────────┘  │
              └──────────────┼────────────────┘
                  │          │           │
         ┌────────▼──┐  ┌────▼─────┐  ┌──▼──────────────┐
         │ Profile   │  │ Proxy    │  │ Chrome (CDP)    │
         │ disk      │  │ inventory│  │ stealth apply   │
         │ contexts/ │  │ + geo    │  │ process tier    │
         └───────────┘  └──────────┘  └─────────────────┘
                  │
                  ▼
         Run manifest / receipts / metrics / session logs
```

### 5.4 Ownership boundaries

| Responsibility | Owner |
|---|---|
| UI (console / live view) | WebX server frontend surfaces (consumes session metadata; not identity composer) |
| API (session/task create) | `webx-server` HTTP / Browserbase compat |
| Domain rules (coherence, distance, continuity) | `session_identity` + `proxy_manager` |
| Persistent context files | `contexts` + process orchestrator profile dirs |
| Durable session catalogue | `SessionStore` / repositories (SQLite or Postgres) |
| Infrastructure (k8s, pool, Postgres) | Platform / ops |
| Monitoring | Platform (Prometheus rules in `ops/`) |
| Incident response | Platform on-call |
| Product decisions (default policy, geo product) | Product + engineering |

Ambiguous ownership is an operational defect — identity composition is **not** owned by the LLM agent.

---

## 6. Architecture

### 6.1 Repository architecture

```
rust_mono_browser/
├── crates/
│   ├── webx-server/          # API, SessionIdentity, ProxyManager, ContextStore, launch
│   │   ├── src/
│   │   │   ├── session_identity.rs   # canonical identity domain
│   │   │   ├── proxy_manager.rs      # lease, health, failover, inventory
│   │   │   ├── contexts.rs           # persistent profile + network identity files
│   │   │   ├── run_launch.rs         # compose + acquire on task launch
│   │   │   ├── browserbase_compat.rs # /v1/sessions path
│   │   │   ├── run_manifest.rs       # provenance binding
│   │   │   ├── metrics.rs            # proxy/identity golden metrics
│   │   │   └── stealth applied via webx-browser
│   │   ├── migrations/postgres/
│   │   └── tests/
│   ├── webx-browser/         # CDP, FingerprintProfile, apply_stealth
│   ├── webx-agent/           # ODEV loop (consumer of launched session)
│   ├── webx-verify/          # membrane / txlog / receipts (adjacent)
│   ├── webx-orchestrator/    # process tier profiles, engines
│   └── …
├── clients/                  # py / ts SDK surfaces
├── docs/                     # this record, MANAGED_PROXIES, UAT_RUNBOOK, …
├── uat/
│   ├── manifest/v1/uat-manifest.json   # UAT-047..054
│   ├── contracts/test_identity_network_contracts.py
│   └── runner/
├── ops/                      # backup, SLO rules, single-node manifests
├── k8s/                      # enterprise / egress proxy examples
└── scripts/                  # live UAT / production regression helpers
```

### 6.2 Runtime architecture

```
Request (task or /v1/sessions)
   │
   ▼
┌────────────┐
│ Edge/Auth  │  x-api-key / Bearer / X-BB-API-Key
└─────┬──────┘
      │
      ▼
┌──────────────────┐
│ Launch handler   │  run_launch / browserbase_compat
└──────┬───────────┘
       │
       ├─ load prior ContextNetworkIdentity (if contextId)
       ├─ ProxyManager.acquire(LeaseRequest{ geo, sticky, preferred_lease_hash, budget })
       ├─ SessionIdentity::compose(…)
       ├─ IdentityValidator (policy fail-closed?)
       │
       ▼
┌────────────────┐
│ Domain service │  identity + lease + provenance
└───┬─────────┬──┘
    │         │
    ▼         ▼
┌───────┐  ┌──────────────────┐
│Context│  │ Chrome process   │
│ disk  │  │ CDP + stealth    │
└───────┘  └────────┬─────────┘
                    │ optional geo-check through proxy
                    ▼
             apply_post_egress / drift
                    │
                    ▼
         Events / Metrics / Run manifest / Logs
```

### 6.3 Request / workflow lifecycle (sticky geo session)

1. Integrator creates session with managed proxy geo + optional `contextId` / sticky key.  
2. Auth validates API key / project scope.  
3. Handler loads prior `webx-network-identity.json` if context exists.  
4. `ProxyManager.acquire` selects inventory entry: prefer `preferred_lease_hash`, else sticky key, else geo/type match; quarantine unhealthy; enforce capacity and network budget.  
5. If identity-preserving failover required and no candidate within distance ≤ 50 → `NoSafeFailover` / HTTP error.  
6. `SessionIdentity::compose` builds secret-free identity; validates fingerprint schema; applies continuity rules vs prior.  
7. Under coherent/strict failures → reject admission (`invalid_identity_policy` / coherence errors mapped to 400-class).  
8. Chrome launches with profile dir + fingerprint applied via `apply_stealth`.  
9. Optional egress verification updates `observation.country` via `apply_post_egress` (never invents).  
10. Context bind writes network identity snapshot; run manifest records digests.  
11. Telemetry increments acquire / validation metrics (bounded labels).  
12. On teardown, lease released; proxy receipt cleared; profile flush on release paths.  
13. Failure recovery: quarantine bad endpoints; do not silent country hop; operator re-runs with corrected pool/geo.

This section should make it possible to debug the system without reading every source file.

---

## 7. Data Model

### 7.1 Core entities

| Entity | Purpose | Identity | Lifecycle owner |
|---|---|---|---|
| `SessionIdentity` | Authoritative browser+network composition for one session | `sid_<uuid>` or supplied id; schema `webx.session-identity.v1` | `session_identity` / launch |
| `FingerprintProfile` | Immutable coherent browser surface | Content digest via profile JSON; schema `webx.fingerprint.v1` | Env `WEBX_FINGERPRINT_PROFILE_JSON` or request path |
| `ContextNetworkIdentity` | Sticky secret-free network snapshot on a context | `identity_id` + `profile_digest` | `ContextStore` |
| `Lease` / lease hash | Managed proxy allocation | One-way `leaseHash` | `ProxyManager` |
| `NetworkObservation` | Observed exit facts | Optional IP/ASN/country; DNS flags | Post-egress checks |
| `Proxy inventory entry` | Operator pool config | server + geo + optional ASN/type/pricing | Env / file / signed URL inventory |
| Run manifest identity block | Evidence for audit | digests only | `run_manifest` / receipts |

### 7.2 State transitions

**Identity composition**

```
REQUESTED
   │
   ▼
COMPOSE (fingerprint validate)
   │
   ├──── invalid fingerprint ────► REJECTED
   │
   ▼
VALIDATE (coherence / continuity / DNS)
   │
   ├──── policy permissive ──► ADMITTED (findings may exist)
   ├──── policy fail-closed + findings ──► REJECTED
   │
   ▼
LEASED (managed) / DIRECT
   │
   ▼
OBSERVED (optional geo-check)
   │
   ├──── strict + missing verified country ──► REJECTED
   ├──── country mismatch (coherent/strict) ──► REJECTED
   │
   ▼
BOUND_TO_CONTEXT (optional)
   │
   ▼
ACTIVE_SESSION
   │
   ├──── drift detected ──► DRIFT_FLAGGED / fail-closed per policy
   │
   ▼
RELEASED (lease cleared, profile flush)
```

| State | Meaning | Allowed transitions |
|---|---|---|
| REQUESTED | Inputs assembled | → COMPOSE |
| COMPOSE | Building structure | → VALIDATE, REJECTED |
| VALIDATE | Deterministic checks | → LEASED/DIRECT, REJECTED |
| OBSERVED | Post-egress facts applied | → BOUND, ACTIVE, REJECTED |
| ACTIVE_SESSION | Browser running | → DRIFT_FLAGGED, RELEASED |
| REJECTED | Fail-closed admission/runtime | terminal for that attempt |
| RELEASED | Teardown complete | terminal |

Illegal transitions should be impossible at the type/API boundary (compose returns `Result`, acquire returns `ProxyError`).

### 7.3 Data ownership

| Field / artifact | Creates | Mutates | Consumes | Retention | Sensitive? | Schema change |
|---|---|---|---|---|---|---|
| Fingerprint profile | Operator / env | Immutable per run | Stealth, validator | Config lifetime | Low (public browser claims) | Version `webx.fingerprint.v1` |
| Proxy credentials | Operator inventory | Inventory refresh | Launch args only | Secret store | **Yes** | Never copy into identity JSON |
| `leaseHash` | ProxyManager | Per lease | Receipts, preferred reacquire | Session lifetime | Low (one-way) | Hash versioned prefix |
| `observedCountry` | Geo-check through proxy | `apply_post_egress` | Validator, receipt | Session / logs | Medium (geo) | Honest null allowed |
| Exit IP | Observation | Drift compare | Logs (controlled); **not** metrics labels | Short | Medium | Do not label-metric |
| `webx-network-identity.json` | bind on success | Rebind on reuse | Next launch | With context dir | Secret-free by construction | Additive fields preferred |
| Identity digests | `digest()` / provenance | Immutable for run | Manifests, auditors | With run evidence | Low | Schema version in material |

---

## 8. API / Contract Design

### Stable interfaces (identity-relevant)

| Interface | Role |
|---|---|
| `POST /api/tasks` | Agent task launch; identity composed in `run_launch` |
| `POST /v1/sessions` | Browserbase-compatible session create; proxies + context |
| `GET /v1/sessions/:id` | Returns proxy receipt fields when managed lease present |
| Context APIs / launch fields using `contextId` | Sticky profile + network identity |
| Env: `WEBX_IDENTITY_POLICY`, `WEBX_FINGERPRINT_PROFILE_JSON`, `WEBX_PROXY_*` | Operator contracts |
| Run manifest / receipt identity provenance block | Audit consumers |

### Managed proxy request (Browserbase-shaped)

```jsonc
// POST /v1/sessions
{
  "proxies": [
    {
      "type": "webx",
      "geolocation": { "country": "US", "state": "CA", "city": "SAN_FRANCISCO" },
      "rotation": "per_session",
      "stickyKey": "login-flow-7"
    }
  ]
}
```

External proxy still supported verbatim (`type: external`).

### Contract concerns

| Concern | Definition |
|---|---|
| Authentication | `x-api-key`, `Authorization: Bearer`, or `X-BB-API-Key`; query `token` for WS only |
| Authorization | Project-scoped keys / existing RBAC; identity does not bypass tenancy |
| Request schema | Proxies array; optional fingerprint via deployment env; contextId for stickiness |
| Response schema | Session id + optional `proxy` receipt (`provider`, `requestedGeo`, `observedCountry`, `leaseHash`, `bytes`, `rotationPolicy`) |
| Error contract | `400 managed_proxy_unavailable`, invalid identity policy, coherence failures; no silent geo rewrite |
| Idempotency | Retained browser continuations made idempotent on branch; preferred lease hash reacquire |
| Pagination | N/A for identity compose |
| Rate limit | Session concurrency caps (`WEBX_MAX_CONCURRENT_SESSIONS`); proxy `maxSessions` |
| Compatibility policy | Default permissive; coherent/strict opt-in; fingerprint schema versioned |

### Error semantics (identity / proxy)

| Error | Meaning | Retry? | User action |
|---|---|---|---|
| 400 invalid fingerprint / coherence | Profile or geo/timezone contradiction | No | Fix profile / geo / policy |
| 400 managed_proxy_unavailable | No healthy inventory match | Maybe later | Fix pool / geo / wait quarantine |
| 400 / mapped NoSafeFailover | No identity-safe alternate route | No (without policy change) | Fix inventory or accept new identity |
| 400 identity_continuity | Sticky context needs compatible managed lease | No | Request managed proxy matching prior |
| 401 | Auth required | No | Authenticate |
| 403 | Not authorized | No | Request access |
| 429 / capacity | Session or proxy capacity | Yes | Back off |
| 5xx | Server / dependency failure | Usually | Retry / escalate |

Domain codes include: `invalid_identity_policy`, `identity_continuity`, `identity_drift`, `proxy_geo_unverified`, `no_safe_failover`, `managed_proxy_unavailable`.

---

## 9. Critical User Journeys

### Journey J-01 — Geo-pinned Browserbase session

| | |
|---|---|
| **Actor** | Aisha — API Integrator |
| **Trigger** | `POST /v1/sessions` with managed US proxy |
| **Before** | Session might launch with mismatched locale/timezone or wrong egress |
| **Happy path** | 1) Auth OK → 2) Acquire US lease → 3) Compose identity → 4) Launch Chrome + stealth → 5) Optional geo-check records observed US → 6) Response includes proxy receipt |
| **Expected outcome** | Ready `connectUrl` + coherent identity evidence |
| **Failure paths** | Auth fails → 401; no US inventory → 400 unavailable; geo mismatch under coherent → reject; geo-check down under strict → geo unverified |
| **Evidence** | UAT-047, UAT-048; unit tests in `session_identity` / `proxy_manager` |
| **Telemetry** | `webx_proxy_acquire_total`, `webx_identity_validation_failures_total` |
| **Demo** | `docs/BROWSERBASE_MIGRATION.md`, `docs/MANAGED_PROXIES.md` |

### Journey J-02 — Persistent login context with network continuity

| | |
|---|---|
| **Actor** | Maya (via automation) / integrator reusing `contextId` |
| **Trigger** | Second session with same context after successful login |
| **Before** | Cookies restored but egress identity could change → site re-challenges |
| **Happy path** | 1) Load prior network identity → 2) Acquire with `preferred_lease_hash` → 3) Continuity validation passes → 4) Rebind snapshot → 5) Continue logged-in workflow |
| **Expected outcome** | Same network family + cookies |
| **Failure paths** | Prior concrete network + no managed lease under coherent → `IdentityContinuity`; country jump → drift fail-closed |
| **Evidence** | UAT-049; `contexts` isolation tests; scripts `uat_persistent_context_workflow.py` |
| **Telemetry** | `webx_identity_drift_total` |

### Journey J-03 — Identity-preserving proxy failover

| | |
|---|---|
| **Actor** | Jordan — Platform Operator / system self-heal |
| **Trigger** | Preferred endpoint quarantined (health / geo mismatch) |
| **Before** | Failover might pick another country |
| **Happy path** | Select min-distance healthy route within budget; continue |
| **Expected outcome** | Session survives without country hop |
| **Failure paths** | Only far candidates → `NoSafeFailover` (honest) |
| **Evidence** | UAT-050; `identity_preserving_failover` cargo test |

### Journey J-04 — Cross-context isolation

| | |
|---|---|
| **Actor** | Sam — Security reviewer |
| **Trigger** | Two contexts A/B with different bound identities |
| **Happy path** | Separate dirs; separate `webx-network-identity.json`; digests differ |
| **Expected outcome** | No identity cross-talk |
| **Evidence** | UAT-054; `two_contexts_produce_isolated` |

---

## 10. Non-Functional Requirements

### 10.1 Reliability

| Item | Target / statement |
|---|---|
| Availability target | Identity path must not silently degrade correctness; prefer refuse-over-lie under coherent/strict |
| Maximum tolerable data loss | Losing a live browser kills the session (design); durable audit should survive; network identity file loss → lose stickiness, not invent new coherence |
| Maximum tolerable recovery time | Session-level: retry new session; pool quarantine temporary |
| Dependency failure behavior | Geo-check failure → honest null; inventory empty → unavailable; Chrome product mismatch → fail-closed when policy requires |

### 10.2 Performance

| Operation | p50 | p95 | p99 | Maximum acceptable |
|---|---|---|---|---|
| Identity compose + validate | <1 ms (CPU) | <5 ms | <10 ms | Dominated by Chrome start |
| Proxy acquire (in-process static pool) | <5 ms | <20 ms | <50 ms | Inventory lock contention rare |
| Geo-check HTTP (optional) | ~100–400 ms | <1 s | <2 s | Must not block forever; timeout per client defaults |
| Full session cold start | ~2.5 s (engine cold_start_ms) | higher under load | — | Browser-bound |

**Scale assumptions**

| Assumption | Value / note |
|---|---|
| Concurrent sessions | POC ~4; enterprise N × cap or browser pool (see `docs/SCALING.md`) |
| Objects/day | Operator-dependent; enterprise 10s–100s concurrent high-value workflows, not consumer 1000s |
| Largest identity artifact | Fingerprint JSON + small network identity file (KB-scale) |
| Expected growth | Proxy inventory size and sticky keys grow with tenants |

### 10.3 Scalability

| Item | Statement |
|---|---|
| Current practical limit | Single-node process-tier browsers; in-process proxy health state |
| First bottleneck | Chrome processes / CDP, not identity compose |
| Next bottleneck | LLM step rate for agent tasks; proxy vendor capacity for managed egress |
| Horizontal scaling | API replicas + browser pool; identity files need shared volume or future context v2 for multi-worker stickiness |
| Partitioning | Context ids under profile root; project_id in durable store |
| When redesign becomes necessary | Multi-worker sticky context without shared FS; multi-region sticky egress SLAs |

### 10.4 Availability vs consistency

**This workflow prefers consistency (coherence) of browser+network identity over availability of “any browser that starts.”**  

Under `coherent`/`strict`, WebX will refuse a session rather than admit a contradictory identity. Under default `permissive`, availability of existing clients is preferred and findings do not block admission.

---

## 11. Failure Model

### Failure analysis

| Failure | Detection | User impact | Recovery | Prevention |
|---|---|---|---|---|
| Proxy dependency / endpoint down | Health check, transport failures, quarantine | Acquire fails or failover | Prefer sticky; else min distance; else fail closed | Inventory redundancy same country |
| Geo mismatch | Observed vs requested country | Reject under coherent/strict | Fix inventory / geo-check | Fail closed; quarantine endpoint |
| DB unavailable | Store errors on durable paths | Status/audit degraded; live session may continue in-memory | Fail readiness in multi-replica | Postgres HA (operator) |
| Partial launch (lease ok, Chrome fail) | Launch error path | Session not ready; lease should release on teardown paths | Retry session | Idempotent release |
| Duplicate / sticky reacquire | preferred lease hash | Same egress when healthy | Fallback min distance | Unit tests preferred_lease_hash |
| Bad deploy (bad fingerprint JSON) | Profile validate at launch | All profiled sessions fail | Rollback env / image | Startup checks; UAT |
| Identity continuity violation | Validator | Context reuse rejected | Request compatible managed proxy | Document sticky contract |
| DNS leak signal | `local_dns_used` + proxy DNS mode | Strict/coherent fail | Fix proxy mode (SOCKS remote DNS) | DnsMode inference + validation |
| Network budget without prices | PricingUnevaluable | Acquire reject | Add inventory pricing or drop budget | Cost-aware scheduling tests |

### Partial failure specifics

| Scenario | Behavior |
|---|---|
| Database succeeds but external geo-check fails | Persist session without fabricated country; strict may fail if verification required after observation attempt |
| Geo-check succeeds but response lost | Treat as unverified; do not echo request country as observed |
| Worker crashes mid-session | Live browser ownership lost → unrecoverable live session by design; audit may remain if durable |
| Client retries after timeout | Prefer idempotent continuation / same session id where supported; new session gets new identity compose |
| Two actors mutate same context | Last bind wins on file write; isolation is per context id, not multi-writer CRDT |
| Old and new app versions simultaneous | Schema versions on identity/fingerprint; additive fields; unknown policy fails closed on admission |

### Retry behavior

| Class | Policy |
|---|---|
| Retryable | Transient proxy transport; capacity 429; temporary quarantine expiry |
| Not retryable | Coherence contradiction; invalid fingerprint; identity continuity without managed lease; no safe failover |
| Backoff | Client/standard; pool quarantine temporary exclusion |
| Maximum attempts | Session-level product timeouts (`timeout`); not infinite acquire loops |
| Dead-letter / manual recovery | Operator fixes inventory; release stuck sessions; restore context from backup if profile dir lost |

---

## 12. Security and Privacy

### Threat model — assets

- Proxy credentials (inventory secrets)  
- Customer cookies / logged-in portal state (context profiles)  
- Session tokens / API keys  
- Network observations (exit IP, ASN, country)  
- Fingerprint profiles (deployment config)  
- Run artifacts (screenshots, logs, receipts)  

### Threats

| Threat | Mitigation |
|---|---|
| Unauthorized cross-tenant access | Existing project authz; context path traversal hardening (`is_safe_id`) |
| Privilege escalation | Identity does not grant new roles |
| Injection | Typed JSON schemas; deny_unknown_fields on fingerprint |
| Secret leakage | Secret-free identity types; receipts use lease hash; bind refuses password-like payloads |
| Sensitive logs | Controlled fields; no proxy passwords in receipts |
| Replay of lease credentials | Credentials not in client-visible identity docs |
| Enumeration | Standard auth on APIs |
| Insecure direct object reference | Context ids unguessable UUIDs + authz on session APIs |
| Dependency compromise | `deny.toml` / supply chain practices at workspace level |

### Trust boundaries

```
Browser / integrator client
   │ UNTRUSTED
   ▼
Public API (auth required)
   │ authenticated boundary
   ▼
webx-server application (compose, acquire, launch)
   │ controlled boundary
   ▼
Chrome process / proxy egress / disk profiles / Postgres
```

Never trust client-side enforcement as authorization. Never treat client-supplied “observed country” as verified without server-side check.

### Security controls

| Concern | Control |
|---|---|
| Authentication | API keys / Bearer / BB key |
| Authorization | Project-scoped resources |
| Secret storage | Inventory env/files/secrets; not git |
| Encryption in transit | TLS at ingress (`https://webx.agentslab.host`) |
| Encryption at rest | Operator/Postgres volume policy |
| Tenant isolation | project_id + context path isolation |
| Audit logging | Session logs, identity provenance digests, proxy receipts |
| Input validation | Fingerprint validate; geo normalize; policy parse fail-closed |
| Dependency security | Workspace deny / CI |

### Sensitive-data rule

Treat as potentially public if placed in: browser bundle, public/, frontend env, public repository, downloadable artifacts, client-visible logs.  
**Therefore:** proxy passwords and raw authenticated proxy URLs never appear in `SessionIdentity`, receipts, or `webx-network-identity.json`.

---

## 13. Observability

### 13.1 Logs

Logs should answer: what happened, for which request/session/project, which component (compose/acquire/stealth), duration, retry/quarantine, error code, correlation across services.

Recommended context fields: `request_id`, `session_id`, `project_id` / tenant, `operation`, `duration_ms`, `result`, `error_code`, `proxy_provider` (not password), `identity_policy`, `lease_hash` (not credentials).

**Never log secrets.** Exit IPs only in controlled durable fields, not high-cardinality metrics.

### 13.2 Metrics

**Golden / identity platform metrics (bounded labels):**

| Metric | Purpose |
|---|---|
| `webx_proxy_leases_active` | Saturation |
| `webx_proxy_acquire_total` | Traffic / outcomes |
| `webx_proxy_connection_failures_total` | Errors |
| `webx_proxy_geo_mismatch_total` | Correctness |
| `webx_proxy_http_status_total` | Dependency health |
| `webx_identity_validation_failures_total` | Policy enforcement |
| `webx_identity_drift_total` | Long-run continuity |
| `webx_sessions_by_proxy_type` | Product mix |
| `webx_network_cost_microusd_total` | Cost |
| `webx_identity_audit_event_total` | Audit volume |

Platform SLO rules (`ops/webx-slo-rules.yaml`) also page on durable terminal, verified receipt integrity, and correctness invariants for the broader WebX runtime.

### 13.3 Tracing

Important spans: request auth → identity compose → proxy acquire → Chrome launch → stealth apply → geo-check → bind context → run loop.

### 13.4 Alerts

| Alert | Trigger | User impact | Owner | First action |
|---|---|---|---|---|
| Proxy acquire failure spike | Elevated `webx_proxy_acquire_total{result=error}` | Sessions cannot start with managed geo | Platform | Check inventory health / vendor |
| Geo mismatch storm | `webx_proxy_geo_mismatch_total` rising | Fail-closed rejects / quarantine thrash | Platform | Validate geo-check URL + pool geo labels |
| Identity validation failures | Failures under coherent/strict | Admission rejects | Platform + integrators | Inspect fingerprint vs geo configs |
| Identity drift | `webx_identity_drift_total` | Sticky sessions breaking site trust | Platform | Check failover distance / vendor rotation |
| WebXDurableTerminalSLOBurn | SLO rule | Runs accept but lack durable terminal | Platform | See `ops/webx-slo-rules.yaml` |

Avoid alerts that only say “CPU > 80%” without user impact.

---

## 14. Testing Strategy

### Testing pyramid / portfolio

| Layer | What it proves | Where |
|---|---|---|
| Static analysis | Structural correctness | `cargo fmt`, clippy / workspace CI |
| Unit | Coherence, distance, continuity, quarantine, budgets | `session_identity`, `proxy_manager`, `contexts`, `stealth` |
| Contract | Source surface + UAT ID presence | `uat/contracts/test_identity_network_contracts.py` |
| Integration | Launch paths call `.acquire(` / LeaseRequest | run_launch + browserbase_compat string/unit proofs |
| E2E / live scripts | Persistent context, selenium login, diagnostics | `scripts/uat_*.py`, production regressions |
| Load | Capacity | `production_capacity_regression.py` |
| Failure injection | Quarantine / no safe failover | unit tests |
| Security | Secret-free provenance; no banned marketing language | identity contracts |
| Production smoke | Deployed candidate evaluation | `webx-eval`, release workflows |

### Critical test catalog

| ID | Scenario | Risk covered |
|---|---|---|
| **UAT-047** | Identity consistency (browser + network composition) | INV-01..03 |
| **UAT-048** | Proxy country enforcement and geo fail-closed | INV-04, silent geo |
| **UAT-049** | Sticky identity across persistent context reuse | INV-07, INV-08 |
| **UAT-050** | Failover minimizes identity distance; fails closed | INV-05, INV-06 |
| **UAT-051** | DNS mode coherence and leak fail-closed | DNS leak |
| **UAT-052** | Exit-IP / identity drift detection | Long-run drift |
| **UAT-053** | Proxy health quarantine | Bad endpoint exclusion |
| **UAT-054** | Cross-context identity separation | Isolation |
| TC-unit | `detect_drift_flags`, `preferred_lease_hash`, `identity_preserving_failover`, `network_budget_without_price`, `capacity_is_enforced_at_register`, `two_contexts_produce_isolated` | Implementation proofs |

### Test-source-of-truth rule

| Kind | Path |
|---|---|
| Canonical UAT IDs | `uat/manifest/v1/uat-manifest.json` |
| Harness contracts | `uat/contracts/` |
| Domain unit tests | `crates/webx-server/src/session_identity.rs` (inline), `proxy_manager.rs`, `contexts.rs` |
| Docs mirror | `docs/MANAGED_PROXIES.md`, this system record, `docs/UAT_RUNBOOK.md` |
| Production authority | `docs/PRODUCTION_AUTHORITY_HARDENING_2026-08-09.md` |

Synchronization: UAT contracts assert source tokens and run focused cargo tests; do not re-implement WebX in Python toys.

---

## 15. Architecture Alternatives

### Option A — Independent knobs (status quo ante)

**Advantages:** Simple; maximum caller freedom.  
**Disadvantages:** Contradictions; silent trust failures; weak audit.  
**When it wins:** Throwaway scrapes with no login stickiness.

### Option B — Unified SessionIdentity composition (chosen)

**Advantages:** Single source of truth; policy ladder; secret-free evidence; sticky continuity; distance-bounded failover.  
**Disadvantages:** More code paths; operators must configure inventory/geo-check for full value; default permissive still allows weak mode.  
**When it wins:** Logged-in, geo-sensitive, auditable automation (WebX’s market).

### Option C — Full probabilistic anti-detect browser farm

**Advantages:** Marketing appeal.  
**Disadvantages:** Arms race, legal/ToS risk, unprovable claims, huge maintenance.  
**When it wins:** Not aligned with WebX “honest verification” positioning.

### Decision matrix

| Criterion | Weight | A Independent | B Unified identity | C Anti-detect farm |
|---|---|---|---|---|
| Product fit (trustable automation) | High | Low | **High** | Misleading high |
| Reliability / honesty | High | Low | **High** | Low (opaque) |
| Simplicity | Medium | **High** | Medium | Low |
| Delivery speed | Medium | High | Medium | Low |
| Operating cost | Medium | Low | Medium | High |
| Reversibility | Medium | High | **High** (policy env) | Low |

**Selected:** Option B with policy ladder and explicit non-goals against Option C claims.

---

## 16. Decision Log

### ADR-001 — Unified SessionIdentity as composition root

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Fingerprint, proxy, and context were independent and could contradict |
| **Decision** | Introduce `SessionIdentity` + `IdentityValidator` as single composition point |
| **Alternatives** | Keep independent knobs; soft warnings only |
| **Why** | Trust layer requires evidence; fail-closed needs a single object to validate |
| **Consequences (+)** | Auditable digests; clearer launch code |
| **Consequences (−)** | Launch path complexity |
| **Reversibility** | Moderate (types wired into launch) |
| **Revisit when** | Schema needs multi-hop identity graphs or hardware-backed attestation |

### ADR-002 — Default policy permissive; coherent/strict opt-in

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Existing clients must not break on day one |
| **Decision** | `WEBX_IDENTITY_POLICY` default permissive; admission uses `try_from_env` fail-closed on unknown values |
| **Why** | Backward compatibility + safe misconfiguration detection |
| **Revisit when** | Majority of production tenants ready for coherent default |

### ADR-003 — Identity distance failover with hard country barrier

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Failover that changes country breaks sticky login trust |
| **Decision** | Weighted `identity_distance`; `MAX_SAFE_IDENTITY_DISTANCE = 50`; country delta = 100 |
| **Why** | Country changes must never be silent under identity-preserving mode |
| **Revisit when** | Product explicitly supports multi-country rotation policies |

### ADR-004 — Secret-free context network identity file

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Sticky network needed beside cookies without credential sprawl |
| **Decision** | `webx-network-identity.json` stores digests/preferences only |
| **Why** | Disk profiles are sensitive enough without proxy passwords |
| **Revisit when** | Portable context v2 encrypts blobs in object storage |

### ADR-005 — Honest null observed geography

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Temptation to echo requested country as observed |
| **Decision** | Never fabricate `observedCountry` |
| **Why** | Receipts must be evidence, not theater |
| **Revisit when** | N/A (invariant) |

### ADR-006 — No probabilistic anti-detect claims in identity modules

| | |
|---|---|
| **Status** | Accepted |
| **Context** | Market pressure to claim “undetectable” |
| **Decision** | Banned language in identity/proxy modules; UAT contract asserts absence |
| **Why** | Align with verified-execution product honesty |

---

## 17. Implementation Journey

### Phase 1 — Fingerprint foundation

| | |
|---|---|
| **Hypothesis** | Versioned fingerprint profile can bind UA/platform/locale/timezone consistently |
| **What we built** | `FingerprintProfile` (`webx.fingerprint.v1`), validation, stealth application, UA client hints binding |
| **Evidence** | `webx-browser` stealth tests; production authority doc |
| **Surprise** | Live Chrome major vs profile major must be checked after connect |
| **Mistake / limitation** | Profile alone does not fix network contradictions |
| **Decision** | Proceed to unified composition |
| **Lesson** | Validate against `Browser.getVersion`, not only config strings |

### Phase 2 — Managed proxy receipts & inventory

| | |
|---|---|
| **Hypothesis** | Leasing by geo + observed exit country creates real evidence |
| **What we built** | ProxyManager, inventory refresh, quarantine, proxy receipt, bandwidth metering |
| **Evidence** | `docs/MANAGED_PROXIES.md`; unit tests |
| **Surprise** | Sticky reuse and failover need identity distance, not only geo string match |
| **Lesson** | Fail closed when inventory cannot satisfy — never silent region downgrade |

### Phase 3 — SessionIdentity platform (this branch)

| | |
|---|---|
| **Hypothesis** | Composing browser + network + persistence policy closes the integrity hole |
| **What we built** | `session_identity.rs`, continuity enforcement, context bind/load, launch integration, metrics, UAT-047..054 |
| **Evidence** | Branch commits: coherent identities, persistent network continuity, profile flush, fingerprint major binding |
| **Surprise** | Prior context must not copy lease hash into “active lease” claims on direct sessions |
| **Mistake avoided** | Fabricating verified geography at lease time before egress check |
| **Lesson** | Continuity is a first-class error (`IdentityContinuity`), not a log line |

### Phase 4 — Operational hardening (ongoing)

| | |
|---|---|
| **Hypothesis** | Metrics + UAT gates make the platform operable |
| **What we built** | Bounded metrics; UAT contracts running cargo proofs; docs |
| **Remaining** | Promote coherent default carefully; portable context v2; multi-worker sticky storage |

---

## 18. Product Feedback Loop

| Feedback | Source | Interpretation | Change |
|---|---|---|---|
| “Sessions re-login randomly” | Operator anecdotes | Network identity changed beside cookies | Sticky `ContextNetworkIdentity` + preferred lease |
| “Proxy said US but site localized DE” | Support-style reports | Timezone/locale vs geo contradiction | Coherence checks timezone/locale vs country |
| “Just pick any proxy” | Integrator convenience | Conflicts with evidence product | Reject unavailable geo; no silent downgrade |
| “Don’t break our existing scripts” | Integrators | Need compatibility | Default permissive policy |
| Production audit findings | `COMPLEX_PRODUCTION_AUDIT` / authority hardening | Need release evidence | UAT expansion + fail-closed production coverage |
| What users said | Want “stealth that always works” | Overclaim risk | Explicit non-goals; banned marketing language |
| What telemetry will show | Validation failures / drift counters | Config quality vs code bugs | Operator runbooks for inventory/fingerprint |

---

## 19. Rollout Strategy

| Stage | Audience | Exit criteria |
|---|---|---|
| 0. Local / unit | Engineers | Cargo identity/proxy/context tests green |
| 1. UAT harness | CI / release eng | `python3 -m uat.runner --profile local-deterministic` includes UAT-047..054 contracts |
| 2. Internal dogfood | Platform team on staging/single-node | Managed pool configured; coherent policy manual tests |
| 3. Limited tenants | High-assurance customers opt-in `WEBX_IDENTITY_POLICY=coherent` | No unexpected admission regressions |
| 4. Percentage / cohort | Broader production | Metrics stable; support playbooks ready |
| 5. GA default reconsider | Product decision | Evidence that permissive default is the residual risk |

### Feature flag

| | |
|---|---|
| **Flag** | `WEBX_IDENTITY_POLICY` |
| **Default** | `permissive` (unset/empty) |
| **Scope** | Deployment / process environment |
| **Owner** | Platform engineering |
| **Removal plan** | Not a temporary flag — permanent policy ladder; “removal” means choosing a new default, not deleting the control |

Related flags: `WEBX_FINGERPRINT_PROFILE_JSON`, `WEBX_PROXY_POOL*`, `WEBX_PROXY_INVENTORY_*`, `WEBX_PROXY_GEO_CHECK_URL`.

---

## 20. Rollback Strategy

| Question | Answer |
|---|---|
| Can application code be rolled back? | Yes — standard image/deploy rollback |
| Can schema changes be rolled back? | Identity files are additive JSON; durable DB migrations follow expand/contract separately |
| Can previous version read new identity files? | Unknown fields may be ignored if serde allows; fingerprint uses `deny_unknown_fields` — pin schema carefully |
| Can the feature be disabled independently? | Yes — set `WEBX_IDENTITY_POLICY=permissive` and omit fingerprint/managed proxies |
| In-flight operations? | Running sessions keep their process; new admissions follow new binary/env |
| How do operators know rollback succeeded? | Health/ready; acquire success rate; absence of new identity failure spike |

**Rollback command (illustrative):** re-deploy previous `webx-server` image/tag; restore prior env ConfigMap/Secret; `kubectl -n webx rollout undo deploy/webx-api` (adjust to live manifests).

**Rollback validation:** `GET /health`, `GET /ready`; create a session without managed proxy; confirm permissive admission; check metrics not stuck failing.

---

## 21. Database / Schema Evolution

Identity platform MVP **does not require a new SQL table** for `SessionIdentity`; sticky network identity is a file beside the Chromium profile. Durable session catalogue remains in SQLite/Postgres (`sessions`, logs, etc.).

| Evolution concern | Guidance |
|---|---|
| Additive JSON fields on `ContextNetworkIdentity` | Preferred |
| Fingerprint schema bump | New `webx.fingerprint.vN` with explicit support window |
| Session identity schema bump | New `webx.session-identity.vN` |
| Simultaneous old/new binaries | Keep digests version-prefixed (`webx.session-identity.v1\0`) |
| Backfill | None for files; missing file ⇒ no prior network |
| Failed halfway write | Small JSON replace; next bind overwrites |
| Postgres HA | Operator-owned (enterprise manifest requires external HA) |

Prefer expand → observe → contract for any future SQL-backed identity catalogue.

---

## 22. Capacity Planning

### Current load (qualitative)

| Dimension | Note |
|---|---|
| Concurrent sessions | Deployment-dependent (POC 4; scale per `docs/SCALING.md`) |
| Identity CPU | Negligible |
| Proxy inventory size | 10s–100s entries typical for static pools |
| Geo-check QPS | One per lease verification (optional) |
| Disk | Profile dirs dominate; identity JSON trivial |

### Expected growth

| Horizon | Driver |
|---|---|
| 3 months | More managed geo tenants; coherent opt-in |
| 12 months | Multi-replica sticky contexts may force shared storage / context v2 |
| 24 months | Multi-region sticky egress productization |

### Resource bottlenecks

| Resource | Current | Limit | Headroom |
|---|---|---|---|
| Chrome processes | Primary cost | Node memory/CPU | Scale browser pool |
| Proxy vendor capacity | External | Vendor contract | Multi-provider inventory |
| Geo-check API | Optional dependency | Provider rate limits | Cache carefully without lying |
| Profile disk | Grows with contexts | Volume size | Retention / flush on release |

---

## 23. Cost Model

| Unit | Drivers |
|---|---|
| Cost / session | Chrome runtime + LLM (agent) + proxy bandwidth/time |
| Cost / managed lease | Vendor `pricePerSession` / GB / minute when configured |
| Cost / identity feature itself | Near-zero compute; engineering cost is correctness |
| Network budget | `network_usd` / microusd metering; unknown pricing → unevaluable fail |

Architecture choice: **pay for honest managed egress + browser time**, not for fake fingerprint entropy.

---

## 24. Dependencies

| Dependency | Purpose | Failure mode | Ownership |
|---|---|---|---|
| Chrome / Chromium process tier | Browser | Session fail | WebX image pin |
| CDP | Control | Launch/control fail | webx-browser |
| Proxy inventory / vendor | Egress | Unavailable / quarantine | Operator |
| Geo-check URL | Observed country | null / strict fail | Operator config |
| Disk profile volume | Contexts | Lose stickiness | Ops |
| Postgres (multi-replica) | Durable catalogue | Readiness fail closed | Ops |
| LLM provider | Agent decide (not identity core) | Task fail | Config |

---

## 25. Configuration Reference

| Variable | Meaning | Default |
|---|---|---|
| `WEBX_IDENTITY_POLICY` | `permissive` \| `coherent` \| `strict` | permissive |
| `WEBX_FINGERPRINT_PROFILE_JSON` | Immutable fingerprint profile JSON | unset |
| `WEBX_PROXY_POOL` / `_FILE` | Legacy static pool JSON | unset (managed opt-in) |
| `WEBX_PROXY_INVENTORY_FILE` | Refreshable inventory | unset |
| `WEBX_PROXY_INVENTORY_URLS` | Signed HTTPS inventory endpoints | unset |
| `WEBX_PROXY_INVENTORY_SIGNING_SECRET` | HMAC for inventory | unset |
| `WEBX_PROXY_GEO_CHECK_URL` | Exit geo verification | unset → observed null |
| `WEBX_PROFILES_DIR` | Profile/context root | temp `webx-profiles` |
| `WEBX_DB_URL` | Durable store | SQLite local / Postgres prod cluster |
| `WEBX_RUNTIME_PROFILE` | production / high_assurance constraints | dev-friendly local |

---

## 26. Deployment

| Environment | Notes |
|---|---|
| Local | `cargo run -p webx-server`; optional pool JSON; permissive |
| Single-node k8s | `ops/webx-single-node.yaml` |
| Enterprise | `k8s/webx-enterprise.yaml` — external HA Postgres, browser pool options |
| Production URL | `https://webx.agentslab.host` |

Deploy identity platform by shipping `webx-server` + `webx-browser` with inventory secrets configured. No separate microservice.

---

## 27. Operational Runbook

### Symptom: managed proxy 400 unavailable

1. Confirm inventory env/file loaded.  
2. Confirm requested geo exists and not all quarantined.  
3. Check healthCheckUrl endpoints.  
4. Review `webx_proxy_geo_mismatch_total` and connection failures.  
5. Fix inventory; wait quarantine expiry; retry.

### Symptom: identity coherence rejection

1. Read error detail (timezone, locale, mobile+desktop, country mismatch).  
2. Align `WEBX_FINGERPRINT_PROFILE_JSON` with requested geo.  
3. Or temporarily use permissive **only** if product accepts weaker guarantees.

### Symptom: context reuse continuity failure

1. Ensure second session requests managed proxy compatible with prior snapshot.  
2. Inspect `contexts/<id>/webx-network-identity.json`.  
3. If intentional new identity, create a **new** context id.

### Symptom: drift mid-session

1. Check vendor rotation policy vs `per_session` expectation.  
2. Inspect quarantine and failover metrics.  
3. Prefer sticky lease hash; avoid multi-country inventory for sticky logins.

### Symptom: Chrome major mismatch

1. Align fingerprint `browser_version` major with pinned browser image.  
2. Rebuild/redeploy matching image (`Dockerfile.fullchrome` / process tier pin).

---

## 28. Incident Response

| Severity | Example | Response |
|---|---|---|
| SEV-1 | Coherent tenants cannot acquire any lease | Page platform; freeze deploy; fix inventory/geo-check |
| SEV-2 | Drift spike causing re-login storms | Disable aggressive failover; pin sticky; notify affected tenants |
| SEV-3 | Single bad fingerprint config | Fix env; no full rollback |

Preserve evidence: session logs, proxy receipts, identity digests, metrics windows.

---

## 29. Backup and Recovery

| Artifact | Backup | Restore |
|---|---|---|
| SQLite / Postgres | `ops/webx-backup.sh` / `pg_dump` | Restore DB then artifacts |
| Context profiles + network identity files | Part of `/data` or profiles volume | Restore volume; verify JSON loads |
| Proxy inventory secrets | Secret manager | Re-apply secrets (not from session backups) |

Network identity without profile cookies is incomplete stickiness; restore both.

---

## 30. Security Operations

- Rotate proxy inventory credentials via `credentialVersion` and inventory refresh.  
- Rotate API tokens independently.  
- Audit that receipts never contain passwords (spot-check session JSON).  
- On suspected secret leakage in logs, rotate vendor credentials immediately.

---

## 31. Compliance / Audit posture

| Need | How identity helps |
|---|---|
| Prove which egress was used | Proxy receipt + optional observed country |
| Prove browser surface | Fingerprint + profile digest |
| Prove continuity policy | `identityPolicy` + `identityPolicyVersion` on provenance |
| Avoid secret sprawl in audits | Digests and hashes only |

Does **not** by itself satisfy industry compliance certifications; it provides evidence primitives.

---

## 32. Known Limitations

1. Default permissive allows contradictory identities if callers do not opt into coherent/strict.  
2. Timezone/locale plausibility maps are conservative high-value rules, not a complete IANA×ISO database.  
3. In-process quarantine state is not a distributed consensus fabric.  
4. Context stickiness is filesystem-local unless shared volume / future context v2.  
5. Not a bot-bypass product.  
6. `per_request` / `on_failure` rotation recorded for vendor adapters; static pool treats as per-session semantics.  
7. Shared-context orchestrator tier does not materialize on-disk context persistence.

---

## 33. Evolution Triggers

Revisit architecture when:

- Multi-worker sticky contexts without shared FS become a GA requirement.  
- Product sets **coherent** as default for all production binds.  
- Need hardware attestation or TPMs for browser identity.  
- Multi-region sticky egress SLA requires control-plane lease authority.  
- Fingerprint schema cannot express required surfaces (e.g., full UA-CH brands list evolution).  
- Evidence shows distance weights mis-rank safe failovers.

---

## 34. Open Questions

1. When should production default move from permissive → coherent?  
2. Should Browserbase session responses expose a public identity provenance object beyond proxy receipt?  
3. What is the supported retention for context profiles in paid tiers?  
4. Which geo-check providers are blessed for high-assurance strict mode?  
5. How should network budgets interact with multi-provider price hints in scheduling?

---

## 35. Glossary

| Term | Meaning |
|---|---|
| SessionIdentity | Authoritative composed browser+network document |
| FingerprintProfile | Versioned browser surface configuration |
| Coherent policy | Fail closed on high-value contradictions |
| Strict policy | Coherent + require verification / fail on DNS leak signals |
| Lease hash | One-way identifier for a managed proxy allocation |
| Identity distance | Weighted dissimilarity for failover safety |
| Context network identity | Sticky secret-free snapshot beside Chromium profile |
| Observed country | Server-verified exit country, never fabricated |
| ODEV | Observe → Decide → Execute → Verify agent loop |

---

## 36. FAQ (handoff completeness)

| Question | Answer |
|---|---|
| What is it? | Unified browser+network identity composition and enforcement for WebX sessions |
| Who is it for? | Integrators, operators, and logged-in automation workloads on WebX |
| What problem does it solve? | Contradictory UA/geo/proxy/context state and unprovable egress identity |
| What are the invariants? | See §4 INV-01..12 |
| What is in/out of scope? | §5 |
| How does a request flow? | §6.3 |
| What is the data model? | §7 |
| What are the APIs? | §8 |
| Critical journeys? | §9 J-01..J-04 |
| What are SLOs? | Prefer refuse-over-lie; platform durable-terminal SLO in ops rules |
| How do we know it is healthy? | Proxy/identity metrics + UAT-047..054 |
| How do we deploy it? | Ship webx-server with env inventory + policy |
| How do we roll it back? | Previous image + permissive policy |
| How do we recover bad state? | Fix inventory; new context; release sessions |
| Largest security risks? | Proxy credential leakage; cookie profile theft; fabricated geo if invariant broken |
| Largest scaling limit? | Chrome + multi-worker sticky storage |
| What makes it expensive? | Browser time + paid egress, not identity CPU |
| Why this architecture? | Honesty + continuity for logged-in automation |
| Alternatives rejected? | Independent knobs; anti-detect farm claims |
| Assumptions? | Process-tier profiles; operator-configured inventory; policy ladder |
| When revisit? | §33 |
| Who owns production? | WebX platform team |

---

## 37. Source Map (debug index)

| Concern | File |
|---|---|
| Compose / validate / distance / drift | `crates/webx-server/src/session_identity.rs` |
| Acquire / quarantine / inventory / pricing | `crates/webx-server/src/proxy_manager.rs` |
| Context bind/load | `crates/webx-server/src/contexts.rs` |
| Agent launch integration | `crates/webx-server/src/run_launch.rs` |
| Browserbase path | `crates/webx-server/src/browserbase_compat.rs` |
| Manifest provenance | `crates/webx-server/src/run_manifest.rs` |
| Metrics | `crates/webx-server/src/metrics.rs` |
| Fingerprint + stealth | `crates/webx-browser/src/stealth.rs` |
| Managed proxy product doc | `docs/MANAGED_PROXIES.md` |
| Authority hardening | `docs/PRODUCTION_AUTHORITY_HARDENING_2026-08-09.md` |
| Scaling | `docs/SCALING.md` |
| UAT runbook | `docs/UAT_RUNBOOK.md` |
| UAT cases | `uat/manifest/v1/uat-manifest.json` |
| Identity contracts | `uat/contracts/test_identity_network_contracts.py` |

---

## 38. Change History (implementation)

| Commit (branch history) | Summary |
|---|---|
| `c4819a8` | Bind UA client hints to fingerprint profiles |
| `7d4c78f` | Harden production authority and release evidence |
| `bbf9e1c` / `c5ee65d` | Persistent Chrome profile reuse + flush on release |
| `8872a12` | Build coherent browser and network identities |
| `ea7f04f` | Enforce persistent network identity continuity |
| Related | Idempotent retained continuations; replay; UAT harness expansion |

---

## 39. Risks Register

| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Tenants stay on permissive forever | High | Weak guarantees | Product migration plan |
| Geo-check provider outage | Medium | Strict admissions fail | Timeout + runbook; multi-provider later |
| Shared FS missing multi-replica | Medium | Sticky break across pods | Session affinity / context v2 |
| Over-tight timezone maps false reject | Low–Med | False admissions deny | Conservative unknowns pass |
| Operator mislabels inventory geo | Medium | Mismatch / quarantine | observedCountry evidence |

---

## 40. Handoff Checklist

A senior engineer can answer:

- [x] What it is and why  
- [x] Invariants and policies  
- [x] Compose → acquire → launch → observe flow  
- [x] Sticky context continuity rules  
- [x] Failover distance semantics  
- [x] Metrics and UAT IDs  
- [x] Config knobs and rollback  
- [x] Non-goals (no anti-detect claims)  
- [x] When to revisit  

If any checkbox fails for a reader, update this record.

---

## 41. Quick Reference

```bash
# Install / build
cargo build -p webx-server

# Development server
cargo run -p webx-server

# Static checks
cargo fmt --all -- --check
git diff --check -- . ':!combined_project.txt'

# Unit tests (identity-focused)
cargo test -p webx-server --lib detect_drift_flags
cargo test -p webx-server --lib preferred_lease_hash
cargo test -p webx-server --lib identity_preserving_failover
cargo test -p webx-server --lib two_contexts_produce_isolated
cargo test -p webx-server --lib network_budget_without_price
cargo test -p webx-server --lib capacity_is_enforced_at_register
cargo test -p webx-browser --lib stealth

# UAT harness contracts
python3 -m unittest discover -s uat/contracts -v

# Deterministic UAT profile
python3 -m uat.runner --profile local-deterministic

# Production build (image)
docker build -f Dockerfile.fullchrome -t webx-server:local .

# Run task (local)
curl -X POST http://localhost:8081/api/tasks \
  -H "x-api-key: $WEBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"task":"Go to https://example.com and report the main heading."}'

# Managed session (Browserbase-shaped)
curl -X POST https://webx.agentslab.host/v1/sessions \
  -H "X-BB-API-Key: $WEBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"timeout":300,"proxies":[{"type":"webx","geolocation":{"country":"US"}}]}'

# Health
curl -s https://webx.agentslab.host/health
curl -s https://webx.agentslab.host/ready

# Deploy / rollback
# (environment-specific) kubectl -n webx rollout undo deploy/<webx-api>

# Recovery
# Fix WEBX_PROXY_* inventory; release stuck sessions; recreate context if identity file corrupt
```

### Recommended production identity settings (high assurance)

```bash
WEBX_IDENTITY_POLICY=coherent   # or strict
WEBX_FINGERPRINT_PROFILE_JSON='{"schema_version":"webx.fingerprint.v1", ...}'
WEBX_PROXY_INVENTORY_FILE=/secrets/proxy-inventory.json
WEBX_PROXY_GEO_CHECK_URL=https://ipinfo.io/json
```

---

## 42. Related Artifacts

| Artifact | Purpose |
|---|---|
| `README.md` | Product entry point |
| `/docs` portal | Consumer-facing documentation catalog (served by `webx-server`) |
| `/docs/session-identity` | Integrator guide |
| This document | System record for Session Identity Platform (`/docs/session-identity-system-record`) |
| `docs/portal/` | Portal catalog + consumer guides (embedded at build time) |
| `docs/MANAGED_PROXIES.md` | Proxy product contract |
| `docs/BROWSERBASE_MIGRATION.md` | Sessions API migration |
| `docs/SCALING.md` | Multi-replica topology |
| `docs/UAT_RUNBOOK.md` | Acceptance operations |
| `docs/PRODUCTION_AUTHORITY_HARDENING_2026-08-09.md` | Release authority |
| `docs/USER_GUIDE.md` | Live API guide |
| `uat/manifest/v1/uat-manifest.json` | Behavioral acceptance IDs |
| `ops/webx-slo-rules.yaml` | Runtime SLO alerts |
| `ops/webx-backup.sh` | Backup tooling |

---

## 43. Document Maintenance Contract

Update this record when there is a material change to:

- product intent or default identity policy  
- architecture / composition boundaries  
- invariants  
- fingerprint or session-identity schema versions  
- proxy failover distance policy  
- external contracts (`/v1/sessions` proxy fields)  
- security model for identity artifacts  
- deployment/rollback for identity flags  
- SLOs / metrics names  
- UAT-047..054 scope  
- known limits or evolution triggers  

Do not preserve obsolete instructions merely because they once existed.  
Use ADRs and implementation journey for history.  
Keep operational instructions describing **what works today**.

---

## 44. Final Engineering Principles

1. **Start with the problem** — coherent, sticky, provable identity for logged-in automation.  
2. **Architecture is boundaries and invariants** — not a fingerprint JSON alone.  
3. **Explicit tradeoffs** — consistency over availability under coherent/strict; compatibility under permissive.  
4. **Design failure intentionally** — no safe failover is better than a silent country hop.  
5. **Operability is part of the feature** — metrics, quarantine, UAT IDs.  
6. **Tests protect risks and invariants** — UAT-047..054 map to INV-*.  
7. **Irreversible decisions carefully** — schema versions and default policy changes.  
8. **One canonical source of truth** — `SessionIdentity` composition; UAT IDs in manifest.  
9. **Measure outcomes after shipping** — validation failure and drift rates, not just deploys.  
10. **Document why** — ADRs record rejected anti-detect fantasy.  
11. **Record mistakes without rewriting history** — e.g., never copy prior lease into a fake active lease.  
12. **Define when to change** — multi-worker sticky storage and default policy promotion are explicit triggers.

---

## 45. Final System Statement

**Session Identity Platform** exists to help **automation integrators, operators, and logged-in portal workflows** accomplish **browser sessions whose fingerprint, geography, egress, and sticky context remain coherent, evidence-backed, and fail-closed when integrity cannot be guaranteed**. It is implemented using a **unified `SessionIdentity` composition root in `webx-server`, integrated with `ProxyManager` acquisition, process-tier Chrome profiles, and `FingerprintProfile` stealth application**, because **independent knobs produced silent trust failures and unprovable receipts**. The system guarantees **secret-free provenance, non-fabricated observed geography, identity-distance-bounded failover, and continuity enforcement under coherent/strict policies**, operates within **backward-compatible default permissive mode, existing auth, and operator-supplied proxy inventory**, and is considered healthy when **acquire/validation metrics are stable, UAT-047..054 pass, and high-assurance tenants do not see silent country or fingerprint major drift**. Its most significant current risks are **permissive-default underuse, filesystem-local sticky contexts in multi-replica deployments, and operator inventory misconfiguration**. The architecture should be reconsidered when **portable multi-worker context storage or a production default of coherent becomes mandatory**. Production ownership belongs to the **WebX platform / browser runtime team**.

---

*This is a living engineering record. It should contain enough product context, architectural reasoning, operational knowledge, and implementation history for another senior engineer to safely understand, operate, challenge, extend, migrate, or replace the Session Identity Platform within WebX.*
