rsync

--delete-strict-order opt-in gate (#1940) - SUPERSEDED

Status: SUPERSEDED. This design is retained for historical context only. The opt-in --delete-strict-order flag was replaced by the always-on two-phase parallel-deterministic delete model specified in docs/design/parallel-deterministic-delete.md (tasks #2251 - #2285). The flag is removed from the CLI surface; upstream per-directory ordering is the default and only behaviour. See docs/architecture/delete-during.md for the current architecture.

Status: Design (task #1940; cites audit #1893, follow-up #1894) - superseded Audience: transfer, cli, filters maintainers Scope (historical): introduce an opt-in --delete-strict-order flag that forces oc-rsync’s --delete-during path onto upstream’s per-directory interleaved order, without changing the default batched behaviour.

1. Current --delete-during behaviour (#1893 audit)

The audit captured in docs/architecture/delete-during.md documents oc-rsync’s deletion model and its divergence from upstream rsync 3.4.1:

Upstream’s interleave is Delete(dir_A) -> Transfer(dir_A) -> Delete(dir_B) -> Transfer(dir_B), dispatched serially through generator.c::recv_generator() -> delete_in_dir().

2. Proposal: --delete-strict-order opt-in

Introduce a new long-only CLI flag --delete-strict-order that, when present, forces oc-rsync’s deletion to mirror upstream’s batched-vs- interleaved model byte-for-byte. The flag is opt-in: omitting it leaves today’s batched sweep unchanged.

2.1 Surface

2.2 Receiver dispatch

When strict_order is set, run_pipelined MUST:

  1. Skip the standalone delete_extraneous_files call between the metadata pre-pass and build_files_to_transfer.
  2. Drive deletion per-directory inside the transfer loop. Each directory entry, before signature generation or file dispatch, runs the equivalent of delete_in_dir() against the pre-loaded file list and the FilterChain snapshot in effect for that directory (after any .rsync-filter merge files for that subtree have been applied).
  3. Force sequential deletion: bypass parallel_io::map_blocking and the DEFAULT_DELETION_THRESHOLD cutoff. Use the existing delete_extraneous_files primitives in crates/transfer/src/receiver/directory/deletion.rs, but invoke them one directory at a time from the generator’s serial loop.
  4. Adopt upstream’s “log and continue” error policy on per-entry delete_item() failures, mirroring rsync.c::do_delete().

2.3 Itemize and stats

2.4 Mutual exclusion

3. Backward compatibility: default unchanged

Omitting --delete-strict-order MUST leave receiver behaviour identical to today’s batched sweep. The audit’s three risk areas (error propagation, observable delete order, per-dir merge files) remain present by default; the flag exists solely so users who need upstream parity on those axes can opt in. No man-page, CHANGELOG, or default-config bump beyond documenting the new flag is required.

A regression test under crates/transfer/tests/delete_during_strict_order.rs asserts:

4. Cross-references