Skip to content

feat: qualify resilient native capture - #78

Merged
abrichr merged 1 commit into
mainfrom
codex/capture-production-release-gates
Aug 20, 2026
Merged

feat: qualify resilient native capture#78
abrichr merged 1 commit into
mainfrom
codex/capture-production-release-gates

Conversation

@abrichr

@abrichr abrichr commented Aug 18, 2026

Copy link
Copy Markdown
Member

Outcome

This pull request makes the native Capture path resilient to window movement,
window resize, and stable multiple-monitor desktops. It also adds fail-closed
production qualification and release evidence.

It was stacked on #76. #76 merged as 07990886b1e206bcc807ba95f822ef859e9b7325,
and this branch is rebased onto that main.

Lifecycle labels held back

Capture moves from Experimental to Production in one visible change, at the
end, once its qualification evidence exists. There is no interim Beta step.
The rebase removed every Beta relabel this branch carried:

File Held hunk
README.md **Status: Beta.** in the status banner (inherited from #76)
README.md **Status: Beta.** for the window-scoped recording section (this branch's own). Replaced with the factual "implemented, with display-free unit coverage on every supported operating system", which keeps the release-gate wording.
docs/DESIGN.md "The package lifecycle is Beta" (this branch's own). Replaced with "Experimental", which matches README.md.
pyproject.toml Development Status :: 4 - Beta (inherited from #76)
CLAUDE.md, chrome_extension/README.md "Beta canonical native recorder" (inherited from #76)

The pre-rebase head 4595c872b9d5c10e2207fe23314eb8b56c4aebf3 is preserved on
branch codex/capture-production-release-gates-original.

Capture behavior

  • keep one encoded viewport for a window recording while allowing the source window to move and resize
  • scale each changed source frame to fit and letterbox it instead of dropping the frame
  • retain the fixed output viewport, current source viewport, exact content rectangle, and x/y coordinate scales
  • translate input with the same current geometry, including integer resize rounding
  • bind the session to one exact native window identity
  • terminate the session on a lost window, capture failure, identity change, or unexpected output frame instead of retrying across an evidence gap
  • commit new window geometry only after its matching frame is captured
  • persist the combined MSS virtual-desktop origin and monitor rectangles for full-screen sessions
  • translate negative-origin and secondary-monitor input into the captured frame
  • check fresh monitor topology before and after each frame, during input translation, and at finalization
  • reject same-size origin/layout changes, display hot-plug, rotation, resolution changes, and scale changes as a new-recording boundary
  • reject ambiguous window-plus-desktop scope metadata and malformed desktop topology

Flow PR #366 consumes these contracts.

Browser security boundary

The package shipped an unauthenticated Chrome-extension WebSocket and a legacy
direct replay API. That path contradicted the supported Playwright-only
governed browser boundary. This pull request:

  • keeps passive browser-event schemas so old local captures remain readable
  • removes BrowserBridge, BrowserMode, run_browser_bridge, and direct replay from the published package API
  • excludes openadapt_capture/browser_bridge.py and chrome_extension/ from wheel and source archives
  • removes websockets from runtime dependencies
  • makes the former browser_events=True opt-in fail before any listener bind, encoder check, display access, or database creation
  • keeps the extension and bridge as repository-only development files

No repository in the organization imports BrowserBridge, BrowserMode,
run_browser_bridge, or openadapt_capture.browser_bridge, so the removal has
no known downstream consumer.

Production release gate

The manual production-qualification.yml workflow binds a request to one exact
protected-main SHA, builds and validates one wheel and source archive, runs
exact-wheel install/import/CLI/uninstall checks on hosted Ubuntu, macOS, and
Windows, runs live native tests on controlled hosts, requires at least two
stable physical monitors on each interactive host, and requires no skipped,
failed, missing, duplicate, or extra qualification jobs.

Both release.yml and production-qualification.yml are workflow_dispatch
only. Merging this pull request publishes nothing.

Version contract

The repository stays at the published v1.2.2 version. CHANGELOG.md carries
the published v1.0.0 through v1.2.2 history only. There is no untagged v1.3.0
section, and no downstream dependency floor moves.

No production-acceptance claim

Nothing in this change states that a customer accepted this software, that a
signed acceptance record exists, or that any deployment is qualified. The two
customer mentions are caveats: a customer RDP or Citrix deployment still needs
its own task- and environment-specific qualification.

Validation on the rebased head

  • 422 passed, 1 skipped, 9 deselected
  • Ruff passed on openadapt_capture/
  • python scripts/check_changelog.py passed
  • wheel and source archive built, both passed scripts/verify_distribution.py
  • python scripts/check_source_boundary.py --require-dist passed

The live production-qualification workflow has not run. It must run on an exact
merged main commit before any 1.3.0 release.

External setup still required before a release

Create a protected GitHub environment named production-qualification,
restricted to main and requiring a reviewer. It needs no secret. Provide
self-hosted runner labels self-hosted, Linux, X64, openadapt-capture-qualified,
self-hosted, macOS, ARM64, openadapt-capture-qualified, and
self-hosted, Windows, X64, openadapt-capture-qualified. Each runner needs a
visible signed-in desktop, two physical monitors, native screen and input
permissions, reviewed ffmpeg and ffprobe on PATH, and permission to inject
qualification input.

🤖 Generated with Claude Code

abrichr added a commit that referenced this pull request Aug 19, 2026
PR #78 targets codex/promote-capture-beta, so the branches: [main] filter
on pull_request matched almost nothing. The pull request reports
mergeStateStatus CLEAN with 1 check instead of the full set, which makes an
unverified change look the same as a passing one.

Remove the base-branch filter from the three pull_request triggers. The
push trigger keeps branches: [main].

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@abrichr abrichr closed this Aug 19, 2026
@abrichr abrichr reopened this Aug 19, 2026
@abrichr
abrichr force-pushed the codex/promote-capture-beta branch from c937787 to 0848cf9 Compare August 20, 2026 01:16
Base automatically changed from codex/promote-capture-beta to main August 20, 2026 01:19
Make the native Capture path resilient to window movement, window resize,
and stable multiple-monitor desktops, and add fail-closed release evidence.

Capture behavior:
- keep one encoded viewport for a window recording while the source window
  moves and resizes; scale each changed source frame to fit and letterbox it
  instead of dropping the frame
- retain the fixed output viewport, current source viewport, exact content
  rectangle, and x/y coordinate scales, and translate input with the same
  current geometry
- bind the session to one exact native window identity, and terminate the
  session on a lost window, capture failure, identity change, or unexpected
  output frame instead of retrying across an evidence gap
- commit new window geometry only after its matching frame is captured
- persist the MSS virtual-desktop origin and monitor rectangles, translate
  negative-origin and secondary-monitor input, and reject hot-plug, rotation,
  resolution, scale, and same-size layout changes as a new-recording boundary

Browser boundary:
- keep the passive browser-event schemas so old local captures stay readable
- remove BrowserBridge, BrowserMode, run_browser_bridge, and direct replay
  from the published package API
- exclude openadapt_capture/browser_bridge.py and chrome_extension/ from the
  wheel and the source archive, and drop websockets from runtime dependencies
- make the former browser_events opt-in fail before any listener bind,
  encoder check, display access, or database creation

Release gate:
- add a manual production-qualification workflow bound to one exact
  protected-main SHA, with hosted install checks and live native tests
- require successful exact-SHA test.yml and manually dispatched qualification
  evidence before release; missing, stale, partial, skipped, or failed
  evidence blocks publication
- add CHANGELOG.md with the published v1.0.0 through v1.2.2 history and
  require a two-way match between stable tags and changelog sections

The repository stays at the published v1.2.2 version. This change publishes
nothing: both the release and the qualification workflows are
workflow_dispatch only.

This change carries no lifecycle label movement. The package stays
Experimental in README.md and stays "Development Status :: 2 - Pre-Alpha"
in pyproject.toml.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abrichr
abrichr force-pushed the codex/capture-production-release-gates branch from 4595c87 to 7ecd665 Compare August 20, 2026 01:24
@abrichr
abrichr marked this pull request as ready for review August 20, 2026 01:26
@abrichr
abrichr merged commit b04e829 into main Aug 20, 2026
12 checks passed
@abrichr
abrichr deleted the codex/capture-production-release-gates branch August 20, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant