Hosted runs record measured screen geometry instead of guessed viewports - #287
Merged
Conversation
Hosted-browser bundles previously copied the requested device preset into stream.viewport, so a guess was indistinguishable from a measurement. Runs now record requested virtual screen, verified X screen, measured browser outer-window bounds, and measured CSS viewport as separate facts. stream.viewport is written only from a real CDP measurement; unmeasurable lanes omit the field and carry an explicit warning. Verify fails closed on a forged stream/geometry mismatch. Concurrent lanes record a screen-size mismatch as evidence and proceed; single-lane and fan-out routes keep failing closed. Sequential shared-world seats terminate the previous seat's browser at turn end (bounded, warning on failure) and chromium observers re-resolve the CDP port at observe time. Conscious pre-1.0 breaking change: root-exported buildCuaBundle drops the deviceScaleFactor input; it existed only to fabricate stream.viewport from the requested size, which this contract forbids. Full suite 1061 passed / 10 skipped; typecheck, build, diff --check, and public-surface scan clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The regenerated fixture from the feature commit embedded that worktree's ambient git state (18 unstaged files). Recaptured from the committed tree so the recorded leaves are clean. Masked by lab-golden.test.ts either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
danielgwilson
added a commit
that referenced
this pull request
Aug 1, 2026
Ships the checksum-pinned drawDB four-persona study composite (docs/assets/humanish-drawdb-hero.png, SHA-256 0a61840b...) in the npm payload alongside the existing synthetic hero, and bumps the package and doc version pins to 0.16.0. The README switch to the new hero follows in a separate PR once the version-pinned unpkg URL exists. 0.16.0 is a minor bump because #287 consciously changed the root-exported buildCuaBundle input surface: deviceScaleFactor is gone; callers pass desktopRoute/desktopGeometry. stream.viewport is now measured-only. The image comes from live run drawdb-study-20260801-wide-05: four computer-use personas driving a commit-pinned local drawDB checkout (9d334355), 4/4 passed, verify 15/15, all sandboxes torn down by exact id. drawDB is the public application studied, not an adopter or endorser. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Anyone reading a hosted-browser run bundle today sees a
stream.viewportthat was copied from the requested device preset, never measured. On the E2B desktop route the requested size actually picks the virtual screen; the browser's real CSS viewport is smaller because chrome occupies space, and a failed lookup silently became a "measured" claim. Evidence consumers (Observer, verify, downstream analysis) could not tell an honest measurement from a guess.Why: run bundles are the product's source of truth. A geometry field that might be fabricated poisons every claim built on top of it.
Fix: hosted-browser runs now record requested virtual screen, verified X screen, measured browser outer-window bounds, and measured CSS viewport (innerWidth/innerHeight/DPR) as separate facts.
stream.viewportis written only from a real CDP measurement; when measurement is unavailable the field is absent and the bundle carries an explicit warning instead of a copy of the request. Verify fails closed on a forged stream/geometry mismatch. The Observer renders full screenshots without viewport-aspect cropping, and lane status wording no longer overstates dry-run lanes. Sequential shared-world seats terminate the previous seat's browser when a turn ends, so a prior role's live session cannot mutate the shared plane during a later role's turn.Done when:
browserWindow(sourcecdp) and a measuredstream.viewportdistinct from the requested screen.stream.viewportand records a warning, never a substituted size.stream.viewportstill verify and render without migration.Not in this PR: any npm release (separately gated); the replacement README hero capture; live-E2B rebaselines of the CDP timing heuristics (reasoned, not executed, on the deterministic substrate).
Details for the implementer:
docs/contracts/run-bundle.md; honest-fidelity language updated inREADME.mdanddocs/goals/current.md.src/cua-actor-lab.ts(window finder keyed on browser family with identity as refinement;ChromeCdpEndpointwith cached-port, DevToolsActivePort re-read at observe time, then legacy 9222 fallback; CDP page attribution pinned targetId / lane target URL / single-page; teardown capture merged final-else-launch with Set-deduped warnings),src/shared-world-lab.ts(same restructure for sequential seats + per-seat browser termination by recorded PID with profile-dir pkill fallback),src/concurrent-shared-world-lab.ts(screenMismatchPolicy: "record-evidence"for independent evidence seats),src/run.ts(geometry schema + fail-closed stream/geometry consistency),src/oss-meta-lab.ts(dry-run bundles carry requested screen only, no fabricated viewport),src/device-presets.ts,src/observer-assets.ts.buildCuaBundledrops thedeviceScaleFactorinput; it existed only to fabricatestream.viewportfrom the requested size, which this contract forbids. Callers now passdesktopRoute/desktopGeometry. Flag for the next version bump's release notes.find_named_windowtitle-match fallback is removed, and unknown-family launches (desktop.opennon-http route) skip window lookup; those routes stream the full desktop with a warning instead of a window-scoped stream.tests/golden/labs/oss.jsonregenerated via the capture path: dry-run bundles now emitdesktopGeometry.screen.requestedinstead of a fabricated viewport. Timestamp/git-state leaves are masked bylab-golden.test.ts.tsc --noEmitclean; build clean;git diff --checkclean; public-surface scan ok (base scan locally; the denylist-augmented variant runs in CI).🤖 Generated with Claude Code