Skip to content

Switching projects discards unflushed autosave and reports the project as clean #19

Description

@BootBlock

Switching projects discards any edit made within the last AUTOSAVE_DEBOUNCE_MS (2000 ms), and the UI then tells the user everything is saved.

The path

src/core/project/projectService.tsloadProject tears the queue down before hydrating:

async function loadProject(id: string): Promise<void> {
  teardownAutosave();

teardownAutosave calls queue.dispose(), and dispose() in src/core/project/autosave.ts is:

dispose(): void {
  this.disposed = true;
  this.disarm();
  this.dirty.clear();
}

It disarms the pending timer and clears the dirty set without flushing it. There is no flushNow() anywhere on this path.

Why it is a defect

Spec §4.4 requires the write-behind queue to be flushed:

immediately on visibilitychange → hidden and before project switch/export

Export complies — exportMpcweb awaits saveNow(). The switch does not. newProject routes through loadProject too, so "New Project" loses the same window.

Why it is worse than plain data loss

dispose() clears the dirty set, so onIdle never fires to report the loss — and the subsequent hydration calls setModified(false). The unsaved-dot is cleared. The user is shown a clean project having just lost work, with no error and no toast.

Per §4.4 the dot exists precisely to represent unflushed state, so this makes the one indicator that could have warned them assert the opposite.

Suggested fix

Await a flush before tearing down:

await queue?.flushNow();
teardownAutosave();

Worth a regression test: mutate, switch project inside the debounce window, and assert the mutation is present in the database afterwards.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdata-lossCan lose or silently corrupt the user's workstorageOPFS, SQLite, repositories, and persistence (spec 9)

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions