Skip to content

Windows: contract for mm uninstall --force against a live writer is undefined #730

@memtomem

Description

@memtomem

Summary

mm uninstall --force against a live SQLite writer is well-defined on POSIX but has no contract on Windows. The current behavior is implicit and tracked nowhere.

POSIX (current)

shutil.rmtree on the state directory succeeds even while the writer holds an open BEGIN IMMEDIATE lock — POSIX unlink removes the directory entry while the inode lives until the last fd closes. The state directory ends up wiped; the lock-holding process keeps a dangling fd to a now-unlinked inode and eventually exits without further drama.

This is exercised by test_force_overrides_db_lock in packages/memtomem/tests/test_uninstall_cmd.py.

Windows (current — undefined)

Windows refuses to unlink a file held by an open handle:

[WinError 32] The process cannot access the file because it is being
used by another process: ...\.memtomem\memtomem.db

mm uninstall --force returns a non-zero exit and prints Deletion failed at .... The state dir is partially wiped (other files may be gone before the DB unlink fails) — the user is left in a half-cleaned state with no clear next step.

The POSIX-only contract test was skipped on Windows in #729 (cluster H-2 of #643) so CI can go green, but the underlying behavior question remains.

Open questions

  1. What should --force mean on Windows when a writer is alive? Options:

    • (a) Refuse with a Windows-specific error message: "close the writer first; --force cannot wipe an open file on Windows" — symmetric with the POSIX contract that --force overrides the writer-detection refusal, but explicit about the platform limitation.
    • (b) Best-effort partial wipe (current behavior) but with a clear warning + exit code.
    • (c) Probe for the writer pid via the existing flock/lockfile path (which already powers refusal) and signal it before attempting the wipe — closer to POSIX semantics but requires kill/permission flow.
  2. Should the state-dir wipe be transactional? The half-wipe failure mode on Windows leaks orphaned files (memories/, config.json) when the DB unlink fails. Worth considering staging the deletion (shutil.rmtree to a temp sibling, then atomic rename + cleanup) so partial failure leaves the user with the original tree intact.

Why this matters

Without an explicit contract, Windows users hitting --force against a live writer get a confusing partial failure. Worse, the test gap (covered only on POSIX) means future refactors of the uninstall path can silently regress Windows without anyone noticing.

Scope

Cross-refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions