Skip to content

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

Open
Q-Ze wants to merge 2 commits into
ActivityWatch:masterfrom
Q-Ze:fix/multidevice-query-use-actual-bucket-ids
Open

fix(activity): use actual bucket IDs in multidevice query (fixes BucketNotFound with aw-sync data)#969
Q-Ze wants to merge 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

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
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).

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.

1 participant