Skip to content

fix(query): don't modify events that other query variables still hold - #172

Merged
ErikBjare merged 2 commits into
masterfrom
fix/period-union-mutation
Sep 26, 2026
Merged

ErikBjare merged 2 commits into
masterfrom
fix/period-union-mutation

Conversation

@ErikBjare

@ErikBjare ErikBjare commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Found while measuring the query parity suite (ActivityWatch/activitywatch#1467) for the ActivityWatch/activitywatch#1466 changes. Query variables share Event objects, and several transforms modified their input events in place, so one variable's events changed when another was transformed. aw-server-rust has value semantics, so the servers disagreed on the canonical queries.

period_union cleared .data on the events it returned, and events it didn't merge were the input objects themselves. aw-client's and aw-webui's always_active_pattern query does

not_treat_as_afk = filter_keyvals_regex(events, "app", "Slack|Terminal");  // same objects as `events`
not_afk = period_union(not_afk, not_treat_as_afk);
events = filter_period_intersect(events, not_afk);

so Slack/Terminal window events lost app and title and were categorized Uncategorized. It now returns new events.

categorize, tag, split_url_events set keys in event.data in place. In aw-webui's multideviceQuery (not_afk = events; events = categorize(events, ...)), the Android events in not_afk got $category too. The query wrappers now pass copies: a new Event and data dict per event, which is all these transforms modify. The aw_transform functions themselves are unchanged.

I checked the other query transforms for input mutation (flood, merge, chunk, sort, limit, filters, union_no_overlap, concat, simplify): they don't modify their inputs.

Tests: test_period_union_does_not_modify_inputs, and a query-level test covering all three transforms plus the always_active pattern on every datastore. Both fail before the fix. 308 passed locally.

Parity: on top of the #1466 PR (#173), this fixes 64 more canonical-query cases: aw-client fullDesktopQuery+always_active/+browser and webui multidevice (from 451 known failures to 166 with both PRs). The remaining multidevice-webui-android-merge cases come from aw-server-rust's merge_events_by_keys returning HashMap order (ActivityWatch/aw-server-rust#757).

period_union cleared .data on the events it returned, and events that
weren't merged with another were the input objects themselves. Queries
share event objects between variables (filter_keyvals_regex returns the
same objects), so e.g. aw-client's always_active_pattern query

  not_treat_as_afk = filter_keyvals_regex(events, "app", "Slack");
  not_afk = period_union(not_afk, not_treat_as_afk);
  events = filter_period_intersect(events, not_afk);

wiped app/title from the Slack window events in 'events'. aw-server-rust
doesn't mutate its inputs. Return new events instead.
…er variables' events

Query variables share Event objects (`other = events;`, or a filter that
returns the same objects), and categorize, tag and split_url_events set keys
in event.data in place. So in aw-webui's multidevice query

  not_afk = events;
  events = categorize(events, ...);

the Android events in not_afk got $category as well. aw-server-rust has
value semantics. The query wrappers now pass copies (a new Event and data
dict per event, which is all these transforms modify).
@ErikBjare

Copy link
Copy Markdown
Member Author

@greptileai review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T21:44:17.366938Z 05719b8 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Fixes event mutation bug in query transforms.

The PR appears safe to merge; no actionable regression was identified.

Summary

The PR prevents query transforms from changing Event objects still held by other variables.

  • Copies events before categorization, tagging, and URL splitting.
  • Makes period_union return new, data-free events rather than clearing input data.
  • Adds transform-level and query-level regression tests.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Shared input events] --> B[Copy event and data dictionary]
    B --> C[Categorize, tag, or split URL]
    A --> D[Other query variable remains unchanged]
    A --> E[period_union]
    E --> F[New events with empty data]
Loading

Reviews (1) · Last reviewed commit: "fix(query): don't let categorize, tag an..."

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