Fix issues#4
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses spec-review round 1: bases captured for STOP/UPDATE/DELETE pre-mutation, oldest-base reuse for op chains, delete-conflict resolution actions, edit-lock with stop exception, paginated window fetch with documented residual risks, epoch-millis canonical comparison, auth-time template claim, horizon semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Foundation for SV-027 conflict detection: a content-based snapshot of the conflict-relevant time-entry fields (start/end parsed leniently to epoch millis with raw-string fallback, description, projectId, taskId, billable, sorted tagIds), since the Solidtime API has no updated_at/version/ETag to compare instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sorted-tags comparison in matches() (canonicalization enforced at compare time), clarified DELETED_MARKER sentinel KDoc, asymmetric-parseability and direct-construction tests, strict equality on JSON round-trip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add SyncState.CONFLICT, OutboxEntity.baseSnapshotJson (last server-acked content a local edit was based on), and TimeEntryEntity.conflictServerJson (full server TimeEntry JSON captured as "theirs" at conflict-detection time). Bumps Room schema to v5 with MIGRATION_4_5 adding both nullable TEXT columns. Schema-only change for SV-027 sync-conflict detection; later tasks populate these columns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements SV-027's base-snapshot capture rules for content-based conflict detection: STOP/UPDATE/DELETE enqueues now record the pre-mutation entity content (or reuse an already-queued base, or leave it null for locally-created entries) inside the same transaction, before the local mutation lands. START/CREATE remain base-less as specced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Thread the account TemporalPolicy (zone + firstDayOfWeek) through the statistics range resolution and aggregation instead of ZoneId.systemDefault and WeekFields.ISO: - StatRange.resolve now takes firstDayOfWeek; week-based variants compute the week start with WeekFields.of(firstDayOfWeek, 4), so Monday reproduces the ISO week start exactly and e.g. Sunday-start accounts bucket on Sunday. - StatisticsAggregator.compute/buildTrend take firstDayOfWeek; the WEEK branch uses WeekFields.of(firstDayOfWeek, 4) — minimal-days pinned to ISO's 4 so Monday reproduces the W## week numbers byte-for-byte. - StatisticsViewModel injects TemporalPolicyProvider and drives range resolve, remote-fetch bounds and aggregation from the policy flow (zone AND firstDayOfWeek); no ZoneId.systemDefault in these files. Regression guard: existing Monday/UTC assertions unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Calendar, review and tracking display/pick surfaces now derive day/week boundaries from the account TemporalPolicy (zone + firstDayOfWeek) instead of ZoneId.systemDefault()/WeekFields.of(Locale...). ViewModels inject TemporalPolicyProvider, seed a first-frame-correct zone from current(), and keep it current via the policy flow; composables read the zone from uiState. Reminder scheduling stays device-local and is untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SV-005 T4.1: a fresh Review inbox no longer dumps the full historical
backlog. InboxSettingsDataStore gains horizonStartMs/horizonChosen (both
device-scoped, preserved across logout) with a setHorizonStart setter.
A pure resolveHorizonStartMs() maps the choice to an inclusive lower
bound: not-chosen -> start of today; chosen+null -> now-370d
("Everything", aligned with the gap cap); chosen+X -> X.
InboxAnalyzer.analyze/count take horizonStartMs and drop any issue whose
window ends before it (straddling windows kept); gap generation is
bounded by max(horizon, now-370d) so it never widens past the cap.
CONFLICT issues are DB-derived and added by the view-model, so they are
never subject to the clamp. Both the badge repository and the inbox
view-model resolve the horizon from settings and pass it, so the badge
count follows the same policy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The VM launches coroutines on viewModelScope (Dispatchers.Main.immediate) — the init policy collector and the uiState pipeline (which hop to Dispatchers.IO/Default and post continuations back to Main). These outlive the runTest body; a straggler racing @after's resetMain() intermittently threw 'Dispatchers.Main is used concurrently with setting it'. Teardown now cancels each VM's scope (cancelAndJoin via a @VisibleForTesting seam, since ViewModel.clear() is internal in lifecycle 2.8.x) and drains the scheduler before resetMain(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split the single per-org sync freshness moment into the sources that are genuinely distinct in this codebase (roadmap #35, #79), as the data-layer foundation for the sync-center screen (#33). - SyncMetaEntity: add nullable lastPushAtMs (last successful outbox flush); keep lastFullSyncAtMs as the pull-refresh moment (catalog+history share one honest moment). No active-timer column: that fetch is account-wide and ephemeral, so a per-org timestamp could not be populated honestly. - Room v7 + MIGRATION_6_7 (additive nullable column); export 7.json. - SyncMetaDao: observe() Flow for #33; stampFullSync/stampPush use insert-if-absent + single-column UPDATE so pull and push never clobber each other. - refreshAll stamps via stampFullSync; SyncWorker stamps lastPushAtMs per org that had at least one op reach the server (not on retry/fail/superseded). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a full-screen Sync Center (#33) surfacing freshness (last pull / last push), a plain-language status summary, pending changes, and failures with per-item Retry / Discard plus Retry All and Sync now. Reuses the existing outbox retry/discard/refresh actions; adds no new sync control flow. Reached from the Track screen's sync summary via a new SyncRoutes.SYNC_CENTER destination. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Debounce the app-foreground full refresh on wall-clock so returning to the app (or a rapid start/stop) within a few seconds reuses the just- fetched data instead of re-hitting the network, and flush pending local changes via SyncTrigger.requestSync() on the same schedule. Reuses the existing loadAllData/refreshAll fetch path and the existing Track-screen refresh affordance (pull-to-refresh + app-bar refresh action). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Roadmap #49: privacy-reviewed diagnostic bundle (app/Android version, sanitized server host, categorized recent sync errors). No settings UI yet — #48 wires the button. Redaction is by construction: the pure DiagnosticBundle core takes only primitives and already-categorized DiagnosticFailure records, so it has no parameter through which a raw error, token, description or project name could reach the output. Raw outbox errors are bucketed via classifyOutboxError (mirrors the #33 Sync Center classifier) before the formatter ever sees them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a Privacy & data-management screen (#48) that explains what is stored locally, what is sent to the selected server, how tokens are protected, and which optional permissions enable notifications/calendar. Provides controls to export diagnostics (#49), clear the re-syncable cache without logout, and log out / revoke the local session, each behind a confirmation for destructive actions. Reuses existing primitives: UserCacheCleaner.clear for the safe cache wipe, DiagnosticExporter for the bundle, and the host's existing logout path. Storage usage sums the Room DB file (+wal/shm/journal) and cache dir off the main thread. Strings in en/nl/ja; status shown with text + icons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The assertion relied on the default endpoint, but AuthDataStore is a process-wide on-disk DataStore, so another test class persisting a custom endpoint made it fail in the full suite (passed in isolation). Set an explicit endpoint in the test instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add repository actions to duplicate a completed entry and split it at a chosen time, reusing createCompletedEntry/updateEntry so both go through the existing outbox (no sync bypass) and preserve all metadata + tags. - duplicateEntry: straight copy (same start/end/metadata); refuses running and CONFLICT (SV-027 edit-lock) entries. - splitEntry: shortens the original to end at `at` and creates a new entry for [at, end]; validates strictly-interior instant (half-open, roadmap #64: at==start / at==end rejected); returns the second-half id. - UI: Duplicate/Split actions in the edit sheet, shown only for completed, editable entries; split picker constrained to the open (start,end) interval; on success the new/second-half entry opens for editing. - Strings x3 locales (en/nl/ja). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.