From 2bbaea0c23638e547f3fe8f14a8b7354b2d07416 Mon Sep 17 00:00:00 2001 From: jdpigeon Date: Thu, 25 Jun 2026 14:57:45 -0400 Subject: [PATCH] Fix six bugs from bugfix-todo - saveEpochs: add missing closing paren so raw_epochs.save no longer raises a Python syntax error and silently fails - Remove dead Pause/'PAUSE' experiment action (zero references) - Remove dead `jitter` param (declared/assigned 200, never read) - pyodideReducer: ExperimentCleanup now also resets topoPlot and channelInfo (were left stale after cleanup) - DisconnectFromDevice: give it its own 'DISCONNECT_FROM_DEVICE' type instead of colliding with 'EXPERIMENT_CLEANUP'; an epic in experimentEpics translates it to ExperimentCleanup (behavior preserved) - Document the post-CSV string-coercion trap in .llms/learnings.md - .gitignore: exclude generated pyodide/src runtime payload and __pycache__ Co-Authored-By: Claude Opus 4.8 --- .gitignore | 7 +++++++ .llms/learnings.md | 6 ++++++ src/renderer/actions/deviceActions.ts | 4 ++-- src/renderer/actions/experimentActions.ts | 1 - src/renderer/constants/interfaces.ts | 1 - src/renderer/epics/experimentEpics.ts | 21 +++++++++++++++++-- .../experiments/faces_houses/params.ts | 1 - .../experiments/multitasking/params.ts | 1 - src/renderer/experiments/search/params.ts | 1 - src/renderer/experiments/stroop/params.ts | 1 - src/renderer/reducers/pyodideReducer.ts | 2 ++ src/renderer/utils/labjs/protocols/custom.ts | 1 - src/renderer/utils/webworker/index.ts | 2 +- 13 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index eb02e035..a8ea39b5 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,10 @@ dist .idea keys.js src/renderer/utils/webworker/src + +# Generated Pyodide runtime payload (downloaded by install scripts, not source) +src/renderer/utils/pyodide/src + +# Python bytecode cache +__pycache__/ +*.pyc diff --git a/.llms/learnings.md b/.llms/learnings.md index ddf0af50..97eb22ca 100644 --- a/.llms/learnings.md +++ b/.llms/learnings.md @@ -82,6 +82,12 @@ In dev: use `/@fs` (Vite's `/@fs/` serving). In prod: use `file://('CONNECT_TO_DEVICE'), - DisconnectFromDevice: createAction( - 'EXPERIMENT_CLEANUP' + DisconnectFromDevice: createAction( + 'DISCONNECT_FROM_DEVICE' ), SetConnectionStatus: createAction( 'SET_CONNECTION_STATUS' diff --git a/src/renderer/actions/experimentActions.ts b/src/renderer/actions/experimentActions.ts index 43edfba1..73b40ec8 100644 --- a/src/renderer/actions/experimentActions.ts +++ b/src/renderer/actions/experimentActions.ts @@ -13,7 +13,6 @@ import { ExperimentStateType } from '../reducers/experimentReducer'; export const ExperimentActions = { Start: createAction('START'), - Pause: createAction('PAUSE'), Stop: createAction<{ data: string }, 'STOP'>('STOP'), SetType: createAction('SET_TYPE'), SetExperimentObject: createAction( diff --git a/src/renderer/constants/interfaces.ts b/src/renderer/constants/interfaces.ts index c4370a46..feda5d19 100644 --- a/src/renderer/constants/interfaces.ts +++ b/src/renderer/constants/interfaces.ts @@ -24,7 +24,6 @@ export type ExperimentParameters = { description?: ExperimentDescription; intro: string; iti: number; - jitter: number; nbPracticeTrials?: number; nbTrials: number; presentationTime?: number; diff --git a/src/renderer/epics/experimentEpics.ts b/src/renderer/epics/experimentEpics.ts index ee8855d9..eb3f97e2 100644 --- a/src/renderer/epics/experimentEpics.ts +++ b/src/renderer/epics/experimentEpics.ts @@ -9,7 +9,11 @@ import { tap, } from 'rxjs/operators'; import { isActionOf } from '../utils/redux'; -import { ExperimentActions, ExperimentActionType } from '../actions'; +import { + DeviceActions, + ExperimentActions, + ExperimentActionType, +} from '../actions'; import { RouterActions } from '../actions/routerActions'; import { DEVICES, @@ -214,6 +218,18 @@ const navigationCleanupEpic: Epic = ( map(() => ExperimentActions.ExperimentCleanup()) ); +// Disconnecting a device tears down the experiment too: this triggers the BLE +// disconnect (deviceCleanupEpic) and resets experiment + pyodide state. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const disconnectFromDeviceEpic: Epic = ( + // DeviceActions input action is outside this slice's action union + action$ +) => + action$.pipe( + filter(isActionOf(DeviceActions.DisconnectFromDevice)), + map(() => ExperimentActions.ExperimentCleanup()) + ); + export default combineEpics( createNewWorkspaceEpic, startEpic, @@ -221,5 +237,6 @@ export default combineEpics( updateSessionEpic, autoSaveEpic, saveWorkspaceEpic, - navigationCleanupEpic + navigationCleanupEpic, + disconnectFromDeviceEpic ); diff --git a/src/renderer/experiments/faces_houses/params.ts b/src/renderer/experiments/faces_houses/params.ts index 822d7d66..e35fd466 100644 --- a/src/renderer/experiments/faces_houses/params.ts +++ b/src/renderer/experiments/faces_houses/params.ts @@ -39,7 +39,6 @@ export const params = { iti: 500, presentationTime: 1000, selfPaced: true, - jitter: 200, sampleType: 'with-replacement', intro: `You will view a series of faces and houses. Press 1 when a face appears and 9 for a house. Press the the space bar on your keyboard to start doing the diff --git a/src/renderer/experiments/multitasking/params.ts b/src/renderer/experiments/multitasking/params.ts index 400c0ac5..d6939c48 100644 --- a/src/renderer/experiments/multitasking/params.ts +++ b/src/renderer/experiments/multitasking/params.ts @@ -4,7 +4,6 @@ export const params = { trialDuration: 1000, nbTrials: 150, iti: 1000, - jitter: 200, sampleType: 'with-replacement', intro: `In this task you will learn about multitasking difficulties using a task mixing and switching paradigm. You will go through several instruction diff --git a/src/renderer/experiments/search/params.ts b/src/renderer/experiments/search/params.ts index 28f8302b..975eca63 100644 --- a/src/renderer/experiments/search/params.ts +++ b/src/renderer/experiments/search/params.ts @@ -4,7 +4,6 @@ export const params = { trialDuration: 1000, nbTrials: 150, iti: 500, - jitter: 200, sampleType: 'with-replacement', intro: `You know how difficult it is to find your keys in a messy room. We want to know how good you are in quickly finding your keys. Instead of keys, diff --git a/src/renderer/experiments/stroop/params.ts b/src/renderer/experiments/stroop/params.ts index b0b2d527..1b20cfd8 100644 --- a/src/renderer/experiments/stroop/params.ts +++ b/src/renderer/experiments/stroop/params.ts @@ -10,7 +10,6 @@ export const params = { trialDuration: 1000, nbTrials: 150, iti: 500, - jitter: 200, sampleType: 'with-replacement', intro: `In this experiment, your task will be to identify the color of the word shown on the screen. The word itself is immaterial - you can safely diff --git a/src/renderer/reducers/pyodideReducer.ts b/src/renderer/reducers/pyodideReducer.ts index 75f87da4..536afb25 100644 --- a/src/renderer/reducers/pyodideReducer.ts +++ b/src/renderer/reducers/pyodideReducer.ts @@ -83,7 +83,9 @@ export default createReducer(initialState, (builder) => return { ...state, epochsInfo: [], + channelInfo: [], psdPlot: null, + topoPlot: null, erpPlot: null, }; }) diff --git a/src/renderer/utils/labjs/protocols/custom.ts b/src/renderer/utils/labjs/protocols/custom.ts index e46df525..f4d52510 100644 --- a/src/renderer/utils/labjs/protocols/custom.ts +++ b/src/renderer/utils/labjs/protocols/custom.ts @@ -54,7 +54,6 @@ export const buildCustomTimeline = () => ({ iti: 500, presentationTime: 1000, selfPaced: true, - jitter: 200, sampleType: 'with-replacement', intro: '', taskHelp: '', diff --git a/src/renderer/utils/webworker/index.ts b/src/renderer/utils/webworker/index.ts index 15456aa5..7283cd05 100644 --- a/src/renderer/utils/webworker/index.ts +++ b/src/renderer/utils/webworker/index.ts @@ -186,5 +186,5 @@ export const saveEpochs = ( 'EEG', `${subject}-cleaned-epo.fif` ) - )}`, + )})`, });