Skip to content

Files: recover pending deletes after process death #503

Open

Description

@veryCrunchy

Problem

The Files delete write fence added in #498 keeps in-flight deletes and refresh-required blocks in memory, owned per account for the life of the app process. If the process dies after a DELETE reaches the server but before its outcome is recorded and verified, the restarted app starts with no block for that path. Cached Files content can still show the item, and writes (rename, move into, upload into, edit) can then target a path whose server state is unknown.

The window is narrow (process death between sending the DELETE and recording its verified outcome), but the result is an ambiguous non-idempotent mutation with no durable recovery path, which AGENTS.md sections 7, 8 and 10 rule out for durable mutation paths.

Raised in review of #498 (thread on FileWriteFence.kt). It was deliberately kept out of that PR, which documents the in-memory limitation in ADAPTER_ARCHITECTURE.md ("Files delete write fence").

Proposed direction

  • Before sending a DELETE, persist an account-scoped pending-delete record: the local account identity (non-secret digest), remote path, server file ID and ETag when known, item type, and a request generation.
  • On startup and account activation, reconcile each record before enabling writes for the affected path:
    • re-register the refresh-required block;
    • verify the postcondition with a server listing that starts after startup;
    • clear the record only on a verified outcome.
  • Clear the record on a verified outcome, and drop all records for an account on sign-out or account removal.
  • Keep the existing lifting rule (only a server listing that started after the outcome lifts a block) and the identity rules (file ID, type, ETag).

Acceptance criteria

  • A pending-delete record is durable before the request can leave the client, on desktop and Android.
  • After a simulated process death at each stage (before send, after send but before response, after response but before verification), the restarted app blocks writes to that path with the typed refresh-required reason until verified.
  • Records are scoped to the local account identity, contain no credentials or raw server URLs, and are removed on sign-out and account removal.
  • Unknown or corrupt records fail closed (path stays blocked until verified) and are bounded in count.
  • Deterministic restart, cancellation, stale-generation, and account-removal tests; Android unit tests execute.
  • ADAPTER_ARCHITECTURE.md and the changelog no longer say a new process starts unblocked.

Activity

  1. added
    bugSomething isn't working
    area:files-syncFiles, offline storage, transfer, and synchronization
    type:reliabilityCorrectness, crash prevention, recovery, and data safety
    platform:androidAndroid-specific implementation or validation
    platform:desktopDesktop-specific implementation or validation
    on Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:files-syncFiles, offline storage, transfer, and synchronizationbugSomething isn't workingplatform:androidAndroid-specific implementation or validationplatform:desktopDesktop-specific implementation or validationpriority:P2Important follow-uptype:reliabilityCorrectness, crash prevention, recovery, and data safety

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions