Skip to content

fix(android): don't merge on 'title' key for aw-watcher-android buckets - #960

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/android-activity-view-zero-on-title-key
Sep 3, 2026
Merged

ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/android-activity-view-zero-on-title-key

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Problem

Regression from bf0fc84 ("fix(ios): screentime compatibility patch", 2026-07-24, #917):

- isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app"]);' : '',
+ isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "title"]);' : '',

aw-watcher-android events carry app, package, classnameno title key.
merge_events_by_keys in aw-server-rust skips any event missing a requested key (continue 'event), so this one change silently drops every Android event and the Activity view reports Time active: 0s + Top Applications: No data.

Measured on a live bucket (same bucket, same day):

Query Result
no merge 4878.8 s
merge_events_by_keys(events, ["app", "title"]) 0.0 s
merge_events_by_keys(events, ["app"]) 4878.8 s

The same "title" addition appears in appQuery's title_events step at line 240.

Not present in v0.14.0b2 (pins aw-webui 749585f, 2026-07-22 — two days before bf0fc84). Affects master builds and any aw-webui ≥ bf0fc84 that renders aw-watcher-android buckets.

Reported by Judemasic in ActivityWatch/aw-android#247, full analysis in #959.

Fix

Add an optional isIos?: boolean field to AndroidQueryParams. The appQuery() caller in activity.ts already detects the ScreenTime bucket (iosBucket) — it now passes isIos=true only for those buckets.

  • Android watcher path: merges on ["app"] / ["app", "classname"]
  • iOS ScreenTime path: unchanged — still merges on ["app", "title"] / ["app", "classname", "title"]

Tests

Added a regression test to test/unit/queries.test.node.ts verifying that:

  • appQuery(..., isIos=false) does not include "title" in merge keys
  • appQuery(..., isIos=true) does include "title" (iOS path unchanged)

Closes #959

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR restores source-specific event merging so Android events are retained while iOS ScreenTime title distinctions remain available.

  • Adds an isIos query parameter to select Android versus ScreenTime merge keys.
  • Propagates ScreenTime detection through activity categorization and Category Builder queries.
  • Adds regression tests for Android and iOS application and category query generation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/queries.ts Adds source-aware merge keys and preserves ScreenTime titles without dropping title-less Android events.
src/stores/activity.ts Detects the selected ScreenTime bucket and consistently propagates its source type to application and category queries.
src/views/settings/CategoryBuilder.vue Passes ScreenTime source information into canonical event generation for title-aware categorization suggestions.
test/unit/queries.test.node.ts Adds regression coverage confirming distinct Android and ScreenTime merge-key behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  B[Selected mobile bucket] --> D{ScreenTime bucket?}
  D -->|Yes| I[Set isIos true]
  D -->|No| A[Use Android defaults]
  I --> T[Merge by app and title]
  A --> M[Merge by app]
  T --> C[Categorization and summaries]
  M --> C
Loading

Reviews (2): Last reviewed commit: "fix(android): pass isIos to categoryQuer..." | Re-trigger Greptile

Comment thread src/queries.ts
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.33333% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.25%. Comparing base (7141e39) to head (08b925c).

Files with missing lines Patch % Lines
src/stores/activity.ts 0.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #960      +/-   ##
==========================================
+ Coverage   49.62%   50.25%   +0.62%     
==========================================
  Files          46       46              
  Lines        2783     2790       +7     
  Branches      597      635      +38     
==========================================
+ Hits         1381     1402      +21     
+ Misses       1381     1309      -72     
- Partials       21       79      +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.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

The CI failure is not caused by this PR's changes — all 246 tests passed in the failing job.

The failure is in the post-test "Print server logs to console" step, which exits non-zero because ~/.cache/activitywatch/log/*/*.log doesn't exist when aw-server-rust master is used. The same failure appears in another unrelated PR run today (run 33693702863), confirming this is a pre-existing CI infra issue.

The other two matrix variants (aw-server-rust v0.12.3b18 and aw-server v0.12.3b18) passed cleanly. The log-collection step likely needs continue-on-error: true in the workflow YAML, but that's a separate fix from this PR.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Root-caused and fixed in #962.

The aw-server-rust master leg started failing because ActivityWatch/aw-server-rust#652 (named instance profiles, merged 2026-08-31) changed get_user_log_dir() from a hardcoded activitywatch root to appname(). On a fresh runner with no legacy testing data, aw-server --testing now logs under ~/.cache/activitywatch-testing/, so the hardcoded ~/.cache/activitywatch/log/*/*.log glob in the log-collection steps matches nothing and the step exits 1.

That is exactly why only this leg fails: the v0.12.3b18 legs run released pre-#652 binaries and still use the old root.

#962 globs both roots (restoring the diagnostics, which have been silently empty — note the No files were found with the provided path: logs/dist/* warning) and adds a nullglob guard so these always()-gated diagnostic steps can no longer fail the job. This PR needs no changes; rebase or re-run once #962 lands.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Closed duplicate #964 in favor of this source-aware fix: #964's unconditional classname key would drop iOS ScreenTime events lacking that field. I also resolved the already-addressed Greptile thread here.

#960 remains the canonical fix. Its only red check is the pre-existing log-collection failure fixed and proven green in #962; I attempted a failed-job rerun, but this account lacks the repository admin permission GitHub requires for reruns.

TimeToBuildBob and others added 2 commits September 3, 2026 06:49
aw-watcher-android events carry 'app', 'package', 'classname' but NOT
'title'. merge_events_by_keys skips events missing any requested key, so
the 'title' key added in bf0fc84 (for iOS ScreenTime compatibility)
silently collapsed all Android Activity data to 0s.

Fixes by gating the 'title' merge key on isIos (new optional field on
AndroidQueryParams). The appQuery() caller in activity.ts already has
iosBucket detection; it now passes isIos=true only for ScreenTime buckets.

Verified against live bucket data (ActivityWatch#959):
  merge on ['app', 'title'] → 0.0 s
  merge on ['app']          → 4878.8 s (actual data)

Regression from bf0fc84 (2026-07-24, iOS ScreenTime patch ActivityWatch#917).
Not present in v0.14.0b2 (pins aw-webui 749585f, pre-regression).
Affects master builds and any aw-webui >= bf0fc84 rendering Android buckets.

Closes ActivityWatch#959

Git-Session-Id: b5092fb7-a3f0-5a15-8da3-fd21d8d7f2a8
…ime callers

The primary appQuery path was fixed in the initial commit, but two callers
still omitted isIos when passing an aw-import-screentime bucket to categoryQuery
(via query_category_time_by_period) and canonicalEvents (via CategoryBuilder).
Without isIos=true, canonicalEvents merges iOS events only by ['app'] instead
of ['app', 'title'], losing title distinctions before category assignment and
phrase extraction.

Fix:
- activity.ts query_category_time_by_period: detect iosBucketForCategory and
  pass isIos: !!iosBucketForCategory alongside bid_android in the categoryQuery params
- CategoryBuilder.vue: pass isIos: !!screentimeBucket in the bucketParams spread

Tests: add categoryQuery merge key regression describe block covering both
Android (no title) and iOS (with title) paths.

Git-Session-Id: b5092fb7-a3f0-5a15-8da3-fd21d8d7f2a8
@TimeToBuildBob
TimeToBuildBob force-pushed the fix/android-activity-view-zero-on-title-key branch from be4a200 to 08b925c Compare September 3, 2026 06:50
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

#962 is merged. I rebased this branch onto it, which triggered fresh CI with the log-collection fix included. The local node suite passes (162 tests); waiting for the fresh GitHub checks and maintainer review/merge.

@TimeToBuildBob

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

@ErikBjare
ErikBjare merged commit 85db7b5 into ActivityWatch:master Sep 3, 2026
8 checks passed
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.

On Android, the Activity view reports Time active: 0s

2 participants