Skip to content

fix(activity): use actual bucket IDs in multidevice query (fixes BucketNotFound with aw-sync data) - #969

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
Q-Ze:fix/multidevice-query-use-actual-bucket-ids
Sep 17, 2026
Merged

ErikBjare merged 2 commits into
ActivityWatch:masterfrom
Q-Ze:fix/multidevice-query-use-actual-bucket-ids

Conversation

@Q-Ze

@Q-Ze Q-Ze commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fix BucketNotFound in multidevice query when viewing aw-sync data

Problem

With aw-sync set up between machines, enabling the "Use multidevice query" developer setting and opening the Activity view fails on every machine except the one being viewed:

BucketNotFound("Failed to find bucket 'aw-watcher-window_<hostname>'")

Root cause

Buckets pulled in by aw-sync keep their original hostname field, but their bucket ID gets an -synced-from-<host> suffix (e.g. aw-watcher-window_myhost-synced-from-myhost).

  • bucketsByHostname groups by the hostname field, so synced hosts correctly appear in the device list;
  • but multideviceQuery reconstructs bucket IDs from the hostname (get_params: bid_window: 'aw-watcher-window_' + host) and query_multidevice_full passes host_params: {}, so the existing per-host override mechanism in get_params is never used;
  • query_bucket("aw-watcher-window_myhost") then fails with BucketNotFound, since only the suffixed ID exists in the local datastore.

Fix

  1. Fill host_params with each host's actual bucket IDs (first window/afk bucket from the buckets store), so synced buckets are queried by their real IDs.
  2. Only include hosts that have both a window and an afk bucket (the pair canonicalEvents requires), matching the single-device path — previously only the window bucket was required, which could produce the same error for the afk bucket.

Verification

With two machines synced via aw-sync (one viewing the other's data):

  • Before: the query the UI generates returns HTTP 400 BucketNotFound("Failed to find bucket 'aw-watcher-window_QBZdeMac-mini.local'").
  • After: the same multidevice query (two hosts, union_no_overlap) executes successfully, e.g. {"duration": 22392.738} for the day across both hosts.

The multidevice query reconstructed bucket IDs as
'aw-watcher-window_<hostname>'/'aw-watcher-afk_<hostname>', but buckets
synced from another host via aw-sync carry an '-synced-from-<host>'
suffix in their ID while keeping their original hostname field, so on
any machine viewing synced data the query failed with BucketNotFound.

Fill host_params (an override mechanism that already existed in
get_params but was passed as an empty object) with each host's actual
bucket IDs, and require both window and afk buckets for a host to be
included in the multidevice query, matching the single-device query.
@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes multidevice activity queries for synchronized data by passing each host's actual window and AFK bucket IDs instead of reconstructing IDs from hostnames.

  • Restricts multidevice queries to hosts with the required window/AFK pair.
  • Builds host-specific query overrides from the loaded bucket inventory.
  • Leaves the new regression path untested and bypasses its declared parameter type with any.

Confidence Score: 4/5

The PR appears safe to merge, with only non-blocking test-coverage and type-safety improvements recommended.

The new host-specific bucket overrides match the query builder's runtime contract and resolve the synced-ID failure, while the remaining findings concern regression protection and maintainability rather than incorrect runtime behavior.

Files Needing Attention: src/stores/activity.ts

Important Files Changed

Filename Overview
src/stores/activity.ts Filters hosts by required bucket pairs and supplies actual bucket IDs to multidevice queries; behavior appears correct, with test-coverage and typing improvements recommended.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Inventory[Bucket inventory] --> Filter{Host has window and AFK buckets?}
  Filter -- No --> Skip[Exclude host]
  Filter -- Yes --> IDs[Select actual bucket IDs]
  IDs --> Params[Build host_params by hostname]
  Params --> Query[Generate multidevice query]
  Query --> Server[Query ActivityWatch]
  Server --> Merge[Merge per-host activity]
Loading

Reviews (1): Last reviewed commit: "fix(activity): use actual bucket IDs in ..." | Re-trigger Greptile

Comment thread src/stores/activity.ts Outdated
Comment on lines 430 to 448
hosts.forEach(host => {
const bid_window = bucketsStore.bucketsWindow(host)[0];
const bid_afk = bucketsStore.bucketsAFK(host)[0];
if (bid_window && bid_afk) {
host_params[host] = { bid_window, bid_afk };
hosts_with_buckets.push(host);
} else {
console.warn(`Skipping host ${host} in multidevice query: missing window/afk bucket`);
}
});

const q = queries.multideviceQuery({
hosts,
hosts: hosts_with_buckets,
filter_afk,
categories,
filter_categories,
host_params: {},
host_params: host_params as any,
always_active_pattern,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing multidevice regression tests

The new synced-bucket override path has no focused test covering suffixed bucket IDs or the exclusion of hosts missing an AFK bucket. Because this behavior is enforced during query generation rather than by the type system, a later change could silently restore the original BucketNotFound failure. Please add a multidevice query test that verifies the actual window and AFK bucket IDs are emitted and incomplete hosts are omitted.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread src/stores/activity.ts Outdated
categories,
filter_categories,
host_params: {},
host_params: host_params as any,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Host parameters bypass typing

Casting host_params to any suppresses the query builder's declared parameter contract. This means a future incompatible change to either side would not produce a type error. Please model this value using the partial desktop-parameter shape that get_params actually accepts instead of bypassing type checking.

- Extract buildMultideviceHostParams into a pure helper
  (src/util/multidevice.ts), covered by unit tests including the
  synced-bucket-ID regression (the query must not reference
  reconstructed 'aw-watcher-window_<host>' IDs).
- Replace the 'as any' cast by typing host_params values as Partial
  overrides, matching what get_params actually applies.
@Q-Ze

Q-Ze commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Both non-blocking findings are addressed in d5ab9e7:

  • Test coverage: the host-selection logic now lives in a pure helper (buildMultideviceHostParams, src/util/multidevice.ts) with unit tests, plus a regression test asserting the generated query references the actual (suffixed) bucket IDs and not the reconstructed aw-watcher-window_<host> ones.
  • Type safety: the as any cast is gone — host_params values are now typed as Partial<DesktopQueryParams> | Partial<AndroidQueryParams>, which matches the override semantics in get_params (only keys present and non-empty are applied).

@ErikBjare

Copy link
Copy Markdown
Member

Reviewed in the context of the sync work tracked in ActivityWatch/activitywatch#1445 — this is the right fix for the current model, and it is directionally the change proposed in ActivityWatch/activitywatch#302 (stop reconstructing bucket IDs from hostnames in the frontend; query the IDs the store actually has).

Verified: buildMultideviceHostParams uses the store's real per-host bucket lists, no prefix matching is added, the window+afk pairing matches what canonicalEvents requires, and the tests cover the -synced-from- case that produced the BucketNotFound. The [0] pick when a host has two currentwindow buckets is pre-existing behaviour from the single-device path, not something this PR introduces.

Thanks for the clear root-cause write-up — it is the same hostname-as-identity problem the sync issues keep hitting from the other side. Recommending merge.

@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.92308% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.03%. Comparing base (a2ca625) to head (d5ab9e7).
⚠️ Report is 13 commits behind head on master.

Files with missing lines Patch % Lines
src/stores/activity.ts 14.28% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #969      +/-   ##
==========================================
+ Coverage   51.99%   53.03%   +1.03%     
==========================================
  Files          48       49       +1     
  Lines        2927     2949      +22     
  Branches      652      688      +36     
==========================================
+ Hits         1522     1564      +42     
+ Misses       1385     1307      -78     
- Partials       20       78      +58     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ErikBjare
ErikBjare merged commit 52ad886 into ActivityWatch:master Sep 17, 2026
8 checks passed
ErikBjare added a commit to ActivityWatch/aw-server-rust that referenced this pull request Sep 17, 2026
Pulls in ActivityWatch/aw-webui#969 (multidevice query uses actual bucket IDs,
fixes BucketNotFound with aw-sync data) and ActivityWatch/aw-webui#983
(Raw Data page renders device.device_id instead of the missing device.id).

d0cf630..52ad886
ErikBjare pushed a commit that referenced this pull request Oct 6, 2026
…ws (#1068)

Search, Report, Graph, Alerts, Trends and Category Builder built
'aw-watcher-window_<host>' / 'aw-watcher-afk_<host>' by hand. Buckets
synced via aw-sync carry a '-synced-from-<device>' suffix, so selecting a
synced host in these views queried a bucket that doesn't exist.

Add a desktopBucketIds(host) getter to the buckets store that returns the
host's actual window/afk bucket ids, falling back to the conventional ids
when none are loaded, and use it at all six call sites. Same fix the
Activity view got in #969.

Git-Session-Id: c7e4
Q-Ze added a commit to Q-Ze/aw-webui that referenced this pull request Oct 10, 2026
Upstream highlights:
- feat: custom date range period (ActivityWatch#1005)
- feat: device selection (all / subset) in Activity view (ActivityWatch#1004)
- feat: category rule priority (ActivityWatch#968)
- feat: layered category sets (ActivityWatch#1027, ActivityWatch#1072)
- feat: always show Year period (ActivityWatch#1003)
- feat: AI summary privacy filter (ActivityWatch#948)
- feat: 'Add on top of mine' import option (ActivityWatch#1071)
- fix: multidevice queries use real bucket IDs (ActivityWatch#969, ActivityWatch#1068)
- fix: timeline hourly bar Y-axis >1h (ActivityWatch#1021)
- fix: CSV streaming export (ActivityWatch#993, ActivityWatch#997)
- fix: Android browser data display (ActivityWatch#1069)
- fix: various mobile/dark-mode/layout improvements

Conflict resolution: took upstream for activity.ts (major refactor),
multidevice.ts (Android support), Activity.vue, TimelineBarChart.vue,
summary.ts. Re-applied our fixes on top:
- query_active_history: bucket_sig cache clearing + per-event interval
  union (dead-watcher marathon immunity)
- query_active_history_multidevice: bucket_sig + period-length cap
- Removed useMultidevice references (upstream removed the setting in
  favour of device-selection UI); our code paths now always aggregate
  across all hosts
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