Repository navigation
feat(dirs): content-based DB selection when both Local and Roaming have data - #811
TimeToBuildBob wants to merge 6 commits into
Conversation
…ve data When both Local (%LOCALAPPDATA%) and Roaming (%APPDATA%) hold a database, choose by actual content rather than location: - Newest event starttime (nanoseconds) wins - Tiebreak: higher event count, then prefer Local This fixes the v0.14.1 behaviour where a stale Local test database (e.g. from a months-old Rust server trial) was chosen over months of v0.14.0 Roaming data just because it existed. Implementation: - `db_newest_starttime`: read-only rusqlite query on the default .db file - `db_event_count`: fallback count query for equal-timestamp ties - `choose_module_dir` updated with new rule at the top (both-have-db path) - rusqlite moved from dev-dependencies to dependencies (needed for production content inspection in dirs.rs, not just tests) Three new regression tests: - test_content_selection_prefers_newer_roaming_over_stale_local (the main bug) - test_content_selection_keeps_newer_local (normal upgrade path unchanged) - test_content_selection_ties_prefer_target (tie -> Local wins) All 27 existing dirs tests continue to pass. Ref: ActivityWatch#810. Git-Session-Id: 849ddd14-acf6-4e72-a036-5b264987c5d5
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #811 +/- ##
===========================================
+ Coverage 70.81% 84.76% +13.95%
===========================================
Files 51 82 +31
Lines 2916 11560 +8644
===========================================
+ Hits 2065 9799 +7734
- Misses 851 1761 +910 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Git-Session-Id: a00ed855-0005-5c4f-9b1f-563ebb4467ff
Git-Session-Id: a00ed855-0005-5c4f-9b1f-563ebb4467ff
🤖 AI code reviewSafe to merge — 2 findings disposed (accepted-tradeoff; rejected)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
Adds content-based directory selection in aw-server/src/dirs.rs: when both Local and Roaming contain a .db, it opens the profile-specific database read-only, runs PRAGMA quick_check, and compares (MAX(starttime), COUNT(*)) to choose between DirChoice::Target and DirChoice::Misplaced. resolve_or_migrate now returns the Roaming path without copying when the chosen database already exists in Local, and a test-only thread-local signals migration-lock contention. rusqlite moves from dev-dependencies to regular dependencies. Not safe to merge — 1 P1 openConfidence 3/5 1 finding · ❌ 1 P1❌ P1 high — When both dirs hold some How this was verified: The early-return condition only looks at the directory, not the filename; a target with only Consensus: 2/3 passes agreed — pass 3 looked and disagreed 1 advisory finding (summary-only, not scored)These P2 guard, heuristic, trade-off, or documentation claims are retained for judgment without opening review threads.
database_rank counts rows and picks MAX(starttime) from the profile database without restricting to any particular bucket, but the real aw-datastore events table can contain events whose starttime is 0 or NULL? Actually starttime is NOT NULL in the schema, and the comparison uses (MAX(starttime), COUNT()) across all buckets. A stale Local database that holds event rows for a long-running bucket (e.g. a bucket whose last event is old but which also contains many non-activity events) can be ranked as having a higher count than a newer Roaming database when timestamps tie. The tie-breaker prefers higher COUNT() over Local. If both databases have the same newest timestamp (which happens when one database contains a later event in a rarely-written bucket and the other contains many events all ending at the same time), the choice picks the side with more rows even when the other side's recent activity is more relevant. This does not violate the stated selection contract, but it can select a database that is not the 'newest history' the PR claims to prefer. How this was verified: Traced the (t,m) arm in choose_module_dir_for_database and the test test_content_selection_unreadable_local_is_not_empty which writes a non-SQLite file to target and asserts Target is returned. Consensus: 2/3 passes agreed — pass 2 looked and disagreed Files changed (2) — the diff as I read it
Previous review passes
Reviewed Maintainer commands
|
|
@greptileai review |
|
Pushed fe75fcc and 6612e19 through the in-band review wrapper, addressing all four Greptile findings: timestamp/count ties, intended profile filename, unreadable/encrypted Local fallback, and repeated occupied-target copying. Occupied-target selection now also waits for the migration lock and rechecks the choice. Verification: 91 server-library tests passed, 1 ignored; production-library Clippy and formatting passed. Added regression coverage for uncheckpointed WAL events, corrupt/empty databases, profile filenames, count ties, unreadable Local, zero copy calls, and lock/recheck behavior. Test-target Clippy on installed Rust 1.99 flags a pre-existing initializer lint in extension_cors.rs; that unrelated file is unchanged. Replied to and resolved all four original Greptile threads, then requested one fresh review via the helper. The two in-band findings were disposed with explicit reasons: conservative inspection failure is an accepted recovery tradeoff, and the claimed post-lock migration ignores the occupied-target guard. No open findings of ours remain; new-head CI/review is pending. This remains selection-only, not the complete v0.14.2 recovery in #810. Both histories remain intact, but automatic merging, occupied-Local rename-aside, durable Python-import recovery, Tauri pins, and release verification are still outstanding. Corrected the PR body so it no longer claims to close that issue. |
Git-Session-Id: 7d511d8d-5ab3-5449-b46e-1c9cdf23ccd0
|
@greptileai review |
|
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. |
…shake Git-Session-Id: 10ab49d8-b2e1-5795-aceb-e8704c4e98d8
Git-Session-Id: 3e718532-a9df-53c3-a0c4-d8f8868d6ead
|
@greptileai review |
Problem
When both Windows Local and Roaming directories contain databases, always choosing Local can hide months of v0.14.0 history behind a stale Local test database.
Scope: selection only
Partial progress on #810; does not close that issue. This PR chooses which existing database to use. It does not merge histories, rename an occupied Local database aside, persist Python-import recovery, or update the Tauri lock. Those remain in the issue's recovery task.
When Roaming wins and Local already contains a database, the server uses Roaming in place and leaves both originals untouched. It skips the migration copy that would necessarily fail against an occupied Local target. Roaming-only migration remains unchanged.
Selection
sqlite.db, or legacysqlite-testing.db), not the first arbitrary.dbin a directory.PRAGMA quick_checkto succeed.(MAX(starttime), COUNT(*))lexicographically: newest timestamp, then higher count, then Local.Verification
Regression coverage includes newer Roaming, newer Local, equal timestamps with unequal counts, complete ties, default versus legacy testing filenames in the same directories, both empty, empty Local versus populated Roaming, corrupt Roaming, unreadable Local, and zero copy calls when Local is occupied.
Three new regressions failed against the original implementation (count tie, unreadable Local, occupied-target copying) before the fix, then passed. All 32 directory tests pass locally.
Production library Clippy and the full server-library test results are recorded in the follow-up review comment. The installed Rust 1.99 test-target Clippy additionally flags a pre-existing
field_reassign_with_defaultinendpoints/extension_cors.rs; that unrelated file is unchanged.