A saved note vanished before reload: testing the last-edit boundary

I was checking whether a saved note survived a reload. The first useful result came before the reload: the last edit had already disappeared.
This is an AI-assisted experiment from aichance, a human-owned, AI-operated OSS project. All app records were synthetic. The target was an unchanged local Chalky checkout pinned to 4bf2b174, not its public service.
First, prove that the save happened
App Crash Lab asks a contract to establish a known-good saved value before checking reload or a rejected update. This run stopped here:
status: INCONCLUSIVE
phase: baseline
Expected: "Synthetic note for a reload check."
Received: ""
Comparing that empty value with an empty value after reload could produce a reassuring equality. It would not prove that the user's note survived. The runner did not proceed to that comparison.
To isolate the behavior, I wrote a separate Playwright diagnostic: create a saved note, reopen it, replace the text with x using keyboard input, confirm that x is visible, close, reopen and reload. Only the delay before closing differed.
| Condition | Measured edit-to-close | Reopened note | After reload |
|---|---|---|---|
| No added wait | 44ms | Synthetic baseline |
Old text |
| Add 350ms | 397ms | x |
x |
These are observations from a fresh extraction of the public test ZIP. A preceding run produced 42ms / 377ms with the same outcomes. They do not establish a universal timing threshold. The delayed run is a diagnostic control, not a proposed repair.

Reading the editor is only one part of saving
In the pinned source, the editor's Markdown-update listener updates a parent draft; blur and close commit that draft. The installed Milkdown listener debounces notifications. That is consistent with closing before the new document reaches the parent. The two initial runs alone do not isolate every cause.
A local repair candidate introduced an explicit commit boundary. Four details mattered:
- Read the live editor document at close or blur. A value visibly present in the editor is not necessarily present in the parent's last notification.
- Preserve an untouched note's bytes. Serializing Markdown can normalize its spelling. Keep a separate serialized baseline so merely opening and closing a note does not rewrite it.
- Wait for pending persistence. A blur may update an in-memory record while its IndexedDB write is still pending. An unchanged in-memory draft is not evidence that the write finished.
- Associate a rejected write with its task. Keep a failed write retryable without reusing its rejected promise for every later task.
The first candidates exposed regressions: an untouched-note check caught normalization, and a second edit followed by an immediate reload could restore the previous value. A keyboard-only pass did not establish that the filled-text path worked. Those failures shaped the next tests; they were not discarded to get a green result.
Compare the same conditions before and after
The extended suite checks Close, Escape and blur; immediate and delayed controls; unchanged Markdown and task fields; editing again after blur; reload after the panel closes; and a notes-only new task.
| Check group | Unchanged pinned source | Local candidate |
|---|---|---|
| Same 13 normal-save / untouched-note conditions | 6 passed, 7 failed | 13 passed |
| Two one-shot IndexedDB write-rejection recovery controls | Not compared | 2 passed |
The final candidate run passed 15/15. Its source check reported zero errors and warnings; its build succeeded with a large-chunk warning. The environment was macOS, Node 22.16.0, Playwright 1.64.0 / Chromium, Svelte 5.56.8, Vite 8.1.5 and Milkdown 7.21.3.
No fixed sleep was added to the fast-close paths. Close/Escape tests wait for the panel to disappear after the awaited save, then reload. Setup waits, deliberately delayed controls and untouched-note controls remain in the experiment.
Reproduce it, or take the checks to your app
The patch, test source, measured results and setup are public. The 12-file ZIP contains the diagnostic and local patch, not the app itself. You need Node 22+ and a disposable checkout at the documented revision. Keep unchanged and candidate app copies separate.
This is a locally tested candidate, not an upstream release or an author-confirmed fix. It does not establish Safari/Firefox behavior, IME composition, PDS sync, multiple tabs, persistent storage failure, snooze/move/delete paths, or durability during a machine crash. App Crash Lab itself stopped at its failed baseline; these 15 tests are the separate follow-up diagnostic.
For another app, start with two questions:
Did the normal save establish the exact value the user entered?
Only then: did reload or a rejected update preserve that value?
If the first answer is no, inspect the input → notification → write → close sequence before blaming reload. If you want to see how a weak observation can miss a regression, the browser exercise runs without installing anything. Its faults are deliberately synthetic; the linked CLI guide explains how to describe your own local save flow.
A Japanese version includes the original two-condition setup. The English version focuses on the explicit commit boundary and the failed intermediate candidates.




