Update policy for replacement of managed files

This commit is contained in:
2026-06-18 13:38:44 -05:00
parent 8b0ce4d134
commit 69043801d0
18 changed files with 330 additions and 107 deletions

View File

@@ -67,12 +67,14 @@ Published destination bundle paths contain `.distributor.json`. See [Destination
- No destination state and no destination content: publish new outputs.
- Matching destination state: skip as already published.
- Older destination state for the same source id: replace if transfer policy allows it.
- Newer destination state for the same source id: skip by default.
- Valid managed state with an identity, source, or shared-root output-owner mismatch: replace only when destination `takeover.mode` allows it.
- Invalid destination state, identity, source, or shared-root output-owner mismatches not allowed by `takeover.mode`, or same-created digest mismatch: fail by default.
- Newer destination state for the same source id: skip by default, or replace when `transfer.on_destination_newer: replace` is configured.
- Valid managed state with an identity, source, same-created digest, or shared-root output-owner mismatch: replace when destination `takeover.mode` allows it or, for remaining valid managed conflicts, when `transfer.on_conflict: replace` is configured.
- Invalid destination state, identity, source, same-created digest, or shared-root output-owner mismatches not allowed by `takeover.mode` or `transfer.on_conflict: replace`: fail by default.
- Content without `.distributor.json`: fail as unmanaged content by default.
When destination state is older than the source, `transfer.on_destination_older` controls whether publication may proceed and `reconciliation.mode` controls how managed outputs are updated.
When destination state is older or newer than the source, `transfer.on_destination_older` and `transfer.on_destination_newer` control whether publication may proceed and `reconciliation.mode` controls how managed outputs are updated.
When `transfer.on_conflict: replace` permits `replace_conflict`, the destination is valid managed state but does not match the current source, pipeline, destination, or same-created digest. `replace_conflict` rewrites the affected managed destination state and does not retain omitted outputs through merge reconciliation.
For takeover replacement, `reconciliation.mode: merge` does not retain omitted outputs from the previous source identity. The destination is rewritten as a managed replacement for the current source or shared-root owner.
@@ -159,6 +161,8 @@ Review these action labels before publishing:
- `publish_new`: destination state is absent, or a shared-root owner is absent and planned paths are publishable.
- `replace_older`: destination state is older than the source.
- `replace_newer`: destination state is newer than the source and `transfer.on_destination_newer: replace` allows managed replacement.
- `replace_conflict`: destination state is valid managed state with a conflict and `transfer.on_conflict: replace` allows managed replacement.
- `replace_takeover`: destination state is valid managed state and `takeover.mode` allows replacement across an identity, source, or shared-root output-owner mismatch.
- `skip_same`: destination state already matches the source.
- `skip_destination_newer`: destination state is newer than the source and is skipped.
@@ -167,7 +171,7 @@ Review these action labels before publishing:
Fixed destinations add fixed-path warnings during dry runs, including the selected source bundle and replacement warnings when the destination root would be replaced.
Text and JSON summaries count `publish_new`, `replace_older`, `replace_takeover`, `force_replace`, skipped, and failed destinations separately. Takeover action records include the configured takeover mode and the conflict reason. JSON output includes warnings, pipeline summaries, destination action records, output records, URLs when configured, final counters, and partial failure details. Fatal setup failures such as unreadable config or invalid secrets do not produce a JSON result document.
Text and JSON summaries count `publish_new`, `replace_older`, `replace_conflict`, `replace_newer`, `replace_takeover`, `force_replace`, skipped, and failed destinations separately. Takeover action records include the configured takeover mode and the conflict reason. JSON output includes warnings, pipeline summaries, destination action records, output records, URLs when configured, final counters, and partial failure details. Fatal setup failures such as unreadable config or invalid secrets do not produce a JSON result document.
## Forced Replacement Workflow
@@ -178,10 +182,7 @@ go run ./cmd/distributor run --config <config-path> --dry-run --force
go run ./cmd/distributor run --config <config-path> --force
```
Forced replacement can claim unmanaged non-empty destination paths. State conflicts require both `--force` and transfer policy that permits replacement:
- newer destination state requires `transfer.on_destination_newer: replace`;
- conflict outcomes require `transfer.on_conflict: replace`.
Forced replacement can claim unmanaged non-empty destination paths and is reserved for exceptional destructive replacement. Valid managed newer state and valid managed conflict state use `replace_newer` and `replace_conflict` when the corresponding transfer policy allows replacement; they do not require `--force`.
Forced replacement deletes the current destination bundle path before writing outputs and state. It does not delete parent paths, sibling paths, or storage outside the destination bundle path. For fixed destinations, the destination bundle path is the backend root, so a forced replacement can clear that configured root.