docs: bootstrap .planning/ via /gsd-ingest-docs (2 docs) /home/parf/projects/work/repremium/.planning/PROJECT.md /home/parf/projects/work/repremium/.planning/REQUIREMENTS.md /home/parf/projects/work/repremium/.planning/ROADMAP.md /home/parf/projects/work/repremium/.planning/STATE.md /home/parf/projects/work/repremium/.planning/intel /home/parf/projects/work/repremium/.planning/INGEST-CONFLICTS.md /home/parf/projects/work/repremium/.ingest-manifest.yaml

This commit is contained in:
2026-05-15 15:16:30 +02:00
parent 555eb0543f
commit 89ca09ccec
12 changed files with 1637 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
## Conflict Detection Report
### BLOCKERS (0)
(none — no LOCKED-vs-LOCKED contradictions, no cycle-detection blockers, no UNKNOWN-confidence-low classifications)
### WARNINGS (0)
(none — no competing acceptance variants; only one SPEC and one DOC ingested, with no overlapping requirement asserting divergent acceptance criteria)
### INFO (1)
[INFO] Auto-resolved: SPEC > DOC on extension RAM footprint
Note: README.md §"Память" (line 106) states an expected steady-state of "~5-10 МБ в фоновом режиме"; the SPEC Тз расширение фаза1.md §10 acceptance criterion 9 sets the binding ceiling at "не превышает 50 МБ в фоне" — the same README §"Критерии приёмки Фазы 1" line 118 also restates the 50 МБ ceiling identically. Per precedence ADR > SPEC > PRD > DOC, the SPEC §10 ceiling wins and is recorded as constraints.md CON-ram-ceiling at 50 MB. The README's 5-10 МБ figure is preserved as a non-binding informational target alongside CON-ram-ceiling (sources: /home/parf/projects/work/repremium/Тз расширение фаза1.md §4, §10; /home/parf/projects/work/repremium/README.md lines 106, 118).

155
.planning/PROJECT.md Normal file
View File

@@ -0,0 +1,155 @@
# Mokosh
## What This Is
Mokosh is a Chrome Manifest V3 browser extension that silently and continuously
records an operator's browser session — the last 30 seconds of active-tab video,
the last 10 minutes of DOM events (via rrweb), and the last 10 minutes of user
and runtime events — and, on a single button press, packages everything plus a
screenshot into a self-contained ZIP delivered to the user's "Downloads" folder
for handoff to support.
The name is taken from Mokosh (Мокошь), the Slavic goddess of fate and weaving:
each operator session is a thread she weaves into the archive.
## Core Value
When an operator hits a bug, one click MUST produce a self-contained archive
that lets support reproduce what happened — in under five seconds, with no
server involved, and with the operator's passwords never appearing in the
output.
## Requirements
### Validated
<!-- Shipped and confirmed valuable. -->
(None yet — Phase 1 of the SPEC ships from a partially-broken first attempt;
nothing is validated until SPEC §10 acceptance passes.)
### Active
<!-- Current scope. Building toward these. See REQUIREMENTS.md for IDs. -->
- [ ] Continuous 30 s active-tab video ring buffer (REQ-video-ring-buffer)
- [ ] 10 min / 5 000-event rrweb DOM buffer with sensitive masking (REQ-rrweb-dom-buffer)
- [ ] 10 min user/runtime event log with password filtering (REQ-user-event-log)
- [ ] One-shot screenshot at export time (REQ-screenshot-on-export)
- [ ] Russian-language popup with idle → "Сохраняю..." → "Готово! ✓" state machine (REQ-popup-ui)
- [ ] ZIP archive layout `session_report_YYYY-MM-DD_HH-MM-SS.zip` (REQ-archive-layout)
- [ ] `meta.json` schema (REQ-meta-json-schema)
- [ ] Exact manifest permission set per SPEC §7 (REQ-manifest-permissions)
- [ ] Click-to-download latency < 5 s (REQ-archive-export-latency)
- [ ] Passwords never appear in rrweb snapshots or event log (REQ-password-confidentiality)
- [ ] Extension installs unpacked into Chrome without errors (REQ-install-clean)
### Out of Scope
<!-- Explicit boundaries. Includes reasoning to prevent re-adding. -->
- Server upload of captured data — SPEC §9; reserved for Phase 2.
- AI-driven diagnostics — SPEC §9; reserved for Phase 2.
- Automatic ticket creation — SPEC §9; reserved for Phase 2.
- Analytics dashboard — SPEC §9; reserved for Phase 2.
- Audio recording — SPEC §9; reserved for Phase 2.
- Persisting rolling buffers to `chrome.storage` / IndexedDB — CON-buffer-storage;
buffers are in-memory only in Phase 1.
## Context
- **Source documents:** Russian-authored SPEC (`Тз расширение фаза1.md`) and a
Russian-authored README. All user-facing UI strings ("Сохранить отчёт об
ошибке", "Последние 30 сек видео + 10 мин лога", "Сохраняю...", "Готово! ✓")
are part of the contract and MUST be preserved verbatim. Section identifiers
and code use Latin script.
- **Codebase state:** A partially-broken first attempt at the SPEC already
exists under `src/` (background service worker, content script, popup) and
`offscreen/`. An external audit identified 7 P0 defects that prevent SPEC §10
acceptance. Phase 1 of this roadmap is remediation against the SPEC, not
greenfield. See ROADMAP.md.
- **Operator context (SPEC §1):** Operators work inside a browser and
periodically make mistakes that are hard to diagnose after the fact. The
extension runs silently in the background; the operator only interacts with
it when they need to file a report.
- **Build toolchain (DOC-only):** Vite + the `crxjs` plugin in TypeScript. The
SPEC does not prescribe a build tool, so this is auto-overridable by a future
ADR/SPEC.
## Constraints
- **Performance**: Click-to-archive-on-disk < 5 s (CON-archive-export-latency,
SPEC §10 #6) — drives synchronous Blob assembly and avoidance of base64 data
URLs.
- **Memory**: Background RAM ceiling 50 MB (CON-ram-ceiling, SPEC §10 #9).
Expected steady-state is ~310 MB; the ceiling is a hard upper bound, not a
target.
- **Video format**: `video/webm; codecs=vp9` @ 400 000 bps, `MediaRecorder`
timeslice 2000 ms, single continuous recorder (CON-video-codec). The first
chunk (WebM header) MUST be retained indefinitely (CON-webm-header-retention,
DEC-009) — without it, the assembled file is not playable.
- **Buffer windows**: Video 30 s rolling, rrweb 10 min / 5 000 events whichever
is tighter, user-event log 10 min (CON-video-window, CON-rrweb-window,
CON-event-log-window).
- **Sensitive data**: `input[type=password]` and `[data-sensitive="true"]` MUST
be masked in rrweb (via v2 `maskInputFn`) AND the event logger MUST drop
password field values (CON-sensitive-data-masking).
- **Service Worker lifecycle**: MV3 SW unloads after ~30 s idle; a
`chrome.alarms` alarm fires every 20 s to keep it alive
(CON-service-worker-keepalive).
- **Tab capture binding**: `chrome.tabCapture` is tied to the active tab,
requires a user gesture on first invocation, and MUST re-attach on tab
activation/update events (CON-tab-capture-binding).
- **Manifest permissions**: `tabCapture`, `activeTab`, `downloads`, `scripting`,
`storage`; `host_permissions: ["<all_urls>"]` — exactly this set, no more, no
less (CON-manifest-permissions).
- **Storage strategy**: All Phase 1 rolling buffers live in memory only
(CON-buffer-storage). `chrome.storage` is permitted but MUST NOT be used to
persist rolling buffers.
- **Network**: No server upload in Phase 1 (CON-no-server-upload). All export
is local-only via `chrome.downloads`.
## Key Decisions
<!-- Decisions that constrain future work. All 12 below are SPEC-Accepted
acting as ADR-equivalents for Phase 1 per orchestrator instruction. They
are LOCKED for Phase 1: any change requires a formal ADR. None are
formally LOCKED in the ingest classification — a future ADR can revise
any of them, but Phase 1 implementation MUST treat them as locked. -->
| Decision | Rationale | Outcome | Status |
|----------|-----------|---------|--------|
| **DEC-001**: Chrome Extension Manifest V3 | SPEC §2, §7 — required for `chrome.tabCapture`, `chrome.downloads`, `chrome.alarms`. | — Pending | locked (Phase 1) |
| **DEC-002**: Service Worker as background coordinator | SPEC §2, §3, §8 — MV3 has no persistent background page; SW coordinates video buffer + archive packaging. | — Pending | locked (Phase 1) |
| **DEC-003**: Tab video via `chrome.tabCapture` (vp9 / 400 kbps / 2000 ms) | SPEC §2, §4.1, §7 — only API that captures active-tab video; codec/bitrate/timeslice locked. | — Pending | locked (Phase 1) |
| **DEC-004**: DOM capture via rrweb with `maskInputSelector` + 5 000-event cap | SPEC §2, §4.2 — rrweb is the only mature DOM-recording option; masking + cap are part of the privacy/memory contract. | — Pending | locked (Phase 1) |
| **DEC-005**: Archive packaging via JSZip | SPEC §2, §3, §6 — only ZIP library bundled per SPEC. | — Pending | locked (Phase 1) |
| **DEC-006**: File download via `chrome.downloads` | SPEC §2, §5, §7 — no server upload in Phase 1 (SPEC §9). | — Pending | locked (Phase 1) |
| **DEC-007**: In-memory buffers only (no Phase 1 persistence) | SPEC §2, §4.1§4.3 — rolling buffers in SW (video) and Content Script (rrweb + log). | — Pending | locked (Phase 1) |
| **DEC-008**: Screenshot via `chrome.tabs.captureVisibleTab` | SPEC §4.4, §5 — captured at export time, not continuously. | — Pending | locked (Phase 1) |
| **DEC-009**: WebM header chunk retained indefinitely | SPEC §4.1, §8 — WebM without its header is not playable. | — Pending | locked (Phase 1) |
| **DEC-010**: Service Worker keepalive via `chrome.alarms` (20 s) | SPEC §8 — MV3 SW unloads at ~30 s idle; 20 s alarm cadence keeps it alive. | — Pending | locked (Phase 1) |
| **DEC-011**: Manifest permissions set | SPEC §7 — `tabCapture`, `activeTab`, `downloads`, `scripting`, `storage` + `host_permissions: ["<all_urls>"]`. | — Pending | locked (Phase 1) |
| **DEC-012**: Vite + crxjs + TypeScript build toolchain | README §"Технический стек" — DOC-level only; SPEC does not prescribe. | — Pending | locked (Phase 1) — auto-overridable by future ADR |
## Success Metric (Developer-Facing)
Phase 1 is "done" when all **9 SPEC §10 acceptance criteria** pass against an
unpacked load of the build into Chrome:
1. Extension installs in Chrome without errors.
2. Video buffer runs continuously on any tab.
3. Buffer never holds more than 30 s of footage.
4. rrweb records DOM events without errors on typical pages (forms, tables,
modals).
5. Event log captures clicks, navigation, and network errors.
6. Archive downloads to "Downloads" in < 5 s after button press.
7. Archive opens cleanly; `last_30sec.webm` plays back in a browser.
8. Passwords do not appear in the event log or rrweb snapshots.
9. Extension RAM consumption does not exceed 50 MB in the background.
The verbatim list lives in REQUIREMENTS.md under "Phase 1 Acceptance Criteria
(SPEC §10 verbatim)".
---
*Last updated: 2026-05-15 after initial bootstrap from intel synthesis*

207
.planning/REQUIREMENTS.md Normal file
View File

@@ -0,0 +1,207 @@
# Requirements: Mokosh
**Defined:** 2026-05-15
**Core Value:** When an operator hits a bug, one click produces a self-contained
archive that lets support reproduce what happened — in under 5 s, no server, no
password leaks.
All requirements below are extracted from the SPEC `Тз расширение фаза1.md`.
The intel files `.planning/intel/requirements.md`, `.planning/intel/constraints.md`,
and `.planning/intel/decisions.md` carry the verbatim wording, source citations,
and technical bindings; this file is the GSD-shaped projection of those facts.
## v1 Requirements
Requirements for the Phase 1 SPEC. Each maps to one phase in ROADMAP.md.
### Video
- [ ] **REQ-video-ring-buffer**: The extension maintains an in-memory ring
buffer containing the most recent 30 seconds of active-tab video. Video is
captured via `chrome.tabCapture.capture()` at `video/webm; codecs=vp9` @
400 000 bps with a `MediaRecorder` timeslice of 2000 ms. A single continuous
recorder per session; tab activation changes trigger re-attach. The first
emitted chunk (WebM header) is retained indefinitely; subsequent chunks
rotate out by the 30-second TTL rule. Bindings: DEC-003, DEC-009,
CON-video-window, CON-video-codec, CON-webm-header-retention.
- SPEC §10 acceptance criteria: #2, #3, #7.
### DOM Capture
- [ ] **REQ-rrweb-dom-buffer**: The extension records DOM events via rrweb
(`rrweb.record()`) running in the Content Script over a rolling 10-minute
window, capped at 5 000 events (oldest dropped on overflow). Sensitive
fields are masked via rrweb v2 `maskInputFn` covering `input[type=password]`
and `[data-sensitive="true"]`. Bindings: DEC-004, CON-rrweb-window,
CON-sensitive-data-masking.
- SPEC §10 acceptance criteria: #4.
### Event Logging
- [ ] **REQ-user-event-log**: The extension logs user and runtime events over
a rolling 10-minute window. Captured types: `click` (records target selector
and element text), `input` (excludes password fields), `navigation`
(`popstate`, `hashchange`, page transitions), `js_error` (`window.onerror`,
`window.onunhandledrejection`), `network_error` (`fetch` / `XMLHttpRequest`
with response code >= 400). Each entry conforms to the verbatim
`CON-event-log-schema`. Bindings: CON-event-log-window, CON-event-log-schema,
CON-sensitive-data-masking.
- SPEC §10 acceptance criteria: #5, #8.
### Export
- [ ] **REQ-screenshot-on-export**: On "Save archive" click, the extension
captures a PNG screenshot of the active tab via
`chrome.tabs.captureVisibleTab()` and includes it as `screenshot.png` in the
archive. Binding: DEC-008.
- [ ] **REQ-popup-ui**: The extension exposes a minimal popup with a single
button labeled "Сохранить отчёт об ошибке" and a sub-label "Последние 30 сек
видео + 10 мин лога". Button state machine:
`idle → "Сохраняю..." → "Готово! ✓" → idle` (3 s revert). On click:
(1) capture screenshot, (2) request video buffer + event log from SW,
(3) request rrweb snapshots from Content Script, (4) assemble archive,
(5) trigger download, (6) display "Готово! ✓". Russian strings are part of
the contract and preserved verbatim.
- [ ] **REQ-archive-layout**: The archive is named
`session_report_YYYY-MM-DD_HH-MM-SS.zip` and contains exactly:
```
session_report_2025-05-15_14-32-10.zip
├── video/
│ └── last_30sec.webm
├── rrweb/
│ └── session.json
├── logs/
│ └── events.json
├── screenshot.png
└── meta.json
```
Binding: CON-archive-layout.
- SPEC §10 acceptance criteria: #7.
- [ ] **REQ-meta-json-schema**: `meta.json` inside the archive conforms to the
verbatim schema:
```json
{
"timestamp": "2025-05-15T14:32:10Z",
"url": "https://...",
"userAgent": "Chrome/...",
"extensionVersion": "1.0.0",
"videoBufferSeconds": 30,
"logDurationMinutes": 10,
"totalEvents": 143
}
```
All fields required. Binding: CON-meta-json-schema.
### Manifest & Install
- [ ] **REQ-manifest-permissions**: `manifest.json` declares exactly the
permission set in DEC-011 (`tabCapture`, `activeTab`, `downloads`, `scripting`,
`storage`; `host_permissions: ["<all_urls>"]`) and requests a user gesture
for `tabCapture` on first activation. Binding: DEC-011, CON-manifest-permissions.
- SPEC §10 acceptance criteria: #1.
- [ ] **REQ-install-clean**: The extension installs in Chrome without errors
via the unpacked-extension load flow.
- SPEC §10 acceptance criteria: #1.
### Performance & Security
- [ ] **REQ-archive-export-latency**: From the moment the user clicks the
export button, the ZIP archive lands in the "Downloads" folder in under
5 seconds. Binding: CON-archive-export-latency.
- SPEC §10 acceptance criteria: #6.
- [ ] **REQ-password-confidentiality**: Passwords do not appear in rrweb
snapshots OR the user event log. Masking is enforced via rrweb v2
`maskInputFn` AND explicit value filtering in the event logger for password
fields. Binding: CON-sensitive-data-masking.
- SPEC §10 acceptance criteria: #8.
## v2 Requirements
Deferred to a future phase per SPEC §9 ("Что НЕ входит в Фазу 1"). Tracked
but not in current roadmap.
### Server & Diagnostics
- **SRV-01**: Upload captured archives to a remote server.
- **SRV-02**: AI-driven diagnostics of captured sessions.
- **SRV-03**: Automatic ticket creation from captured reports.
- **SRV-04**: Analytics dashboard summarising captured sessions.
### Capture
- **CAP-01**: Audio recording in addition to video.
## Out of Scope
Explicitly excluded in Phase 1. Documented to prevent scope creep.
| Feature | Reason |
|---------|--------|
| Server upload | SPEC §9 — Phase 2 work. Phase 1 is local-only via `chrome.downloads`. |
| AI diagnostics | SPEC §9 — Phase 2 work. |
| Automatic ticketing | SPEC §9 — Phase 2 work. |
| Analytics dashboard | SPEC §9 — Phase 2 work. |
| Audio recording | SPEC §9 — Phase 2 work. |
| `chrome.storage` / IndexedDB persistence of rolling buffers | CON-buffer-storage — buffers are in-memory only in Phase 1. |
| Recording inactive tabs | CON-tab-capture-binding — `chrome.tabCapture` is active-tab-bound by design. |
## Phase 1 Acceptance Criteria (SPEC §10 verbatim)
For traceability, all SPEC §10 acceptance criteria are listed once here, each
cross-referenced to its supporting REQ-* entries. The developer-facing success
metric for the whole project is "all 9 pass".
1. The extension installs in Chrome without errors. → REQ-install-clean,
REQ-manifest-permissions
2. The video buffer runs continuously on any tab. → REQ-video-ring-buffer
3. The buffer always contains no more than 30 seconds of video. →
REQ-video-ring-buffer
4. rrweb records DOM events without errors on typical pages (forms, tables,
modal windows). → REQ-rrweb-dom-buffer
5. The event log captures clicks, navigation, and network errors. →
REQ-user-event-log
6. On button press, the archive is downloaded to "Downloads" in < 5 seconds. →
REQ-archive-export-latency
7. The archive opens; `last_30sec.webm` plays back in a browser. →
REQ-archive-layout, REQ-video-ring-buffer
8. Passwords do not appear in the log or rrweb snapshots. →
REQ-password-confidentiality
9. Extension RAM consumption does not exceed 50 MB in the background. →
CON-ram-ceiling (NFR, not a functional REQ).
## Traceability
Which phase covers which requirement. See ROADMAP.md for phase details.
| Requirement | Phase | Status |
|-------------|-------|--------|
| REQ-video-ring-buffer | Phase 1 | Pending |
| REQ-rrweb-dom-buffer | Phase 2 | Pending |
| REQ-user-event-log | Phase 2 | Pending |
| REQ-password-confidentiality | Phase 2 | Pending |
| REQ-popup-ui | Phase 3 | Pending |
| REQ-screenshot-on-export | Phase 3 | Pending |
| REQ-archive-layout | Phase 3 | Pending |
| REQ-meta-json-schema | Phase 3 | Pending |
| REQ-archive-export-latency | Phase 3 | Pending |
| REQ-manifest-permissions | Phase 3 | Pending |
| REQ-install-clean | Phase 4 | Pending |
**Coverage:**
- v1 requirements: 11 total
- Mapped to phases: 11
- Unmapped: 0 ✓
Note on CON-ram-ceiling (SPEC §10 #9): tracked as a non-functional constraint
verified in Phase 4 (smoke verification) rather than as a standalone
functional REQ, per the intel synthesis. Phase 4 success criteria include the
RAM-ceiling check.
---
*Requirements defined: 2026-05-15*
*Last updated: 2026-05-15 after initial bootstrap from intel synthesis*

222
.planning/ROADMAP.md Normal file
View File

@@ -0,0 +1,222 @@
# Roadmap: Mokosh
## Overview
The Mokosh codebase is a partially-broken first attempt at SPEC `Тз расширение
фаза1.md`. An external audit identified 7 P0 defects that prevent SPEC §10
acceptance. This roadmap therefore frames Phase 1 as **stabilization to spec**,
not greenfield: phases 13 each remediate a tightly-grouped subset of the P0
defects along sensible commit boundaries; phase 4 runs the SPEC §10 smoke pass
end-to-end. An optional phase 5 absorbs the P1/P2 follow-ups (SW state
persistence, `fetch` interception fix, `meta.json` field hardening,
`generate-icons.js` ESM/CJS, dead-code cleanup).
The journey: **broken-but-installable → playable video → masked DOM + log →
working export → green §10 smoke → harden + clean up**.
## Phases
**Phase Numbering:**
- Integer phases (1, 2, 3): Planned milestone work.
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED).
Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 1: Stabilize video pipeline** — Collapse offscreen duality, fix MediaRecorder shadow, fix WebM ring buffer playability, make capture always-on with tab re-attach
- [ ] **Phase 2: Stabilize DOM + event capture privacy** — Migrate rrweb to v2 `maskInputFn`, plug `content/index.ts setupInputLogging` password leak
- [ ] **Phase 3: Stabilize export pipeline** — Restore user-activation gesture in popup, delete dead `permissions.request`, replace base64 `data:` URL with Blob URL minted in offscreen
- [ ] **Phase 4: SPEC §10 smoke verification** — End-to-end install-and-record-and-export pass against all 9 acceptance criteria
- [ ] **Phase 5: Harden + clean up** _(optional)_ — P1/P2 follow-ups: SW state persistence, fetch interception, `meta.json` fields, `generate-icons.js` ESM/CJS, dead-code
## Phase Details
### Phase 1: Stabilize video pipeline
**Goal**: The video ring buffer captures the most recent 30 s of the active
tab's video continuously across tab switches, with a playable WebM header
retained — so that on export the assembled `last_30sec.webm` will play.
**Depends on**: Nothing (first phase). Operates on the existing `offscreen/`
directory + `vite.config.ts` inline string + `src/background/`.
**Requirements**: REQ-video-ring-buffer
**P0 defects addressed**:
- P0-1: Collapse the offscreen duality (`offscreen/index.ts` + inline string in
`vite.config.ts`) into a single source of truth; fix the `mediaRecorder`
shadow that breaks `stopRecording`.
- P0-2: Fix WebM ring buffer playability — single continuous `MediaRecorder`,
2000 ms timeslice per spec (CON-video-codec), cluster-timestamp-based rolling
window honouring the WebM header retention rule (DEC-009).
- P0-3: Make capture always-on with `chrome.tabs.onActivated` /
`chrome.tabs.onUpdated` re-attachment; start on `onInstalled` / `onStartup`,
not on popup open (CON-tab-capture-binding, REQ-video-ring-buffer).
**Success Criteria** (what must be TRUE):
1. There is exactly one source of truth for the offscreen document; rebuilding
`vite.config.ts` does not regenerate a divergent inline duplicate, and
`stopRecording` runs without `mediaRecorder is undefined` shadow errors.
2. With the extension loaded and a tab open, a single continuous
`MediaRecorder` is running on the active tab with timeslice 2000 ms; on
tab switch the recorder re-attaches to the new active tab without losing
the WebM container header.
3. The in-memory video ring buffer at any instant contains the WebM header
chunk plus the most recent 30 s of subsequent chunks (no more, no less);
concatenating header + buffered chunks yields a byte sequence a browser
would play.
**Plans**: TBD
### Phase 2: Stabilize DOM + event capture privacy
**Goal**: rrweb captures DOM events on typical pages and the user-event log
captures clicks/navigation/network errors — and in neither stream do password
values appear.
**Depends on**: Phase 1 (no functional dependency, but Phase 1 establishes the
"capture is always-on" baseline that this phase plugs into).
**Requirements**: REQ-rrweb-dom-buffer, REQ-user-event-log,
REQ-password-confidentiality
**P0 defects addressed**:
- P0-5: rrweb data-sensitive leak — migrate to rrweb v2 `maskInputFn` (the
legacy `maskInputSelector` is gone in v2.0.0-alpha.4 per `package.json`); fix
the parallel leak in `src/content/index.ts setupInputLogging` so password
field values are dropped at logger entry, not just at rrweb level.
**Success Criteria** (what must be TRUE):
1. On a page containing `<input type="password">` and elements with
`data-sensitive="true"`, rrweb snapshots for that page mask the value of
both kinds of fields (verified by inspecting exported `rrweb/session.json`).
2. On the same page, typing into a password field produces no `input` event
entry containing the typed value in the user-event log
(`logs/events.json`).
3. On a typical page with forms, tables, and a modal, rrweb records DOM
events without throwing in the Content Script console; the event log
captures clicks, navigations (`popstate`/`hashchange`), and network errors
(`fetch` / `XHR` >= 400).
**Plans**: TBD
**UI hint**: yes
### Phase 3: Stabilize export pipeline
**Goal**: A click on "Сохранить отчёт об ошибке" produces a SPEC-conformant ZIP
archive on disk in under 5 s, containing a screenshot taken at click time,
laid out per CON-archive-layout, with `meta.json` per CON-meta-json-schema, and
declared by a manifest carrying exactly the permission set in DEC-011.
**Depends on**: Phase 1, Phase 2 (export consumes the video + rrweb + event-log
buffers established by phases 1 and 2).
**Requirements**: REQ-popup-ui, REQ-screenshot-on-export, REQ-archive-layout,
REQ-meta-json-schema, REQ-archive-export-latency, REQ-manifest-permissions
**P0 defects addressed**:
- P0-4: Restore the user-activation gesture for `getMediaStreamId` by moving
the call to the popup-click handler; delete the dead `permissions.request`
dance that was masking the missing gesture (REQ-popup-ui,
CON-tab-capture-binding).
- P0-6: Replace the base64 `data:` URL download with a Blob URL minted in the
offscreen document — the Service Worker lacks `URL.createObjectURL` (DEC-006,
REQ-archive-export-latency).
**Success Criteria** (what must be TRUE):
1. Opening the popup shows a button reading "Сохранить отчёт об ошибке" with
sub-label "Последние 30 сек видео + 10 мин лога"; clicking it transitions
idle → "Сохраняю..." → "Готово! ✓" → idle (with 3 s revert) and triggers
a `chrome.downloads` download.
2. The downloaded file lands in the user's Downloads folder, named
`session_report_YYYY-MM-DD_HH-MM-SS.zip`, in under 5 seconds from click;
opening it reveals exactly the layout in REQ-archive-layout
(`video/last_30sec.webm`, `rrweb/session.json`, `logs/events.json`,
`screenshot.png`, `meta.json` at the root) with no extra entries.
3. `meta.json` validates against the verbatim CON-meta-json-schema (all 7
fields present, types correct, `timestamp` is ISO-8601 with `Z`).
4. `manifest.json` in `dist/` after `npm run build` declares exactly the
permission set in DEC-011 with no additional or missing entries; loading
unpacked into Chrome produces no permission-related warnings or errors in
`chrome://extensions/`.
**Plans**: TBD
**UI hint**: yes
### Phase 4: SPEC §10 smoke verification
**Goal**: All 9 SPEC §10 acceptance criteria pass against an unpacked load of
the build into a real Chrome instance.
**Depends on**: Phase 1, Phase 2, Phase 3.
**Requirements**: REQ-install-clean (and end-to-end verification of all
preceding REQs)
**P0 defects addressed**:
- P0-7: End-to-end smoke verification against §10. This is a verification
phase, not a new implementation — it confirms the cumulative output of
phases 13 actually satisfies the SPEC.
**Success Criteria** (what must be TRUE):
1. The extension installs into Chrome via "Load unpacked" against `dist/`
with no errors or warnings in `chrome://extensions/`.
2. With the extension loaded and a normal browsing session under way, the
video buffer runs continuously across tab switches and never holds more
than 30 s of footage (confirmed by inspecting the SW console / a debug
export).
3. On a typical page (form + table + modal) rrweb records without throwing,
the event log captures clicks/navigation/network errors, and passwords
are absent from both streams.
4. A click on the popup button produces a ZIP in Downloads in under 5 s; the
ZIP opens; `video/last_30sec.webm` plays in a browser.
5. Background RAM consumption (measured via Chrome Task Manager) does not
exceed 50 MB during a sustained recording session (CON-ram-ceiling).
**Plans**: TBD
### Phase 5: Harden + clean up _(optional)_
**Goal**: Eliminate the P1/P2 follow-ups identified in the audit so that the
codebase is not just spec-conformant but maintainable. This phase has no new
v1 requirements — it improves robustness and removes technical debt around
already-shipped behaviour.
**Depends on**: Phase 4 (do not harden until §10 is green).
**Requirements**: none (no new v1 REQs; all v1 REQs are covered by phases 14)
**P1/P2 items addressed** (informative list from the audit, exact scope
finalized at plan time):
- SW state persistence around the 30 s idle unload edge cases.
- `fetch` interception fix in the network-error path of REQ-user-event-log.
- `meta.json` field hardening (timestamp source, version source, totalEvents
derivation).
- `generate-icons.js` ESM/CJS compatibility with the rest of the toolchain.
- Dead-code cleanup (the `permissions.request` dance removed in Phase 3 may
have stranded helpers; the offscreen duality removed in Phase 1 may have
stranded shims).
**Success Criteria** (what must be TRUE):
1. After running the extension idle for >5 minutes, then exporting, the
archive still contains a non-empty video buffer (proves SW state
persistence works across one or more SW unload/reload cycles).
2. A page that issues a failing `fetch` (response code >= 400) produces a
`network_error` entry in `events.json`; a failing `XMLHttpRequest` does
too.
3. `npm run build` and `node generate-icons.js` both succeed under the
project's module setting (`"type": "module"` in `package.json`) with no
`require is not defined` or `Cannot use import statement outside a
module` errors.
4. A repo grep for the symbols deleted in phases 1 and 3
(`permissions.request`, the duplicate offscreen inline string) returns no
live references.
**Plans**: TBD
## Progress
**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5.
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Stabilize video pipeline | 0/TBD | Not started | - |
| 2. Stabilize DOM + event capture privacy | 0/TBD | Not started | - |
| 3. Stabilize export pipeline | 0/TBD | Not started | - |
| 4. SPEC §10 smoke verification | 0/TBD | Not started | - |
| 5. Harden + clean up (optional) | 0/TBD | Not started | - |

85
.planning/STATE.md Normal file
View File

@@ -0,0 +1,85 @@
# Project State
## Project Reference
See: .planning/PROJECT.md (updated 2026-05-15)
**Core value:** When an operator hits a bug, one click MUST produce a
self-contained archive that lets support reproduce what happened — in under 5 s,
no server, no password leaks.
**Current focus:** Phase 1 — Stabilize video pipeline
## Current Position
Phase: 1 of 5 (Stabilize video pipeline)
Plan: 0 of TBD in current phase
Status: Ready to plan
Last activity: 2026-05-15 — bootstrap from intel synthesis (PROJECT.md,
REQUIREMENTS.md, ROADMAP.md, STATE.md written)
Progress: [░░░░░░░░░░] 0%
## Performance Metrics
**Velocity:**
- Total plans completed: 0
- Average duration: —
- Total execution time: —
**By Phase:**
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 1. Stabilize video pipeline | 0 | — | — |
| 2. Stabilize DOM + event capture privacy | 0 | — | — |
| 3. Stabilize export pipeline | 0 | — | — |
| 4. SPEC §10 smoke verification | 0 | — | — |
| 5. Harden + clean up | 0 | — | — |
**Recent Trend:**
- Last 5 plans: —
- Trend: —
*Updated after each plan completion*
## Accumulated Context
### Decisions
Decisions are logged in PROJECT.md Key Decisions table (DEC-001 through
DEC-012, all SPEC-Accepted and locked for Phase 1). Recent decisions affecting
current work:
- Phase 1 framing: roadmap treats the existing codebase as a partially-broken
first attempt to be remediated against the SPEC, not as greenfield. The
7 P0 defects from the audit are split across phases 13 along commit
boundaries; phase 4 is end-to-end SPEC §10 smoke verification.
- All 12 SPEC decisions (`DEC-001`..`DEC-012`) are LOCKED for Phase 1.
Changing any of them requires a formal ADR; none are formally LOCKED in the
ingest classification, so a future ADR can revise.
### Pending Todos
None yet.
### Blockers/Concerns
- (informational) `chrome.tabCapture` requires a user gesture on first
activation — Phase 3 (P0-4) restores this by moving the call into the popup
click handler; until Phase 3 lands, recording cannot start cleanly even if
Phase 1's pipeline is correct. Phases 13 should not be re-ordered.
## Deferred Items
Items acknowledged and carried forward from previous milestone close:
| Category | Item | Status | Deferred At |
|----------|------|--------|-------------|
| *(none)* | | | |
## Session Continuity
Last session: 2026-05-15 — bootstrap
Stopped at: Wrote PROJECT.md, REQUIREMENTS.md, ROADMAP.md, STATE.md from
intel synthesis. Coverage validated: 11/11 v1 REQs mapped.
Resume file: None — ready for `/gsd-plan-phase 1`.

View File

@@ -0,0 +1,161 @@
# Synthesis Summary
Entry point for `gsd-roadmapper` and other downstream consumers.
Mode: `new` (fresh bootstrap — no pre-existing `.planning/` files consulted).
Precedence applied: `ADR > SPEC > PRD > DOC` (default).
---
## Doc counts by type
- ADRs: 0
- PRDs: 0
- SPECs: 1
- DOCs: 1
- UNKNOWN: 0
- **Total docs synthesized:** 2
Sources:
- `/home/parf/projects/work/repremium/Тз расширение фаза1.md` — SPEC (precedence 0)
- `/home/parf/projects/work/repremium/README.md` — DOC (precedence 1)
Cross-ref graph: empty (`cross_refs: []` on both classifications). No cycle
detection issues; depth 0 / cap 50.
---
## Decisions locked
- **Formally `locked: true` decisions:** 0
- **SPEC-prescribed Accepted decisions (acting as ADR-equivalents for Phase 1
per orchestrator instruction):** 12
Decision IDs (see `decisions.md`):
- DEC-001 — Chrome Extension Manifest V3
- DEC-002 — Service Worker as background coordinator
- DEC-003 — Tab video capture via `chrome.tabCapture` (vp9 / 400 kbps / 2000 ms)
- DEC-004 — DOM capture via rrweb (with sensitive-input masking + 5 000-event cap)
- DEC-005 — Archive packaging via JSZip
- DEC-006 — File download via `chrome.downloads`
- DEC-007 — In-memory buffers only (no Phase 1 persistence)
- DEC-008 — Screenshot via `chrome.tabs.captureVisibleTab`
- DEC-009 — WebM header chunk retained indefinitely
- DEC-010 — Service Worker keepalive via `chrome.alarms` (20 s cadence)
- DEC-011 — Manifest permissions set
- DEC-012 — Vite + crxjs + TypeScript build toolchain (DOC-level)
All 12 are `Accepted` / `locked: false`. None of them are formally LOCKED ADRs,
so any future ADR can revise them; today they are the authoritative baseline.
Source: `/home/parf/projects/work/repremium/.planning/intel/decisions.md`
---
## Requirements extracted
- **Count:** 11 functional requirements + 1 verbatim Phase 1 acceptance-criteria
list (cross-referenced from the REQs).
Requirement IDs (see `requirements.md`):
- REQ-video-ring-buffer
- REQ-rrweb-dom-buffer
- REQ-user-event-log
- REQ-screenshot-on-export
- REQ-popup-ui
- REQ-archive-layout
- REQ-meta-json-schema
- REQ-manifest-permissions
- REQ-archive-export-latency
- REQ-password-confidentiality
- REQ-install-clean
Source: `/home/parf/projects/work/repremium/.planning/intel/requirements.md`
---
## Constraints
- **Count:** 15 constraint entries.
- **Type breakdown:**
- `nfr`: 7 (CON-ram-ceiling, CON-archive-export-latency, CON-video-window,
CON-rrweb-window, CON-event-log-window, CON-sensitive-data-masking,
CON-buffer-storage, CON-no-server-upload) — note: two of these
(CON-sensitive-data-masking, CON-buffer-storage, CON-no-server-upload) are
cross-categorized; primary type listed
- `protocol`: 3 (CON-video-codec, CON-webm-header-retention, plus protocol
aspects of CON-video-window / CON-rrweb-window / CON-event-log-window)
- `api-contract`: 3 (CON-tab-capture-binding, CON-service-worker-keepalive,
CON-manifest-permissions)
- `schema`: 3 (CON-archive-layout, CON-meta-json-schema, CON-event-log-schema)
Constraint IDs (see `constraints.md`):
- CON-ram-ceiling (50 MB background ceiling)
- CON-archive-export-latency (< 5 s)
- CON-video-window (30 s)
- CON-rrweb-window (10 min / 5 000 events)
- CON-event-log-window (10 min)
- CON-video-codec (vp9 / 400 kbps / 2 s chunks)
- CON-webm-header-retention
- CON-tab-capture-binding
- CON-service-worker-keepalive (20 s alarm)
- CON-manifest-permissions (verbatim manifest fragment)
- CON-sensitive-data-masking
- CON-archive-layout (verbatim ZIP layout)
- CON-meta-json-schema (verbatim)
- CON-event-log-schema (verbatim)
- CON-buffer-storage (in-memory only)
- CON-no-server-upload (Phase 1 scope boundary)
Source: `/home/parf/projects/work/repremium/.planning/intel/constraints.md`
---
## Context topics
- **Count:** 6 topics.
Topics (see `context.md`):
- Project goal (SPEC §1)
- Phase 1 scope (what is in)
- Phase 1 non-goals (Phase 2 work — server upload, AI diagnostics, ticketing,
dashboard, audio)
- Developer workflow (DOC-only — install, build, Chrome load, debug, layout)
- User-facing flow
- Licensing and support (MIT)
- Russian-source provenance (UI strings preserved verbatim)
Source: `/home/parf/projects/work/repremium/.planning/intel/context.md`
---
## Conflicts
- **Blockers:** 0
- **Competing variants:** 0
- **Auto-resolved (INFO):** 1
- SPEC > DOC on extension RAM footprint — SPEC's 50 MB ceiling wins; README's
510 MB figure preserved as informational target alongside
CON-ram-ceiling.
Full report: `/home/parf/projects/work/repremium/.planning/INGEST-CONFLICTS.md`
---
## Pointers
- Decisions: `/home/parf/projects/work/repremium/.planning/intel/decisions.md`
- Requirements: `/home/parf/projects/work/repremium/.planning/intel/requirements.md`
- Constraints: `/home/parf/projects/work/repremium/.planning/intel/constraints.md`
- Context: `/home/parf/projects/work/repremium/.planning/intel/context.md`
- Conflicts report: `/home/parf/projects/work/repremium/.planning/INGEST-CONFLICTS.md`
- Classifications consumed:
- `/home/parf/projects/work/repremium/.planning/intel/classifications/tz-rasshirenie-faza1-3a5e9b41.json`
- `/home/parf/projects/work/repremium/.planning/intel/classifications/README-a1b2c3d4.json`
Status for routing: **READY** — no blockers, no awaiting-user variants, safe to
hand off to `gsd-roadmapper`.

View File

@@ -0,0 +1,28 @@
{
"source_path": "/home/parf/projects/work/repremium/README.md",
"type": "DOC",
"confidence": "high",
"manifest_override": true,
"title": "AI Call Recorder - Браузерное расширение для записи сессий операторов",
"summary": "Developer-facing README covering installation, usage, technical stack, and Phase 1 acceptance criteria for a Chrome extension that records operator sessions locally and exports a ZIP archive.",
"scope": [
"Chrome Extension Manifest V3",
"Service Worker",
"Content Script",
"Popup UI",
"chrome.tabCapture video buffer",
"rrweb DOM capture",
"user event logging",
"JSZip archive packaging",
"chrome.downloads",
"Vite + crxjs + TypeScript build",
"ring buffer (video 30s, rrweb 10min, events 10min)",
"sensitive data masking",
"Phase 1 acceptance criteria",
"memory consumption targets"
],
"cross_refs": [],
"locked": false,
"precedence": 1,
"notes": "Manifest declared type=DOC and precedence=1, treated as authoritative. POTENTIAL CONFLICT WITH SPEC: line 106 states expected memory '~5-10 МБ in background mode', while line 118 acceptance criterion states ceiling 'не превышает 50 МБ' — synthesizer should reconcile against the SPEC's 50 МБ ceiling. INTERNAL INCONSISTENCY: README presents both an expected-value (5-10 МБ) and a ceiling (50 МБ) for the same memory metric without explicit relationship. Other claims to cross-check against SPEC: video buffer = 30s, rrweb buffer = 10min/5000 events, user event buffer = 10min, archive delivery < 5s, sensitive data masking via input[type=password] and data-sensitive='true'."
}

View File

@@ -0,0 +1,28 @@
{
"source_path": "/home/parf/projects/work/repremium/Тз расширение фаза1.md",
"type": "SPEC",
"confidence": "high",
"manifest_override": true,
"title": "Техническое задание: Браузерное расширение для записи сессий операторов — Фаза 1 (Локальная запись + экспорт архива)",
"summary": "Technical specification for Phase 1 of a Chrome Manifest V3 browser extension that continuously records operator session video, DOM snapshots, and event logs locally and exports them as a ZIP archive on demand.",
"scope": [
"Chrome Extension Manifest V3",
"Service Worker / Background Script",
"Tab video capture (chrome.tabCapture)",
"DOM recording via rrweb",
"User event logging (Content Script)",
"ZIP archive packaging (JSZip)",
"File download via chrome.downloads",
"Popup UI for archive export",
"Screenshot capture (chrome.tabs.captureVisibleTab)",
"Ring buffer video (last 30 seconds)",
"DOM/event buffer (last 10 minutes)",
"Sensitive data masking (passwords, data-sensitive)",
"Manifest permissions configuration",
"Phase 1 acceptance criteria"
],
"cross_refs": [],
"locked": false,
"precedence": 0,
"notes": "Manifest-declared SPEC; document contains explicit technical contracts (codec/bitrate, API surface, manifest permissions, archive layout, meta.json schema, event log JSON schema), engineering constraints (WebM header retention, Service Worker keepalive, rrweb buffer cap of 5000 events, 50MB RAM ceiling), and Phase 1 acceptance criteria. Explicit Phase 1 vs Phase 2 scope boundary documented in section 9. Russian-language source; scope translated to English while preserving technical identifiers."
}

View File

@@ -0,0 +1,204 @@
# Constraints (synthesized from SPEC)
All constraints below are sourced from `Тз расширение фаза1.md` (the SPEC,
precedence 0). The DOC (`README.md`, precedence 1) is a confirming source where
noted; where it diverges, the SPEC takes precedence per the
`ADR > SPEC > PRD > DOC` rule.
Type taxonomy:
- `nfr` — non-functional requirement (performance, memory, latency, security)
- `protocol` — wire/file format or sequence contract
- `schema` — data structure contract
- `api-contract` — external API binding (Chrome extension APIs)
---
## CON-ram-ceiling
- Source: `Тз расширение фаза1.md` §10 (acceptance criterion 9)
- Type: nfr
- Constraint: The extension's RAM footprint MUST NOT exceed **50 MB** while
running in the background.
- Component-level expected breakdown (SPEC §4, informative, not binding):
- Video ring buffer: ~1.52 MB steady
- rrweb buffer: ~13 MB
- Event log: ~100300 KB
- Total steady-state expected component sum: ~2.65.3 MB
- DOC confirming source: `README.md` §"Критерии приёмки Фазы 1" — restates the
50 MB ceiling identically.
- DOC informational target: `README.md` §"Память" reports an expected
steady-state of ~510 MB. This is a non-binding **estimate**, not a
contradicting requirement; the binding ceiling remains 50 MB. See
`INGEST-CONFLICTS.md` for the auto-resolved INFO entry.
---
## CON-archive-export-latency
- Source: `Тз расширение фаза1.md` §10 (acceptance criterion 6)
- Type: nfr
- Constraint: From click to file landing in the Downloads folder MUST be
**< 5 seconds**.
- DOC confirming source: `README.md` §"Критерии приёмки Фазы 1".
---
## CON-video-window
- Source: `Тз расширение фаза1.md` §4.1
- Type: nfr / protocol
- Constraint: The video ring buffer MUST hold **exactly the most recent 30
seconds** of footage; older chunks are evicted after each new chunk arrives.
- Exception (DEC-009): the first chunk (WebM header) is exempt from eviction.
---
## CON-rrweb-window
- Source: `Тз расширение фаза1.md` §4.2, §8
- Type: nfr / protocol
- Constraint: rrweb events MUST be retained for **at most 10 minutes** AND **at
most 5 000 events**, whichever is tighter. Eviction sweep runs every 60 s on
the time dimension; the 5 000-event cap is enforced on insert (oldest first
out).
---
## CON-event-log-window
- Source: `Тз расширение фаза1.md` §4.3
- Type: nfr / protocol
- Constraint: The user event log MUST be retained for **at most 10 minutes**.
---
## CON-video-codec
- Source: `Тз расширение фаза1.md` §4.1
- Type: protocol
- Constraint: Video chunks MUST be encoded as `video/webm; codecs=vp9` at a
target bitrate of `400 000 bps` (~3 MB/min raw). Chunk cadence (MediaRecorder
timeslice) is `2000 ms`.
---
## CON-webm-header-retention
- Source: `Тз расширение фаза1.md` §4.1, §8
- Type: protocol
- Constraint: The first MediaRecorder chunk (WebM container header) MUST be
retained in the buffer indefinitely; the assembled `last_30sec.webm` MUST
remain playable in a browser.
---
## CON-tab-capture-binding
- Source: `Тз расширение фаза1.md` §8
- Type: api-contract
- Constraint: `chrome.tabCapture` operates only on the active tab. On tab
activation change, the recorder MUST re-attach to the new active tab. First
invocation requires a user gesture.
---
## CON-service-worker-keepalive
- Source: `Тз расширение фаза1.md` §8
- Type: api-contract
- Constraint: MV3 Service Workers unload after ~30 s of inactivity. The
extension MUST keep the worker alive via a `chrome.alarms` alarm firing every
**20 seconds**.
---
## CON-manifest-permissions
- Source: `Тз расширение фаза1.md` §7
- Type: api-contract / schema
- Constraint: `manifest.json` MUST declare exactly:
```json
{
"permissions": [
"tabCapture",
"activeTab",
"downloads",
"scripting",
"storage"
],
"host_permissions": [
"<all_urls>"
]
}
```
---
## CON-sensitive-data-masking
- Source: `Тз расширение фаза1.md` §4.2, §8
- Type: nfr (security / privacy)
- Constraint: Sensitive input fields MUST be masked in both rrweb snapshots and
the event log. Specifically:
- `input[type=password]` — value NEVER recorded; element MUST be masked in
rrweb via `maskInputSelector`.
- Any element with `data-sensitive="true"` — masked in rrweb via
`maskInputSelector`.
- The event logger MUST filter `input` events to drop password field values.
---
## CON-archive-layout
- Source: `Тз расширение фаза1.md` §6
- Type: schema (file layout)
- Constraint: The exported ZIP MUST follow the layout in REQ-archive-layout
(verbatim, four top-level entries: `video/`, `rrweb/`, `logs/`,
`screenshot.png`, `meta.json`). Filename pattern:
`session_report_YYYY-MM-DD_HH-MM-SS.zip`.
---
## CON-meta-json-schema
- Source: `Тз расширение фаза1.md` §6
- Type: schema
- Constraint: `meta.json` MUST conform to the verbatim schema in
REQ-meta-json-schema. All listed fields are required.
---
## CON-event-log-schema
- Source: `Тз расширение фаза1.md` §4.3
- Type: schema
- Constraint: Each entry in `events.json` MUST conform to:
```json
{
"timestamp": <epoch_ms>,
"type": "click | input | navigation | error | network",
"target": "<css_selector>",
"value": "<value_or_masked>",
"url": "<page_url>",
"meta": {}
}
```
---
## CON-buffer-storage
- Source: `Тз расширение фаза1.md` §2
- Type: nfr
- Constraint: All Phase 1 buffers MUST live in memory only (Service Worker for
video, Content Script for rrweb + event log). `chrome.storage` is permitted
but MUST NOT be used to persist the rolling buffers.
---
## CON-no-server-upload
- Source: `Тз расширение фаза1.md` §9
- Type: nfr (scope boundary)
- Constraint: Phase 1 MUST NOT transmit any captured data to a remote server.
All export is local-only via `chrome.downloads`.

126
.planning/intel/context.md Normal file
View File

@@ -0,0 +1,126 @@
# Context (synthesized from SPEC §1, §9 and DOC)
Background, stakeholders, scope boundaries, and developer-facing operational
context. Functional requirements are in `requirements.md`; technical decisions
are in `decisions.md`; non-functional constraints are in `constraints.md`.
---
## Topic: Project goal
- Source: `Тз расширение фаза1.md` §1 (Контекст и цель)
- Notes:
- Operators work inside a browser and periodically make mistakes that are
hard to diagnose after the fact.
- The goal of Phase 1 is to silently and continuously record an operator's
session so that, on a button press, a self-contained archive of the
session can be exported to the "Downloads" folder for handoff to support.
- Phase 1 is local-only; no server, no AI, no auto-ticketing.
---
## Topic: Phase 1 scope (what is in)
- Source: `Тз расширение фаза1.md` §4, §5, §6, §7, §10; `README.md` §"Особенности"
- Notes:
- Continuous in-memory recording of:
- Last 30 s of active-tab video (`chrome.tabCapture` + MediaRecorder)
- Last 10 min of DOM events via rrweb (cap 5 000 events)
- Last 10 min of user/runtime events (click, input, navigation, js_error,
network_error)
- One-shot screenshot at export time (`chrome.tabs.captureVisibleTab`).
- Local ZIP packaging via JSZip and delivery via `chrome.downloads`.
- Sensitive-data masking for passwords and `[data-sensitive="true"]` fields.
- Single-button popup UI with idle / saving / done state machine.
---
## Topic: Phase 1 non-goals (Phase 2 work)
- Source: `Тз расширение фаза1.md` §9 (Что НЕ входит в Фазу 1)
- Notes — explicitly excluded from Phase 1 and reserved for Phase 2:
- Sending data to a server
- AI-driven diagnostics
- Automatic ticket creation
- Analytics dashboard
- Audio recording
---
## Topic: Developer workflow (install, build, debug)
- Source: `README.md` §"Установка и запуск", §"Отладка", §"Структура проекта"
- Provenance: This topic is DOC-only — the SPEC does not specify a build
toolchain. Per precedence `SPEC > DOC`, any future SPEC/ADR that prescribes a
different toolchain auto-overrides what is recorded here.
- Notes:
- **Install deps:** `npm install`
- **Dev build with HMR:** `npm run dev`
- **Prod build:** `npm run build`
- **Load in Chrome:**
1. `npm run build`
2. Open `chrome://extensions/`
3. Enable Developer mode
4. "Load unpacked"
5. Select the `dist/` folder
- **Debugging entry points:**
- Service Worker: Chrome DevTools → Extensions → Service Worker → Console
- Content Script: Chrome DevTools on the page → Console
- Popup: right-click popup → "Inspect"
- **Project layout (DOC-described, may be stale relative to actual repo):**
```
ai-call-extension/
├── src/
│ ├── background/ # Service Worker
│ │ └── index.ts
│ ├── content/ # Content Script
│ │ └── index.ts
│ ├── popup/ # Popup UI
│ │ ├── index.html
│ │ ├── index.ts
│ │ └── style.css
│ └── shared/ # Common types + utilities
│ ├── types.ts
│ └── logger.ts
├── icons/
├── dist/
├── manifest.json
├── vite.config.ts
├── tsconfig.json
└── package.json
```
---
## Topic: User-facing flow
- Source: `Тз расширение фаза1.md` §5; `README.md` §"Использование"
- Notes:
1. First popup open requests screen-recording permission (mandatory).
2. Recording starts automatically once granted.
3. To file an error report:
- Click the extension icon.
- Click "Сохранить отчёт об ошибке".
- Archive lands in the user's "Downloads" folder automatically.
4. Button state cycle: `idle` → "Сохраняю..." → "Готово! ✓" → `idle`
(3 s revert).
---
## Topic: Licensing and support
- Source: `README.md` §"Лицензия", §"Контакты"
- Notes:
- License: **MIT**
- Support contact: addressed to "support" (no concrete channel listed in
DOC).
---
## Topic: Russian-source provenance
- Source: both documents (`Тз расширение фаза1.md`, `README.md`)
- Notes: Both source documents are authored in Russian. UI strings ("Сохранить
отчёт об ошибке", "Последние 30 сек видео + 10 мин лога", "Сохраняю...",
"Готово! ✓") are part of the user-facing contract and MUST be preserved
verbatim. Section identifiers and technical names use Latin script.

View File

@@ -0,0 +1,180 @@
# 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` §"Технический стек".
---
## 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.
---
## 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.

View File

@@ -0,0 +1,227 @@
# Functional Requirements (synthesized from SPEC §4§7, acceptance §10)
The SPEC `Тз расширение фаза1.md` does not formally label itself as a PRD set,
but sections 47 describe user-visible / functional behavior and §10 lists
acceptance criteria. Per the orchestrator's instruction, these are extracted
here as requirements with IDs derived `REQ-{slug}`.
Source key:
- `SPEC §X``Тз расширение фаза1.md`, section X
- `DOC``README.md`
All requirements below are sourced from the SPEC; the DOC is a confirming
source unless noted otherwise.
---
## REQ-video-ring-buffer
- Source: `Тз расширение фаза1.md` §4.1
- Scope: Continuous video capture of the active tab
- Description: The extension MUST maintain an in-memory ring buffer containing
the most recent 30 seconds of video from the currently active browser tab.
- Acceptance criteria (from SPEC §10):
- Video buffer runs continuously on any tab.
- The buffer never holds more than 30 seconds of footage.
- The bundled `last_30sec.webm` from the exported archive plays back in a
browser.
- Technical bindings (see decisions.md):
- DEC-003 — `chrome.tabCapture.capture()` for acquisition
- DEC-003 — `video/webm; codecs=vp9` @ 400 000 bps, 2000 ms chunks
- DEC-009 — header chunk retained indefinitely
- Confirming source: `README.md` §"Использование" and §"Кольцевой буфер".
---
## REQ-rrweb-dom-buffer
- Source: `Тз расширение фаза1.md` §4.2
- Scope: DOM event recording
- Description: The extension MUST record DOM events via rrweb over a rolling
10-minute window from the active page, capped at 5 000 events.
- Acceptance criteria (from SPEC §10):
- rrweb records DOM events without errors on typical pages (forms, tables,
modal windows).
- Technical bindings:
- DEC-004 — rrweb library
- DEC-004 — `maskInputSelector` for `input[type=password]` and
`[data-sensitive="true"]`
- SPEC §8 — 5 000-event cap; oldest dropped on overflow
- SPEC §4.2 — 10-minute TTL purge every 60 s
- Confirming source: `README.md` §"Кольцевой буфер".
---
## REQ-user-event-log
- Source: `Тз расширение фаза1.md` §4.3
- Scope: User and runtime event logging
- Description: The extension MUST log user and runtime events over a rolling
10-minute window.
- Captured event types (SPEC §4.3):
- `click` — click on any element; records `target` selector and element text
- `input` — field value change (passwords excluded)
- `navigation``popstate`, `hashchange`, page transitions
- `js_error``window.onerror`, `window.onunhandledrejection`
- `network_error``fetch` / `XMLHttpRequest` with response code `>= 400`
- Log entry schema (SPEC §4.3, verbatim):
```json
{
"timestamp": 1716800000000,
"type": "click | input | navigation | error | network",
"target": "CSS-селектор элемента",
"value": "текст/значение (маскируется для паролей)",
"url": "текущий URL",
"meta": {}
}
```
- Acceptance criteria (from SPEC §10):
- Event log captures clicks, navigation, and network errors.
- Passwords do not appear in either the event log or rrweb snapshots.
- Confirming source: `README.md` §"Записываемые события".
---
## REQ-screenshot-on-export
- Source: `Тз расширение фаза1.md` §4.4, §5
- Scope: One-shot visual capture
- Description: At the moment the user clicks "Save archive", the extension MUST
capture a PNG screenshot of the active tab via `chrome.tabs.captureVisibleTab`
and include it as `screenshot.png` in the archive.
- Technical binding: DEC-008.
---
## REQ-popup-ui
- Source: `Тз расширение фаза1.md` §5
- Scope: User-facing trigger
- Description: The extension MUST expose a minimal popup with a single button
labeled "Сохранить отчёт об ошибке" and a sub-label "Последние 30 сек видео
+ 10 мин лога".
- Button state machine (SPEC §5):
- `idle` → `Сохраняю...` → `Готово! ✓` → `idle` (after 3 s)
- On-click behavior (SPEC §5):
1. Capture screenshot of active tab.
2. Request video buffer + event log from Service Worker.
3. Request rrweb snapshots from Content Script.
4. Assemble archive (see REQ-archive-layout).
5. Trigger download via `chrome.downloads.download()`.
6. Display "Готово! ✓" status.
- Confirming source: `README.md` §"Использование".
---
## REQ-archive-layout
- Source: `Тз расширение фаза1.md` §6
- Scope: ZIP archive structure
- Description: The archive MUST be named
`session_report_YYYY-MM-DD_HH-MM-SS.zip` and contain exactly:
```
session_report_2025-05-15_14-32-10.zip
├── video/
│ └── last_30sec.webm # склеенные чанки видеобуфера
├── rrweb/
│ └── session.json # массив DOM-событий rrweb
├── logs/
│ └── events.json # лог действий пользователя
├── screenshot.png # скриншот в момент сохранения
└── meta.json # метаданные сессии
```
- Acceptance criteria (from SPEC §10):
- Archive opens cleanly.
- `last_30sec.webm` plays back in a browser.
- Confirming source: `README.md` §"Структура архива" (byte-identical layout).
---
## REQ-meta-json-schema
- Source: `Тз расширение фаза1.md` §6
- Scope: Archive metadata
- Description: `meta.json` inside the archive MUST conform to the schema:
```json
{
"timestamp": "2025-05-15T14:32:10Z",
"url": "https://...",
"userAgent": "Chrome/...",
"extensionVersion": "1.0.0",
"videoBufferSeconds": 30,
"logDurationMinutes": 10,
"totalEvents": 143
}
```
- Fields are required (SPEC does not mark any optional).
---
## REQ-manifest-permissions
- Source: `Тз расширение фаза1.md` §7
- Scope: Browser permission surface
- Description: The extension MUST declare exactly the permission set in DEC-011
and MUST request user gesture for `tabCapture` on first activation.
- Acceptance criteria (from SPEC §10):
- Extension installs in Chrome without errors.
---
## REQ-archive-export-latency
- Source: `Тз расширение фаза1.md` §10 (acceptance)
- Scope: Performance — archive delivery
- Description: From the moment the user clicks the export button, the ZIP
archive MUST land in the "Downloads" folder in under 5 seconds.
- Confirming source: `README.md` §"Критерии приёмки Фазы 1".
---
## REQ-password-confidentiality
- Source: `Тз расширение фаза1.md` §4.2, §4.3, §8, §10
- Scope: Sensitive data handling
- Description: Passwords MUST NOT appear in either rrweb snapshots or the user
event log. Masking MUST be enforced by:
- rrweb `maskInputSelector` covering `input[type=password]` and
`[data-sensitive="true"]`
- the event logger explicitly filtering value capture for password fields
- Acceptance criteria (from SPEC §10):
- Passwords do not leak into either output stream.
- Confirming source: `README.md` §"Маскирование чувствительных данных".
---
## REQ-install-clean
- Source: `Тз расширение фаза1.md` §10
- Scope: Installability
- Description: The extension MUST install in Chrome without errors via the
unpacked-extension load flow.
- Confirming source: `README.md` §"Установка расширения в Chrome".
---
## Phase 1 Acceptance Criteria (full list, SPEC §10 verbatim)
For traceability, all SPEC §10 acceptance criteria are listed here once. Each
is also referenced from one or more REQ-* entries above.
1. The extension installs in Chrome without errors. → REQ-install-clean,
REQ-manifest-permissions
2. The video buffer runs continuously on any tab. → REQ-video-ring-buffer
3. The buffer always contains no more than 30 seconds of video. →
REQ-video-ring-buffer
4. rrweb records DOM events without errors on typical pages (forms, tables,
modal windows). → REQ-rrweb-dom-buffer
5. The event log captures clicks, navigation, and network errors. →
REQ-user-event-log
6. On button press, the archive is downloaded to "Downloads" in < 5 seconds. →
REQ-archive-export-latency
7. The archive opens; `last_30sec.webm` plays back in a browser. →
REQ-archive-layout, REQ-video-ring-buffer
8. Passwords do not appear in the log or rrweb snapshots. →
REQ-password-confidentiality
9. Extension RAM consumption does not exceed 50 MB in the background. → see
`constraints.md` CON-ram-ceiling (NFR, not a functional REQ).