Files
Mark 4d828f1080 docs(01-10): install-flow + auto-select research — both asks INFEASIBLE
Researcher (gsd-phase-researcher) returned HIGH-confidence verdicts on the
12-area brief from .continue-here.md:

Ask 1 (install-time auto-start): INFEASIBLE in unmanaged Chrome.
  W3C Screen Capture spec §5.1 mandates transient user activation;
  chrome.runtime.onInstalled confers none. Floor: 2 clicks
  (toolbar/welcome-page → Share button on picker). Enterprise policy
  ScreenCaptureWithoutGestureAllowedForOrigins exists (Chrome+Edge ≥ 123)
  but only applies to managed-Chrome contexts with extension URL
  whitelisted — does NOT apply to Load-Unpacked deployment; deferred-idea.

Ask 2 (auto-select desktop / skip picker): INFEASIBLE in unmanaged Chrome.
  W3C spec mandates user MUST choose every time. displaySurface:'monitor'
  is a hint (already applied src/offscreen/recorder.ts:270).
  chooseDesktopMedia doesn't auto-accept on single-monitor setups AND
  streamId not usable in MV3 offscreen documents (Chrome DevRel position).

Primary recommendation: KEEP Plan 01-10's current informational CTA
charter (commit 3a530c2 unchanged). Both architectures hit the same
2-click floor; informational CTA has lower maintenance surface AND
teaches operator where the toolbar icon lives (critical for day-2+
sessions).

Enhancement candidate (NOT required for 01-10): add
monitorTypeSurfaces:'include' (Chrome ≥ 119) to offscreen getDisplayMedia
constraints — single line, zero risk, removes tab/window panes from
picker entirely. Suggest as Plan 01-09 amendment OR mini-plan.

Open questions for orchestrator (3):
1. Confirm informational CTA charter (this research recommends YES)
2. Ship monitorTypeSurfaces:'include' as Plan 01-09 amendment vs deferred?
3. Are Repremium operators on Wayland Linux? (affects welcome-page copy)

File: .planning/phases/01-stabilize-video-pipeline/01-10-RESEARCH.md
  (1092 lines; full W3C citations, Chromium issue links, prior art for
  Loom/Screencastify/Veed/Awesome-Screenshot, ASCII flow diagrams,
  edge-case enumeration for macOS/Wayland/incognito/managed-Chrome)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 20:12:18 +02:00

60 KiB

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):

// 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:

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.

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)

// 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)

// 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);
}
// 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'

// 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)

Secondary (MEDIUM confidence)

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