Skip to content

fix(persist): Protect session stores from stale and failed reads - #52

Merged
mhiro2 merged 5 commits into
mainfrom
fix/persist-store-safety
Oct 3, 2026
Merged

mhiro2 merged 5 commits into
mainfrom
fix/persist-store-safety

Conversation

@mhiro2

@mhiro2 mhiro2 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Sync saves now queue behind in-flight async updates and fail on timeout instead of overwriting them, including when requested from a save callback.
  • An unreadable, undecodable or unknown-version session store is never replaced with an empty one, and reads no longer truncate a file swapped in by an atomic rename.
  • Counts, sizes and durations in the config must be finite integers, and every invalid section or value falls back to its defaults with a warning that says so.

Changes

  • 94238fb : fix(persist): keep sync saves ordered behind slow async writes
    • Sync updates join the ordered update queue and run with blocking I/O on their turn; they are withdrawn and reported as failed if the queue does not drain within one second.
    • The queue is released before completion callbacks, so a sync save from a PeekstackSave handler or on_done does not wait on its own caller.
  • 1ac1edd : fix(persist): keep the session store intact when it cannot be read
    • I/O errors, invalid JSON, non-object JSON and unsupported versions abort save/delete/rename and leave the cache untouched; only a missing file counts as an empty store.
    • Reads go to EOF on the opened descriptor instead of a size from an earlier stat.
  • 61d1ee3 : fix(config): require finite integers for counts, sizes and durations
    • Fractions, NaN and infinities are rejected for integer settings such as persist.max_items, which previously emptied saved sessions; ratios reject NaN too.
    • ui.path.max_width uses the same validator, and its warnings now name the fallback value.
  • 3518bd4 : fix(config): fall back to defaults when persist.auto is not a table
    • A non-table persist.auto gets the same default fallback and warning as other sections.
  • a6b7612 : docs: describe store read failures, save on leave timeout and integer settings
    • README and :help peekstack cover store read-failure protection, the save-on-leave timeout and integer-only numeric settings.

mhiro2 added 5 commits October 3, 2026 12:02
A sync save waited at most one second for queued async updates and then
wrote anyway, so a slower in-flight save could finish afterwards and
overwrite it with an older snapshot. Sync updates now join the same
queue and run with blocking I/O when their turn comes; if the queue does
not drain in time they are withdrawn and reported as failed.
Read errors, undecodable JSON and unknown store versions were all
treated as an empty store, so the next save, delete or rename replaced
every existing session. Reads now return nil on failure, which aborts
the update and leaves the cache untouched; only a missing file counts
as empty. Reads also go to EOF on the opened descriptor instead of a
size taken from an earlier stat, so a store replaced by an atomic rename
is no longer truncated mid-read.
Numeric settings only had to be numbers within bounds, so a fractional
persist.max_items passed validation and made the session item slice
come back empty, and NaN slipped through every bounds check. These
settings now reject fractions, NaN and infinities and fall back to the
default with a warning that names it; ratios reject NaN as well.
Every other config section that must be a table is replaced with its
defaults and the warning says so, but a non-table persist.auto was kept
as is with a bare warning that did not say which settings applied. It
now follows the same fallback and message, and the special-case options
for that one field are gone.
… settings

Document that an unreadable session store is never replaced with an
empty one, that the save on leave gives up after waiting a second for
earlier saves, and that numeric settings must be integers.
@mhiro2 mhiro2 self-assigned this Oct 3, 2026
@mhiro2 mhiro2 added the bug Something isn't working label Oct 3, 2026
@mhiro2
mhiro2 merged commit 41dc15c into main Oct 3, 2026
3 checks passed
@mhiro2
mhiro2 deleted the fix/persist-store-safety branch October 3, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant