Affected Component
statewave-grounded-shop-assistant — packages/statewave-core/src/index.ts
Bug Description
StatewaveStore._load() handles a corrupt persistence file by warning and starting from an empty store. The warning tells the operator they still have a choice:
Starting from an empty store — delete the file or restore a backup if this is unexpected.
They don't, in practice. The store is now empty but persistPath is unchanged, so the very next createEpisode schedules _save(), and flush() calls writeFileSync(this.persistPath, ...) with only the new episodes. The corrupt file — and whatever was recoverable from it — is gone within SAVE_DEBOUNCE_MS of the first write. For the server this is one chat turn or one ingestion row.
The recovery advice is only actionable if the operator reads the warning and stops the process before anything writes, which is not how the demo runs.
Expected Behavior
The file the warning tells you to restore should still exist when you go to restore it. Either:
- rename the unreadable file aside on load (
db.json → db.json.corrupt-<timestamp>) and then start empty, so the warning's advice is actionable; or
- set
persistPath = null after a failed load, so the process runs in memory and refuses to overwrite until an operator intervenes.
The first is friendlier for a demo — it self-heals and still keeps the evidence.
Steps to Reproduce
- Run the server with persistence enabled so
db.json has content.
- Stop it and truncate the file mid-object (or
echo '{' > db.json).
- Start the server — observe the warning.
- Send one chat message, wait a second, and look at
db.json: the old content is gone.
Environment
main as of 2026-09-07, Node 18+.
Severity
Medium — silent, unrecoverable loss of the demo's only persistent state, immediately after a message promising the opposite.
Affected Component
statewave-grounded-shop-assistant—packages/statewave-core/src/index.tsBug Description
StatewaveStore._load()handles a corrupt persistence file by warning and starting from an empty store. The warning tells the operator they still have a choice:They don't, in practice. The store is now empty but
persistPathis unchanged, so the very nextcreateEpisodeschedules_save(), andflush()callswriteFileSync(this.persistPath, ...)with only the new episodes. The corrupt file — and whatever was recoverable from it — is gone withinSAVE_DEBOUNCE_MSof the first write. For the server this is one chat turn or one ingestion row.The recovery advice is only actionable if the operator reads the warning and stops the process before anything writes, which is not how the demo runs.
Expected Behavior
The file the warning tells you to restore should still exist when you go to restore it. Either:
db.json→db.json.corrupt-<timestamp>) and then start empty, so the warning's advice is actionable; orpersistPath = nullafter a failed load, so the process runs in memory and refuses to overwrite until an operator intervenes.The first is friendlier for a demo — it self-heals and still keeps the evidence.
Steps to Reproduce
db.jsonhas content.echo '{' > db.json).db.json: the old content is gone.Environment
mainas of 2026-09-07, Node 18+.Severity
Medium — silent, unrecoverable loss of the demo's only persistent state, immediately after a message promising the opposite.