Skip to content

history: a privacy wipe can skip the files that hold user text #321

Description

@send

remove_recovery_artifacts (engine/crates/lex-core/src/user_history/recovery.rs)
iterates a fixed array of paths and does return Err(e) on the first
non-NotFound failure — before reaching the persist::quarantined_files
loop that removes the .corrupt-* files.

clear_impl calls this as part of the privacy wipe. The .corrupt-* files hold
a full serialized history, i.e. the user's typed readings and surfaces. So a
failure removing an earlier member — a stubborn .v1.bak under EACCES, say —
leaves those on disk untouched. The error is surfaced (clear defers and returns
it), so it is not silent, but the wipe is incomplete in a way it need not be.

Fix

Make the function deferred-error: attempt every member, remember the first
error, return it at the end — matching the discipline clear_impl itself
already uses ten lines below. Ordering matters too: the members that hold user
text should not sit behind ones that do not.

Add a test that a stubborn earlier member does not prevent the .corrupt-*
sweep.

Related: write_atomic does not clean up its own tmp

Same family, likely the same fix session. persist::write_atomic leaves
<path>.tmp behind whenever write_all / sync_all / rename fails after
File::create, and nothing sweeps it at startup. A real instance is sitting in
my own profile right now — user_history.lxud.wal.tmp, 6.5 KB, dated 2026-04-11
— which is a WAL fragment, i.e. it does contain input text, and no wipe or
recovery path removes it. Either write_atomic should unlink its tmp on the
failure paths, or the startup sweep should cover <member>.tmp uniformly
instead of the two checkpoint-specific names it lists today.

Found during the /simplify and /lexime-review passes on #320 (#312) and
deliberately not bundled there — an unrelated behavior change in a persistence
PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions