Skip to content

aw-sync: sync failures are silent — add aw-sync status, loud diagnostics, per-device manifest, and surface peers in Raw Data #684

Description

@ErikBjare

Setting up sync and having it silently do nothing is currently indistinguishable, from the user's side, from setting it up correctly. Two concrete bugs that produce exactly that are filed separately (#682 daemon layout mismatch, #683 duplicate-folder truncation) — this issue is about the fact that neither was diagnosable without reading the source and opening the peer sqlite files by hand.

In the case that prompted this, the daemon ran 102 sync passes over ~19 hours, logged Pulling... 102 times, imported nothing, and reported no problem at any level: not in the log, not in the UI, not in the sync folder.

1. Fail loud

sync_run() logs Pulling... unconditionally and then iterates an empty vec. It only logs when remotes are found:

if !remote_dbfiles.is_empty() {
    info!("Found {} remote db files: {:?}", ...);
}

Finding zero peers in a directory the user explicitly configured for sync is the interesting case, not the boring one. It should warn! with the glob that was tried and the directory entries that were skipped and why. Same for a peer database that fails to open, or whose schema version is unrecognised (there is already a TODO: Check for compatible remote db version before opening).

2. aw-sync status

A doctor subcommand, dumping in one screen:

  • resolved sync dir, profile, local hostname + device_id, target server + port
  • every directory found in the sync dir, classified: recognised peer / own staging copy / unrecognised
  • per peer: device_id, hostname as recorded on its buckets, db size, bucket count, newest event timestamp, and whether it has been imported locally
  • warnings for: two folders sharing a device_id, folder name ≠ bucket hostname, staging copy older than the local server's newest event, peers not imported

list_buckets() is already 80% of the data-gathering for this; it just isn't reachable in a form that answers "why is my phone missing".

This one command replaces the entire manual investigation that produced these issues.

3. Per-device manifest.json

Write a small JSON file next to each test.db:

{
  "device_id": "41662faa-...",
  "hostname": "poco_f8_ultra",
  "display_name": "POCO F8 Ultra",
  "aw_version": "v0.14.2b1",
  "last_push": "2026-09-14T19:54:12Z",
  "buckets": [{"id": "aw-watcher-android", "events": 1027343, "last_event": "..."}]
}

Cheap to write, and it buys:

4. Surface sync peers in the existing Raw Data page

Correction to an earlier draft of this: the "Devices" view already exists. /buckets (Raw Data) groups by device via the bucketsByDevice getter in aw-webui/src/stores/buckets.ts, shows hostname + device ID + "this device" badge + last-updated with a recency highlight + desktop/mobile icon, and already runs consistency checks per device:

runChecks: function (device) {
  // "Device known by several hostnames: ..."
  // "Device known by several IDs: ..."
}

So the structure to extend is there, and runChecks is the natural home for sync warnings. The gap is that the page can only see devices that already have buckets locally — it is built from this.buckets. A device that is present in the sync folder but failing to import is invisible on the one page a user would look at to find it, which is precisely the failure mode above.

Proposed: expose sync-folder peers (from manifest.json, or a /api/0/sync/peers-style endpoint) and render them on the same page as devices in a "in sync folder, not imported" state, with the reason. Plus a runChecks entry for "this device has not published to the sync folder since {date}" — which would have caught the 8-month-stale local staging copy on its own.

5. Unify the two folder walkers

find_remotes() / find_remotes_nonlocal() / get_remotes() are three different directory walks with two different depth assumptions, and the source already carries // TODO: share logic with find_remotes and find_remotes_nonlocal. One walker returning a typed Vec<Peer> — rather than Vec<PathBuf> that callers re-derive meaning from — removes the class of bug entirely.

6. Smaller items

  • Name the staging database after the device rather than test.db — it reads as leftover test scaffolding in a directory users are told to inspect.
  • Clean up (or at least warn about) staging databases containing …-synced-from-… buckets left over from before fix(sync): never re-sync buckets synced from another host #648; they are re-exported peer data that nothing prunes.
  • First-run flow: aw-qt currently has no sync entry in autostart_modules and no way to pick a sync directory, so getting to a working setup means finding the binary inside the .app bundle and knowing that sync and daemon behave differently.

cc @TimeToBuildBob

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions