Fix replay state rehydration - #1367
Conversation
|
A preview of 232f2e8 is uploaded and can be seen here: ✨ https://revisit.dev/study/PR1367 ✨ Changes may take a few minutes to propagate. |
There was a problem hiding this comment.
Pull request overview
This PR improves analysis replay fidelity by rehydrating previously recorded component state (sliders, Vega, UpSet, MVNV iframe state, and virtual-chinrest) and ensuring replay remains read-only (no new answers/provenance emitted). It also adds regression coverage to validate deterministic seeking behavior and non-mutating replay.
Changes:
- Add shared Playwright helpers for reading persisted participant/provenance data and seeking within the replay timeline.
- Make replay state deterministic and inert across Vega, UpSet, iframe surfaces, and virtual-chinrest calibrations (rehydration + read-only controls).
- Add focused Vitest + Playwright regression tests for slider rehydration, Vega forward/back/root seeking, and replay immutability.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/utils.ts | Adds IndexedDB read helpers and a replay seek helper for Playwright tests. |
| tests/replay-slider-rehydration.spec.ts | New Playwright test verifying SMEQ slider value rehydration and no participant-data writes during replay. |
| tests/demo-vega.spec.ts | Extends Vega e2e coverage to verify deterministic seek replay and immutability of stored provenance. |
| tests/demo-trrack.spec.ts | Refactors to use shared IndexedDB/seek helpers for replay verification. |
| src/public/libraries/virtual-chinrest/assets/VirtualChinrestCalibration.tsx | Rehydrates saved card-size calibration in analysis and disables interactive controls. |
| src/public/libraries/virtual-chinrest/assets/ViewingDistanceCalibration.tsx | Selects prior card-size calibration for repeated sequences and rehydrates saved viewing-distance state; blocks input/provenance in analysis. |
| src/public/libraries/virtual-chinrest/assets/tests/VirtualChinrestCalibration.spec.tsx | Adds unit coverage for virtual-chinrest replay rehydration and repeated-sequence lookup behavior. |
| src/public/demo-upset/assets/Upset.tsx | Integrates UpSet provenance state with reVISit replay and makes the surface inert in analysis. |
| src/public/demo-upset/assets/tests/Upset.spec.tsx | Adds unit coverage for UpSet provenance publication and analysis-mode inertness/no emission. |
| src/controllers/VegaController.tsx | Tracks cumulative Vega signals and restores deterministically across seeks; prevents tracking while applying analysis replay and makes the surface inert. |
| src/controllers/tests/IframeController.spec.tsx | Adds unit coverage asserting iframes are inert/non-interactive in analysis replay. |
| src/controllers/tests/ComponentController.spec.tsx | Extends Vega controller unit tests for cumulative signal restoration and analysis-mode non-tracking. |
| src/controllers/IframeController.tsx | Makes website iframes inert/disabled with pointer-events blocked during analysis replay. |
| src/components/response/tests/ResponseInput.spec.tsx | Enhances slider mock and adds tests ensuring replayed slider values rehydrate while disabled. |
| src/components/response/SliderInput.tsx | Rehydrates displayed SMEQ/NASA-TLX slider state on answer changes and blocks updates when disabled. |
| public/example-mvnv/assets/js/loadTasks.js | Rehydrates MVNV iframe task selection state from received answers to support replay. |
| .gitattributes | Adds whitespace handling rule for the MVNV JS asset file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const fraction = (targetTime - startTime) / (endTime - startTime); | ||
| const x = 20 + Math.min(1, Math.max(0, fraction)) * (timerBounds.width - 40); |
| export function findPreviousCardSizeAnswer( | ||
| answers: Record<string, StoredAnswer>, | ||
| currentTrialOrder: StoredAnswer['trialOrder'] | undefined, | ||
| ) { | ||
| const currentStep = Number.parseInt(currentTrialOrder ?? '', 10); | ||
| if (!Number.isFinite(currentStep)) { | ||
| return undefined; | ||
| } | ||
|
|
||
| return Object.values(answers) | ||
| .filter((answer) => ( | ||
| answer.componentName === cardSizeComponent | ||
| && Number.parseInt(answer.trialOrder, 10) < currentStep | ||
| )) | ||
| .sort((a, b) => Number.parseInt(b.trialOrder, 10) - Number.parseInt(a.trialOrder, 10))[0]; | ||
| } |
jaykim1213
left a comment
There was a problem hiding this comment.
Thanks for working on this!
Vega, UpSet, and SMEQ are working nicely now, but three surfaces still don't show the restored state on screen:
- MVNV: the answer data is restored, but the adjMatrix view doesn't update (answerBox checks and row/column selections stay empty).
- Virtual chinrest: the final values is shown in replay, but we can't see the card adjustment or the space-bar measurements replaying
- NASA-TLX: no value is visible in replay.
Summary
Scope
Check Answer replay and video playback replay remain out of scope and are tracked separately in #1365 and #1366.
Root cause
Several components either kept participant state only in local UI state or replayed only the latest interaction instead of the cumulative tracked state. NASA-TLX's disabled Mantine thumb was hidden, MVNV restored answer text without mapping saved full node names back into its adjacency-matrix state, and virtual-chinrest did not track intermediate calibration state. Some replay paths could also invoke live interaction listeners while applying analysis state, and virtual-chinrest fallback lookup did not distinguish repeated component occurrences.
Validation
yarn unittest --run— 2,042 passed, 1 skippedyarn typecheckyarn lintyarn buildgit diff --checkPlaywright coverage verifies real Vega forward/root/forward replay, inert analysis controls, unchanged provenance storage, exact SMEQ/NASA-TLX slider rehydration, virtual-chinrest card/measurement traversal, and MVNV adjacency-matrix restoration.
The implementation received independent adversarial review; all confirmed correctness, coverage, and minimality findings were addressed.
Closes #1336