Skip to content

Sync: joining adopts the sync data's default key; CLI asks per item; iCloud placeholders download - #358

Merged
fylorn merged 1 commit into
feat/sync-backupfrom
feat/sync-fixes-2
Oct 19, 2026
Merged

fylorn merged 1 commit into
feat/sync-backupfrom
feat/sync-fixes-2

Conversation

@fylorn

@fylorn fylorn commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Three follow-ups on sync, on top of #357.

Default gateway key on join

Every installation generates a default gateway key. When the key that default_key points to has the same name on both sides and a different value, joining does not treat it as a conflict. The joining device takes the sync data's value, so it lines up with the devices already syncing:

  • merge: that row is decided as overwrite; any decision given for it is ignored.
  • use_remote: a pinned default key is no longer kept over the sync data's value.
  • GatewayKeysChanged follows, so clients set up on the joining device are updated.

POST /sync/enable/preview returns the new SyncJoinPreview.auto: [{ item, action: "overwrite", reason: "default_key" }]. The row stays in rows, and the UI shows it as "use the sync data" with the note about clients. auto is also filled for initial configurations.

twcore sync enable

  • When merging, each item that differs is asked: u use the sync data (default), k keep this device's version (the prompt says it replaces the other devices' one), and r keep both where a new name is suggested. Before this, Enter skipped every conflict, which uploaded this device's values (its default key included) over the other devices'.
  • The device name defaults to the computer name: scutil --get ComputerName (then LocalHostName) on macOS, the host name on Linux, COMPUTERNAME on Windows. Before this, macOS fell back to server.

iCloud placeholders (macOS 13 and earlier)

Reading the real name behind a legacy .name.icloud placeholder does not download it.

  • The folder location now asks iCloud to download it with NSFileManager startDownloadingUbiquitousItemAtURL:error: (the documented API, available since 10.7; brctl download is gone on current macOS).
  • The call goes through the system osascript (JavaScript for Automation), with the path passed as an argument, at most every 5 minutes per file. There are no native calls in core.
  • A placeholder reads as empty and counts as "arriving", not "unreadable". It does not count toward the 30-minute skip and is skipped only after a day. The keyring gets the same treatment.

Tests

  • tw-control/tests/sync_regressions.rs: merge join adopts the default key even with a "skip" decision; a fresh device with taken-over clients adopts it on use_remote; GatewayKeysChanged is emitted; the other device's key is unchanged. The earlier merge-join test is updated to the new rule.
  • tw-sync/tests/regressions.rs: placeholders are still waited for after 30 minutes and skipped after a day. A macOS-only unit test runs the download request script (it answers false for a file outside iCloud). The device-name helper has unit tests.
  • Local: cargo test --workspace 3828 passed, 0 failed; cargo clippy --workspace --all-targets -D warnings clean; cargo fmt --check clean; scripts/smoke.sh 84 passed, 0 failed. The platform-specific functions were also linted for the Linux and Windows targets in a scratch crate.
  • Manual run with two real cores and a folder location: twcore sync enable offered the computer name as the device name, printed the default-key note, asked about the one differing upstream (default: use the sync data), and adopted the sync data's default key. The other device's key stayed as it was.
  • Not verified on a real macOS 12/13 iCloud Drive: the download request was only checked to run.

🤖 Generated with Claude Code

…iCloud placeholders download

Default gateway key on join
- Every installation generates a default gateway key. When the key that
  default_key points to has the same name on both sides and a different
  value, joining is not a conflict: the joining device takes the sync
  data's value, in both join modes (a pinned default key is no longer kept
  over it on use_remote), and GatewayKeysChanged follows so taken-over
  clients are updated. Decisions given for that item are ignored.
- POST /sync/enable/preview lists it in the new SyncJoinPreview.auto
  ({ item, action: overwrite, reason: default_key }); the row itself stays
  in rows. auto is filled for initial configurations too.

twcore sync enable
- Merging asks about each item that differs; the default is "use the sync
  data", "keep this device's version" says it replaces the other devices'
  one, and "keep both" is offered where a new name is suggested. Before,
  pressing Enter skipped every conflict, which pushed this device's values
  (its default key among them) onto the other devices.
- The device name defaults to the computer name: ComputerName (then
  LocalHostName) on macOS, the host name on Linux, COMPUTERNAME on Windows.

iCloud placeholders (macOS 13 and earlier)
- Reading the real name of a legacy .name.icloud placeholder does not
  download it. The folder location now asks iCloud to download it through
  NSFileManager startDownloadingUbiquitousItemAtURL:error:, called from the
  system osascript (JavaScript for Automation) with the path as an argument,
  at most every 5 minutes per file.
- A placeholder (an empty read) is "arriving", not "unreadable": it does not
  count toward the 30 minutes after which unreadable files are skipped, and
  is skipped only after a day so it cannot hold uploads back forever. The
  keyring gets the same treatment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn
fylorn merged commit 6d23290 into feat/sync-backup Oct 19, 2026
6 checks passed
@fylorn
fylorn deleted the feat/sync-fixes-2 branch October 19, 2026 10:22
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant