Files
mokosh/.planning/phases/01-stabilize-video-pipeline/01-14-PLAN.md
Mark 41c1f7e82f feat(01-14): plan — monitorTypeSurfaces picker enhancement (canonical post-closure scope)
Plan 01-14 ships W3C Screen Capture monitorTypeSurfaces: 'include' (Chrome
119+) on the offscreen getDisplayMedia call, plus an A23 harness regression
assertion that verifies the constraint reaches the call site via the
existing offscreen-hooks bridge.

Scope: 1 source line + A23 wiring + Tier-1 grep gate inventory update
(lockstep extension of unit-gate + UAT A0 FORBIDDEN_HOOK_STRINGS).
Autonomous, single executor; no operator empirical checkpoint (UAT 16/16
harness coverage suffices per feedback-pre-checkpoint-bundle-gates.md).

Canonical sources:
- Plan 01-10 RESEARCH section 5 ('monitorTypeSurfaces: include' recommendation)
- Plan 01-10 RESEARCH section Pitfall-5 ('Misinterpreting displaySurface
  as a hard constraint' — monitorTypeSurfaces is the picker-UI complement
  to D-15's post-grant validation)
- W3C Screen Capture spec section 6.1 DisplayMediaStreamOptions
- developer.chrome.com/docs/web-platform/screen-sharing-controls

Decisions honored:
- D-01 (whole-desktop only via getDisplayMedia; reject window/tab) — the
  new constraint is the picker-UI realization of D-01's intent.
- D-15 (post-grant displaySurface validation) — UNCHANGED; remains the
  enforcement (this plan is belt-and-suspenders at the picker UI level).

Ceremony note: this plan replaces the prior AMENDMENT-A.md improvisation
path retired per 01-11-SUMMARY Architectural Notes. Canonical GSD ceremony
(plan -> checker -> executor -> SUMMARY).

Validations:
- gsd-sdk frontmatter.validate -> valid: true (8/8 required fields).
- gsd-sdk verify.plan-structure -> valid: true (1 task; hasFiles/hasAction
  /hasVerify/hasDone all true).
- ROADMAP.md Phase 1 plans list extended with 01-14 entry.

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

31 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, gap_closure, requirements, tags, must_haves
phase plan type wave depends_on files_modified autonomous gap_closure requirements tags must_haves
01-stabilize-video-pipeline 14 execute 1
src/offscreen/recorder.ts
src/test-hooks/offscreen-hooks.ts
src/test-hooks/types.ts
tests/uat/extension-page-harness.ts
tests/uat/lib/harness-page-driver.ts
tests/uat/harness.test.ts
tests/background/no-test-hooks-in-prod-bundle.test.ts
true false
REQ-video-ring-buffer
mv3-extension
getDisplayMedia
monitorTypeSurfaces
picker-friction-reduction
uat
harness
truths artifacts key_links
Operator picker dialog presents ONLY monitor surfaces — no 'Window' pane, no 'Chrome Tab' pane (W3C `monitorTypeSurfaces: 'include'` semantics, Chrome ≥ 119). The 1-click W3C consent gate remains; the choice space is narrowed.
`src/offscreen/recorder.ts` `getDisplayMedia()` call passes `monitorTypeSurfaces: 'include'` as a top-level constraint (sibling of `video:`, NOT nested inside `video:`) per W3C Screen Capture spec — the option is a `DisplayMediaStreamOptions` member, not a `MediaTrackConstraints` member.
UAT harness assertion A23 verifies the constraint reaches the call site: extends `installFakeDisplayMedia` to record the last-received constraints object; new `__mokoshOffscreenQuery` op `get-last-getDisplayMedia-constraints` returns it; `assertA23` reads it and asserts `monitorTypeSurfaces === 'include'`.
`npm run test:uat` exit 0 with 16/16 GREEN (A0 grep gate + A1..A14 preserved + A23 new). A23 chains AFTER A14 (A14 is the final read-only post-SAVE state check; A23 makes a fresh getDisplayMedia call to inspect the constraint, which is independent of A14's no-side-effects contract because A23 only reads the recorded constraints from the LAST call — A2's setupFreshRecording already invoked it).
Existing vitest baseline preserved at 98/98 GREEN. The change is additive at the source level; no existing unit test references the constraints object structure explicitly (verified via `grep -rn 'displaySurface.*monitor' tests/` → only documentation comments, no test inspects the constraint payload).
`npm run build` exits 0; `tsc --noEmit` exits 0 (no new types beyond extending the existing `MokoshTestSurface` cross-cast).
Tier-1 grep gate preserved: `tests/background/no-test-hooks-in-prod-bundle.test.ts` FORBIDDEN_HOOK_STRINGS extended with `lastGetDisplayMediaConstraints` and `get-last-getDisplayMedia-constraints`; production `dist/` contains ZERO occurrences of either string (gated identically to the Plan 01-13 hook surface — `__MOKOSH_UAT__` dead-branch tree-shake).
Production bundle hook-free: `npm run build` produces `dist/` with no test-hook leakage. The grep gate's mirror in `tests/uat/harness.test.ts:85` (FORBIDDEN_HOOK_STRINGS — UAT-level A0) is extended in lockstep with the unit-gate inventory.
Commit message follows project convention: `feat(01-14): monitorTypeSurfaces:'include' — narrow picker to monitor surfaces only`.
path provides contains
src/offscreen/recorder.ts Single new line added to the `getDisplayMedia` constraints block at line ~270: `monitorTypeSurfaces: 'include'` as a sibling of `video:` (per W3C `DisplayMediaStreamOptions` shape). The existing `as DisplayMediaStreamOptions & {video:...}` typed widening is extended to include `monitorTypeSurfaces: 'include'` so the cross-cast stays explicit (no `as any`). The D-15 post-grant validation block at line ~294 is UNCHANGED — the new option is belt-and-suspenders at the picker UI level; the post-grant guard remains the actual enforcement. monitorTypeSurfaces
path provides contains
src/test-hooks/offscreen-hooks.ts `installFakeDisplayMedia` extended to record the last-received constraints object in a module-scoped `lastGetDisplayMediaConstraints: DisplayMediaStreamOptions | null` (already takes `_constraints?: DisplayMediaStreamOptions` parameter at line 236 — currently unused, now captured into the module-level cell on every call). New `__mokoshOffscreenQuery` op `get-last-getDisplayMedia-constraints` added to the dispatcher at line ~407 (after `get-display-surface`, before `get-segment-count`) that responds with `{ constraints: lastGetDisplayMediaConstraints }` or `{ constraints: null }` if no call has been made yet. lastGetDisplayMediaConstraints
path provides
src/test-hooks/types.ts Extends `MokoshTestSurface` (or the equivalent typed surface contract per Plan 01-13 Wave 3 extension) with optional `lastGetDisplayMediaConstraints?: DisplayMediaStreamOptions | null` field IF the cross-cast in `offscreen-hooks.ts` needs it for clean typing; if the bridge op route (op string match → response) does not require the surface to expose this directly, this file may need no change. Defer to the implementer's read of the current cross-cast shape.
path provides min_lines
tests/uat/extension-page-harness.ts New `assertA23` function added BEFORE the `getManifestVersion` helper at line ~1906. Mirrors the `assertA3` pattern (offscreenQuery bridge call → structured AssertionResult). Verifies the recorded constraints object contains `monitorTypeSurfaces === 'include'`. The `__mokoshHarness` global surface (declared at line 1922) is extended with `assertA23: () => Promise<AssertionResult>`; the export at line 1942 adds `assertA23`. Console-log + status-bar message at line 1965 updated to reference A23. 70
path provides
tests/uat/lib/harness-page-driver.ts New `driveA23(page: Page): Promise<AssertionRecord>` exported after `driveA14` at line ~995 (mirrors the `driveA14` page.evaluate wrapper pattern — single `page.evaluate(() => window.__mokoshHarness.assertA23())` call). Standard read-only driver: no host-side side effects, just bridges to the page-side assertion.
path provides
tests/uat/harness.test.ts FORBIDDEN_HOOK_STRINGS list at line 85 extended with `lastGetDisplayMediaConstraints` and `get-last-getDisplayMedia-constraints`. The `drivers` array at line 289-312 extended with `{ name: 'A23', drive: driveA23 }` as the LAST entry (after A14 — A23 is independent and adds no new state). The total assertion count comment at line 354 updated: `Total = 1 (A0) + drivers.length (A1..A14, A23) = 16`. The `import { driveA14 }` block at line ~55-69 extended to import `driveA23` from `./lib/harness-page-driver`. Header comment block (lines 1-26) updated to mention A23 + Plan 01-14 charter.
path provides contains
tests/background/no-test-hooks-in-prod-bundle.test.ts FORBIDDEN_HOOK_STRINGS list at line 105 extended with `lastGetDisplayMediaConstraints` and `get-last-getDisplayMedia-constraints` (lockstep mirror of the UAT A0 list). Confirms production `dist/` has zero occurrences of either symbol after `npm run build` — the `__MOKOSH_UAT__` Vite define-token dead-branch tree-shake correctly elides the new surface. lastGetDisplayMediaConstraints
from to via pattern
src/offscreen/recorder.ts Chrome picker UI navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: 'monitor', cursor: 'always' }, monitorTypeSurfaces: 'include', audio: false }) monitorTypeSurfaces:\s*['"]include['"]
from to via pattern
src/test-hooks/offscreen-hooks.ts:installFakeDisplayMedia src/test-hooks/offscreen-hooks.ts:__mokoshOffscreenQuery dispatcher 'get-last-getDisplayMedia-constraints' op module-scoped lastGetDisplayMediaConstraints cell populated on every fakeGetDisplayMedia call; bridge op reads it lastGetDisplayMediaConstraints
from to via pattern
tests/uat/extension-page-harness.ts:assertA23 src/test-hooks/offscreen-hooks.ts:get-last-getDisplayMedia-constraints bridge op offscreenQuery<{ constraints: DisplayMediaStreamOptions | null }>('get-last-getDisplayMedia-constraints') get-last-getDisplayMedia-constraints
from to via pattern
tests/uat/harness.test.ts drivers array tests/uat/lib/harness-page-driver.ts:driveA23 { name: 'A23', drive: driveA23 } appended after A14 entry name:\s*['"]A23['"]
from to via pattern
tests/background/no-test-hooks-in-prod-bundle.test.ts FORBIDDEN_HOOK_STRINGS dist/ bundle artifact tree post-build grep for lastGetDisplayMediaConstraints + get-last-getDisplayMedia-constraints FORBIDDEN_HOOK_STRINGS.*lastGetDisplayMediaConstraints

Scope Sanity Note

1 task, autonomous, single executor. This is the canonical-floor "small surgical plan" shape: one source change + one harness regression assertion + grep-gate inventory update. Per <scope_estimation> Light context weight: ~10-15% context cost for a single executor. No split signals; no checkpoint (UAT harness coverage suffices per feedback-pre-checkpoint-bundle-gates.md — A23 + A0 grep gates are the empirical floor that replaces operator-time-spend for this enhancement).

Genesis note. This plan ships a Plan 01-10 RESEARCH §5 + §Pitfall-5 recommendation ("Add monitorTypeSurfaces: 'include' to the offscreen getDisplayMedia constraints. Single-line, zero-risk change that removes visual noise from the picker"). The prior attempt to ship the same change as an AMENDMENT-A.md anti-pattern was retired per 01-11-SUMMARY.md Architectural Notes — this plan replaces that improvised path with canonical GSD ceremony (plan → checker → executor → SUMMARY).

gap_closure: false — this is a research-discovered enhancement, NOT a VERIFICATION.md gap closure. The flag is set explicitly to make the distinction unambiguous: VERIFICATION-gap closure plans must verify against .planning/phases/<phase>/VERIFICATION.md; this plan's must_haves contract is the verification reference.

Ship the W3C Screen Capture `monitorTypeSurfaces: 'include'` parameter (Chrome ≥ 119) on the `getDisplayMedia` call in `src/offscreen/recorder.ts`. This narrows the picker dialog presented to operators by removing the "Window" and "Chrome Tab" panes — only monitor surfaces are offered. The 1-click W3C-mandated consent gate (the "Share" button on the picker) remains and is fundamentally non-bypassable in unmanaged Chrome per Plan 01-10 RESEARCH §1, §5, §11 verdicts; the achievable improvement is narrowing the operator's choice space and eliminating the "Share this tab instead" footgun at the UI level rather than catching it post-grant via D-15's wrong-display-surface error path.

The change is consistent with PROJECT.md D-01 (whole-desktop only via getDisplayMedia; reject window/tab surfaces) — monitorTypeSurfaces: 'include' is the picker-UI realization of D-01's intent. D-15 post-grant validation stays as belt-and-suspenders.

Purpose: reduce operator picker friction within W3C-spec bounds; ship a research-validated single-line enhancement via canonical GSD ceremony (not amendment improvisation). Output: 1 source line + A23 harness regression assertion + Tier-1 grep gate inventory update; UAT 16/16 GREEN; vitest 98/98 GREEN; production bundle hook-free.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-stabilize-video-pipeline/01-10-RESEARCH.md @.planning/phases/01-stabilize-video-pipeline/01-13-SUMMARY.md @.planning/phases/01-stabilize-video-pipeline/01-11-SUMMARY.md @src/offscreen/recorder.ts @src/test-hooks/offscreen-hooks.ts @src/test-hooks/types.ts @tests/uat/extension-page-harness.ts @tests/uat/lib/harness-page-driver.ts @tests/uat/harness.test.ts @tests/background/no-test-hooks-in-prod-bundle.test.ts

W3C DisplayMediaStreamOptions (per spec §6.1 — https://www.w3.org/TR/screen-capture/#dom-displaymediastreamoptions):

interface DisplayMediaStreamOptions {
  video?: boolean | MediaTrackConstraints;
  audio?: boolean | MediaTrackConstraints;
  controller?: CaptureController;
  selfBrowserSurface?: 'include' | 'exclude';
  surfaceSwitching?: 'include' | 'exclude';
  systemAudio?: 'include' | 'exclude';
  monitorTypeSurfaces?: 'include' | 'exclude';   // <-- THIS PLAN ADDS
  preferCurrentTab?: boolean;
}

Critical: monitorTypeSurfaces is a TOP-LEVEL member of DisplayMediaStreamOptions, NOT a nested member of MediaTrackConstraints (no video: { monitorTypeSurfaces }). Spec ref: https://www.w3.org/TR/screen-capture/#dom-displaymediastreamoptions-monitortypesurfaces.

Current call site (src/offscreen/recorder.ts:270):

const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor', cursor: 'always' },
  audio: false,
} as DisplayMediaStreamOptions & {
  video: { displaySurface: 'monitor'; cursor: 'always' };
});

Required target (the only source change):

const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor', cursor: 'always' },
  monitorTypeSurfaces: 'include',  // Plan 01-14 — Chrome ≥ 119 picker narrowing per W3C spec §6.1
  audio: false,
} as DisplayMediaStreamOptions & {
  video: { displaySurface: 'monitor'; cursor: 'always' };
  monitorTypeSurfaces: 'include';
});

Existing offscreen-hooks bridge dispatcher pattern (src/test-hooks/offscreen-hooks.ts:370-468):

chrome.runtime.onMessage.addListener((rawMessage, _sender, sendResponse) => {
  // ...
  if (op === 'get-display-surface') {
    try {
      if (currentStream === null) { sendResponse({ displaySurface: null }); return false; }
      const track = currentStream.getVideoTracks()[0];
      // ...
      sendResponse({ displaySurface });
    } catch (err) {
      sendResponse({ ok: false, error: err instanceof Error ? err.message : String(err) });
    }
    return false;
  }
  // New A23 op handler goes here (after get-display-surface, before get-segment-count)
});

Existing installFakeDisplayMedia signature (src/test-hooks/offscreen-hooks.ts:236) — already accepts _constraints (currently unused, prefixed _ to suppress lint):

const fakeGetDisplayMedia = async (
  _constraints?: DisplayMediaStreamOptions,
): Promise<MediaStream> => { ... };

Existing assertA3 pattern to mirror (tests/uat/extension-page-harness.ts:686-724) and existing driveA14 pattern to mirror (tests/uat/lib/harness-page-driver.ts:987-994) — both are direct copy-paste templates for A23's read-only assertion + driver shape.

Existing FORBIDDEN_HOOK_STRINGS inventory locations (both kept in lockstep per Plan 01-13 Wave 0 contract):

  • tests/background/no-test-hooks-in-prod-bundle.test.ts:105
  • tests/uat/harness.test.ts:85
Task 1: Add monitorTypeSurfaces:'include' to getDisplayMedia constraints + wire A23 harness assertion + extend Tier-1 grep gate inventory in lockstep src/offscreen/recorder.ts, src/test-hooks/offscreen-hooks.ts, src/test-hooks/types.ts, tests/uat/extension-page-harness.ts, tests/uat/lib/harness-page-driver.ts, tests/uat/harness.test.ts, tests/background/no-test-hooks-in-prod-bundle.test.ts **Step 1: Source change** — `src/offscreen/recorder.ts` line ~270. Add `monitorTypeSurfaces: 'include'` as a top-level constraint sibling of `video:` (NOT nested inside `video:` — per W3C spec §6.1 DisplayMediaStreamOptions structure). Extend the existing typed widening cast (line ~273-275) to include `monitorTypeSurfaces: 'include'` so the explicit-typing contract is preserved (no `as any`). Add an inline comment citing Plan 01-10 RESEARCH §5 + W3C spec §6.1 + Chrome 119+ feature-gate URL (https://developer.chrome.com/docs/web-platform/screen-sharing-controls). Leave the D-15 post-grant validation block (line ~294) UNCHANGED — `monitorTypeSurfaces: 'include'` is belt-and-suspenders at the picker UI level; D-15 remains the actual enforcement (operator can still defeat the constraint via picker click, per spec HINT semantics).

Step 2: offscreen-hooks bridgesrc/test-hooks/offscreen-hooks.ts. (a) At module scope (near line 97 where fakeInstalled lives), declare let lastGetDisplayMediaConstraints: DisplayMediaStreamOptions | null = null; with a docstring referencing Plan 01-14 A23 contract. (b) Inside installFakeDisplayMedia's fakeGetDisplayMedia closure (line ~236 where _constraints?: DisplayMediaStreamOptions is currently received-but-unused), rename _constraintsconstraints and add the first line in the function body: lastGetDisplayMediaConstraints = constraints ?? null;. (c) In the __mokoshOffscreenQuery dispatcher (line ~370), add a new if (op === 'get-last-getDisplayMedia-constraints') block AFTER the get-display-surface handler (line ~407) and BEFORE get-segment-count (line ~436). Response shape: { constraints: lastGetDisplayMediaConstraints }. Follow the existing try/catch + sendResponse pattern — no exceptions allowed to propagate to chrome.runtime.sendMessage.

Step 3: types.ts (optional)src/test-hooks/types.ts. Only extend the surface contract IF the offscreen-hooks cross-cast at the bottom of the file (line ~322-330 area; see the MokoshTestSurface & {...} shape) requires it for clean typing. The bridge-op route uses op-string matching not surface-method dispatch, so the recorded constraints cell is a module-internal detail — types.ts probably needs no change. Read the current cross-cast and decide; if no change is needed, document the decision in the commit body.

Step 4: harness page A23tests/uat/extension-page-harness.ts. Add async function assertA23(): Promise<AssertionResult> BEFORE the getManifestVersion helper at line ~1906. Mirror assertA3 (line 686-724) structure exactly: call offscreenQuery<{ constraints: DisplayMediaStreamOptions | null; ok?: boolean; error?: string }>('get-last-getDisplayMedia-constraints'); push two checks: A23.1: constraints object recorded (non-null) (passed: resp.constraints !== null) and A23.2: constraints.monitorTypeSurfaces === 'include' (expected 'include', actual resp.constraints?.monitorTypeSurfaces). Standard try/catch/diag pattern.

Then extend the Window.__mokoshHarness declaration (line 1922) with assertA23: () => Promise<AssertionResult>; and the runtime export (line 1942) with assertA23,. Update the console.log (line 1965) and the status-bar text (line 1962) to reference A23.

Step 5: harness drivertests/uat/lib/harness-page-driver.ts. Add export async function driveA23(page: Page): Promise<AssertionRecord> after driveA14 (line ~995). Mirror driveA14 (line 987-994) — single page.evaluate(() => window.__mokoshHarness.assertA23()) call. Docstring references Plan 01-14 A23 contract.

Step 6: harness orchestratortests/uat/harness.test.ts. (a) Add 'lastGetDisplayMediaConstraints' and 'get-last-getDisplayMedia-constraints' to FORBIDDEN_HOOK_STRINGS (line 85). (b) Add driveA23 to the import block (line ~55-69 — import from ./lib/harness-page-driver). (c) Append { name: 'A23', drive: driveA23 } to the drivers array (line 292-312, after the A14 entry on line 311). (d) Update the comment at line 354: // Total = 1 (A0) + drivers.length (A1..A14, A23) = 16.. (e) Update the header comment block (lines 1-26) — add a Plan 01-14 paragraph: A23 added as the final functional assertion (post-A14 chain; read-only inspection of last getDisplayMedia constraints from A2's setupFreshRecording; verifies monitorTypeSurfaces:'include' reached the call site).

Step 7: Tier-1 grep gate unit testtests/background/no-test-hooks-in-prod-bundle.test.ts. Add 'lastGetDisplayMediaConstraints' and 'get-last-getDisplayMedia-constraints' to FORBIDDEN_HOOK_STRINGS (line 105). The two list locations stay in lockstep per Plan 01-13 Wave 0 architectural commitment (belt-and-suspenders per feedback-pre-checkpoint-bundle-gates.md).

Step 8: verify the build chainnpm run build (production); npm run build:test (test bundle); tsc --noEmit. Production dist/ must have zero occurrences of lastGetDisplayMediaConstraints and get-last-getDisplayMedia-constraints (the __MOKOSH_UAT__ Vite define-token dead-branch tree-shake elides them).

Step 9: verify the test chainnpm test (vitest 98/98 GREEN, plus the Tier-1 grep gate now exercises the new forbidden-strings against a fresh production build); npm run test:uat (UAT 16/16 GREEN — A0 grep gate + A1..A14 + A23).

Atomic commit with message: feat(01-14): monitorTypeSurfaces:'include' — narrow picker to monitor surfaces only. Commit body includes: (a) link to Plan 01-10 RESEARCH §5 + §Pitfall-5 + W3C spec §6.1 + Chrome screen-sharing-controls doc URL; (b) D-01 + D-15 references (consistency with whole-desktop-only intent + belt-and-suspenders relationship with post-grant validation); (c) UAT 16/16 PASS report (counts before/after); (d) vitest 98/98 PASS report; (e) Tier-1 grep gate post-build clean confirmation. npm run build && npm run build:test && npx tsc --noEmit && npm test && npm run test:uat

Expected outputs:

  • npm run build exits 0; dist/ produced.
  • npm run build:test exits 0; dist-test/ produced.
  • npx tsc --noEmit exits 0; no type errors.
  • npm test exits 0; 98+ vitest tests GREEN (the no-test-hooks-in-prod-bundle gate now greps for the two new forbidden strings against the freshly-built dist/ and confirms zero occurrences).
  • npm run test:uat exits 0; final line reads UAT harness: 16/16 assertions passed.

Production-bundle hook-free spot-check (orchestrator may run as a sanity gate before checkpointing):

grep -rc 'monitorTypeSurfaces' /home/parf/projects/work/repremium/dist/ | grep -v ':0$'    # expected: only the recorder.ts compiled chunk; the constant 'include' string is production-shipped intentionally
grep -rc 'lastGetDisplayMediaConstraints\|get-last-getDisplayMedia-constraints' /home/parf/projects/work/repremium/dist/ | grep -v ':0$'    # expected: ZERO matches (every line has count 0 → grep -v ':0$' yields no output)
- `src/offscreen/recorder.ts` `getDisplayMedia` call passes `monitorTypeSurfaces: 'include'` at the top level (sibling of `video:`), with the typed widening cast updated to match. - `src/test-hooks/offscreen-hooks.ts` records the last-received constraints object on every `fakeGetDisplayMedia` call and exposes it via the `get-last-getDisplayMedia-constraints` bridge op. - `tests/uat/extension-page-harness.ts` exposes `window.__mokoshHarness.assertA23` that verifies `monitorTypeSurfaces === 'include'` round-trips through the fake getDisplayMedia path. - `tests/uat/lib/harness-page-driver.ts` exports `driveA23` page.evaluate wrapper. - `tests/uat/harness.test.ts` runs A23 as the final functional assertion; final report reads `16/16 assertions passed`. - `tests/background/no-test-hooks-in-prod-bundle.test.ts` and `tests/uat/harness.test.ts` FORBIDDEN_HOOK_STRINGS lists both contain `lastGetDisplayMediaConstraints` and `get-last-getDisplayMedia-constraints`; production `dist/` is hook-free per both gates. - Single atomic commit with the prescribed message lands on the working branch. - vitest 98/98 GREEN; UAT 16/16 GREEN; `tsc --noEmit` clean.

<threat_model>

Trust Boundaries

Boundary Description
operator ↔ Chrome picker UI Operator's monitor-source selection click is the W3C-mandated consent gate. The new constraint narrows the choice surface but does NOT bypass the gate.
extension offscreen ↔ browser screen-capture engine getDisplayMedia is the API boundary; constraints are advisory HINTS (per spec) for displaySurface but monitorTypeSurfaces: 'include' is a stronger filter (per Chrome 119+ implementation; spec §6.1 grammar describes it as a binary include/exclude category gate). D-15 post-grant validation remains the actual enforcement.
production dist/ ↔ test-hook surface New lastGetDisplayMediaConstraints cell + get-last-getDisplayMedia-constraints bridge op live behind __MOKOSH_UAT__ Vite define-token gate; dead-branch tree-shake elides from production. Tier-1 grep gate (unit + UAT) enforces.

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-01-14-01 Spoofing A web page tricks operator into thinking the picker now offers MORE surface types (e.g., adversarial extension claims Mokosh enables tab-recording) accept Mokosh's picker presents FEWER options than before, not more. Operator-facing surface area shrinks. No new spoofing vector.
T-01-14-02 Tampering Operator overrides the monitorTypeSurfaces: 'include' constraint via Chrome flags / DevTools / managed-policy accept Spec semantics: constraints are advisory in the worst case. D-15 post-grant validation already tears down + throws wrong-display-surface if track.getSettings().displaySurface !== 'monitor' (recorder.ts:296). Belt-and-suspenders chain unchanged.
T-01-14-03 Repudiation (n/a — no audit-log surface added) n/a
T-01-14-04 Information Disclosure New test hook leaks the operator's getDisplayMedia constraints object into production builds mitigate __MOKOSH_UAT__ Vite define-token dead-branch tree-shake elides lastGetDisplayMediaConstraints and the get-last-getDisplayMedia-constraints op handler from production. Tier-1 grep gate (unit at tests/background/no-test-hooks-in-prod-bundle.test.ts:105 + UAT mirror at tests/uat/harness.test.ts:85) extends FORBIDDEN_HOOK_STRINGS in lockstep. Verified GREEN via npm test + npm run test:uat per Task 1 verify block.
T-01-14-05 Denial of Service Chrome < 119 receives the unknown constraint and rejects getDisplayMedia with OverconstrainedError or similar, breaking the recorder for older Chromes accept Per Plan 01-10 RESEARCH §Environment-Availability: target Chrome is ≥ 119 (recommended for monitorTypeSurfaces). The constraint is an OPTIONAL member of DisplayMediaStreamOptions per spec — unknown options are ignored per W3C JavaScript dictionary semantics, NOT rejected. Older Chrome (<119) silently ignores it; behavior degrades to the current (pre-Plan-01-14) state (picker shows all panes). No DoS exposure.
T-01-14-06 Elevation of Privilege New get-last-getDisplayMedia-constraints bridge op exposes a constraints-object-introspection capability to any page that can send a __mokoshOffscreenQuery message accept The chrome.runtime.onMessage channel is extension-internal: only pages with the extension's runtime ID can send. The harness page (tests/uat/extension-page-harness.html) is in web_accessible_resources ONLY in the test bundle (vite.test.config.ts); production dist/ does NOT include it. Production dist/ does NOT include the bridge handler either (__MOKOSH_UAT__ dead-branch). Two-layer elision (resource list + handler code) — no production exposure surface.

Mitigation acceptance summary: 6 threats reviewed; 1 (T-01-14-04) actively mitigated via the existing Plan 01-13 Tier-1 grep gate (extended for this plan); 5 accepted with explicit rationale. No new permissions, no new web_accessible_resources, no new manifest changes. Threat surface delta from main: ZERO permission additions; new internal test-hook surface (gated identically to Plan 01-13's hook inventory). </threat_model>

**Per-task** (Task 1's verify block): full chain `npm run build && npm run build:test && npx tsc --noEmit && npm test && npm run test:uat`.

Phase gate (executor → /gsd-verify-work):

  1. Source-line correctness: grep -n "monitorTypeSurfaces" src/offscreen/recorder.ts returns the new line at the expected position. The string monitorTypeSurfaces: 'include' appears as a TOP-LEVEL constraint (sibling of video:), NOT nested inside video:. (W3C spec §6.1 compliance check.)
  2. A23 round-trips: npm run test:uat final summary line shows 16/16 assertions passed with [PASS] A23 in the per-assertion roll-up.
  3. Tier-1 grep gates GREEN: npm test shows no-test-hooks-in-prod-bundle.test.ts GREEN with the new forbidden strings in the inventory; npm run test:uat A0 grep gate confirms zero occurrences of lastGetDisplayMediaConstraints and get-last-getDisplayMedia-constraints in dist/.
  4. No vitest regression: full vitest run produces 98 GREEN tests (no change in count from pre-plan baseline; the change is additive at the source level and does not introduce or remove unit-test cases).
  5. Type cleanliness: npx tsc --noEmit exits 0; the typed widening cast on the getDisplayMedia constraints includes monitorTypeSurfaces: 'include' explicitly.
  6. Commit shape: single atomic commit on the working branch with the prescribed message and the documented commit body (research link, decision references, test reports).

<success_criteria>

  • Operator picker dialog presents ONLY monitor surfaces under Chrome ≥ 119 (W3C monitorTypeSurfaces: 'include' semantics). Verified empirically via the UAT A23 assertion's bridge-inspection of the recorded constraints object. The 1-click W3C consent gate remains (spec floor; not bypassable in unmanaged Chrome per Plan 01-10 RESEARCH).
  • The change is consistent with PROJECT.md D-01 (whole-desktop only via getDisplayMedia; reject window/tab surfaces) — the new constraint is the picker-UI realization of D-01's intent.
  • D-15 post-grant validation block (recorder.ts:294-307) is UNCHANGED; belt-and-suspenders chain preserved.
  • UAT harness exits 0 with 16/16 assertions passed.
  • vitest exits 0 with 98/98 GREEN; production-bundle Tier-1 grep gate confirms zero hook-surface leakage.
  • TypeScript compilation clean (tsc --noEmit exit 0).
  • Single atomic commit on the working branch (no fixup/squash commits). </success_criteria>
After completion, create `.planning/phases/01-stabilize-video-pipeline/01-14-SUMMARY.md` per the standard PLAN → SUMMARY contract. SUMMARY MUST include:
  1. What shipped — the single source line + A23 harness assertion + grep gate inventory updates + commit SHA.
  2. Verification evidencenpm test count (98/98), npm run test:uat count (16/16), tsc --noEmit clean, production-bundle grep-gate clean.
  3. Research linkage — citation to Plan 01-10 RESEARCH §5, §Pitfall-5, §Environment-Availability + W3C spec §6.1 + Chrome screen-sharing-controls doc URL.
  4. Decision linkage — D-01 (consistency: monitor-only intent realized at the picker UI level); D-15 (relationship: monitorTypeSurfaces is picker-UI belt; D-15 post-grant validation is the enforcement suspenders).
  5. Ceremony note — confirm this plan replaces the prior AMENDMENT-A.md improvisation path retired per 01-11-SUMMARY Architectural Notes; canonical GSD ceremony (plan → checker → executor → summary) is what landed.
  6. Architectural delta — ZERO new permissions; ZERO new manifest changes; ZERO new web_accessible_resources; new internal test-hook surface gated identically to Plan 01-13's inventory.
  7. What did not change — D-15 post-grant validation block; Plan 01-09 toolbar onClicked chain; Plan 01-10 welcome-page architecture; Plan 01-12 design-integration scope; Plan 01-13 harness architecture (the 14 existing assertions are unmodified; A23 is purely additive).