Append Amendment blocks to DEC-003 (getDisplayMedia replaces tabCapture) and DEC-010 (long-lived port replaces alarms keepalive) so downstream phases see the new API contract. Original text intact; amendments are appended, not replacements. Maintains intel/* provenance for the Phase 01 doc cascade.
199 lines
8.6 KiB
Markdown
199 lines
8.6 KiB
Markdown
# Architectural Decisions (synthesized from SPEC)
|
||
|
||
The SPEC `Тз расширение фаза1.md` does not formally label itself as ADR-set, but
|
||
sections 2 ("Стек"), 7 ("Разрешения в manifest.json"), and 8 ("Важные
|
||
ограничения и решения") encode binding technical choices that act as
|
||
architectural decisions for Phase 1. Each decision below is reproduced from the
|
||
SPEC verbatim where possible and tagged with its origin.
|
||
|
||
Status legend (synthesized, since SPEC has no formal ADR status field):
|
||
- `Accepted` — SPEC §2/§7/§8 prescribed, no contradicting source
|
||
- `locked: false` everywhere — SPEC is `locked: false` in classification, so
|
||
these decisions can still be revised by a future ADR; today they are the
|
||
authoritative baseline.
|
||
|
||
---
|
||
|
||
## DEC-001: Chrome Extension Manifest V3
|
||
|
||
- Source: `Тз расширение фаза1.md` §2 (Стек), §7 (Разрешения)
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Extension platform / packaging
|
||
- Decision: The extension MUST be implemented as a Chrome Extension targeting
|
||
Manifest V3 (Service Worker background, no persistent background page).
|
||
- Rationale (from SPEC): Required for modern Chrome compatibility; implied by
|
||
every API used (`chrome.tabCapture`, `chrome.downloads`, `chrome.tabs`,
|
||
`chrome.alarms`).
|
||
- Confirming source: `README.md` §"Технический стек" — "Chrome Extension,
|
||
Manifest V3".
|
||
|
||
---
|
||
|
||
## DEC-002: Service Worker as Background Coordinator
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §3 (Структура расширения), §8
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Background execution model
|
||
- Decision: Background logic runs in a Manifest V3 Service Worker
|
||
(`background/service-worker.js`) that coordinates the video buffer and
|
||
archive packaging.
|
||
- Constraint binding: Service Worker is unloaded after ~30 s idle; keepalive
|
||
MUST be maintained via `chrome.alarms` firing every 20 seconds (SPEC §8).
|
||
- Confirming source: `README.md` §"Технический стек".
|
||
|
||
---
|
||
|
||
## DEC-003: Tab Video Capture via `chrome.tabCapture`
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §4.1, §7
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Video acquisition
|
||
- Decision: Active-tab video is captured via `chrome.tabCapture.capture()`.
|
||
- Codec/bitrate binding: `video/webm; codecs=vp9` at `400 000 bps`.
|
||
- `MediaRecorder` chunk cadence: 2000 ms.
|
||
- Activation constraint: `tabCapture` is tied to the active tab and requires a
|
||
user gesture on first invocation; on tab switch the capture re-attaches.
|
||
- Confirming source: `README.md` §"Технический стек".
|
||
|
||
## Amendment (Phase 01-stabilize-video-pipeline, 2026-05-15)
|
||
|
||
- AMENDED-BY: Phase 01 CONTEXT.md D-01..D-05
|
||
- Replace `chrome.tabCapture.capture()` with `navigator.mediaDevices.getDisplayMedia()` called from the offscreen document.
|
||
- Offscreen document is created with `chrome.offscreen.Reason.DISPLAY_MEDIA` (replaces `USER_MEDIA`).
|
||
- Codec/bitrate/timeslice binding unchanged: `video/webm; codecs=vp9` @ 400 000 bps, MediaRecorder timeslice 2000 ms.
|
||
- Trade-off accepted: SPEC §1 "silent operation" is given up — Chrome's permanent "Sharing your screen" indicator is shown while recording. Phase 1 accepts this in exchange for broader capture coverage and elimination of `tabCapture` user-gesture juggling.
|
||
- Tab-switch re-attachment clause is REMOVED — `getDisplayMedia` captures a screen/window, not a tab. There is nothing to re-attach.
|
||
- Manifest permission `tabCapture` is REPLACED with `desktopCapture` (the latter is harmless: `getDisplayMedia` is a web standard API and does NOT actually require `desktopCapture`, but we declare it for clarity per CONTEXT.md D-05).
|
||
|
||
---
|
||
|
||
## DEC-004: DOM Capture via rrweb
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §4.2
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: DOM recording
|
||
- Decision: DOM events are captured via the `rrweb` npm library
|
||
(`rrweb.record()`), running in the Content Script, with events forwarded to
|
||
the Service Worker on archive-export request.
|
||
- Sensitive-data binding: rrweb is configured with `maskInputSelector` to mask
|
||
`input[type=password]` and `[data-sensitive="true"]`.
|
||
- Buffer cap binding: 5 000 rrweb events maximum; oldest dropped on overflow
|
||
(SPEC §8).
|
||
- Confirming source: `README.md` §"Технический стек", §"Особенности".
|
||
|
||
---
|
||
|
||
## DEC-005: Archive Packaging via JSZip
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §3, §6
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Archive assembly
|
||
- Decision: ZIP packaging uses the `jszip` npm library bundled as
|
||
`libs/jszip.min.js` (or the Vite-bundled equivalent).
|
||
- Archive layout binding: see REQ-archive-layout in `requirements.md`.
|
||
- Confirming source: `README.md` §"Технический стек".
|
||
|
||
---
|
||
|
||
## DEC-006: File Download via `chrome.downloads`
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §5, §7
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: File delivery
|
||
- Decision: The assembled ZIP is delivered to the user's "Downloads" folder via
|
||
`chrome.downloads.download()`. No server upload in Phase 1.
|
||
- Confirming source: `README.md` §"Технический стек".
|
||
|
||
---
|
||
|
||
## DEC-007: In-Memory Buffers in Service Worker + Content Script
|
||
|
||
- Source: `Тз расширение фаза1.md` §2, §4.1, §4.2, §4.3
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Storage strategy
|
||
- Decision: All recorded data (video chunks, rrweb events, user-event log) is
|
||
held in memory only — video chunks in the Service Worker, rrweb events and
|
||
user-event log in the Content Script. No `chrome.storage` / IndexedDB
|
||
persistence for the rolling buffers in Phase 1.
|
||
- Confirming source: `README.md` §"Технический стек" — "In-memory (Service
|
||
Worker + Content Script)".
|
||
|
||
---
|
||
|
||
## DEC-008: Screenshot via `chrome.tabs.captureVisibleTab`
|
||
|
||
- Source: `Тз расширение фаза1.md` §4.4, §5
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Screenshot capture
|
||
- Decision: A single PNG screenshot is captured via
|
||
`chrome.tabs.captureVisibleTab()` at the moment the user clicks "Save
|
||
archive". The screenshot is bundled as `screenshot.png` inside the ZIP.
|
||
|
||
---
|
||
|
||
## DEC-009: WebM Header Retention
|
||
|
||
- Source: `Тз расширение фаза1.md` §4.1, §8
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Video container integrity
|
||
- Decision: The first chunk emitted by `MediaRecorder` (which contains the WebM
|
||
container header) MUST be retained in the ring buffer indefinitely; only
|
||
subsequent chunks rotate out by the 30-second TTL rule.
|
||
- Rationale (from SPEC §8): WebM without its header is not playable.
|
||
|
||
---
|
||
|
||
## DEC-010: Service Worker Keepalive via `chrome.alarms`
|
||
|
||
- Source: `Тз расширение фаза1.md` §8
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Service Worker lifecycle
|
||
- Decision: To prevent the 30 s idle unload of MV3 Service Workers, a
|
||
`chrome.alarms` alarm fires every 20 seconds to keep the worker alive.
|
||
|
||
## Amendment (Phase 01-stabilize-video-pipeline, 2026-05-15)
|
||
|
||
- AMENDED-BY: Phase 01 CONTEXT.md D-17..D-18
|
||
- Replace `chrome.alarms`-driven 20 s keepalive with a long-lived `chrome.runtime.connect` port opened from the offscreen document to the Service Worker. The port emits a `PING` message every 25 s; both directions of traffic reset the SW's 30 s idle timer per Chrome 110+ semantics (developer.chrome.com/blog/longer-esw-lifetimes).
|
||
- The `alarms` permission is removed from `manifest.json` (it is no longer used by Phase 1; Phase 2 / 3 may re-add if needed).
|
||
- Port lifetime cap (~5 minutes per Chromium-extensions community gist sunnyguan/f94058f66fab89e59e75b1ac1bf1a06e) is mitigated by reconnecting on `onDisconnect` and pre-emptively at ~290 s.
|
||
- See `.planning/phases/01-stabilize-video-pipeline/01-RESEARCH.md` Pattern 5 for the canonical implementation.
|
||
|
||
---
|
||
|
||
## DEC-011: Manifest Permissions Set
|
||
|
||
- Source: `Тз расширение фаза1.md` §7
|
||
- Status: Accepted
|
||
- Locked: false
|
||
- Scope: Manifest configuration
|
||
- Decision: `manifest.json` requests exactly:
|
||
- `permissions`: `tabCapture`, `activeTab`, `downloads`, `scripting`,
|
||
`storage`
|
||
- `host_permissions`: `<all_urls>`
|
||
- Note: `tabCapture` requires explicit user gesture on first activation.
|
||
|
||
---
|
||
|
||
## DEC-012: Vite + crxjs + TypeScript Build Toolchain
|
||
|
||
- Source: `README.md` §"Технический стек"
|
||
- Status: Accepted (DOC-level — not asserted by SPEC)
|
||
- Locked: false
|
||
- Scope: Build tooling
|
||
- Decision: The extension is built with Vite + the `crxjs` plugin in
|
||
TypeScript. The SPEC does not prescribe a build tool, so this is a
|
||
DOC-level decision not contradicted by any higher-precedence source.
|
||
- Provenance caveat: If a future ADR/SPEC selects a different toolchain, this
|
||
DEC is auto-overridden.
|