Fix broken Clean→Analyze round-trip: persist cleaned epochs to host disk#222
Open
jdpigeon wants to merge 1 commit into
Open
Fix broken Clean→Analyze round-trip: persist cleaned epochs to host disk#222jdpigeon wants to merge 1 commit into
jdpigeon wants to merge 1 commit into
Conversation
The "Clean Data" flow told Pyodide to `raw_epochs.save("<host OS path>")`,
but the worker's filesystem is MEMFS (in-memory) and cannot reach host
disk — so the cleaned `-epo.fif` never landed on disk and the Analyze
screen's `readWorkspaceCleanedEEGData` picker found nothing in a fresh
workspace. This repairs that flow with a MEMFS→host write-back bridge,
the one slice the epoch-review plan (§6d / Open Question 8) declares
resolved and standalone.
Chain: Python saves to MEMFS `/tmp/<subject>-cleaned-epo.fif` → the
worker reads the bytes and posts them back zero-copy (transferable
ArrayBuffer) on a new `savedEpochs` dataKey → `pyodideMessageEpic`
writes them to `Data/<subject>/EEG/<subject>-cleaned-epo.fif` via a new
`fs:writeCleanedEpochs` IPC channel that mirrors `fs:storePyodideImagePng`.
- src/main/index.ts: new `fs:writeCleanedEpochs` handler (binary
renderer→disk write)
- src/preload/index.ts + electron.d.ts: `writeCleanedEpochs` bridge + type
- webworker.js: `readFileAfter` read-back path posts MEMFS bytes as a
transferable
- webworker/index.ts: `saveEpochs(worker, subject)` now saves to MEMFS
(overwrite=True) and requests read-back
- pyodideEpics.ts: route `savedEpochs` → `writeCleanedEpochs`, with a
success/error toast
Output path is bit-identical to what the Analyze picker globs (`epo.fif`
suffix). Also tempers docs/epoch-review-ui-plan.md against source.
typecheck: clean · eslint: clean · build: green
This was referenced Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Forged from
docs/epoch-review-ui-plan.md(Interactive Epoch Review UI plan). The plan is a preliminary vision doc (Phases 0–4, 8 open questions), so only the one slice it declares resolved and standalone was implemented: the MEMFS→host write-back bridge that repairs a currently-broken flow (plan §6d + Open Question 8).The bug: The "Clean Data" flow told Pyodide to
raw_epochs.save("<host OS path>"), but the worker's filesystem is MEMFS (in-memory) and can't reach host disk. So the cleaned-epo.fifnever landed on disk, and the Analyze screen'sreadWorkspaceCleanedEEGDatapicker found nothing in a fresh workspace. The Clean→Analyze round-trip was silently broken.The fix — a write-back bridge across every process boundary
The output path is bit-identical to what the Analyze picker globs (
epo.fifsuffix) and matches OQ8's stated target. The new main handler mirrors the existingfs:storePyodideImagePng(binary renderer→disk write) — the reuse anchor the plan called out.Files
src/main/index.ts— newfs:writeCleanedEpochsIPC handlersrc/preload/index.ts+src/renderer/types/electron.d.ts—writeCleanedEpochsbridge + typesrc/renderer/utils/webworker/webworker.js—readFileAfterread-back path posts MEMFS bytes as a transferable ArrayBuffersrc/renderer/utils/webworker/index.ts—saveEpochs(worker, subject)saves to MEMFS (overwrite=True) and requests read-backsrc/renderer/epics/pyodideEpics.ts— routesavedEpochs→writeCleanedEpochs, success/error toastdocs/epoch-review-ui-plan.md— tempered against source (grounding corrections)Explicitly out of scope (blocked on open design questions)
Interactive epoch-array transport, the React
EpochReviewercomponent, click-to-reject, bad-channel flagging, and the onboarding layer all depend on unresolved Open Questions (esp. Canvas vs WebGL, RPC-first). They were intentionally not forged. Note:cleanEpochsEpicstill re-saves epochs unchanged (the plan's §4 caveat) — this PR ensures that saved object now actually persists, unblocking future interactive cleaning.Verification
npm run typecheck— 0 errorseslinton changed files — cleannpm run build(electron-vite) — green, worker bundle buildsFS.readFilereturns a fresh file-sized buffer, not the WASM heap), no undefined-buffer path (workercatchpostserror, handled first), and MNE-epo.fifsuffix satisfied.🤖 Generated with Claude Code