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:
222
.planning/ROADMAP.md
Normal file
222
.planning/ROADMAP.md
Normal 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 1–3 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 1–3 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 1–4)
|
||||
|
||||
**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 | - |
|
||||
Reference in New Issue
Block a user