# 0.20.0 — External-public shared-world plane + CDP lobby-code handoff

Additive minor release. No breaking change to the provisioned-getHost path, its schema, or its verify
asserts (byte-stable; a snapshot regression pins it).

## Highlights

- **External-public shared-world plane class** (`sharedWorld.planeClass: "external-public"`). A real,
  operator-OWNED public deployment can now be the shared plane DIRECTLY: `subject.source: app-url` +
  `subject.topology: shared-world` + `policies.allowPublicTargets: true` +
  `execution.concurrency > 1`. NO getHost, NO clone, NO subject sandbox, NO seed. The N>1 +
  `allowPublicTargets` refusal now ROUTES here when `topology: shared-world` is declared, instead of
  failing.
- **Operator-ownership attestation** `subject.publicTarget: { owner, authorized: true }` — the honest
  analog of `exposure: synthetic` for a plane the harness does not own (author-trust, unverifiable).
- **CDP lobby-code handoff barrier.** A new runtime-only `CuaLoopOptions.onObservedUrl(url)` callback
  (fired after every `executor.observe()`, never persisted) feeds a host-first barrier: the host seat
  creates the shared lobby, the orchestrator extracts `/lobby/CODE` from its CDP-observed URL and
  threads the code into the follower JOIN missions; followers fail closed WITHOUT opening on
  `HUMANISH_CONCURRENT_SHARED_WORLD_LAB_HANDOFF_TIMEOUT`.
- **3-mobile lobby-trivia example** (`humanish/labs/lobby-trivia-3player.yaml` + an init template): 3
  mobile-LAYOUT personas play the same multiplayer lobby on a real public app at once. Dry-run $0.
- **Honest evidence class.** Attribution stays `shared-world`; every strength claim degrades honestly
  and is asserted-ABSENT by verify: `subject.state.provenance == external-public` (not seeded);
  `plane.exposure` ABSENT (no synthetic claim on a real site); `plane.publicOriginDigest` is the
  OBSERVED origin the seats converged on (redirect-tolerant — a cross-origin apex→www/http→https
  redirect is normal; the declared origin is recorded separately as `plane.declaredOriginDigest` and
  is never asserted equal) with every observed `routeHostDigest` converging on it (operator-attested,
  not harness-controlled); NO
  authoritative `stateSeries` (Option A); relaxed concurrency-on-pass (temporal co-occupancy only);
  optional `lobbyConvergenceDigest`. The getHost synthetic gate stays UNCHANGED and is deliberately
  unreachable from the app-url branch.

## Watch-from-phone

`humanish serve --expose` covers the evolving Observer/artifacts from a phone TODAY. Native
live-desktop `--expose` streaming on the concurrent path is a clean 0.20.1 fast-follow reusing
`startExposedObserver` on the concurrent observer server.

## Notes

- Cost tracking (0.19.0) and the CommandExitError resilience fix (0.19.1) remain in place.
- `execution.timeoutMs` caps the host-first handoff deadline (default 120s).
