Skip to content

fix(buckets): render device.device_id instead of missing device.id - #983

Merged
ErikBjare merged 4 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/buckets-device-id
Sep 17, 2026
Merged

ErikBjare merged 4 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/buckets-device-id

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

bucketsByDevice returns device_id; the Raw Data card interpolated device.id. Dead while data.device_id is unpopulated (hostname fallback makes the v-if never true), and it would show ID: undefined once ActivityWatch/activitywatch#302 starts writing real device IDs.

  • Template: device.iddevice.device_id
  • Test: mismatch branch with a fixture that carries data.device_id, plus the several-IDs collection

Does not populate data.device_id itself — that's the identity work. Independent of the aw-sync v0.14.0 slice.

Fixes #982

bucketsByDevice returns device_id; the Raw Data card interpolated
device.id, which is always undefined. Dead while data.device_id is
unpopulated (hostname fallback makes the v-if never true) and would
show "ID: undefined" the moment ActivityWatch/activitywatch#302 starts
writing real device IDs.

Add a bucketsByDevice fixture that actually carries data.device_id,
covering the mismatch branch and the several-IDs collection.

Fixes ActivityWatch#982

Git-Session-Id: 29bd6617-cb27-5894-bcad-90edffb3610c
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Review guide (auto-posted)

Structured warm-up for reviewers — what changed, what to run, where to look.

Key files

  • test/unit/store/buckets.test.node.ts (+76/-0, Δ76)
  • test/unit/Buckets.test.js (+11/-0, Δ11)
  • src/views/Buckets.vue (+1/-1, Δ2)

Suggested verification

  • Run the repo's usual CI-equivalent checks locally

Known risks / watch points

  • No automatic high-risk tags; use file list + diff for judgment.

Suggested review focus

  • Confirm behavior matches the PR description acceptance criteria.
  • Skim the largest diffs first (listed above).
  • If CI is green, spot-check the highest-risk paths called out here.

Generated by scripts/github/pr-warmup-review-guide.py for #983.

@greptile-apps

greptile-apps Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the previously reported mixed-group identity issue is fully fixed and no new actionable failures remain.

Summary

Fixes device identity rendering in the bucket list.

  • Renders the existing device_id property instead of the nonexistent id property.
  • Prefers a real device ID over the hostname fallback in partially migrated bucket groups.
  • Adds coverage for hostname fallback, populated IDs, mixed groups, and multiple IDs.

Reviews (2) · Last reviewed commit: "fix(buckets): prefer real UUID over host..."

Comment thread src/views/Buckets.vue
@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.13%. Comparing base (4d58a55) to head (716a184).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #983      +/-   ##
==========================================
+ Coverage   53.11%   54.13%   +1.01%     
==========================================
  Files          48       48              
  Lines        2984     2989       +5     
  Branches      681      683       +2     
==========================================
+ Hits         1585     1618      +33     
+ Misses       1379     1351      -28     
  Partials       20       20              

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

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

CI-green and mergeable — 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 — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted.

@ErikBjare

Copy link
Copy Markdown
Member

@TimeToBuildBob But #983 (comment)

@TimeToBuildBob

TimeToBuildBob commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 AI code review

Safe to merge — no P0/P1 findings on latest review

Updated after inline dispositions on finding threads — this is the current state; the verdict below is frozen at review time and is kept as the historical record of that pass.

Finding disposition
Finding Severity State
src/stores/buckets.ts:170 P2 accepted-tradeoff
src/views/Buckets.vue:21 P2 superseded by latest review (not reproduced)
test/unit/Buckets.test.js:8 P2 superseded by latest review (not reproduced)
test/unit/store/buckets.test.node.ts:73 P2 superseded by latest review (not reproduced)
test/unit/store/buckets.test.node.ts:69 P2 accepted-tradeoff

The PR changes the Buckets view to display device.device_id instead of the nonexistent device.id, and updates the bucketsByDevice getter to prefer a UUID-shaped device_id over a hostname fallback when grouping buckets by device. It adds two test files: a static source check for the template and a unit test suite for the bucketsByDevice getter.

Needs a look — P2 only

Confidence 4/5

2 findings · ⚠️ 2 P2

⚠️ P2 mediumsrc/stores/buckets.ts:176

The new device_id selection logic in bucketsByDevice can pick a device_id that is not actually a device ID but a hostname from a different group, because the second fallback device_ids.find(id => !hostnameSet.has(id.toLowerCase())) only excludes hostnames from the current group. If a bucket in the group has data.device_id set to a hostname-like string that is not in the current group's hostnames (e.g., a legacy bucket with data.device_id: 'other-host'), and no UUID-shaped ID exists, the getter will return that foreign hostname as the device_id. The Buckets view then shows ID: other-host even though that is not a device ID, and the hostname !== device.device_id guard makes the label appear, misleading the user. The test 'UUID-shaped device_id wins even over a non-group hostname-like id' only covers the case where a UUID exists, so the fallback path is untested. This is a real correctness issue in the fallback heuristic, not just a missing test, because the code as written will mislabel devices when a non-UUID, non-group-hostname string is present.

Consider also excluding device_ids that match any known hostname from the full bucket list, or only accept UUID-shaped IDs and fall back to the first entry otherwise.

How this was verified: Traced the logic: device_ids is built from b.data.device_id || b.hostname. If a bucket has data.device_id='other-host' and no UUID exists, the first find fails, the second find matches 'other-host' because it's not in hostnameSet (which only contains hostnames from the group), so device_id becomes 'other-host'. The view then shows ID: other-host.

⚠️ P2 mediumtest/unit/store/buckets.test.node.ts:69

The test 'prefers real UUID over hostname fallback in mixed group' uses data: { device_id: 'real-uuid-xyz' } which is not a UUID-shaped string (it lacks the 8-4-4-4-12 hyphen pattern). The UUID_RE regex requires a specific format, so 'real-uuid-xyz' does not match. The test expects device_id to be 'real-uuid-xyz', but the code's first find (UUID_RE.test) will fail, then the second find checks if it's in hostnameSet; 'real-uuid-xyz' is not a hostname, so it will be selected by the second fallback. The test passes, but it does not actually test the UUID preference; it tests the non-hostname fallback. The test name and comment claim it verifies UUID preference, but the fixture does not contain a real UUID. This is a test defect: the assertion passes for the wrong reason, so the UUID-preference branch is not actually exercised.

Change the fixture to a real UUID-shaped string, e.g., 'f81d4fae-7dec-11d0-a765-00a0c91e6bf6', to actually exercise the UUID_RE branch.

How this was verified: Checked the UUID_RE regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i. 'real-uuid-xyz' does not match because it has letters beyond hex and no hyphens in the right places. The test still passes because the second fallback selects it.

Files changed (4) — the diff as I read it
  • src/stores/buckets.ts — Adds logic in bucketsByDevice to select a device_id preferring UUID-shaped values, then non-hostname values, then the first entry.
  • src/views/Buckets.vue — Changes the ID label to render device.device_id and adds a guard for device.device_id existence.
  • test/unit/Buckets.test.js — Adds a static test asserting the template uses device.device_id and not device.id.
  • test/unit/store/buckets.test.node.ts — Adds unit tests for bucketsByDevice covering hostname fallback, UUID preference, case-insensitivity, and multiple device_ids.
Previous review passes
commit score findings engine when
c9977b376dbc 4/5 3 llm 2026-09-16 09:46 UTC
d2ec3d7c69be 4/5 2 llm 2026-09-16 10:41 UTC

Reviewed 716a184e9ea6 · openrouter/deepseek/deepseek-v4-flash-0731 · llm engine · 23s · about this reviewer

Maintainer commands

@TimeToBuildBob review (own line) — fresh review · @TimeToBuildBob fix — a worker acts on the findings. Once per comment; 👀 = received.

Comment thread test/unit/Buckets.test.js
Comment thread test/unit/store/buckets.test.node.ts
Comment thread src/views/Buckets.vue Outdated
… groups

When a hostname group contains both buckets without data.device_id (which fall
back to the hostname) and buckets with a real UUID, device_id was picking the
hostname fallback if it appeared first in device_ids[0]. The Buckets view then
hid the ID label because hostname === device_id.

Now we prefer any device_id that differs from the hostname, so partially
migrated device groups correctly surface the real UUID in the label.

Git-Session-Id: 37a7
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Fixed in d2ec3d7.

The root cause: when a hostname group had both buckets without data.device_id (falling back to hostname) and buckets with a real UUID, device_ids[0] could be the hostname fallback. The hostname !== device_id guard then hid the label even though a UUID was present in the group.

Fix: prefer any non-hostname entry in device_ids before falling back to device_ids[0]:

const device_id = device_ids.find(id => id !== hostname) || device_ids[0];

Added a test for the mixed-bucket case ('prefers real UUID over hostname fallback in mixed group').

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@ErikBjare You're right — I declared merge-ready while Greptile still had a P1. Mixed groups could pick the hostname fallback as device.device_id and hide a UUID that was already in the group. That's d2ec3d7. Greptile re-reviewed 5/5, CI green. Now actually waiting on a merge click.

Comment thread src/stores/buckets.ts Outdated
…e_id; guard ID label against empty device_id

Git-Session-Id: 2b238130-ce91-50d6-a8e6-4befe75fbe1a
Git-Session-Id: 2b238130-ce91-50d6-a8e6-4befe75fbe1a
Comment thread test/unit/store/buckets.test.node.ts
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Review cycle converged. Both remaining AI-review threads are now resolved (dispositions posted on-thread, no code change):

  • src/stores/buckets.ts fallback heuristic — the case-sensitivity half was fixed in 1d2562c; the residual (rendering a non-UUID data.device_id when the group has no UUID) is the intended behaviour — accepted trade-off, not a bug.
  • Mixed-group test fixture precision — the UUID-preference branch is covered by the adjacent real-UUID test, so no coverage gap remains.

Status: CI green, MERGEABLE/CLEAN, 0 unresolved threads. Maintainer merge only — Bob has pull-only access on ActivityWatch/aw-webui, so this still needs a maintainer click.

@ErikBjare
ErikBjare merged commit efb8d4d into ActivityWatch:master Sep 17, 2026
8 checks passed
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Merged as efb8d4dd — thanks. I rechecked the final state: all 8 checks passed, the mixed-group P1 is fixed, and the linked issue #982 is closed. Nothing remains on this PR; population of data.device_id is the separate ActivityWatch/activitywatch#302 lane.

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

Buckets.vue renders ID: undefined once data.device_id is populated; device-ID check is dead code

2 participants