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>
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, NOTtabCapture; whole-desktop only; reject window/tab surfaces. - D-06 (locked):
SAVE_ARCHIVEdoes 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):
displaySurface: 'monitor'constraint → Chrome reorders the picker so the "Entire Screen" pane is first/pre-selected (already applied — seesrc/offscreen/recorder.ts:270). [VERIFIED: code grep]- Post-grant validation rejecting non-monitor surfaces → already applied via D-15. [VERIFIED: D-15-display-surface amendment in 01-CONTEXT.md]
- 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
InvalidStateErroras 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 likehttps://www.example.comand[*.]example.edu. - macOS:
defaults write com.google.Chrome ScreenCaptureWithoutGestureAllowedForOriginsvia 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:
- Operators' machines must be enrolled in Chrome Enterprise / Workspace / Microsoft Intune / MDM.
- 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.
- Even with the policy,
getDisplayMediaskips 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-914proves the pattern: toolbar click → SW listener →startVideoCapture()→ offscreen sendMessage →getDisplayMediacall succeeds withoutInvalidStateError. - Plan 01-09 also proves
notifications.onClickedworks 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
chooseDesktopMediareturned 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:
- NO extension auto-starts at install. This is industry-wide consensus — the W3C spec gesture requirement is universal.
- NO extension skips the picker. Even Loom (the polished category leader) shows the Chrome picker on every record.
- 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.
- 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:
desktopCapturepermission: required to callchrome.desktopCapture.*. Already present in manifest.json:7. Does NOT bypassgetDisplayMediagesture requirement.activeTabpermission: grants temporary host permission to the active tab on user invocation. Already present in manifest.json:8. Does NOT bypassgetDisplayMediagesture requirement.tabspermission: enables full tab API access. Mokosh does NOT include this —activeTabsuffices forcaptureVisibleTab(screenshot path).tabCapturepermission: would enablechrome.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
getDisplayMediacall 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
getDisplayMediacall 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 noincognitokey). Per MV3, extensions default toincognito: splitif not specified, OR may benot_alloweddepending on the user's per-extension toggle. - In incognito tabs, Mokosh's content scripts may not load;
getDisplayMediastill 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,
ScreenCaptureWithoutGestureAllowedForOriginspolicy IF applied AND IF accepting extension URLs would allowonInstalledto callgetDisplayMediawithout 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 bygetViewportMedia(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
-
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.
-
Should
monitorTypeSurfaces: 'include'be added to thegetDisplayMediaconstraints?- 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.
-
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 togetDisplayMediaincludemonitorTypeSurfaces: '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
getViewportMediashipping 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