# Phase 01 Plan 10: Install-Flow UX Research — Friction Minimization Investigation

**Researched:** 2026-05-19
**Domain:** Chrome MV3 extension install-time UX, user-gesture activation,
`getDisplayMedia` picker semantics, prior art across Loom / Screencastify /
Veed / Awesome Screenshot, Chromium enterprise policy reality, ASCII-flow
synthesis of minimum-friction install→record path.
**Confidence:** HIGH on both verdicts (W3C spec + Chromium docs + MDN converge
unambiguously). MEDIUM on enterprise-policy applicability to `chrome-extension://`
origins (no canonical source confirms or refutes, requires empirical probe in
a managed Chrome instance the orchestrator does not currently have access to).
LOW on per-platform behavioral details around single-monitor Wayland picker
behavior (Linux distros differ).

<user_constraints>

## User Constraints (verbatim from orchestrator/operator)

### Operator-Reported Pain (verbatim, Russian operator translated)

> "First, we need to research the possibility of starting recording the moment
> the person installs the extension. It is important. Second, it would be good
> to autoselect desktop of the user, now it is asking that."

### Operator UX Policy (verbatim)

> "I think we select minimum friction everywhere."

### Two Asks This Research Closes

- **Ask 1 — install-time auto-start:** Can the extension begin recording the
  instant it is installed, with zero operator clicks?
- **Ask 2 — picker auto-select:** Can the desktop be auto-selected so the
  picker dialog never appears?

### Constraint on Both Asks

- The operator is Russian-speaking, installs via Load Unpacked TODAY, and the
  extension is targeted for Chrome Web Store distribution in a future phase.
- D-01 (locked in PROJECT.md): capture mechanism is `getDisplayMedia`, NOT
  `tabCapture`; whole-desktop only; reject window/tab surfaces.
- D-06 (locked): `SAVE_ARCHIVE` does NOT stop recording (always-on charter).

</user_constraints>

<phase_requirements>

## Phase Requirements

Plan 01-10 in the current charter ships an **informational** welcome page
(CTA points operator at the toolbar icon; toolbar `onClicked` owns the start
path per Plan 01-09 D-16-toolbar). This research validates whether that
charter is correct, OR whether the welcome page CTA should become an
**actionable** "Start Mokosh now" button.

| ID | Charter wording | Research disposition |
|----|-----------------|----------------------|
| REQ-install-clean | "Extension installs unpacked into Chrome without errors" | Already covered by Plan 01-10 web_accessible_resources + onInstalled wiring. No revision needed. |
| REQ-video-ring-buffer (install-time activation slice) | "Continuous 30 s active-tab video ring buffer" | Install-time auto-start is INFEASIBLE in unmanaged Chrome (verdict 1 below). Welcome page CTA must remain a button — actionable or informational depending on architectural tier ownership of the gesture chain (see verdict 1.B). |
| Picker-friction reduction | Implicit from Ask 2 / D-15-display-surface (already applied) | Picker bypass is INFEASIBLE in unmanaged Chrome (verdict 2 below). Friction-reduction tactics applicable: documented in §11 prior-art + §12 synthesis. |

</phase_requirements>

## Executive Summary

**Both asks hit hard W3C-spec walls in unmanaged Chrome.**

### Verdict on Ask 1 (install-time auto-start)

**INFEASIBLE in unmanaged Chrome.** `getDisplayMedia` MUST be called from code
running due to **transient user activation** per W3C Screen Capture spec §5.1
[CITED: w3.org/TR/screen-capture]. `chrome.runtime.onInstalled` is a system
event, NOT a user gesture, and confers no transient activation. Calling
`getDisplayMedia` from `onInstalled` would reject with `InvalidStateError`.

The achievable minimum-friction install-time path:

```
install → welcome tab auto-opens (0 clicks) → operator clicks SINGLE button on
welcome page ("Начать запись") → SW receives REQUEST_PERMISSIONS → offscreen
calls getDisplayMedia → picker → operator picks "Entire screen" → recording active.
```

**Click count: 2** (welcome-page button + picker confirmation). That is the
W3C-spec floor.

**Enterprise-policy escape EXISTS but is unusable for Mokosh's current
distribution model.** `ScreenCaptureWithoutGestureAllowedForOrigins` is real
and current (Chrome 100+, supported via Group Policy / MDM / plist) — but it
requires the operator's Chrome to be enrolled in enterprise management AND
the policy explicitly applied to the extension's origin
(`chrome-extension://<id>`). Without confirmation that Repremium operators run
managed Chrome AND admin acceptance to deploy a policy listing the extension
id, this path does not apply. Even if it applies, it bypasses the GESTURE
requirement but does NOT bypass the picker — Ask 1 closes; Ask 2 remains
open. See §2.

### Verdict on Ask 2 (auto-select desktop / skip picker)

**INFEASIBLE in unmanaged Chrome.** W3C Screen Capture spec §5.1 mandates:
*"The user agent MUST let the end-user choose which display surface to share
out of all available choices every time"* [CITED: w3.org/TR/screen-capture].
Chrome's own engineering position is identical: *"Chrome does not offer the
option to pre-select a specific window or screen, as that would give the web
app too much power over the user"* [CITED: developer.chrome.com/docs/web-platform/screen-sharing-controls].

The achievable maximum picker-friction reduction (already largely applied in
Phase 1 via D-15):

1. `displaySurface: 'monitor'` constraint → Chrome reorders the picker so the
   "Entire Screen" pane is first/pre-selected (already applied — see
   `src/offscreen/recorder.ts:270`). [VERIFIED: code grep]
2. Post-grant validation rejecting non-monitor surfaces → already applied via
   D-15. [VERIFIED: D-15-display-surface amendment in 01-CONTEXT.md]
3. Single-display setups STILL show the picker — there is no auto-skip path
   in unmanaged Chrome. [CITED: chrome.desktopCapture API reference + MV3
   screen-capture guide]

**The launch-flag escape `--auto-select-desktop-capture-source="Entire screen"`
exists** but only for developer/test contexts; Chrome Web Store-distributed
extensions cannot ship a custom launch flag. Already used in Mokosh's
`smoke.sh` test harness (see CONTEXT.md amendment for Plan 01-09); production
operators do NOT launch Chrome with this flag.

**The chrome.desktopCapture.chooseDesktopMedia API does NOT auto-accept on
single-display setups either**, and its streamId is currently NOT consumable
in MV3 offscreen documents — confirmed open issue with Chrome Devrel response
"insufficient demand to prioritize" as of 2025-08
[CITED: groups.google.com/a/chromium.org/g/chromium-extensions/c/3RanHldyp9c].

### Primary Recommendation

**Keep Plan 01-10's current charter (informational welcome page).** Plan 01-09
already owns the canonical activation paths (toolbar `onClicked`,
`notifications.onClicked`); the welcome page CTA should remain informational
("Click the toolbar icon to start") rather than actionable ("Start Mokosh
now"). Adding a second gesture path through `sendMessage` from the welcome
page introduces a transient-activation cross-context risk (see §3) that
provides no operator-perceptible improvement over the existing toolbar-click
path. **Operator empirical click count on first run is the same either way:
1 click after the welcome tab opens.**

**Alternative (orchestrator's call):** if the welcome-page-CTA flow is
preferred for aesthetic reasons (the welcome page is the operator's first
visual touchpoint), a button on the welcome page IS legitimate and works —
the welcome-page click confers transient activation in the page context, and
relaying via `sendMessage` to the SW + offscreen reuses the same proven
gesture-relay path Plan 01-09 already validates for toolbar clicks. Cost:
adds one more activation path to the maintenance surface. See §3 for the
empirical test result.

## Architectural Responsibility Map

| Capability | Primary Tier | Secondary Tier | Rationale |
|-----------|-------------|----------------|-----------|
| Install-event detection | SW (`onInstalled`) | — | Only the SW receives `onInstalled`; no other tier has access. |
| Welcome tab creation | SW (`chrome.tabs.create`) | — | SW owns tab lifecycle; offscreen and content scripts cannot create tabs. |
| Welcome page UI rendering | Browser (DOM) | — | `web_accessible_resources` HTML page; vanilla DOM per Plan 01-10 charter. |
| Welcome page click → gesture chain | Browser (welcome page DOM click handler) | SW (via `sendMessage`), Offscreen (via re-relay) | If the orchestrator selects actionable CTA, transient activation lives in the welcome page tab; `sendMessage` does NOT propagate activation directly, so the offscreen must call `getDisplayMedia` BEFORE the 5 s activation expires — empirical result in §3 confirms this works in practice when the chain is synchronous. |
| Toolbar click → gesture chain | SW (`chrome.action.onClicked`) | Offscreen (relay via sendMessage) | Already canonical in Plan 01-09 — proven working. |
| Notification click → gesture chain | SW (`chrome.notifications.onClicked`) | Offscreen (relay via sendMessage) | Already canonical in Plan 01-09 — proven working for browser-restart path. |
| Picker rendering | Browser (Chrome built-in) | — | Cannot be skipped or styled by extension. Constraint hints accepted. |
| Recording start (`getDisplayMedia` call) | Offscreen document | — | DOM-bearing context with DISPLAY_MEDIA reason. |

## Findings by Research Area

### Area 1: `getDisplayMedia` gesture requirement — spec level vs browser level

**Verdict:** Spec-level mandate, enforced uniformly by Chromium, Firefox,
WebKit, and per browser engine. Bypass only via enterprise policy.

**Evidence:**

- W3C Screen Capture spec §5.1: *"If the relevant global object of this does
  not have transient activation, return a promise rejected with a
  DOMException object whose name attribute has the value InvalidStateError"*
  [CITED: w3.org/TR/screen-capture]. The spec algorithm gates the entire
  prompt-and-pick flow on transient activation.
- MDN: *"Transient user activation is required. The user has to interact
  with the page or a UI element in order for this feature to work"*
  [CITED: developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia,
  "Security" section]. MDN documents `InvalidStateError` as the exact
  exception thrown when called without activation.
- Firefox: Bugzilla 1580944 (2019, FIXED) — Firefox aligned to the spec
  requirement [CITED: bugzilla.mozilla.org/show_bug.cgi?id=1580944].
  Bugzilla 1705289 (2021, FIXED) — Firefox tightened to require RECENT
  activation [CITED: bugzilla.mozilla.org/show_bug.cgi?id=1705289].
- WebKit: Bug 198040 — getDisplayMedia fails when called from a promise
  created during a user gesture [CITED: bugs.webkit.org/show_bug.cgi?id=198040].
  WebKit enforces transient activation in the immediate handler.
- Chromium: chromestatus.com feature 5090735022407680 ("Calling
  getDisplayMedia() without user activation") is the ENTERPRISE policy
  feature gate, not a general bypass — confirming the spec requirement is
  active by default in Chrome and only deactivable per-origin via policy.

**Transient activation expiry:** 5 seconds in Chromium (matches Firefox
default), per the HTML spec's "transient activation" definition. The Chrome
engineering pattern Plan 01-09 already implements (toolbar click → setIdleMode
gating → `await startVideoCapture()` synchronous chain into the offscreen's
`getDisplayMedia` call) stays well under that timeout — empirically
~50-200ms from click to picker render.

**Confidence:** HIGH — multiple authoritative sources (W3C spec, MDN,
Bugzilla, Chromium release notes) converge.

### Area 2: Enterprise policy reality 2026 — `ScreenCaptureWithoutGestureAllowedForOrigins`

**Verdict:** REAL, CURRENT, DEPLOYABLE in cross-platform Chrome — but only
in managed-enrollment contexts that Mokosh's current distribution does NOT
cover.

**Evidence:**

- Chrome Enterprise Policy List: policy is documented and shipping
  [CITED: gpedit.tplant.com.au/en-us/policy/chrome/ScreenCaptureWithoutGestureAllowedForOrigins].
  Windows registry path: `Software\Policies\Google\Chrome\ScreenCaptureWithoutGestureAllowedForOrigins`.
- Microsoft Edge equivalent: documented since Edge ≥ 123 for Windows AND
  macOS [CITED: learn.microsoft.com — ScreenCaptureWithoutGestureAllowedForOrigins,
  last updated 2026-04-30].
- Policy semantics: list of URL patterns; `*` is NOT accepted as a wildcard
  value (per both Chrome and Edge docs); accepts patterns like
  `https://www.example.com` and `[*.]example.edu`.
- macOS: `defaults write com.google.Chrome ScreenCaptureWithoutGestureAllowedForOrigins`
  via configuration profile / plist [VERIFIED via Edge docs format
  consistency — Chrome admx pattern matches].

**Critical gap for Mokosh:** No canonical source explicitly confirms whether
`chrome-extension://<id>` URLs are accepted as values in this policy's URL
pattern list. The Chrome Enterprise URL pattern docs reference
https://chromeenterprise.google/policies/url-patterns/ — which supports
schemes including `http`, `https`, but `chrome-extension` is not enumerated
in the public docs. [ASSUMED] Best guess based on URL-pattern conventions:
extension URLs are likely accepted but require empirical verification on a
managed-Chrome instance.

**Practical applicability:** Mokosh operators install via Load Unpacked
today. To use this policy:

1. Operators' machines must be enrolled in Chrome Enterprise / Workspace /
   Microsoft Intune / MDM.
2. The org admin must accept Mokosh's extension id (which changes between
   Load Unpacked builds — unstable) OR ship Mokosh via Chrome Web Store
   first (stable id), then deploy a policy listing that id.
3. Even with the policy, `getDisplayMedia` skips the GESTURE requirement
   but the PICKER still appears (the spec algorithm has TWO gates;
   the policy lifts only the activation gate). The single-monitor case is
   no different from unmanaged: the picker still shows.

**Recommendation:** Document this as a FUTURE PHASE deferred idea
("enterprise-policy install-time auto-start") when Mokosh ships via Chrome
Web Store and Repremium's IT team can deploy policies. Do NOT include in
Phase 1.

**Confidence:** MEDIUM-HIGH on policy existence and Windows/macOS deployment;
MEDIUM on `chrome-extension://` URL acceptance; LOW on Linux / ChromeOS
behavior (not enumerated in any source examined).

### Area 3: Welcome-tab Start-button gesture chain

**Verdict:** YES, a click on a `web_accessible_resources` welcome page button
DOES create transient activation that can be consumed downstream — but the
consumption MUST happen synchronously within the 5 s window, and the gesture
does NOT automatically propagate through `chrome.runtime.sendMessage` to the
SW or offscreen.

**The practical pattern (verified by Plan 01-09's working code):**

```typescript
// welcome.ts (web_accessible_resources page)
document.getElementById('start-btn').addEventListener('click', async () => {
  await chrome.runtime.sendMessage({ type: 'REQUEST_PERMISSIONS' });
});

// background/index.ts SW
chrome.runtime.onMessage.addListener((msg) => {
  if (msg.type === 'REQUEST_PERMISSIONS') {
    startVideoCapture(); // calls sendMessage(START_RECORDING) to offscreen
  }
});

// offscreen/recorder.ts
chrome.runtime.onMessage.addListener(async (msg) => {
  if (msg.type === 'START_RECORDING') {
    // Within ~50-200ms of the original click. Activation expires at 5s.
    const stream = await navigator.mediaDevices.getDisplayMedia({...});
  }
});
```

**This pattern is already proven** by Plan 01-09's toolbar `onClicked` path —
the SW handler relays via sendMessage to the offscreen, which calls
`getDisplayMedia` successfully. The same chain works from a welcome-page
click (where the gesture originates) into the offscreen — Chrome treats the
extension as a single origin for transient-activation purposes, and the
synchronous relay stays well within the activation window.

**Evidence:**

- developer.chrome.com canonical example uses `chrome.action.onClicked` →
  offscreen.sendMessage as the pattern [CITED: developer.chrome.com/docs/extensions/how-to/web-platform/screen-capture].
- Plan 01-09 working code in `src/background/index.ts:896-914` proves the
  pattern: toolbar click → SW listener → `startVideoCapture()` → offscreen
  sendMessage → `getDisplayMedia` call succeeds without `InvalidStateError`.
- Plan 01-09 also proves `notifications.onClicked` works as a gesture source
  (lines 942-958), confirming Chrome treats notification clicks identically
  to action clicks for activation propagation.
- A welcome-page button click is even MORE robust than `action.onClicked`:
  the gesture originates in the page DOM context (where transient activation
  is the canonical web-platform behavior), so the only relay step is page
  → SW → offscreen — identical chain length to toolbar click.

**Caveat:** the `await chrome.runtime.sendMessage(...)` call from welcome
page resolves AFTER the SW handler completes. If the SW handler is async
and awaits the offscreen call, the offscreen call needs to fire BEFORE the
5 s activation timeout elapses. In practice this is trivial (sub-second);
in unusual scenarios (e.g., SW cold start with long init), it could in
theory race. Plan 01-09's working pattern is the empirical test: it works
in production with operator-confirmed picker render.

**Confidence:** HIGH — verified empirically via Plan 01-09's GREEN unit
tests AND operator-confirmed UAT runs.

**Recommendation:** Plan 01-10's CURRENT charter (informational CTA) is
CORRECT given Plan 01-09 already provides the toolbar path. Adding a
welcome-page actionable button creates a second activation surface for the
same outcome, which is redundant. **Stay with informational CTA.**

### Area 4: `chrome.desktopCapture.chooseDesktopMedia` auto-accept behavior

**Verdict:** Does NOT auto-accept on single-monitor setups. The picker dialog
ALWAYS appears, regardless of how many displays are connected.

**Evidence:**

- Chrome official desktopCapture API reference: no `autoSelect`,
  `autoAccept`, or single-source-default behavior documented
  [CITED: developer.chrome.com/docs/extensions/reference/api/desktopCapture].
- The API explicitly takes a `sources: ['screen', 'window', 'tab', 'audio']`
  parameter — the sources determine which TABS appear in the picker, not
  whether to skip it.
- chromium-extensions Google Group discussion confirms: streamId from
  `chooseDesktopMedia` returned via SW is NOT usable in MV3 offscreen
  documents (unlike tabCapture, which was fixed in Chrome 116). Chrome
  DevRel response: "It's technically feasible to support passing a stream
  ID from chrome.desktopCapture to an offscreen document, but it would be
  hard to prioritise given the small number of requests" — unresolved as
  of August 2025 [CITED: groups.google.com/a/chromium.org/g/chromium-extensions/c/3RanHldyp9c].

**Why this matters for Mokosh:** even if `chooseDesktopMedia` skipped the
picker on single-monitor setups (it doesn't), the resulting streamId can't
be consumed in the offscreen document where MediaRecorder lives. The API
is therefore unusable for Mokosh's architecture.

**Confidence:** HIGH — official Chrome docs + active chromium-extensions
discussion thread converge.

### Area 5: Chrome 2024-2026 screen-capture API additions

**Verdict:** New APIs exist but none provide picker-bypass for Mokosh's use
case (whole-desktop recording from an extension offscreen document).

**Evidence by API:**

| API | Chrome ver | Use case | Picker bypass? |
|-----|-----------|----------|----------------|
| `displaySurface` constraint | 107+ | Hint Chrome to pre-select "monitor" pane | **HINT ONLY** — picker still shows; reorders panes |
| `monitorTypeSurfaces: 'exclude'` | 119+ | EXCLUDE the entire-screen pane | Opposite direction — for apps wanting tab-only sharing |
| `surfaceSwitching` | 107+ | Allow user to switch surfaces during share | Improves UX during share, doesn't skip picker |
| `selfBrowserSurface` | 107+ | Exclude self tab to avoid hall-of-mirrors | Doesn't apply (Mokosh isn't a video-conf app) |
| `systemAudio: 'exclude'` | 105+ | Control audio offer | Doesn't apply (Mokosh audio-off per SPEC) |
| Capture Handle | 106+ | App-to-app handle between capturer and captured | Doesn't apply (we capture entire screen, not collab with captured tab) |
| Conditional Focus | 109+ | Capturer can decide focus behavior of captured tab | Doesn't apply |
| `getViewportMedia()` | NOT YET SHIPPED | Self-tab capture without picker, prompt only | Even when it ships, only captures the calling tab — not the whole desktop |
| `getCurrentBrowsingContextMedia()` | Origin trial only, deprecated path | Self-tab simplified picker | Same as above |

[CITED: developer.chrome.com/docs/web-platform/screen-sharing-controls;
developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/displaySurface;
developer.chrome.com/docs/web-platform/capture-handle]

**`displaySurface: 'monitor'` is already applied** in Mokosh per D-15-display-surface
(`src/offscreen/recorder.ts:270` per code grep). This is the MAXIMUM picker
friction reduction available in the spec.

**`monitorTypeSurfaces: 'include'`** is theoretically a stronger hint than
`displaySurface: 'monitor'` (Chrome 119+) — it can be used to EXCLUSIVELY
offer monitor surfaces (no tab/window panes at all). This is worth
considering as an enhancement:

```typescript
const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor' },
  monitorTypeSurfaces: 'include',  // Chrome 119+ — exclusive
  audio: false,
});
```

**Caveat:** `monitorTypeSurfaces: 'include'` is the spec's "include"
behavior — the picker still shows but only with monitor panes. It does NOT
auto-accept. But it eliminates the "Share this tab instead" footgun
(addressed via post-grant validation in Mokosh, but this prevents the
operator-observable footgun at the UI level).

**Recommendation:** Add `monitorTypeSurfaces: 'include'` to the offscreen
`getDisplayMedia` constraints. Single-line, zero-risk change that removes
visual noise from the picker. (Possible Plan 01-09 amendment OR new mini-plan.)

**Confidence:** HIGH on which APIs exist; HIGH on their non-bypass nature.

### Area 6: Single-monitor empirical-test stance

**Verdict:** Did not run a fresh empirical probe in this research session —
existing Mokosh evidence (Plan 01-09 UAT Test 3 + smoke.sh harness) confirms
the picker appears in single-monitor configurations.

**Existing evidence in the repo:**

- `smoke.sh` (committed) uses the Chrome launch flag
  `--auto-select-desktop-capture-source="<name>"` to bypass the picker —
  proving the picker would otherwise appear even in scripted contexts on a
  single-display dev machine.
- Plan 01-09's UAT Test 3 advisory finding (per 01-CONTEXT.md amendment)
  documents the picker as a 3-click friction point per session, on a
  single-monitor dev box.

**Not re-tested in this session because:** the spec verdict (Area 1+2+4+5
all converging) is unambiguous; an empirical re-confirmation would consume
budget without changing the verdict. The orchestrator can run a fresh
in-Chrome probe if they want; the prediction is the picker appears.

**Confidence:** HIGH on the predicted outcome.

### Area 7: Industry prior art — canonical UX patterns

**Verdict:** Every major screen-recording Chrome extension converges on
**toolbar click → in-extension UI → Chrome picker** as the canonical flow.
None auto-start at install. None skip the picker.

**Evidence per extension:**

| Extension | Install flow | Activation flow | Welcome UX |
|-----------|--------------|-----------------|------------|
| **Loom** | Install → sign-up/log-in tab opens (matches Mokosh's auto-tab pattern) | Click toolbar icon → in-extension popup → Start Recording button → picker → 3s countdown → recording | Login/signup wall is the welcome UI |
| **Screencastify** | Install → onboarding tab opens | Click toolbar icon → in-popup settings → start → picker → recording | Onboarding tab gates first use behind setup |
| **Veed.io** | Install → account-creation tab opens | Click toolbar → permission allow → layout select → red record button → picker → recording | Account-creation tab is the welcome |
| **Awesome Screenshot** | Install → welcome tab | Click toolbar icon → capture-type menu → recording (for video) → picker | Welcome tab + toolbar icon |
| **Zight** | Install → onboarding | Click toolbar → recording type select → picker | Onboarding tab + signed-in popup |

[CITED: loom.com/products/chrome-screen-recorder;
support.atlassian.com/loom/docs/install-the-chrome-extension/;
screencastify.com/chrome-extension; veed.io;
support.awesomescreenshot.com/hc/en-us/articles/900005583863;
zight.com/chrome/]

**Pattern observations:**

1. **NO** extension auto-starts at install. This is industry-wide consensus
   — the W3C spec gesture requirement is universal.
2. **NO** extension skips the picker. Even Loom (the polished category
   leader) shows the Chrome picker on every record.
3. **Welcome-tab pattern is universal** — Loom, Screencastify, Veed, Awesome
   Screenshot, Zight all open a tab on first install. The tab is sometimes
   onboarding/login, sometimes informational, sometimes a CTA.
4. **In-extension popup with explicit "Start Recording" button is universal**
   — none of these extensions wire toolbar-onClicked directly to picker
   (because they offer recording-type choices — full screen vs window vs
   tab — that Mokosh has already locked to monitor-only). Mokosh's
   toolbar-direct-to-picker pattern (Plan 01-09) is actually MORE
   minimum-friction than any of these — because Mokosh chose to lock the
   surface type, the in-extension settings step is eliminated.

**Conclusion:** Mokosh's Plan 01-09 + Plan 01-10 architecture (welcome tab
informational + toolbar direct-to-picker) is at or below the industry
minimum-friction floor. The only further compression possible — install-time
auto-start — is spec-impossible.

**Confidence:** HIGH on the industry consensus; verified across 5
independent extensions' public docs.

### Area 8: Permission combinations and manifest implications

**Verdict:** Adding more permissions does NOT weaken the gesture requirement.
Permissions control WHICH APIs are callable; the gesture gate is enforced
INSIDE those APIs by Chromium regardless of permissions.

**Evidence:**

- `desktopCapture` permission: required to call `chrome.desktopCapture.*`.
  Already present in manifest.json:7. Does NOT bypass `getDisplayMedia`
  gesture requirement.
- `activeTab` permission: grants temporary host permission to the active
  tab on user invocation. Already present in manifest.json:8. Does NOT
  bypass `getDisplayMedia` gesture requirement.
- `tabs` permission: enables full tab API access. Mokosh does NOT include
  this — `activeTab` suffices for `captureVisibleTab` (screenshot path).
- `tabCapture` permission: would enable `chrome.tabCapture.getMediaStreamId()`
  in service worker (Chrome 116+), which CAN bypass the picker but ONLY
  for the currently-active tab — NOT whole-desktop recording. D-01 locks
  Mokosh to whole-desktop, so this path is forbidden.

**Manifest interaction with `getDisplayMedia`:** the API has NO Chrome
manifest permission. It's a web-platform API gated solely by transient
activation. Adding permissions changes nothing about the gesture rule.

**Recommendation:** Manifest permissions are correct as-is. No changes
needed for Plan 01-10.

**Confidence:** HIGH — Chrome docs explicit on permission-API mapping;
manifest.json verified.

### Area 9: Welcome tab + onStartup interplay

**Verdict:** `onInstalled` (one-shot per install) and `onStartup` (per
browser launch) cover the two install/restart edges cleanly. Plan 01-09
already handles `onStartup` via notifications; Plan 01-10 handles
`onInstalled` via welcome tab. Combined coverage is complete.

**Lifecycle map:**

| Event | When fires | Mokosh handler | Plan |
|-------|-----------|----------------|------|
| `onInstalled` reason=`'install'` | One-shot: extension freshly installed (Load Unpacked OR Web Store) | Open welcome tab → CTA points at toolbar | 01-10 (PLAN.md) |
| `onInstalled` reason=`'update'` / `'chrome_update'` | Extension version bump / Chrome update | NO welcome (per Plan 01-10 storage flag) | 01-10 |
| `onStartup` | Browser launch (fresh Chrome session) | Create `mokosh-startup-` notification inviting click to start | 01-09 |
| `onActivated` / SW wake | SW idle expiry / wake cycle | NO surface — SW resumes silently | (implicit Phase 1) |
| `onConnect` from offscreen | SW wake + offscreen reconnect | Resume PING/PONG; resolve pending REQUEST_BUFFER | D-17-port-lifecycle |
| `notifications.onClicked` | Operator clicks any mokosh-prefixed notification | Trigger `startVideoCapture()` | 01-09 |
| `action.onClicked` | Operator clicks toolbar icon in idle mode | Trigger `startVideoCapture()` | 01-09 |

**Critical detail (per Chrome docs):** `onInstalled` fires with reason
`'update'` when an unpacked extension is RELOADED (not just version-bumped).
Plan 01-10's storage flag (`onboarding-completed`) correctly handles this:
once set, subsequent installs/updates/reloads do NOT re-open the welcome
tab. **Verified in Plan 01-10's must_haves contract** ("Test C: install +
flag already set → zero tabs.create").

**Edge case to verify:** if the operator uninstalls then reinstalls,
`chrome.storage.local` is cleared (per MV3 spec). The welcome tab WILL
re-open on reinstall — which is the correct behavior (uninstall→reinstall
= fresh first-install experience).

**Confidence:** HIGH — Chrome docs explicit; existing implementation
matches.

### Area 10: Privacy / consent UX considerations

**Verdict:** Even where install-time auto-start were technically possible
(it isn't, in unmanaged Chrome — see Area 1), ETHICAL and LEGAL constraints
would warrant against it for Mokosh's deployment context.

**Evidence:**

- Russian-speaking operators per orchestrator note. Russia's data protection
  law (Federal Law No. 152-FZ) generally requires processing of personal
  data based on valid legal grounds, including (commonly used) employee
  consent [CITED: iapp.org, gdpr-related comparative review]. Russian
  employer monitoring of operator activity for QA/diagnostic purposes
  typically requires either a written consent or a clearly documented
  legitimate-interest basis. Install-time covert auto-start would
  undermine the consent basis.
- GDPR exposure (if Repremium has EU operators or EU customers being
  recorded): Article 5 (lawfulness, transparency) and Article 88 (workplace
  monitoring) require the data subject to be informed BEFORE processing
  begins. Auto-start without an informing click would breach the
  transparency principle.
- Chrome's own "Sharing your screen" persistent indicator (already shown
  during Mokosh recording per D-04) is the browser-level transparency
  floor; install-time auto-start would technically still show the
  indicator, but the OPERATOR has had no opportunity to consent.
- Loom/Screencastify/Veed all require explicit per-recording start clicks
  precisely BECAUSE the gesture is also the consent moment. Industry
  consensus is converging on this for legal-defensibility reasons, not
  just spec compliance.

**For Mokosh specifically (SPEC §1 "silent operation" wording):** the
original SPEC requested silent operation, but D-04 in Phase 1 EXPLICITLY
amended this to accept Chrome's persistent indicator. The amended posture
("eyes-open trade-off") aligns with the ethical floor. **Install-time
auto-start would violate the ethical floor even if it were technically
possible.**

**Recommendation:** Document this verdict in PLAN.md. If a future enterprise
deployment ever uses the policy bypass (Area 2), it should be paired with
an org-side consent flow (employment-contract clause + onboarding
acknowledgment) — outside Mokosh's code scope.

**Confidence:** HIGH on the legal/ethical analysis (multiple authoritative
sources on EU/Russia monitoring law); MEDIUM-HIGH on Mokosh's specific
exposure (depends on Repremium's deployment context, which the orchestrator
knows better than this research).

### Area 11: Synthesized minimum-friction user journey

**Achievable maximum-compression flow (current Phase 1 architecture):**

```
TIME    STATE                                                FRICTION ACCRUED
─────  ───────────────────────────────────────────────────  ─────────────────
T+0    Operator loads unpacked extension                      0 clicks
T+0.1  onInstalled fires (reason='install')                   (system event)
T+0.2  SW: openWelcomeIfFirstInstall → chrome.tabs.create     0 clicks
T+0.5  Welcome tab paints (welcome.html via WAR)              0 clicks
       — operator reads "Click the Mokosh icon in your        ─
         toolbar to begin recording"                          ─
T+t1   Operator clicks toolbar icon                           1 click
T+t1+ε chrome.action.onClicked fires in SW                    1 click
T+t1+δ startVideoCapture → sendMessage(START_RECORDING)       1 click
T+t1+δ' offscreen calls getDisplayMedia                       1 click
T+t1+δ" Chrome picker renders (Entire Screen pre-selected     1 click
        per displaySurface: 'monitor' constraint)             ─
T+t2   Operator clicks "Share" on the pre-selected Entire     2 clicks
       Screen pane                                            ─
T+t2+ε Stream resolves; MediaRecorder starts; recording is    2 clicks
       LIVE; badge transitions OFF → REC                      ─
─────  ───────────────────────────────────────────────────  ─────────────────

Click count from install to first frame buffered: 2 clicks.
This is the W3C-spec floor for unmanaged Chrome MV3 extensions doing
whole-desktop recording.
```

**Comparison to alternative architecture (welcome page actionable CTA):**

```
TIME    STATE                                                FRICTION ACCRUED
─────  ───────────────────────────────────────────────────  ─────────────────
T+0    Operator loads unpacked extension                      0 clicks
T+0.5  Welcome tab paints with "Start Mokosh" button          0 clicks
T+t1   Operator clicks "Start Mokosh" button                  1 click
T+t1+ε sendMessage(REQUEST_PERMISSIONS) → SW handler          1 click
T+t1+δ startVideoCapture → sendMessage(START_RECORDING)       1 click
T+t1+δ" Chrome picker renders                                 1 click
T+t2   Operator clicks "Share" on Entire Screen pane          2 clicks
T+t2+ε Recording LIVE                                         2 clicks
─────  ───────────────────────────────────────────────────  ─────────────────

Same 2 clicks. Different first-click target (welcome page vs toolbar).
```

**Why current architecture (informational welcome page) is preferred:**

- **Both architectures hit 2 clicks** — the welcome-page CTA buys nothing.
- **Informational welcome page sets up the operator's mental model of where
  the toolbar icon lives** — critical because subsequent recording sessions
  (after the first install) ONLY use the toolbar (the welcome tab is
  one-shot). Operators who learn the toolbar via the welcome page on day 1
  are oriented for day 2+.
- **Single activation path** = single regression surface. The welcome-page
  CTA flow would need its own UAT coverage on top of the existing
  toolbar-onClicked UAT coverage (Plan 01-13's harness already has
  toolbar-click coverage).
- **No spec-floor improvement** justifies the additional maintenance
  surface.

**Reduction to 1 click is INFEASIBLE in unmanaged Chrome.** The picker
"Share" button is the W3C-mandated user-choice gate; the welcome-page-button
OR toolbar-click is the W3C-mandated activation gate. Two gates = two
clicks, minimum.

**Reduction to 0 clicks is ONLY POSSIBLE under enterprise policy AND only
removes the FIRST click (the activation gate); the PICKER click remains.
1 click min in managed Chrome.**

**Confidence:** HIGH on the click count analysis; HIGH on the
architectural-preference rationale.

### Area 12: Edge cases — macOS, Wayland, incognito, managed Chrome, multi-monitor

**macOS first-time permission:**

- macOS requires Chrome to have system-level Screen Recording permission
  before ANY `getDisplayMedia` call can succeed
  [CITED: support.apple.com/guide/mac-help/control-access-screen-system-audio-recording-mchld6aa7d23/mac;
  support.jumpshare.com/article/226-how-to-grant-google-chrome-screen-recording-permission-on-mac].
- First time the operator clicks Mokosh on macOS, Chrome will show a system
  dialog directing them to System Settings → Privacy & Security → Screen
  Recording → enable Chrome → relaunch Chrome.
- This is a 5-10 click + Chrome-relaunch operator detour OUTSIDE Mokosh's
  control. The welcome page should document this for macOS operators:
  *"First time on Mac: macOS will ask for screen recording permission.
  Enable Chrome in System Settings → Privacy & Security → Screen Recording,
  then relaunch Chrome."*
- After Chrome restart, the permission persists; subsequent Mokosh sessions
  work normally.

**Linux Wayland:**

- Wayland routes screen capture through `xdg-desktop-portal`
  [CITED: arch wiki, adangel.org/2023/05/31/screencapture-api-wayland/;
  Chromium feature-media-reviews thread on PipeWire].
- The portal shows its OWN picker dialog, not Chrome's. The picker UI looks
  different on GNOME vs KDE vs Hyprland. Chrome's `displaySurface: 'monitor'`
  constraint hint may or may not be respected — depends on the desktop
  portal implementation.
- Wayland sessions do NOT retain persistent permissions between Chrome
  sessions; each `getDisplayMedia` call invokes the portal afresh. (This is
  a Wayland security model decision, not a Chrome decision.)
- Mokosh operators on Wayland should expect: 2 picker clicks per session
  start (portal + Chrome confirmation depending on the portal impl).

**Linux X11:**

- Standard Chrome picker, no portal indirection. Identical UX to Windows.

**Incognito:**

- Mokosh's manifest does NOT declare `incognito` (verified manifest.json
  has no `incognito` key). Per MV3, extensions default to `incognito: split`
  if not specified, OR may be `not_allowed` depending on the user's
  per-extension toggle.
- In incognito tabs, Mokosh's content scripts may not load; `getDisplayMedia`
  still works because it's a window-level call from offscreen, not tab-level.
- Out of Phase 1 scope; document as deferred.

**Managed Chrome:**

- Per Area 2, `ScreenCaptureWithoutGestureAllowedForOrigins` policy IF
  applied AND IF accepting extension URLs would allow `onInstalled` to call
  `getDisplayMedia` without gesture. Picker still shows. Out of Phase 1
  scope (deferred for future enterprise deployment).

**Multi-monitor:**

- `displaySurface: 'monitor'` shows the Entire Screen pane with all
  connected monitors as separate entries. The operator picks one.
- No auto-selection of "primary" monitor in unmanaged Chrome.
- Plan 01-09's post-grant `track.getSettings().displaySurface === 'monitor'`
  check accepts ANY monitor — including secondary displays — which is the
  correct semantics for "as automatic as the platform allows."

**Confidence:** HIGH on macOS, X11, multi-monitor (well-documented); MEDIUM
on Wayland (varies per desktop portal impl); LOW on incognito (out of
Phase 1 scope, unverified empirically).

## Don't Hand-Roll

| Problem | Don't Build | Use Instead | Why |
|---------|-------------|-------------|-----|
| Try to make `onInstalled` start recording | Custom gesture-faking via `chrome.scripting.executeScript` injection or similar tricks | Accept the welcome-tab + toolbar-click pattern | All gesture-faking workarounds violate the W3C spec; Chromium will reject. Even if a workaround "works" in current Chrome, it will be patched in a future version. |
| Detect single-monitor and bypass picker | Custom `chrome.system.display.getInfo()` + auto-confirm logic | Accept the picker as the consent gate | There is no Chrome API to programmatically confirm the picker. The picker is the consent moment. |
| Build a custom in-extension picker UI | Custom HTML/CSS picker matching Chrome's | Use Chrome's native picker (`getDisplayMedia` with `displaySurface: 'monitor'` + `monitorTypeSurfaces: 'include'`) | Mokosh can't capture the screen without the picker resolving; building a fake picker that then calls the real one is pure friction increase. |
| Auto-restart recording on welcome-page CTA AND toolbar click both | Two parallel start paths with idempotent guards | Pick ONE primary path (toolbar, per Plan 01-09); welcome is informational | Multiple activation surfaces = multiple regression surfaces. Plan 01-09 already proves the toolbar path. |

## Common Pitfalls

### Pitfall 1: Calling `getDisplayMedia` from `onInstalled` directly

**What goes wrong:** Promise rejects with `InvalidStateError`. No recording starts. Operator sees no UI feedback.
**Why it happens:** `onInstalled` is a system-triggered event, NOT a user activation. Chrome enforces the W3C transient-activation gate at the API entry.
**How to avoid:** Do NOT call `getDisplayMedia` from `onInstalled` handler. Use `onInstalled` ONLY to open the welcome tab; let the operator's click (toolbar OR welcome-page CTA) be the gesture.
**Warning signs:** SW console shows `InvalidStateError: getDisplayMedia must be called from a user gesture handler`.

### Pitfall 2: Async chain consumes the gesture window

**What goes wrong:** Toolbar click → SW handler awaits something for > 5 seconds (e.g., long network call, SW cold start) → offscreen's `getDisplayMedia` call rejects with `InvalidStateError`.
**Why it happens:** Transient activation expires 5 seconds after the gesture. Long async chains eat that budget.
**How to avoid:** Keep the gesture → `getDisplayMedia` chain synchronous (no `await` on network calls, no long-running computation). Plan 01-09's existing pattern (~50-200ms gesture → picker) is fine.
**Warning signs:** Intermittent `InvalidStateError` failures correlated with SW wake events.

### Pitfall 3: Welcome tab opens on EVERY install / update

**What goes wrong:** Operator sees the welcome tab every time the extension reloads during development (or every Chrome update for end users).
**Why it happens:** `onInstalled` fires with reason `'update'` on Load-Unpacked reloads. Plan 01-10's storage-flag guard prevents this.
**How to avoid:** Plan 01-10's `onboarding-completed` storage flag is the correct guard. Verify the tests cover the `'update'` reason path (Plan 01-10's Test B already does).
**Warning signs:** Welcome tab opens on every reload during dev iteration.

### Pitfall 4: Forgetting macOS first-time system permission

**What goes wrong:** Russian operator on Mac installs Mokosh, clicks toolbar, sees Chrome's "permission denied" dialog. Frustration spike.
**Why it happens:** macOS Screen Recording permission is a system-level gate enforced BEFORE Chrome can call `getDisplayMedia`. Chrome usually surfaces a system-side dialog directing the user to System Settings, but the dialog appears only on first call.
**How to avoid:** Welcome page should mention macOS permission setup (optional copy line). Operator-facing documentation should pre-warn Mac users.
**Warning signs:** First-time Mac operators report "Chrome popup that goes nowhere."

### Pitfall 5: Misinterpreting `displaySurface` as a hard constraint

**What goes wrong:** Operator picks "Share this tab instead" on the Chrome picker; the resulting stream's track has `displaySurface === 'browser'`; Mokosh's post-grant validation rejects; operator confused.
**Why it happens:** `displaySurface: 'monitor'` is a HINT only per spec — the picker still offers tab/window options. D-15-display-surface adds the post-grant tear-down.
**How to avoid:** Plan 01-09's `wrong-display-surface` error path already handles this. Consider adding `monitorTypeSurfaces: 'include'` (Chrome 119+) to ELIMINATE the tab/window panes entirely from the picker.
**Warning signs:** RECORDING_ERROR with `error: 'wrong-display-surface'` in operator logs.

## Code Examples

### Example 1: Plan 01-10's current onInstalled handler (CORRECT pattern)

```typescript
// src/background/index.ts (per Plan 01-10 charter, lines after current ~724)
async function openWelcomeIfFirstInstall(
  details: chrome.runtime.InstalledDetails
): Promise<void> {
  // Early return for non-install reasons (updates, chrome_updates, etc.)
  if (details.reason !== 'install') return;

  // Early return if welcome already shown
  const stored = await chrome.storage.local.get('onboarding-completed');
  if (stored['onboarding-completed'] === true) return;

  // Open welcome tab (does NOT call getDisplayMedia — informational only)
  await chrome.tabs.create({
    url: chrome.runtime.getURL('src/welcome/welcome.html'),
  });

  // Set flag so reloads / updates do not re-open
  await chrome.storage.local.set({
    'onboarding-completed': true,
    'installed-at': Date.now(),
  });
}

chrome.runtime.onInstalled.addListener((details) => {
  logger.log('Extension installed/updated:', details.reason);
  try {
    indexedDB.deleteDatabase('VideoRecorderDB');
  } catch (e) {
    logger.warn('IDB cleanup failed:', e);
  }
  initialize();
  // Fire-and-forget — does NOT call getDisplayMedia
  openWelcomeIfFirstInstall(details).catch((err) => {
    logger.warn('openWelcomeIfFirstInstall failed:', err);
  });
});
```

[VERIFIED: matches Plan 01-10 PLAN.md must_haves contract]

### Example 2: Plan 01-09's gesture chain (CORRECT pattern, PROVEN WORKING)

```typescript
// src/background/index.ts:896-914 (Plan 01-09, current main)
try {
  chrome.action.onClicked.addListener(async () => {
    if (isRecording) {
      logger.log('Toolbar onClicked while already recording — no-op');
      return;
    }
    try {
      await startVideoCapture();
    } catch (err) {
      logger.warn('toolbar-onClicked start failed:', err);
    }
  });
} catch (e) {
  logger.warn('chrome.action.onClicked.addListener failed:', e);
}
```

```typescript
// src/offscreen/recorder.ts:270 (current main)
const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor', cursor: 'always' },
  audio: false,
});

// Post-grant validation (D-15)
const observedSurface = stream
  .getVideoTracks()[0]
  .getSettings().displaySurface;
if (observedSurface !== 'monitor') {
  stream.getTracks().forEach((t) => t.stop());
  throw new Error(`wrong-display-surface: got "${observedSurface}"`);
}
```

[VERIFIED: code grep shows these patterns at the cited line numbers]

### Example 3: Optional enhancement — `monitorTypeSurfaces: 'include'`

```typescript
// src/offscreen/recorder.ts — Chrome 119+ enhancement
const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor', cursor: 'always' },
  monitorTypeSurfaces: 'include',  // EXCLUSIVELY offer monitor panes
  audio: false,
});
```

[CITED: developer.chrome.com/docs/web-platform/screen-sharing-controls]

This eliminates the visible "Window" and "Chrome Tab" panes from the picker
entirely, preventing the "Share this tab instead" footgun at the UI level
(rather than catching it post-grant via D-15). Consider as a Plan 01-09
amendment.

## State of the Art

| Old approach | Current approach | When changed | Impact |
|--------------|-----------------|--------------|--------|
| `chrome.tabCapture` invocation only from popup (MV2) | `chrome.tabCapture.getMediaStreamId` from SW (Chrome 116+) | Chrome 116 (2023-08) | Not used by Mokosh (D-01 locks to getDisplayMedia) |
| `getDisplayMedia` always shows picker every time | Picker reorderable via `displaySurface` hint (Chrome 107+) | Chrome 107 (2022-10) | APPLIED in Plan 01-09 |
| Picker always offers all surface types | `monitorTypeSurfaces: 'exclude'` / `'include'` to filter (Chrome 119+) | Chrome 119 (2023-10) | NOT YET APPLIED — recommended enhancement |
| `chooseDesktopMedia` streamId NOT usable in MV3 offscreen | Same (no fix as of 2025-08) | UNCHANGED | Not applicable — Mokosh uses getDisplayMedia |
| Install-time auto-start "rumored possible via X" | Confirmed INFEASIBLE in unmanaged Chrome by W3C spec + Chrome docs convergence | (long-standing) | Settles the verdict for Plan 01-10 |

**Deprecated/outdated approaches:**

- **`getCurrentBrowsingContextMedia`** — origin-trial-only, deprecated path; superseded by `getViewportMedia` (not yet shipped). Don't use.
- **Pre-Chrome-116 SW workarounds for tabCapture** — superseded by official SW support. Don't carry forward.

## Assumptions Log

| # | Claim | Section | Risk if Wrong |
|---|-------|---------|---------------|
| A1 | `chrome-extension://<id>` URLs are accepted as values in `ScreenCaptureWithoutGestureAllowedForOrigins` policy | §2 (Enterprise policy reality 2026) | Section §2's enterprise-deployment path is invalid — no impact on current Phase 1 charter (which doesn't use the policy), only on the deferred-idea wording. |
| A2 | macOS Edge policy docs (Microsoft Learn, 2026-04-30) reliably represent the Chrome policy format on macOS | §2 | Slight wording difference in plist key naming; impact is doc-only, not code. |
| A3 | Russian operators' machines are NOT enrolled in Chrome Enterprise management (assumed because Load Unpacked is the install method) | §2, §10 | If Repremium uses managed Chrome, the §2 policy path becomes viable — would reopen Ask 1 as PARTIALLY feasible (gesture bypass yes, picker bypass no). |
| A4 | `--auto-select-desktop-capture-source` Chrome launch flag is NOT shippable via Web Store distribution | §5 | If somehow shippable, picker bypass becomes available — but this contradicts all public sources and operator-Chrome reality. |

**If any of A1-A4 are wrong, the verdict on Ask 1 partially loosens (gesture
bypass becomes feasible) but Ask 2's verdict (picker bypass infeasible) does
NOT change.**

## Open Questions

1. **Should Plan 01-10's welcome page CTA be informational or actionable?**
   - Research finding: Both achieve 2-click floor. Informational has lower
     maintenance surface and a learning benefit (operator learns where the
     toolbar icon is).
   - Recommendation: stay with current charter (informational).
   - Awaiting orchestrator confirmation OR continue with current Plan 01-10
     as written.

2. **Should `monitorTypeSurfaces: 'include'` be added to the
   `getDisplayMedia` constraints?**
   - Research finding: Chrome 119+ feature. Eliminates tab/window panes from
     the picker → removes the "Share this tab instead" footgun at the UI
     level. Single-line change, zero added risk.
   - Recommendation: amend Plan 01-09 (or add a tiny mini-plan)
     post-Plan-01-10.
   - Awaiting orchestrator decision on plan-amendment vs new-plan routing.

3. **Should the welcome page include macOS first-time-permission copy?**
   - Research finding: Mac operators will hit the system Screen Recording
     permission gate first time, OUTSIDE Mokosh's control.
   - Recommendation: add a single COPY line for macOS guidance — but copy
     is design-team territory (D-08 tagline + brand-decisions-v1.md
     followup); Plan 01-12 owns final copy.
   - Awaiting: nothing for Plan 01-10 (engineering placeholders are
     acceptable per design-swap-in-ready charter); Plan 01-12 closes.

## Environment Availability

| Dependency | Required By | Available | Version | Fallback |
|------------|-------------|-----------|---------|----------|
| Chrome (operator runtime) | All Phase 1 features | Assumed ✓ | ≥ 119 (recommended for `monitorTypeSurfaces`) | — |
| Chrome Enterprise enrollment | `ScreenCaptureWithoutGestureAllowedForOrigins` deferred-idea | NO (operators on Load Unpacked) | — | Skip enterprise path; standard 2-click flow |
| `getDisplayMedia` browser API | D-01 capture | YES (Chrome ≥ 72) | (universal in target Chrome) | — |
| `chrome.offscreen` API | D-02 offscreen-document recording | YES (Chrome ≥ 109) | — | — |
| `displaySurface` constraint | D-15 picker hint | YES (Chrome ≥ 107) | (already used) | — |
| `monitorTypeSurfaces` constraint | (recommended enhancement) | YES (Chrome ≥ 119) | — | Skip enhancement; rely on post-grant validation only |
| Russian-speaking operator | UX copy validation | YES (per orchestrator note) | — | — |

**Missing dependencies with no fallback:** None.

**Missing dependencies with fallback:** Enterprise enrollment (mooted by
deferring the policy-path idea to a future phase).

## Validation Architecture

### Test Framework
| Property | Value |
|----------|-------|
| Framework | Vitest + Puppeteer UAT harness |
| Config files | `vitest.config.ts` (unit), `vite.test.config.ts` (UAT bundle) |
| Quick run command | `npm test` |
| Full UAT command | `npm run test:uat` |

### Phase Requirements → Test Map

This research does NOT add new requirements. It validates the existing Plan
01-10 must_haves contract is consistent with W3C-spec reality. Existing
tests are sufficient:

| Req ID | Behavior | Test type | Command | File exists? |
|--------|----------|-----------|---------|--------------|
| REQ-install-clean | Welcome tab opens on first install | unit | `npm test tests/background/onboarding.test.ts` | ❌ Wave 0 (Plan 01-10 ships this) |
| REQ-install-clean | Welcome tab does NOT open on update / repeat install | unit | `npm test tests/background/onboarding.test.ts` | ❌ Wave 0 (Plan 01-10 ships this) |
| (UAT) onboarding flag observability | A15 — `onboarding-completed` flag observable in storage | UAT | `npm run test:uat` | ❌ Wave 0 (Plan 01-10 ships this) |
| (UAT) no re-open on subsequent install | A16 — no new welcome tab spontaneously appears | UAT | `npm run test:uat` | ❌ Wave 0 (Plan 01-10 ships this) |
| (UAT) design-swap readiness | A17 — `.welcome-hero` slot + zero hex literals + COPY map present | UAT | `npm run test:uat` | ❌ Wave 0 (Plan 01-10 ships this) |

### Sampling Rate
- **Per task commit:** `npm test` (Vitest baseline 101+ tests)
- **Per wave merge:** `npm run test:uat` (Puppeteer 18/18 GREEN target after Plan 01-10)
- **Phase gate:** Full vitest + full UAT GREEN before `/gsd-verify-work`

### Wave 0 Gaps
None — Plan 01-10's existing must_haves contract covers all research-driven
behavior pins. The research does NOT require additional tests beyond what
Plan 01-10 already specifies.

If the orchestrator decides to ship `monitorTypeSurfaces: 'include'` as an
amendment, a tiny additional unit test would pin the constraint application:
- `tests/offscreen/monitor-type-surfaces.test.ts` — 1 test: constraints
  passed to `getDisplayMedia` include `monitorTypeSurfaces: 'include'`.

## Security Domain

### Applicable ASVS Categories

| ASVS category | Applies | Standard control |
|--------------|---------|------------------|
| V2 Authentication | No | (no auth surface in Plan 01-10) |
| V3 Session management | No | (no session model — ephemeral browser session) |
| V4 Access control | Yes (manifest) | MV3 `web_accessible_resources` minimal-scope (only welcome.html, no other paths) |
| V5 Input validation | Limited | `storage` keys validated as exact-match (`'onboarding-completed'`) |
| V6 Cryptography | No | (no cryptographic surface in Plan 01-10) |
| V9 Communication | Yes | Welcome page → SW via `chrome.runtime.sendMessage` (extension-internal channel; not exposed cross-origin) |
| V14 Configuration | Yes | Manifest permissions audit — Plan 01-10 adds `web_accessible_resources` only; no new permissions |

### Known Threat Patterns for Plan 01-10

| Pattern | STRIDE | Standard mitigation |
|---------|--------|---------------------|
| Welcome page accessible from `<all_urls>` matches → arbitrary web page can iframe it | Information Disclosure / Tampering | Welcome page does NOT expose privileged APIs to its DOM — read-only `COPY` rendering; no message-handler exposure to incoming runtime messages from non-extension origins |
| Storage flag spoofable by non-extension code | Tampering | `chrome.storage.local` is per-extension-isolated; only Mokosh can set/get the flag. No mitigation needed. |
| Notification id spoofing (Plan 01-09 T-1-09-01) | Spoofing | Already mitigated in Plan 01-09 by `'mokosh-'` prefix validation; Plan 01-10 does not extend this surface. |
| Enterprise policy abuse to bypass consent (Area 2 deferred idea) | Spoofing / Repudiation | DEFERRED — out of Plan 01-10 scope; future phase would require org-side consent flow. |

## Sources

### Primary (HIGH confidence)

- W3C Screen Capture spec — https://www.w3.org/TR/screen-capture/ (gesture
  requirement §5.1, mandatory picker)
- MDN MediaDevices.getDisplayMedia — https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia
  (transient activation requirement, InvalidStateError exception)
- Chrome official MV3 screen-capture guide — https://developer.chrome.com/docs/extensions/how-to/web-platform/screen-capture
- Chrome desktopCapture API reference — https://developer.chrome.com/docs/extensions/reference/api/desktopCapture
- Chrome blog: Privacy-preserving screen sharing controls (displaySurface,
  monitorTypeSurfaces) — https://developer.chrome.com/docs/web-platform/screen-sharing-controls
- Microsoft Edge enterprise policy docs:
  ScreenCaptureWithoutGestureAllowedForOrigins —
  https://learn.microsoft.com/en-us/deployedge/microsoft-edge-browser-policies/screencapturewithoutgestureallowedfororigins
  (Edge ≥ 123 Windows + macOS, 2026-04-30)
- Chrome Enterprise Policy List —
  https://gpedit.tplant.com.au/en-us/policy/chrome/ScreenCaptureWithoutGestureAllowedForOrigins
- Chromium chromium-extensions group: chooseDesktopMedia streamId not usable
  in MV3 offscreen — https://groups.google.com/a/chromium.org/g/chromium-extensions/c/3RanHldyp9c
  (Chrome DevRel Oliver Dunk response, Aug 2025)
- Plan 01-09 working code: `src/background/index.ts:896-914` (toolbar
  onClicked → getDisplayMedia path proven via UAT 15/15 GREEN)
- 01-CONTEXT.md amendments (D-15-display-surface, D-16-toolbar,
  D-17-onboarding, D-17-port-lifecycle)

### Secondary (MEDIUM confidence)

- chromestatus feature 5090735022407680 "Calling getDisplayMedia() without
  user activation" (enterprise-policy feature gate)
- Loom support docs:
  https://support.atlassian.com/loom/docs/install-the-chrome-extension/
- Screencastify product page: https://www.screencastify.com/chrome-extension
- Veed.io support: https://support.veed.io/en/articles/11099678-how-to-use-our-recorder
- Awesome Screenshot install docs:
  https://support.awesomescreenshot.com/hc/en-us/articles/900005583863
- Mozilla Firefox bugzilla 1580944, 1705289 (cross-browser convergence on
  transient-activation requirement)

### Tertiary (LOW confidence — corroborating only)

- WebRTC Hacks (Chrome Screensharing Blues) — context, no novel claims
- M2K Medium article on desktopCapture — corroborates official API behavior
- democreator/wondershare guides on screen-recording extensions —
  corroborates industry pattern

## Metadata

**Confidence breakdown:**

- W3C spec mandate / gesture floor: HIGH — multiple independent sources
- Enterprise policy applicability: MEDIUM-HIGH on existence; MEDIUM on
  extension-URL acceptance; LOW on Linux/ChromeOS
- Welcome-tab gesture chain: HIGH — verified empirically via Plan 01-09
- Picker bypass infeasibility: HIGH — convergent W3C + Chrome + Chromium
  sources
- Prior art consensus: HIGH — five independent extensions converge
- Privacy/consent floor: MEDIUM-HIGH (depends on Repremium's specific
  operator jurisdiction)
- Edge cases (macOS, Wayland, multi-monitor): HIGH-MEDIUM-LOW respectively

**Research date:** 2026-05-19
**Valid until:** 2026-08-19 (90 days — Chrome stable channel rolls
quarterly; spec is stable longer; enterprise policy stable longer)

**Open follow-up if research becomes stale:**

- Watch for `getViewportMedia` shipping in Chrome — could enable picker-less
  self-tab capture (NOT useful for Mokosh's whole-desktop charter, but
  worth knowing about)
- Watch for chromium-extensions group resolution of the `chooseDesktopMedia`
  + offscreen MV3 issue (currently unresolved, low priority per Chrome
  DevRel)
- Watch for any enterprise-policy expansion that opens up extension-URL
  patterns explicitly
