Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,30 @@ Ship a signed-off Muse classroom loop: Design → Collect → Clean → Analyze,
- [x] Cut Emotiv SDK
- [x] Muse + Neurosity first-party drivers (`EEGDriver` registry)
- [x] LSL outlets for connected first-party devices (epochs + stimulus markers)
- [x] External LSL inlet in ConnectModal (when liblsl is available)
- [x] External LSL inlet in headset setup (when liblsl is available)
- [x] Restore custom-experiment authoring (see TODOS — P0)
- [x] QA built-in + custom experiments on Muse hardware
- [x] First release dry-run (`v1.0.0-rc.1`) + packaged-app smoke
- [ ] Cross-platform LSL packaging verification (macOS x64, Windows, Linux)

CSV is still the system of record. Using LSL *internally* for recording is not a V1 goal.

## V1.5 — visual polish
## V1.5 — playtest-driven redesign

Epoch-reviewer onboarding (plain language, guided mode). See TODOS "Next".
Fix what the first naive playtest (`docs/uxr/playtest_naive_1.md`, 2026-09-18) showed: unclear starting point and next action, headset setup, the Explore lessons, and a Clean → Analyze workflow that did not hold together. Plan: `docs/uxr/playtest_naive_1_design_implementation_plan.md` (gitignored). Each surface went Storybook design → approval → integration.

- [x] WS1 Navigation shell and Home (#269)
- [x] WS2 Headset setup and connection (#272, #274)
- [x] WS3 Explore lessons, including the eyes-closed activity (#282, #286)
- [x] WS4 Prepare steps and preview (#276, #281)
- [x] WS5 Participant screens, early exit and incomplete runs (#273, #275, #279)
- [x] WS6 Clean (#280, #285)
- [x] WS7 Analyze (#277, #284)
- [ ] WS8 Full manual QA on real hardware, then a second naive playtest (see TODOS "Next")
- [ ] Fixes and language PR from WS8, then release v1.5

Known gap going in: the Collect pre-run screen never got its own redesign.
Epoch-reviewer guided mode stays a V1.5+ item, contingent on the playtest.

## V2 — lesson content

Expand Down
32 changes: 22 additions & 10 deletions TODOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ Deferred and in-flight work. Keep this current — when something ships, delete
- ~~Collect: ConnectModal fails to appear on first navigation to the collect screen.~~ — shipped 2026-09-23 (WS2, PR #274). `ConnectModal` is gone; Collect opens the shell-owned `HeadsetSetupDialog` whenever EEG is on and no headset is connected, and never scans until `Find my headset`.
- ~~QA (WS2, PR #274): real-Muse pass~~ — done 2026-09-24 (human, real Muse): find → connect → signal prep, cancel/search again, drop → setup reopens, cancel while connecting. Finding: the platform never ends a search itself (it ran until Cancel), hence the one-minute limit below.
- ~~QA (PR #274): one-minute search limit on a real Muse~~ — done 2026-09-24 (human, real Muse): with the headset off, the search ends after a minute on "We couldn't find your Muse" / "Is your Muse turned on?". "Search again" afterwards is covered by `HeadsetSetupDialog.timeout.test.tsx` (real reducer, epics and dialog; faked driver).
- Collect: layout incorrect.
- Clean: crash at "Ready to clean subject" — reproduce and fix.
- Analyze: layout broken by recent component changes; stray elements popping up.
- Student-facing experiment names (current names are placeholder/dev-written).
- Collect: layout incorrect. **Still open.** The pre-run Collect screen (`CollectComponent/PreTestComponent.tsx`) never got a Storybook redesign: WS5's approved design covered only the in-experiment screens, and #270 added the Ready card and SPACE gate. It still uses the old `HelpButton` + `LessonSidebar` pattern that broke Analyze. Re-check in the v1.5 QA pass; redesign if the second playtest trips on it.
- ~~Clean: crash at "Ready to clean subject"~~ — the screen was rewritten in WS6 (PR #285); that path no longer exists. Confirm in the v1.5 QA pass.
- ~~Analyze: layout broken, stray elements~~ — fixed 2026-09-27 (WS7, PR #284): the dead `HelpButton`, the in-flow help panel and the `h-screen` wrapper are gone.
- Student-facing experiment names (current names are placeholder/dev-written). Re-check in the v1.5 QA pass.
- ~~Preview → run CTA; overwrite protection~~ — shipped 2026-09-23 (`Run & record` after a preview on all Design surfaces; an existing subject/group/session — behavior or EEG file — is never overwritten: the run moves to the next free session or is cancelled; branch `feat/run-preview-polish`).
- ~~Larger pre-screen edit affordance~~ — shipped 2026-09-23 (Ready-to-run card, same branch).
- ~~"Press SPACE to begin" prompt~~ — shipped 2026-09-23 (gate between Ready and `Start`; nothing records until SPACE, same branch).
- ~~In-experiment progress~~ — shipped 2026-09-23 in the RunBar (lab.js: innermost loop position + practice/main; jsPsych: total only when the timeline has no loop/conditional functions or custom sampling). Multitasking counts trials within each block — no study-wide total.
- ~~Pre-run coaching copy~~ — shipped 2026-09-23. Pacing is per-protocol (`protocol.pacing`, set for Faces/Houses, Visual Search, Multitasking); the shared EEG line is stillness/no talking only (plan §7.4).
- Clean vs Analyze labels are ambiguous — clarify the step purpose.
- Clean: allow choosing a different file without going back/undoing.
- Add "What does clean your data mean?" student explainer (aligns with Epoch reviewer onboarding work below).
- ~~Clean vs Analyze labels are ambiguous~~ — WS6/WS7 (PRs #285, #284): Clean opens with what cleaning does and its five-step loop; Analyze's EEG tabs say "Clean first" until a cleaned recording exists. Judge it in the second playtest.
- ~~Clean: allow choosing a different file without going back/undoing~~ — shipped 2026-09-27 (WS6, PR #285): `← Pick different data`, one recording at a time.
- ~~"What does clean your data mean?" explainer~~ — shipped 2026-09-27 (WS6, PR #285): the docked cleaning primer.
- ~~Nav-state distinction: the workflow bar (Prepare/Collect/Clean/Analyze) and the local steps bar (Overview/Background/Protocol/Preview) read as one stacked nav on Prepare — Workstream 4, plan §3.2. (playtest 09-23)~~ — shipped 2026-09-25 (WS4 Prepare integration, PR #281). Built-ins' Design screen is `PrepareSteps`: gold step pills under the gold-underline workflow bar, one forward action per step.
- ~~Blocked areas~~ — shipped 2026-09-23 (`WorkspaceAreaGate` on /clean and /analyze, PR #269).
- ~~Device chip is display-only~~ — shipped 2026-09-23 (WS2, PR #274). The header chip opens headset setup; the RunBar chip stays status-only.
Expand All @@ -39,10 +39,20 @@ Deferred and in-flight work. Keep this current — when something ships, delete
- [ ] **Multitasking's Prepare protocol diagram** describes two rules on the same keys (`Top: diamond → B`, `Bottom: 2 dots → B`, …); verify with a teacher whether it reads clearly.
- [ ] **Expanded preview** — the Design preview is fit-to-box at zoom 0.55 (small print ~10px). Add an expanded/full-size preview with the same Preview label and Stop action.
- [ ] **Collect without a workspace** — Collect actions (Preview, Run & record) should be unavailable when there is no workspace (`params` is null after `ExperimentCleanup`, e.g. cancelling headset setup while connecting). `LabjsExperimentWindow` now waits instead of crashing (PR #281), but the buttons still look usable.
- [ ] **Cleaning UXR playtest** (added 2026-09-25, after the WS6 Clean design #280) — a naive user, with no facilitator help, cleans one real recording in the redesigned Clean screen. Can they find the job (leave out noisy trials, flag a bad sensor, review auto-flag suggestions, watch the Live ERP change, save), and do they understand why cleaning comes before Analyze? Run after WS6 integration, before WS8's full second playtest.
- [ ] **Full manual QA pass (WS8, before the second playtest)** — plan §11 WS8 steps 1–13, on real hardware and the packaged build. Checks this round could not run, which a human must:
- Explore on a real Muse: blink bands appear, step 4's paused calm/blinking strips, and the eyes-closed ratio text (the fixture has no blinks, and the hidden agent window was throttled).
- The WS5 hand checks listed under "Playtest 1 fixes" above (complete run, "session 2" prompt, ended-early imported study, behavior-only runs).
- The re-check items above: the Collect pre-run layout, student-facing experiment names, and the WorkflowNav gold border in a visible window.
- Packaged app: a macOS arm64 build of `main` at a1b7153 boots and loads Pyodide.
- [ ] **Second naive playtest (WS8, v1.5 gate)** — protocol in `docs/uxr/` (gitignored). A naive participant runs the whole journey unaided, including cleaning one real recording in the redesigned Clean screen (this replaces the separate cleaning UXR playtest added 2026-09-25). Compare against `docs/uxr/playtest_naive_1.md`; findings feed the v1.5 fixes and language PR.
- [ ] **Bundle the Lato webfont** (found 2026-09-27) — every Storybook design was approved in Lato (`.storybook/preview-head.html` loads it from Google Fonts), but the app has no Lato, so it falls back to Helvetica Neue and text wraps differently on every screen. Ship Lato latin 300/400/700 `woff2` in `assets/fonts/` with `@font-face` rules like the two display fonts, and point Storybook at the same files; classroom machines may be offline.
- [ ] **Run & record does nothing when the session exists as ended-early** (found in the WS6 playtest) — pre-existing: starting a run for a subject/group/session whose files are `*.incomplete.csv` opens nothing. The overwrite guard (#270) should treat it like any taken session.
- [ ] **Fixture headset doubles its markers** (found in the WS6 playtest) — a 120-trial Faces/Houses run under the fixture headset loads as 193 epochs, because the fixture CSV replays its own embedded markers alongside the app's. Testing-only, but it skews every agent playtest count. Strip the replayed markers.
- [ ] **Explore: no stream stall watchdog** (WS3, PR #286) — the stream-stopped banner shows on the stream's `error`/`complete`. A stream that silently stops emitting shows nothing. Add a watchdog if playtests hit it.
- [ ] **Explore: cleaner-signal tips layout had no design** (WS3, PR #286) — the tips reuse the approved step panel, but the head diagram floats top right with blank space below. Merged as-is; decide in the second playtest.
- [ ] **Participant screens for imported jsPsych/lab.js studies** (deferred 2026-09-25): wrap author timelines with BrainWaves instruction/transition/end screens.
- [ ] **Import stimuli into the workspace?** — today custom experiments load images/sounds straight from wherever the student keeps them (Documents/Downloads) via the `bwfile://` allowlist; moving/renaming that folder silently breaks the study, and a workspace can't be zipped up and shared as a self-contained bundle. Alternative: copy stimuli into `BrainWaves_Workspaces/<title>/stimuli/<condition>/` at selection time (single pre-authorized root, portable study bundles; costs disk duplication + stale copies if the source folder is edited later). **Contingent on user testing** — students may actually prefer managing their own folders in Documents/Downloads, since workspace folders are semi-private territory full of mysterious things like `appState.json`. Decide after watching a class use the current flow.
- [ ] **Hooks / function-component migration (AI-friendly).** Most student screens are still class components + `react-redux` `connect()` / `bindActionCreators` containers (`src/renderer/containers/`). Newer work (`EpochReviewer`, `LiveErpPane`, `RunComponent`, `TopNavComponent`) is hooks. Incremental, screen-by-screen; do not big-bang. Pattern to copy: hooks + `useDispatch`/`useSelector` like `App.tsx`. Not a V1 blocker.
- [ ] **Hooks / function-component migration (AI-friendly).** Most student screens are still class components + `react-redux` `connect()` / `bindActionCreators` containers (`src/renderer/containers/`). Newer work (`EpochReviewer`, `LiveErpPane`, `RunComponent`, `AppShell`, the redesigned Clean/Analyze/Explore screens) is hooks. Incremental, screen-by-screen; do not big-bang. Pattern to copy: hooks + `useDispatch`/`useSelector` like `App.tsx`. Not a V1 blocker.
- [ ] **Epoch reviewer Phase 3 — onboarding layer.** Plain-language explanations of epochs + each artifact type, a **guided mode** (step through auto-flagged epochs with "why we flagged this," student confirms/overrides), channel legend tied to head position (Muse 10-20), student-facing tone. Builds on the Phase 0-2 reviewer (PRs #223/#224/#225). **Open question OQ3 (onboarding depth) is still unresolved** — how much curriculum (tooltips only vs. a real walkthrough), guided-mode-as-default? This is product-shaped, not architecture.
- [ ] **WorkflowNav stale gold border** (added 2026-09-27, found in the WS7 Analyze playtest) — intermittent: after reload → Home → open workspace (lands on `/design`) → Analyze, the PREPARE button keeps a computed gold `border-bottom` although its class is `border-transparent`, and the current ANALYZE button stays transparent. Also seen on `/clean`. `aria-current` and `areaForPath` are correct, so the route logic is fine. A clone inserted at the same spot computes transparent, and re-attaching the node (`display: none` → `''`) fixes it. That points at a Chromium style-invalidation issue, not a location bug. The same path is sometimes fine. In one run every class-driven style on the page went stale (Analyze tabs, the selected sensor), and any viewport resize restyled everything correctly. So this may be an artifact of the CDP-driven, occluded Electron window: confirm it in a visible, human-driven window before fixing anything.
- [ ] **Topo legend mislabels conditions** (added 2026-09-27, predates WS7) — `plt.legend(labels)` in `utils.py` `plot_topo` takes its handles from the current axes' lines, so the swatches don't match the conditions (House gets a blue line, Face none). Pass explicit handles, e.g. `Line2D` in each condition's palette color.
Expand All @@ -65,12 +75,14 @@ Deferred and in-flight work. Keep this current — when something ships, delete

- [ ] **(Optional) Full Pyodide worker RPC** — the analysis/Clean pipeline crash is now **fixed** (harvested from PR #194): a `dataKey` routing pattern parallel to `plotKey` — the worker echoes `dataKey` + PyProxy-converted results, and `pyodideMessageEpic` routes `epochsInfo`→`SetEpochInfo` / `channelInfo`→`SetChannelInfo`; the info epics are fire-and-forget. This unblocks the pipeline without the bigger refactor. The deeper latent issue remains, though: `worker.postMessage` returns `undefined` on *post*, so the `await`s in `webworker/index.ts` are no-ops and cross-message sequencing still relies on worker FIFO. A true `runPython(worker, code, ctx?)` RPC — `Map<id,{resolve,reject}>` + one `message` listener, worker echoes `id` — would let epics `await` real results and delete the `plotKey`/`dataKey` switch entirely. Only worth doing if the FIFO sequencing ever actually bites; not urgent now.
- [ ] Pyodide-fidelity smoke test — analysis pipeline is tested against native MNE, not yet under Pyodide/WASM (see `.llms/learnings.md`). **In progress:** the epoch-review Phase 0 adds a *narrow* Pyodide test for the `get_epochs_arrays` float32 buffer path (byteLength, decode-vs-native, transfer detaches source); the full-pipeline Pyodide job remains deferred.
- [ ] **Epoch reviewer Phase 2 polish (from PR #225 review).** Three non-blocking behaviors flagged during the Phase 2 forge: (1) `get_epochs_arrays`/`suggest_rejections` use `pick_types(eeg=True)` whose MNE default is `exclude='bads'`, so after a Clean that flags a bad channel the re-fetched reviewer omits that channel from the display (saved `.fif` is unaffected) — decide whether to keep bad channels visible-but-greyed (`exclude=[]`) instead of vanishing; (2) re-running "Auto-flag" with the same threshold re-adds suggestions the user had manually unclicked (additive union merge in `CleanComponent.componentDidUpdate`); (3) the auto-flag threshold `<input>` has no min guard (0 µV flags everything). All in `src/renderer/components/CleanComponent/` + `webworker/utils.py`.
- [ ] **CI has no feature-flow tests** (2026-09-27) — the `playtest` job only boots the app (preload, React, Pyodide ready). Nothing drives Collect → Clean → Analyze, so every flow check this round was an agent playtest. One scripted fixture-headset flow per journey area is the prerequisite for the proposed automated review → automerge cycle (ponytail review + correctness review + an independent playtest + required checks + `gh pr merge --auto` behind a merge queue, for PRs that implement an approved design only).

## Done recently

<!-- Move finished items here with a date, then prune periodically. -->

- **Playtest-1 redesign round, WS1–WS7** (2026-09-22 → 2026-09-27) — every surface from `docs/uxr/playtest_naive_1_design_implementation_plan.md` went Storybook design → review → integration: nav shell and Home (#269), headset setup (#272, #274), participant screens and early exit (#273, #275, #279), Prepare (#276, #281), Analyze (#277, #284), Clean (#280, #285) and Explore (#282, #286). Clean is one recording at a time with Accept/Restore suggestions and ended-early recordings deletable to the Trash; Analyze has its own cleaned-epoch slot, error states and palette colors for every condition; Explore adds the eyes-closed activity and Disconnect in the setup dialog. The old Phase 2 reviewer polish items (bad channels vanishing, auto-flag re-adding suggestions, no threshold floor) went with the Clean rewrite.

- **Release workflow: manual approval gate** (2026-09-01) — Switched from `push: tags` auto-trigger to `workflow_dispatch` with a `confirm=YES` input. Prevents empty releases caused by GitHub auto-creating a non-draft release that conflicts with electron-builder's `releaseType: draft`. Release process: tag → Actions → Run workflow → type YES → builds draft → manually publish in GitHub UI.
- **Custom experiments Muse QA** (2026-08-26) — Click-through QA on Muse hardware confirmed working post-refactor. Design → Conditions (image + sound folders) → Preview → Collect → Clean → Analyze produces valid ERPs. Sound stimuli latency acceptable for ERP work.
- **Fixture/Replay EEGDriver** (2026-08-26) — Merged (PR #247). Synthetic 4-channel CSV fixture replays as live `Observable<EEGData>` at 256 Hz with injectable markers. 12 tests passing. Enables agent and CI testing of Collect → Clean → Analyze without a physical headset.
Expand Down
Loading
Loading