Files
mokosh/.planning/ROADMAP.md
Mark 6dbed91efd docs(roadmap): re-phase milestone — remove Phase 2 (DOM/event-capture privacy)
Per operator charter shift 2026-05-20: "we don't care about privacy hardening.
At least here." Archive flow is internal-only (no external transmission),
which reframes the password-masking P0-5 defect from privacy-regulation
gravity to operator-hygiene polish.

Re-phasing applied across 4 planning artifacts:

ROADMAP.md:
- Original Phase 2 ("Stabilize DOM + event-capture privacy") REMOVED entirely
  (summary list + Phase Details section + Progress table row).
- DOM + event-log VERIFICATION (REQ-rrweb-dom-buffer + REQ-user-event-log)
  ABSORBED by new Phase 3 (SPEC §10 smoke verification).
- Phase numbering: old 3 → new 2 (export), old 4 → new 3 (smoke), old 5 → new 4
  (optional harden). Dependency chains updated accordingly.
- Overview blurb + journey narrative + success criteria refreshed.
- Phase 3 (smoke) explicitly NOT-in-scope: P0-5 password masking dropped.

REQUIREMENTS.md traceability:
- REQ-rrweb-dom-buffer: Phase 2 → Phase 3 (verification scope; UAT harness
  A24+ extension planned).
- REQ-user-event-log: Phase 2 → Phase 3 (same context).
- REQ-password-confidentiality: Phase 2 → Out of Scope (v1) — DEFERRED per
  charter shift.
- REQ-popup-ui, REQ-screenshot-on-export, REQ-archive-layout,
  REQ-meta-json-schema, REQ-archive-export-latency: Phase 3 → Phase 2
  (renumbered; substantively shipped via Plans 01-08 + 01-09 + 01-12;
  residual gaps in Phase 2).
- Coverage: 10 mapped + 1 out-of-scope (was 11 mapped).

PROJECT.md:
- CON-sensitive-data-masking: DEFERRED 2026-05-20 (preserves audit trail
  via strikethrough; rationale documented).
- DEC-004 amendment: rrweb 5000-event cap retained; masking deferred. Cites
  rrweb 2.0.0-alpha.4 maskInputSelector→maskInputFn API change.

STATE.md:
- frontmatter total_phases: 5 → 4.
- stopped_at narrative captures the re-phasing event.

CLI bug note: this re-phasing was attempted via `gsd-sdk query phase.remove 2`
+ canonical `/gsd-remove-phase 2` Skill invocation, but BOTH paths produced
corrupted output (cascading rename via reverse-iteration loop at
phase.cjs:670-679 collapsed all subsequent phases to "Phase 2", plus a
mysterious "2026"→"2002" date corruption). Recovery applied as manual edits
in this commit. CLI bug logged as upstream GSD-framework concern; not a
Mokosh-side issue.

Plan: next is `/gsd-discuss-phase 2` (new Phase 2 = export pipeline; narrowed
scope per re-phasing — ~2-3 plans expected since Plans 01-08 + 01-09 + 01-10
+ 01-12 already shipped most surface).

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

253 lines
18 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.
# 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 framed Phase 1 as **stabilization to spec**, not
greenfield: phases 12 each remediate a tightly-grouped subset of the P0
defects along sensible commit boundaries; phase 3 runs the SPEC §10 smoke pass
end-to-end (and now also absorbs the DOM + event-log verification surface that
was originally Phase 2). An optional phase 4 absorbs the P1/P2 follow-ups (SW
state persistence, `fetch` interception fix, `meta.json` field hardening,
`generate-icons.js` ESM/CJS, dead-code cleanup).
**Roadmap re-phasing 2026-05-20:** original Phase 2 ("Stabilize DOM +
event-capture privacy") REMOVED per operator charter shift — archive flow is
internal-only (no external transmission); P0-5 password masking dropped as
v1 priority ("we don't care about privacy hardening. At least here."). DOM
+ event-log VERIFICATION (REQ-rrweb-dom-buffer + REQ-user-event-log) absorbed
by new Phase 3 (SPEC §10 smoke). REQ-password-confidentiality moved to Out
of Scope (v1). All subsequent phases renumbered: old 3 → new 2, old 4 → new
3, old 5 → new 4.
The journey: **broken-but-installable → playable video → working export →
green §10 smoke (incl. DOM + event-log verification) → 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.
- [x] **Phase 1: Stabilize video pipeline** — Collapse offscreen duality, fix MediaRecorder shadow, fix WebM ring buffer playability, replace `chrome.tabCapture` with offscreen `getDisplayMedia` (AMENDED from original DEC-003). **CLOSED 2026-05-20** via gsd-verifier goal-backward audit GREEN (17/17 must-haves: 11 REQs/charters + 6 cross-cutting gates; see `.planning/phases/01-stabilize-video-pipeline/01-VERIFICATION.md`). Closure arc: 2026-05-15 (Plan 01-07) → 2026-05-16 (REOPENED on D-13 multi-EBML bug) → Plan 01-08 (WebM remux via ts-ebml + webm-muxer) → Plans 01-09/01-10 (whole-desktop + welcome-tab UX) → Plan 01-11 (spike-pivot) → Plan 01-12 (Design Integration) → Plan 01-13 (UAT harness 15/15 GREEN, 2026-05-19) → Plan 01-14 (monitorTypeSurfaces picker) → Plan 01-10 cycle-2 ack 'All good' 2026-05-20 + 5 inter-cycle debug fixes + brand-rename polish. 14/14 plans; 5 operator acks; 153/153 vitest + 24/24 UAT + Tier-1 grep 12 FORBIDDEN_HOOK_STRINGS all GREEN.
- [ ] **Phase 2: Stabilize export pipeline** — Close remaining export gaps (screenshot-at-click, meta.json schema, archive layout, manifest permission verification). Mostly already shipped via Plans 01-08 + 01-09 + 01-10 + 01-12 — narrowed scope post-re-phasing.
- [ ] **Phase 3: SPEC §10 smoke verification** — End-to-end install-and-record-and-export pass against all 9 acceptance criteria. **ABSORBS** REQ-rrweb-dom-buffer + REQ-user-event-log verification (originally Phase 2) per 2026-05-20 re-phasing. UAT harness extended with A24+ assertions for rrweb/event-log contracts.
- [ ] **Phase 4: Harden + clean up** _(optional)_ — P1/P2 follow-ups: SW state persistence, fetch interception, `meta.json` fields, `generate-icons.js` ESM/CJS, dead-code; plus deferred items from Phase 1 session (cursor visibility, dark-surface logo, tabs permission gap, 2 ffprobe flakes, ROADMAP backfill verification, rrweb 2.0.0-alpha.4 → stable v2 upgrade research).
## 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. [x] 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. [x] With the extension loaded and an operator session active, a `MediaRecorder`
is running on the operator-selected screen/window source. AMENDED 2026-05-15
(D-13 fix-a3 activation): the recorder cycles in 10 s self-contained segments
(stop+restart on the same `MediaStream`) instead of a single continuous
recorder — replaces D-09..D-11 to fix VP9 keyframe orphan-P-frame freezes.
Recording continues unchanged across tab switches (no tab re-attach logic;
AMENDED from the original wording).
3. [x] The in-memory video ring buffer at any instant contains at most 3 of the
most recent 10 s WebM segments (3 × 10 s = 30 s window, no more, no less);
concatenating segments sequentially yields a multi-EBML-header WebM that
Chrome plays end-to-end (SPEC §10 #7 — operator confirmed clean playback
2026-05-15; ffmpeg `-v warning -i fixture -f null -` exit 0 with zero
decoder errors, only expected muxer DTS-monotonicity warnings at segment
join boundaries).
**Plans**: 14 plans (01-01 through 01-14). All 14 functional plans complete; Phase 1 final-closure marker flip pending.
- [x] 01-01-PLAN.md — Doc cascade: amend DEC-003 / DEC-010 / RETIRE constraints / swap manifest permissions (D-A1..D-A6)
- [x] 01-02-PLAN.md — Wave-0 test infrastructure: Vitest install + 4 RED test files + fixtures placeholder
- [x] 01-03-PLAN.md — Offscreen recorder TDD: ring buffer + codec strict-mode + getDisplayMedia + track-ended cleanup; D-13 fallback skeleton pre-staged
- [x] 01-04-PLAN.md — Port keepalive + OFFSCREEN_READY handshake (TDD): replaces alarms keepalive on offscreen side
- [x] 01-05-PLAN.md — SW shrink: delete legacy buffer + alarms + IndexedDB + tabCapture paths; wire SW-side onConnect host
- [x] 01-06-PLAN.md — Build pipeline collapse: delete vite.config.ts inline plugin + top-level offscreen/ dir; declare rollupOptions.input
- [x] 01-07-PLAN.md — Manual smoke + ffprobe D-12 acceptance gate + A3 empirical-playback gate; D-12 + A3 debug sessions resolved mid-execution via pre-staged base64 wire format + D-13 restart-segments; regression fixture committed; SPEC §10 #2/#3/#7 functionally green (Closed 2026-05-15)
- [x] 01-08-PLAN.md — WebM remux via ts-ebml + webm-muxer (replaces D-13 file-concat; closes SPEC §10 #7 playability per debug d13-multi-ebml-concat-unplayable.md)
- [x] 01-09-PLAN.md — Toolbar onClicked direct flow + monitor-only picker + onStartup notification + 3-state badge state machine; closure-by-harness Amendment 2 (Plan 01-13 PASS substitutes for operator UAT). Closure-cycle follow-up debug `a2dfc8c` (startVideoCapture no-tab cleanup; D-01 dead-code removal) + `4bba679` (notifStartup text split into notifStartupCta + notifRecordingStarted) landed during Plan 01-10 closure 2026-05-20.
- [x] 01-10-PLAN.md — Welcome tab (Hero + Loom dial per D-02; first-install onboarding; chrome.runtime.onInstalled + chrome.storage.local flag-gating + chrome.tabs.create + canonical mokosh-mark.svg via Vite ?url import + canonical src/shared/tokens.css @import + chrome.i18n.getMessage for welcomeHeroRu + welcomeHeroEn; harness A15-A17 with A17.7 --mks-rec probe + A17.8 mark-bundling invariant; D-16-toolbar charter preserved). Closure 2026-05-20 via cycle-2 operator ack "All good" + 5 inter-cycle debug fixes (89e1e09 → 49f087f → 8f329d8 → b112cb7 → 4bba679 → d48a715 → 0854baf → a2dfc8c → d21ed17) + brand-rename follow-up "AI Call Recorder" → "Mokosh"; 153/153 vitest + 24/24 UAT GREEN.
- [x] 01-11-PLAN.md — UAT harness Approach-A spike (PIVOTED to 01-13; carries forward Wave 0 infrastructure + Tier-1 grep gate; falsified hypotheses recorded)
- [x] 01-12-PLAN.md — Design integration (R2 Lora self-host, src/shared/tokens.css canonical, 16 i18n keys across en+ru, branded Loom icons replacing Bug A placeholders, manifest i18n + default_locale='en', BADGE_REC_COLOR madder #b2543d, chrome.i18n.getMessage with `|| <const>` fallback, harness A18-A22; operator brand-fit ack 2026-05-20 'all good')
- [x] 01-13-PLAN.md — UAT harness via Approach B (extension-internal-page driver + offscreen synthetic stream; 15/15 GREEN; Plan 01-09 functional closure)
- [x] 01-14-PLAN.md — Picker narrowing via monitorTypeSurfaces:'include' (Chrome 119+ picker enhancement; A23 harness regression)
### Phase 2: 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 (export consumes the video buffer + the rrweb/event-log
infrastructure already shipped in src/content/index.ts; original "Phase 2 DOM"
dependency removed per 2026-05-20 re-phasing).
**Scope note (2026-05-20):** Plans 01-08 (webm-remux + JSZip), 01-09 (popup
state machine + SAVE-only UI), 01-10 (welcome tab + i18n), and 01-12 (manifest
i18n + en+ru locales) already shipped most of the originally-planned export
surface. Phase 2 likely collapses to 2-3 small plans closing residual gaps:
screenshot-at-click capture, meta.json schema validation, and SPEC §10 #6
<5s export-latency verification.
**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 3: SPEC §10 smoke verification + DOM/event-log verification
**Goal**: All 9 SPEC §10 acceptance criteria pass against an unpacked load of
the build into a real Chrome instance. **ABSORBS** DOM + event-log verification
work (REQ-rrweb-dom-buffer + REQ-user-event-log) originally planned as Phase 2
per 2026-05-20 re-phasing.
**Depends on**: Phase 1, Phase 2.
**Requirements**: REQ-install-clean + REQ-rrweb-dom-buffer + REQ-user-event-log
+ 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 12 actually satisfies the SPEC.
**Absorbed Phase-2 scope (2026-05-20 re-phasing):**
- Verify rrweb 2.0.0-alpha.4 captures DOM events on typical pages (form +
table + modal) without throwing in the Content Script console (REQ-rrweb-dom-buffer
acceptance criterion #3).
- Verify the user-event log captures click + input (non-password) +
navigation (popstate/hashchange) + js_error + network_error per
CON-event-log-schema (REQ-user-event-log).
- Extend UAT harness with A24+ assertions covering the above contracts —
consistent with Phase 1's Approach-B harness pattern (Plan 01-13).
- rrweb version research (foreground gsd-phase-researcher spawn) to verify
alpha-pin is safe or if stable v2 has shipped. Deferred to Phase 4 if
Phase 3 plans are tight.
- **NOT in scope:** P0-5 password masking (REQ-password-confidentiality
dropped to Out of Scope v1 per "we don't care about privacy hardening.
At least here." 2026-05-20).
**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. (Password
masking criterion DROPPED per 2026-05-20 re-phasing —
REQ-password-confidentiality is Out of Scope v1.)
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 4: 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 3 (do not harden until §10 is green).
**Requirements**: none (no new v1 REQs; all v1 REQs are covered by phases 13)
**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).
- `getDisplayMedia` cursor visibility constraint (`video: { cursor: 'always' }`)
— refines capture quality for diagnostic UX; surfaced during Phase 1 smoke
(2026-05-15) as a user observation. Operator's screen cursor was absent
from captured frames despite being the highest-signal cue when reproducing
pointer-driven bugs. Constraint is opt-in per the `getDisplayMedia` spec
and Chrome implements it via the `CursorCaptureConstraint` enum (`always`
/ `motion` / `never`).
**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 | 14/14 | **CLOSED 2026-05-20** via gsd-verifier audit GREEN (17/17 must-haves; commit 586836f); all markers flipped | Functional contract closed 2026-05-19 via Plan 01-13 harness PASS; design/brand contract closed 2026-05-20 via Plan 01-12 brand-fit ack; welcome-tab contract closed 2026-05-20 via Plan 01-10 cycle-2 operator ack "All good" + 5 inter-cycle debug fixes |
| 2. Stabilize export pipeline | 0/TBD | Not started (narrowed scope post-2026-05-20 re-phasing; ~2-3 plans expected) | - |
| 3. SPEC §10 smoke + DOM/event-log verification | 0/TBD | Not started (absorbed Phase-2 DOM verification per 2026-05-20 re-phasing; ~2-3 plans) | - |
| 4. Harden + clean up (optional) | 0/TBD | Not started (deferred backlog: cursor visibility, dark-surface logo, tabs perm gap, ffprobe flakes, ROADMAP backfill, rrweb-version upgrade research, REQ-password-confidentiality v2 candidate) | - |