feat(web): make each web session its own device

Merged
KA
3h ago
+2325-355

Summary

Each web session is now its own device, so sessions with different --session names run in parallel on one host. Closes #4190.

 open --platform web --session a
-  device agent-browser-chrome                 # one per host: a second open gets DEVICE_IN_USE
+  device agent-browser-chrome:session:p_a     # tenant: t_<hash12(tenant)>_a
+    lock, claim, conflict check, and agent-browser --session all read this one value
  • The request scope alone derives the web session identity from the supplied name and attested tenant; batch and replay carry it unchanged, other readers take the backend key from the device id. Replay records on its held attempt session's device, so the identity does not cross the replay port.
  • Names match [A-Za-z0-9_-], case-insensitively, and must fit the socket path; blank or padded names get web_session_name_invalid on every route.
  • No web command binds the host. Claims follow ADR 0035's host-scoped rule; ADR 0037 records the web decisions.
  • Scope expansion: tenant-isolated keys, the generic claim rule, the ADR split, the request-scope refactor.
  • 85 files, +2,325/−355 at a9691d07b, in self-contained commits.
agent-device open https://example.com --platform web --session a
agent-device open https://www.iana.org/help/example-domains --platform web --session b

Follow-ups: #4233 (workspace key for implicit web sessions), #4234 (lease platform vs. lease backend).

Validation

  • Before, at dc39b316f: the second open fails with Device is already in use by session "a". After, at 2aa956fc0: both sessions open, each snapshot reports its own URL.
  • Head a9691d07b: 11 checks pass, 2 skipped. 2aa956fc0 differs from this head by one test-only fixture commit.
  • Live evidence: https://github.com/callstack/agent-device/pull/4191#issuecomment-6668566884
  • Door: two-way, nothing migrated. Mixed-version daemons sharing a claims directory may disagree on web device ids.
  • Blast radius: session and claim paths for every platform, since the app-device claim checks are now generic. Sessions without --session share default.