Skip to content

Keep a target-only change with a warning instead of a conflict (1.3.0-beta.1) - #258

Merged
5PK merged 3 commits into
mainfrom
fix/target-only-edits-warn
Nov 3, 2026
Merged

5PK merged 3 commits into
mainfrom
fix/target-only-edits-warn

Conversation

@5PK

@5PK 5PK commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Changes how the sync treats an entity that was changed on the target since the last sync while the source wasn't. 1.3.0-beta.0 made that a conflict. It's now skipped with a warning.

Why

Testing 1.3.0-beta.0 on a clone pair synced by an older CLI found 120 conflicts on items nobody had changed. 115 of the 119 checked had identical fields on both sides, and the other 4 differed only in an asset URL. The target simply had a newer version number than the mapping recorded. Older CLI versions often left the mapping's target version behind the target's real one, and 1.2.x never noticed, because it treated a target-only change as up to date. For anyone upgrading:

  • without --overwrite, the sync exits 1;
  • with --overwrite, every one of those items is re-saved for nothing.

The rule now

For content, pages, models, containers, assets and galleries:

Since the last sync Without --overwrite With --overwrite
Only the source changed update update
Only the target changed kept, with a warning (was: conflict) replaced with the source
Both changed conflict replaced with the source

The mapping isn't refreshed for a kept change, so a later source change to it is reported as a conflict instead of silently overwriting the target.

Unchanged:

  • A page missing from the target pull (file_missing) is still a conflict.
  • A mapped target item that no longer exists is still a conflict.
  • The --syncDeletes "deleted in the source, edited on the target" case is still a conflict.
  • Templates, URL redirections and list order can't tell which side changed yet; that's PROD-3078, now reworded to this rule.

Tracking kept changes

There's a new per-run collector, keptTargetChanges (src/lib/pushers/kept-target-changes.ts), modelled on the foreign CDN report:

  • a warning line for each entity as it's skipped;
  • a "Target changes kept" section at the end of the run, with a CMS link for content and pages;
  • a line in the preflight's warnings ("Target changes kept: 117 content items");
  • one targetChangeKept entry per entity in the --jsonSummary warnings, with sourceID, targetID and targetUrl.

None of it affects the counts, success or the exit code. The README's --overwrite entry describes the rule.

CI harness (ci/permutation/)

  • drift passes when the receiving side's edit is kept with a target-changed warning. It fails if the edit is silently kept, or if it's reported as a conflict when only the target changed.
  • Two picks broke the first run of this branch:
    • model.field-rename renamed a linked field's companion ID field (PermCycleNode.NextID). The link's LinkeContentDropdownValueField then pointed at a missing field, and the server dropped every value saved to it. The rename now skips fields that another field names in its settings.
    • The conflict edit and the drift edit landed on the same item in rounds 3 and 4. The conflict edit now avoids the drift item.

Tests

  • New tests for each of the six types cover three cases:
    • target-only change: skip, with one recorded entry;
    • both sides changed: conflict, nothing recorded;
    • target-only change with --overwrite: update.
  • Tests for the collector cover deduplication, headline plurals (including "galleries"), summary lines and the JSON details.
  • The full suite passes (142 suites, 2,730 tests), as do tsc, ESLint (no errors) and the build.
  • Clone pair:
    • the preflight went from 120 content conflicts to 3, with 117 items kept with a warning. The 3 left are real: stale mappings to target items that were deleted, whose source items have since changed;
    • the real sync exits 0 with nothing failed;
    • verify shows only differences that were already there before this run.
  • Live sync permutation test, beta tier on fresh dev instances, seed 610455120: every check passes in all 5 rounds, with drift kept with a warning each round.

Release

Bumps the version to 1.3.0-beta.1, because 1.3.0-beta.0 is already published with the strict conflict behaviour. After merging, push the v1.3.0-beta.1 tag on main. The publish workflow runs the sync permutation test on it and, if it passes, publishes it under beta.

🤖 Generated with Claude Code

5PK and others added 3 commits November 3, 2026 11:15
An entity changed on the target since the last sync, with the source unchanged, is now skipped
with a warning rather than reported as a conflict, for content, pages, models, containers, assets
and galleries. A change on both sides is still a conflict, and --overwrite replaces either with
the source. The mapping isn't refreshed, so a later source change is caught as a conflict.

Kept changes are collected per run (keptTargetChanges): a warning line per entity, a "Target
changes kept" section at the end of the run, a preflight warning, and one `targetChangeKept`
entry per entity in the --jsonSummary warnings. None of it affects the exit code.

Treating these as conflicts was too aggressive: mappings written by older CLI versions often
record a target version older than the target's real one, with identical content on both sides.
On a clone pair synced by an older CLI, that gave 120 false conflicts on unchanged items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the run

- drift passes when the receiving side's edit is kept with a target-changed warning.
- model.field-rename skips fields another field names in its settings (a linked field's companion
  ID field). Renaming one leaves the link pointing at a missing field, and the server then drops
  every value saved to the link.
- The conflict edit avoids the item the round's drift edited, so each check grades its own item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@5PK 5PK changed the title Keep a target-only change with a warning instead of a conflict Keep a target-only change with a warning instead of a conflict (1.3.0-beta.1) Nov 3, 2026
@5PK
5PK merged commit 95a95b1 into main Nov 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants