Skip to content

Fix issues#4

Merged
Tricked-dev merged 37 commits into
masterfrom
fix/review-findings
Jul 12, 2026
Merged

Fix issues#4
Tricked-dev merged 37 commits into
masterfrom
fix/review-findings

Conversation

@Tricked-dev

Copy link
Copy Markdown
Owner

No description provided.

Tricked-dev and others added 30 commits July 11, 2026 18:05
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>
Tricked-dev and others added 7 commits July 12, 2026 05:48
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>
@Tricked-dev Tricked-dev merged commit cd813e2 into master Jul 12, 2026
1 check failed
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