Skip to content

fix(transform): port aw-core's flood() so both servers agree - #748

Merged
ErikBjare merged 2 commits into
masterfrom
fix/flood-parity
Sep 26, 2026
Merged

ErikBjare merged 2 commits into
masterfrom
fix/flood-parity

Conversation

@ErikBjare

@ErikBjare ErikBjare commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Fixes #746.

ActivityWatch/aw-core#143 fixed ActivityWatch/activitywatch#1369 (flood leaving overlapping events, so time was counted twice) in aw-core only. The Rust flood() still let overlapping events with different data through, and differed from aw-core in a few other ways found by the parity suite in ActivityWatch/activitywatch#1467. This ports aw-core's flood() so both servers return the same events.

Changes

  • Overlap (activitywatch#1369): a normalization pass after the pairwise pass, as in aw-core. Where events with different data overlap, the later one wins and the earlier one is cut at its start, so the output never overlaps. Same-data overlaps merge.
  • Zero-duration events are dropped, as in aw-core.
  • Gap equal to pulsetime is now filled (gap <= pulsetime, was <).
  • Optional pulsetime: flood(events, 10) now works in queries. The default stays 5 s. Negative or non-finite values are an error.
  • Events are sorted by (timestamp, duration), like aw-core.
  • Gaps between differing events are still split at the midpoint, and overlaps under 100 ms between differing events are split the same way (aw-core's negative_gap_trim_thres).
  • Chains of same-data events (e.g. three adjacent 10 s events) merge into one event. aw-core's pairwise pass leaves a merged-away event as a zero-duration placeholder, and its normalization only merged overlapping events, so chains came out as adjacent pieces. The old Rust code merged them. Normalization now also merges touching same-data events, here and in fix(transform): merge adjacent same-data events in flood() aw-core#165 (found by Greptile and Codex in review).

Item 5 in the issue (adjacent same-data events) was an aw-core bug: aw-core skipped zero gaps and didn't merge them. Rust's result was the intended one, so this keeps it, and ActivityWatch/aw-core#165 fixes aw-core.

One behaviour change worth noting: an event with different data contained in a longer event now truncates the longer one at the contained event's start. The tail of the longer event is dropped, as in aw-core. test_flood_containing_diff is updated to that.

Tests

  • The repros from flood() diverges from aw-core: overlapping events, zero-duration events, gap == pulsetime, no pulsetime arg #746: overlap, zero-duration, gap equal to pulsetime, gap just above it, custom pulsetime, adjacent same data.
  • Small negative gap split, a later event overlapping several earlier ones, chains of same-data events, and randomized inputs checked for no overlap, no zero-duration output and no unmerged adjacent same-data events.
  • Every expected result in the new tests was checked against aw-core's flood() on the same input.
  • A query test checks the effect of the pulsetime argument (default, 6.5, 7, 10.5) and rejects a negative one.

cargo test -p aw-transform -p aw-query, cargo clippy --workspace -- -D warnings and cargo fmt --check pass locally.

Parity suite (ActivityWatch/activitywatch#1467)

Run locally against a release build of this branch:

Independent of #744 and #749: no shared code.

aw-core's flood() was fixed in ActivityWatch/aw-core#143 so that its
output never double-counts time (ActivityWatch/activitywatch#1369), but
the Rust flood() still let overlapping events with different data
through. Port aw-core's algorithm:

- a pairwise pass that merges same-data events and splits gaps between
  differing events at the midpoint, for gaps up to and including
  pulsetime (was: strictly less than)
- a normalization pass in which the later of two overlapping events
  with different data wins, and zero-duration events are dropped
- sort by (timestamp, duration) like aw-core

The flood() query function now takes an optional pulsetime in seconds,
defaulting to 5 like aw-core.

Fixes #746
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

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-26T17:12:23.169579Z e780b24 New commits
ℹ️ 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.

@ErikBjare

Copy link
Copy Markdown
Member Author

@greptileai review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7324b3285b

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread aw-transform/src/flood.rs
@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Adds optional pulsetime parameter to the flood function.

The PR appears safe to merge; the previous findings are fixed and no new actionable issue was identified.

Summary

The PR aligns Rust flood() with aw-core for overlaps, zero-duration events, gap thresholds, and optional query pulsetime. The latest changes merge touching same-data chains and add assertions for the resulting event durations. Both previous findings are fixed.

Reviews (2) · Last reviewed commit: "fix(transform): merge chains of same-dat..."

Comment thread aw-transform/src/flood.rs
Comment thread aw-query/tests/query.rs Outdated
The pairwise pass leaves a merged-away event as a zero-duration
placeholder at the end of the merged event, so a chain of same-data
events (e.g. three adjacent 10 s events) came out of normalization as
adjacent pieces. Merge touching same-data events in normalization too,
like ActivityWatch/aw-core#165.

Also check the pulsetime argument's effect in a query test.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e780b24a67

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread aw-transform/src/flood.rs
@ErikBjare

Copy link
Copy Markdown
Member Author

@greptileai review

@TimeToBuildBob

TimeToBuildBob commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AI code review

This PR ports aw-core's flood() behavior into the Rust aw-transform crate, adding a normalization pass to eliminate overlapping events, dropping zero-duration events, filling gaps up to and including pulsetime, and adding an optional pulsetime argument to the flood query function. It also updates the flood tests and adds new tests for the new behavior, including randomized no-overlap checks.

Safe to merge — no P0/P1 findings

Confidence 5/5

✅ No findings. The diff looks correct to me on this pass.

Files changed (3) — the diff as I read it
  • aw-query/src/functions.rs — Adds optional pulsetime argument to flood query function, validates it as non-negative finite seconds, and converts to Duration.
  • aw-query/tests/query.rs — Adds test_flood_pulsetime to verify default and custom pulsetime behavior and rejection of negative values.
  • aw-transform/src/flood.rs — Rewrites flood() with pairwise pass plus normalization pass, sorting by (timestamp, duration), dropping zero-duration events, and merging same-data events.

Reviewed e780b24a6742 · openrouter/deepseek/deepseek-v4-flash-0731 · llm engine · 44s · about this reviewer

Maintainer commands

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

@ErikBjare
ErikBjare merged commit 84d69e0 into master Sep 26, 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

2 participants