feat(sync): show last completion status - #251
Merged
ErikBjare merged 3 commits intoSep 10, 2026
Merged
Conversation
Git-Session-Id: fb82cf8b-dc14-5fab-8861-32589542190d
Greptile SummaryThis PR persists the outcome and completion time of full sync attempts and displays that status in Sync Settings.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported mirror-failure, stale-status, and partial-mirror cancellation paths are addressed at the current head. Important Files Changed
Sequence DiagramsequenceDiagram
participant Trigger as Scheduler / Worker
participant Sync as SyncInterface
participant SAF as Configured SAF directory
participant Prefs as AWPreferences
participant UI as Sync Settings
Trigger->>Sync: Start full sync
Sync->>Sync: Run native synchronization
alt Native sync succeeds
Sync->>SAF: Mirror sync files
SAF-->>Sync: Complete or throw
end
Sync->>Prefs: Persist completion time and outcome
Prefs-->>UI: Send package-scoped status broadcast
UI->>Prefs: Read latest status
UI->>UI: Refresh status row
Reviews (3): Last reviewed commit: "fix(sync): fail incomplete SAF mirrors" | Re-trigger Greptile |
Git-Session-Id: fb82cf8b-dc14-5fab-8861-32589542190d
Contributor
Author
|
@greptileai review |
Git-Session-Id: df671383-72f8-5921-b499-2fc7fec7dabe
Contributor
Author
|
@greptileai review |
Contributor
Author
|
CI-green and mergeable (Greptile 5/5) — waiting only on a maintainer click. This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge. The last Greptile P1 thread (cancellation during SAF mirroring) was already fixed in |
Judemasic
added a commit
to Judemasic/aw-android
that referenced
this pull request
Sep 3, 2026
…laim corrected 1.5's final check passes on hardware. The tablet's server lists aw-watcher-android-synced-from-jude_s_s25_ultra (hostname jude_s_s25_ultra, 6,797 events) beside its own 485 — a bucket it could not have produced — and the Activity query against that host returns 15,503.1s. Phase 1 closes. The same measurement quantifies 1.8's caveat across sync: flood alone yields 366,699.9s, the ["app","title"] merge yields 15,503.1s. 4.2%. The other 96% is pre-fix phone history, already on the tablet, invisible only because of aw-webui#959 — an upstream fix reveals it with no re-sync. Corrects a wrong claim this document carried: 1.8 stated the regression shipped in v0.14.0b2 with "nine days of exposure". It does not. Verified by ancestry rather than by comparing dates — `git merge-base --is-ancestor bf0fc84 749585f` is false, and 749585f is what v0.14.0b2 pins via aw-server-rust e8e6e90. Released users are unaffected; only master builds carry it. The corrected chain is now a table with the command to reproduce it. Also records two things found while inspecting the devices: - Syncthing versioning puts archived peer directories in .stversions/, which has the exact shape the importer scans for. isSafeEntryName()'s dot-prefix guard rejects it, and peers=1 in the logs proves it. - Two stale app-private databases, one a true leftover and one regenerated by sync_run's pull side-effect. The shared folder itself is clean. Notes upstream PR ActivityWatch#251, which touches the same four files as 1.7 and fixes the success-reported-on-failure bug this fork still has. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Judemasic
added a commit
to Judemasic/aw-android
that referenced
this pull request
Sep 3, 2026
Upstream PR ActivityWatch#251 fixes this class of bug for the export path: "a failed SAF mirror was also logged as non-fatal, so the app could report native sync success while the user-selected directory stayed unchanged." This fork had it in both directions, and the import side is worse -- a failed import is exactly the "sync works but the other device never appears" symptom. The root cause was a data structure, not a catch block. Both passes tallied into `counts = intArrayOf(0, 0) // [copied, skipped]`, and `skipped` counted two unrelated things: a file already current, and a file that failed to copy. importFile's own contract admitted it -- "true if bytes were copied; false if the file was already current, or on any failure." A boolean cannot carry three states, so a pass where every file failed logged `copied=0 skipped=1`, identical to a healthy pass with nothing to do. - FileOutcome { COPIED, SKIPPED, FAILED } replaces the Boolean. - TransferResult (copied/skipped/failed/peers + first error reason) replaces IntArray(2), separating deliberate skips from breakage and keeping a reason worth showing the user. - runTransfer() converts an unexpected throw into a failed result. It still catches -- one bad pass must not abort a cycle that can finish -- but the failure now travels back with the result instead of dying in logcat. - The SAF export moved before the callback. An export that runs after the caller has been told "success" can never correct that answer. This removes the only reason syncBothAndMirrorAsync existed, so the two entry points collapse into one and SyncWorker calls it directly. SAF failures are collected rather than thrown: a failed import still leaves the native sync worth running, since peer databases from an earlier cycle are on disk and readable. Native pull/push failures still end the cycle. Sync Settings now shows "Sync failed: export failed: sync folder unreachable (permission revoked, or folder deleted)" where it used to show "Sync complete", and logcat gains a failed=N column with unsuccessful syncs logged at warning. Deliberately unchanged: a failed native pull still skips the export. Noted in roadmap 1.9 so it reads as a decision rather than an oversight. Compiles; scripts/check-local.sh passes. Not yet run -- a local assembleDebug produces an APK with zero .so files, so this needs a CI build to test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Judemasic
added a commit
to Judemasic/aw-android
that referenced
this pull request
Sep 3, 2026
1.10 — the Timeline truncates every peer's name at the first underscore. Reported by the owner as "I don't know which is the S25U and which the tab". Not a naming preference: aw-webui's shortenBucketLabel drops everything from the first "_" onward, because on desktop that separates the host (aw-watcher-window_erb-m2.localdomain -> window). Android's synced buckets are aw-watcher-android-synced-from-<hostname>, and the hostname itself carries the underscores, so the cut lands inside the peer's name. The branch meant to catch this, /^([^_]+)_.*-synced-from-(.+)$/, requires an underscore before "-synced-from-" and so cannot fire for Android at all. Verified by simulating the function against this device's real bucket list: aw-watcher-android-synced-from-jude_s_s25_ultra renders as "android-synced-from-jude". Every device belonging to the same person collapses to the same label. Documents the no-code workaround with its real cost: the hostname comes from Android's DEVICE_NAME with non-[a-z0-9_-] runs replaced by "_", so a device name without spaces produces an underscore-free hostname that survives the shortener (hyphens are preserved). But the hostname is also the sync directory name, so a rename strands the old directory in the shared folder as a permanent phantom peer — the 1.4a failure mode again. Also records a decision that would otherwise be re-litigated: keep the 1.8 title fix rather than withdrawing it once aw-webui#959 is fixed. #959 is an open issue with nobody assigned; the two repair different layers; and a real field cannot be re-broken by a later query edit, which is exactly how the regression happened. Names the one condition that would change the answer. Flags upstream PR ActivityWatch#251 as overlapping 1.7 and 1.9 in all four of the same files, with the advice to rebase onto it rather than propose a parallel design. Updates docs/README.md, whose "sync works one-way, never run" summary predated Phase 1 closing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
#247 reports that sync runs silently: users cannot tell whether it succeeded, failed, or when it last completed. A failed SAF mirror was also logged as non-fatal, so the app could report native sync success while the user-selected directory stayed unchanged.
Fix
Last sync: never,Last sync succeeded at …, orLast sync failed at …in Sync Settings.This addresses the feedback/status portion of #247. The 401 root cause, document picker, and
unknownActivity route are already merged via #249, #248, and #250. Category-import persistence remains separate.Testing
Passed (full JVM unit-test suite).