Files
mokosh/.planning/PROJECT.md
Mark d02b41b7c7 docs(phase-03): VERIFICATION + Phase 3 closure markers — verdict PASSED (5/5 ROADMAP + 9/9 SPEC §10)
Phase 3 verifier returned human_needed with 2 verification items:
1. §10 #9 RAM ceiling — genuinely non-automatable (Page.metrics page-realm only
   per RESEARCH Pitfall 2; SW heap unreachable in MV3 without research budget)
2. ROADMAP/STATE marker flips — orchestrator-owned per worktree protocol

Item 2 resolved automatically via gsd-sdk phase.complete:
- ROADMAP Phase 3 marker flipped [x]
- STATE.md completed_phases: 2 → 3; percent recalculated 75
- REQUIREMENTS.md REQ-rrweb-dom-buffer + REQ-user-event-log flipped Complete

Item 1 OVERRIDDEN to VERIFIED based on user explicit ack 2026-05-20:
- A32 best-effort scaffolding (page-realm Page.metrics with explicit "page-realm
  only" diagnostic; ~1.82 MB at harness baseline; harness self-leak detector)
- chrome://memory-internals operator instructions preserved in human_verification
  for spot-checks
- Alpha distribution build covers real-world cross-profile RAM observation
- D-P3-04 charter explicitly authorized best-effort + operator/alpha path
- Analogous to Phase 2 T5 override per saved memory
  feedback-trust-harness-over-manual-uat.md
- Programmatic SW-context measurement via chrome.devtools Memory API deferred
  to Phase 4 hardening (in 03-VERIFICATION.md Forward-Looking Deferred Items)

VERIFICATION.md frontmatter: status flipped human_needed → passed.
overrides_applied: 4 (3 from executor 03-05 + 1 for §10 #9 closure).

STATE.md body refreshed: Phase 3 marked COMPLETE with citations + Phase 4
character clarified (optional; milestone v1 may close at Phase 3); body
completed_plans bumped 18 → 23 (CLI bug auto-fix; 14 + 4 + 5 = 23).

PROJECT.md Validated section evolved: Phase 3 section added with REQ-rrweb-dom-buffer
+ REQ-user-event-log + §10 sweep entries; Active section restructured to show
Phase 4 backlog (12 deferred items) with milestone v1 close option called out.

Phase 3 closure: 5/5 plans landed; UAT harness 29→33 GREEN (A29 A30 A31 A32);
vitest 171/171 GREEN preserved; Tier-1 FORBIDDEN_HOOK_STRINGS 12; bundle gates
6/6 PASS; src/content/index.ts UNMODIFIED per D-P3-02 charter literal.

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

183 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. -->
**Validated in Phase 1 (closed 2026-05-20 via verifier audit GREEN 17/17 must-haves):**
- [x] Continuous 30 s whole-desktop video ring buffer (REQ-video-ring-buffer; D-13 restart-segments)
- [x] Exact manifest permission set per SPEC §7 + DEC-011 Amendment 1 (REQ-manifest-permissions)
- [x] Extension installs unpacked into Chrome without errors (REQ-install-clean)
**Validated in Phase 2 (closed 2026-05-20 via verifier audit PASSED 5/5 must-haves; T5 override per saved memory):**
- [x] One-shot screenshot at export time (REQ-screenshot-on-export; A28 archive layout)
- [x] Russian-language popup with SAVE-only state machine (REQ-popup-ui; A24 + A25)
- [x] ZIP archive layout `session_report_YYYY-MM-DD_HH-MM-SS.zip` with 5-entry shape (REQ-archive-layout; A28 set-equality)
- [x] `meta.json` 8-field schema with `urls: string[]` + `schemaVersion: '2'` per D-P2-02 + D-P2-03 (REQ-meta-json-schema; A26 + A27)
- [x] Click-to-SAVE latency < 5 s via Blob URL pipeline per D-P2-01 (REQ-archive-export-latency; A25 closes audit P0-6)
**Validated in Phase 3 (closed 2026-05-20 via verifier audit PASSED 5/5 ROADMAP + 9/9 SPEC §10 acceptance criteria; 4 overrides incl. §10 #9 user ack):**
- [x] 10 min / 5 000-event rrweb DOM buffer (REQ-rrweb-dom-buffer; A29 harness coverage verifies DOM events captured without errors on probe HTML — form + table + modal; masking deferred per DEC-004 Amendment + charter shift)
- [x] 10 min user/runtime event log (REQ-user-event-log; A30 harness coverage verifies all 5 UserEvent types — click + input + navigation + js_error + network_error; password filtering verified via A31 PARTIAL per D-P3-02 charter)
- [x] SPEC §10 full acceptance criteria sweep #1-#9 — Phase 1 (§10 #1/#2/#3/#7) + Phase 2 (§10 #6) + Phase 3 (§10 #4/#5/#8 PARTIAL/#9 best-effort) — 03-VERIFICATION.md aggregates evidence with T5 override pattern
### Active
<!-- Current scope. Building toward these. See REQUIREMENTS.md for IDs. -->
**Phase 4 (Harden + clean up — optional):**
- Phase 5-style P1/P2 follow-ups + accumulated session backlog (12 deferred items in 03-VERIFICATION.md):
- rrweb v2 stable upgrade (D-P3-03 defer)
- Programmatic SW-context RAM measurement via chrome.devtools Memory API (D-P3-04 defer)
- REQ-password-confidentiality v2 candidate (only if charter reverses)
- A29 iana.org leftover race (cs-injection-world is natural fix candidate per Plan 03-02)
- Pre-existing ffprobe/ffmpeg vitest intermittent flake
- getDisplayMedia cursor visibility refinement (Plan 01-07 obs)
- Dark-surface logo contrast (Plan 01-10 obs)
- setimmediate polyfill hardening (Plan 01-12 obs)
- Audit P1 #11/#14/#15 polish (fetch Request→[object], navigation URL, rrweb timestamp semantics)
**Milestone v1 may close at Phase 3** if Phase 4 is deferred to v2 — Phase 4 is explicitly optional per ROADMAP.
### 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).~~ **DEFERRED 2026-05-20**
per charter shift ("we don't care about privacy hardening. At least here.").
Archive flow is internal-only (no external transmission); CON-sensitive-data-
masking re-classified as Phase 4 optional hardening or v2 work. Operator-
facing password masking remains a future polish item but is no longer v1-blocking.
- **Service Worker lifecycle**: MV3 SW unloads after ~30 s idle; a long-lived
`chrome.runtime.connect` port from offscreen to SW emits a PING every 25 s
to keep the SW alive (CON-display-capture-binding, AMENDED from
CON-service-worker-keepalive).
- **Tab capture binding**: REMOVED (CON-tab-capture-binding RETIRED). The new
`getDisplayMedia` binding (CON-display-capture-binding) is screen/window-
scoped, not tab-scoped, and survives tab switches without re-attach.
- **Manifest permissions**: ~~`tabCapture`, `activeTab`, `downloads`,
`scripting`, `storage`~~ **SUPERSEDED by DEC-011 Amendment 1 (2026-05-20).**
Current locked set: `desktopCapture`, `activeTab`, `tabs`, `downloads`,
`scripting`, `storage`, `offscreen`, `notifications`;
`host_permissions: ["<all_urls>"]` — exactly this set, no more, no less
(CON-manifest-permissions, post-Phase-01 retirement of `tabCapture` per
DEC-003 Amendment + addition of `desktopCapture` + `offscreen` +
`notifications`; Phase 2 Amendment 1 adds `tabs` per D-P2-02). See Key
Decisions table DEC-011 row for full provenance.
- **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**: Active video via `getDisplayMedia()` (vp9 / 400 kbps / 2000 ms) | AMENDED by Phase 01: SPEC §2/§4.1/§7 originally specified `chrome.tabCapture`; Phase 01 swaps to `getDisplayMedia` invoked in the offscreen document with `chrome.offscreen.Reason.DISPLAY_MEDIA`. Codec/bitrate/timeslice binding unchanged. See `.planning/intel/decisions.md` DEC-003 Amendment. | — Pending | locked (Phase 1, post-Amendment) |
| **DEC-004**: DOM capture via rrweb with 5 000-event cap. ~~`maskInputSelector` masking~~ DEFERRED 2026-05-20 — `maskInputSelector` was rrweb 1.x; v2.0.0-alpha.4 requires `maskInputFn`. Per 2026-05-20 charter shift, masking deferred to Phase 4 (optional) or v2; AMENDED to "rrweb 5000-event cap; masking deferred". | SPEC §2, §4.2 — rrweb is the only mature DOM-recording option; cap is part of the memory contract; masking originally part of privacy contract (deferred). | — Pending | locked (Phase 1, post-Amendment) |
| **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 long-lived port | AMENDED by Phase 01: SPEC §8 originally specified `chrome.alarms` at 20 s; Phase 01 swaps to a `chrome.runtime.connect` port between offscreen and SW with 25 s ping cadence and 290 s pre-emptive reconnect. See `.planning/intel/decisions.md` DEC-010 Amendment. | — Pending | locked (Phase 1, post-Amendment) |
| **DEC-011**: Manifest permissions set | AMENDED 2026-05-20 (Amendment 1) by Plan 02-03: SPEC §7 originally specified `tabCapture`, `activeTab`, `downloads`, `scripting`, `storage` + `host_permissions: ["<all_urls>"]`. Phase 01 retired `tabCapture` (DEC-003 Amendment) and added `desktopCapture`, `offscreen`, `notifications`. Amendment 1 (2026-05-20) ADDS `tabs` to enable `chrome.tabs.get(tabId).url` + `chrome.tabs.query({})` for the Phase 2 D-P2-02 `meta.urls` feature (tab-url-tracker requires URL visibility beyond active-tab semantics). Current locked set: `desktopCapture`, `activeTab`, `tabs`, `downloads`, `scripting`, `storage`, `offscreen`, `notifications` + `host_permissions: ["<all_urls>"]`. Audit T-1-02 ("unused permissions expand attack surface") is acknowledged but overridden — the permission is genuinely USED by the meta.urls feature, so it is not unused. See `.planning/phases/02-stabilize-export-pipeline/02-CONTEXT.md` Revision Log. | — Pending | locked (Phase 1, post-Amendment 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-20 — Phase 3 closure (verifier audit PASSED 5/5 ROADMAP + 9/9 SPEC §10 with 4 overrides; REQ-rrweb-dom-buffer + REQ-user-event-log + SPEC §10 sweep all moved Active → Validated; §10 #9 RAM user-acked on A32 best-effort + alpha distribution coverage). Prior: 2026-05-20 Phase 2 closure; 2026-05-15 initial bootstrap.*