test(parity): option-wave rsync differentials + docs (109/21/26)

- tests/integration/test_option_parity.py: bwlimit parse matrix + throttle
  rate, --info flist/name/nonreg/del(dry+real+itemize)/remove, real-setpriv
  --ignore-errors, rsync-daemon -M forwarding evidence, filter protect/risk
  destination-only divergence pin.
- RSYNC_COMPAT.md: tally 109/21/26; --bwlimit and --ignore-errors -> Parity,
  --filter and -M -> Divergent with differential rationale, --info residual
  narrowed to the categories with no client-observable event.
- HANDOFF/README: protocol 2.27.0, option-wave summary.
This commit is contained in:
2026-09-18 21:16:12 +02:00
parent 6a129b54d4
commit eb7e3fd2e0
19 changed files with 546 additions and 62 deletions
+2 -2
View File
@@ -268,8 +268,8 @@ typedef enum SuperMode { SUPER_MODE_AUTO = 0, SUPER_MODE_ON = 1, SUPER_MODE_OFF
* real (non-dry-run) deletion. It is set only when --info=del is requested with
* --delete; the transfer decision itself is unchanged. */
#define CONFIG_WIRE_OUTPUT_FIELDS(X) \
X(report_dest_info, bool, false, BOOL) X(report_stats, bool, false, BOOL) \
X(report_deletes, bool, false, BOOL)
X(report_dest_info, bool, false, BOOL) \
X(report_stats, bool, false, BOOL) X(report_deletes, bool, false, BOOL)
/* Codec-negotiation wave (protocol 2.26.0). compression_algo is the concrete
* codec the client selected for this transfer (a CompressionAlgo id) and is the
+5 -5
View File
@@ -791,9 +791,9 @@ static bool apply_missing(DeletePlanSession* session, const Config* config) {
size_t deleted = 0;
size_t skipped = 0;
bool limit = false;
bool ok = manifest_delete_missing_args_limited_observed(
config, &manifest, remaining, &deleted, &skipped, &limit, session->observer,
session->observer_context);
bool ok = manifest_delete_missing_args_limited_observed(config, &manifest, remaining, &deleted,
&skipped, &limit, session->observer,
session->observer_context);
session->deleted += deleted;
session->planned += deleted;
session->skipped += skipped;
@@ -893,8 +893,8 @@ static bool apply_deferred_path(DeletePlanSession* session, const Config* config
return ok;
}
void delete_plan_session_set_delete_observer(DeletePlanSession* session, DeletePathObserver observer,
void* context) {
void delete_plan_session_set_delete_observer(DeletePlanSession* session,
DeletePathObserver observer, void* context) {
if (!session)
return;
session->observer = observer;
+2 -2
View File
@@ -84,7 +84,7 @@ size_t delete_plan_session_deleted(const DeletePlanSession* session);
truly removes (including the deferred --delete-delay commit), so the receiver
can report rsync's `deleting PATH` lines through the terminal STATUS_STATS
record. Pass NULL/0 to clear. */
void delete_plan_session_set_delete_observer(DeletePlanSession* session, DeletePathObserver observer,
void* context);
void delete_plan_session_set_delete_observer(DeletePlanSession* session,
DeletePathObserver observer, void* context);
#endif
+5 -6
View File
@@ -3261,10 +3261,9 @@ static bool delete_extras_budgeted_observed(const Config* config, DeleteManifest
remaining = budget->max_delete - budget->deleted;
size_t deleted = 0;
size_t skipped = 0;
DeleteWalkResult result =
delete_extras_limited_observed(config->receive_root_directory, manifest->keeps, manifest->dirs,
remaining, skips, used, &deleted, &skipped, observer,
observer_context);
DeleteWalkResult result = delete_extras_limited_observed(
config->receive_root_directory, manifest->keeps, manifest->dirs, remaining, skips, used,
&deleted, &skipped, observer, observer_context);
if (owned_prefixes) {
for (int i = 0; i < config->basis_count; i++)
free(owned_prefixes[i]);
@@ -3592,8 +3591,8 @@ bool manifest_delete_missing_args_limited_observed(const Config* config, DeleteM
void* observer_context) {
DeleteBudgetState budget = {
.max_delete = max_delete, .deleted = 0, .skipped = 0, .limit_hit = false};
bool ok = delete_missing_args_budgeted_observed(config, manifest, &budget, observer,
observer_context);
bool ok =
delete_missing_args_budgeted_observed(config, manifest, &budget, observer, observer_context);
if (deleted)
*deleted = budget.deleted;
if (skipped)
+2 -1
View File
@@ -132,7 +132,8 @@ bool manifest_delete_missing_args_limited(const Config* config, DeleteManifest*
bool manifest_delete_missing_args_limited_observed(const Config* config, DeleteManifest* manifest,
size_t max_delete, size_t* deleted,
size_t* skipped, bool* limit_hit,
DeletePathObserver observer, void* observer_context);
DeletePathObserver observer,
void* observer_context);
/* Outcome of committing a delete manifest. LIMIT_REACHED reports rsync's
partial --max-delete result: the budget allowed some deletions and the rest
were skipped (the run still stores all file data but the client exits 25). */
+2 -1
View File
@@ -876,7 +876,8 @@ DeleteWalkResult delete_extras_limited_observed(const char* dest_root, const Arr
const ArrayList* synced_dirs, size_t max_delete,
const DeleteSkipEntry* skips, int skip_count,
size_t* deleted_out, size_t* skipped_out,
DeletePathObserver observer, void* observer_context) {
DeletePathObserver observer,
void* observer_context) {
if (deleted_out)
*deleted_out = 0;
if (skipped_out)
+2 -1
View File
@@ -145,7 +145,8 @@ DeleteWalkResult delete_extras_limited_observed(const char* dest_root, const Arr
const ArrayList* synced_dirs, size_t max_delete,
const DeleteSkipEntry* skips, int skip_count,
size_t* deleted_out, size_t* skipped_out,
DeletePathObserver observer, void* observer_context);
DeletePathObserver observer,
void* observer_context);
DeleteWalkResult delete_extras_limited(const char* dest_root, const ArrayList* manifest,
const ArrayList* synced_dirs, size_t max_delete,