Counter test helpers assumed mobile layout (.mobile-dropdown-wrapper)
but simulated clients use 1920x1080 viewport where counters render
inline in .counters-action-group.
- Remove serial mode and networkidle waits in legacy migration tests
- Reduce optional conflict dialog timeout from 5s to 2s
- Add dialog handler for Client B in first-sync-conflict USE_REMOTE test
- Add delay before sync check and lower threshold in burst sync test
- Add waitForArchivePersistence in concurrent same-task archive test
- Use closeContextsSafely, increase keyboard timing, and add
waitForStatePersistence in today-tag reorder tests
planTaskForDay set dueDay and cleared dueWithTime but left remindAt
untouched. The reminder worker kept firing for the past remindAt value,
causing the reminder popup to reopen in a loop after "Reschedule for
tomorrow".
The getByRole('switch', { exact: true }) selector is case-sensitive.
The test labels used Title Case but the actual accessible names from
en.json translations use sentence case, causing intermittent failures.
The devError module has shared mutable state (isShowAlert flag) that
caused flaky test failures in America/Los_Angeles timezone. Add a
test-only reset function and call it before the affected test.
- Extract executeNativeRequestWithRetry and isTransientNetworkError into
shared native-http-retry.ts for reuse by Dropbox and SuperSync
- Add locale-proof error.code checks: iOS NSURLErrorDomain, Android
SocketTimeoutException/UnknownHostException/ConnectException
- Keep English string matching as fallback for web/Electron
- Wrap Dropbox token refresh in retry logic
- Split timeouts: 30s for auth endpoints, 120s for data transfer
- Apply retry wrapper to SuperSync _fetchApiNative and _fetchApiCompressedNative
The reducer unconditionally prepended payload taskIds into state.ids
without checking entity existence. During op-log replay or concurrent
effects, deleted task IDs could be re-injected as orphans, causing
TypeErrors on properties like dueWithTime and dueDay.
Validates both duplication paths that were fixed: download path
(recentOps re-applied on second sync cycle) and piggyback path
(snapshot ops returned during upload).
iOS CapacitorHttp uses URLSession.dataTask which does not auto-retry POST
requests. Large sync payloads crossing the WKWebView bridge are vulnerable
to TCP connection drops (NSURLErrorNetworkConnectionLost / -1005).
- Add _executeNativeRequestWithRetry() with max 2 retries and linear backoff
- Add _isTransientNetworkError() classifier for iOS NSError descriptions
- Increase readTimeout from 60s to 120s for all native CapacitorHttp calls
- Add comprehensive unit tests for error classification and edge cases
Closes#6333
PFLog was named after "Pfapi" which is no longer used. Replace with
SyncLog in sync provider files and OpLog in op-log infrastructure files.
Delete unused migration scripts.
When a fresh client first syncs with a file-based provider (WebDAV,
Dropbox, LocalFile), it receives both a snapshotState and recentOps.
The snapshot was hydrated correctly, but recentOps were not recorded,
causing duplication through two paths:
1. Download path: On the next sync cycle, recentOps bypassed the
appliedOpIds filter (not in IndexedDB) and were re-applied.
2. Piggyback path: The adapter's isForceFromZero guard skipped marking
ops as processed, so they were returned as piggybacked during upload.
Fix by writing recentOps to IndexedDB after snapshot hydration and
always marking downloaded ops as processed for piggyback tracking.
The WCO padding-right rule matched on macOS where window controls are
on the left side, causing header icons to be pushed ~140px inward.
Restrict the rule to non-Mac Electron using the isNoMac body class.
Closes#6337
Counter buttons were always behind a dropdown toggle after the habits
management page change. Restore inline rendering on desktop and restrict
the timer-icon dropdown to mobile viewports only.
* Fix long break condition calculation
Adjust calculation for long break condition to account for cycle update.
* Undo Previous Change to getBreakDuration
* Move fix To Focus-Mode.effects
Adjust break duration calculation to account for cycle increment.
* Fix formatting of getBreakDuration calculation
* fix Test(pomodoro-bug-6044): Change test cases to be correct
* fix(Focus-Mode-Session-done): Subtract 1 from cycle to get last cycle
* Fix Test(focus-mode-effect.spec): Verify decrement of cycle
* Fix(focus-mode.effect.ts): Make comments clearer
* Fix(Pormodoro-Bug-6044.spec): Update tests names
* fix(focus-mode-effects.ts): Fix Missed tests
* Add(fpcis-mode-session-done): add || 1 Guard
* Fix Linting and formatting
* fix(focus-mode.effects.spec.ts): update cycle number for manual break duration calculation
- fix(tasks): preserve selectAllTasks memoization by only filtering when
undefined entities exist, avoiding new array allocation on every call
- fix(sync): replace mutable ARGON2_PARAMS export with getter/setter to
prevent test pollution across spec files
- fix(sync): convert tag-task-page from async pipe to toSignal pattern
to fix OnPush change detection after bulk sync state updates
- fix(sync): remove E2E navigation workarounds that masked the rendering
bug now fixed by the toSignal conversion
- fix(sync): add clarifying comments for archive-wins sibling conflict
resolution and waitForSyncWindow switchMap concurrency semantics
- fix(ios): add hex preview of first 16 bytes to WebDAV UTF-8 decode
error for easier debugging
- docs: add JSDoc to getDiffInWeeks noting negative diff behavior
https://claude.ai/code/session_01Y51QDFEdvrJ9VVgp9XfWLJ
Co-authored-by: Claude <noreply@anthropic.com>
Remove unused _counterTitle parameter from counter helpers, replace
hardcoded waitForTimeout with visibility check, unify timeout strategy
to test.slow(), fix waitForSyncToComplete API call, add
skipConflictDetection for forceDownloadRemoteState, and clean up
package-lock.json.
- Use toEntityKey() utility instead of inline template strings
- Fix stale mock in remote-ops-processing.service.spec.ts to match
new _buildEntityFrontier logic (appliedFrontier !== undefined)
- Fix transient entity resurrection: non-archive conflicts for
locally-archived entities now resolve as local-wins (no localWinOp)
instead of remote-wins, preventing addOne() from resurrecting entities
- Add unit test for multi-conflict pre-scan scenario
- Add TODO comments for Angular reactivity navigation workarounds
Fix two sync bugs causing E2E test failures:
1. Archive-wins pre-scan: When an entity has multiple conflicts (e.g.,
field updates + archive), the archive op was only checked per-conflict.
Non-archive conflicts resolved via LWW, creating local-win update ops
that resurrected archived entities. Now pre-scans ALL conflicts to
build entity-level sets, so all conflicts for an archived entity
resolve as archive-wins.
2. Entity frontier for new entities: When snapshotEntityKeys was undefined
(old format), _buildEntityFrontier used the snapshot vector clock for
ALL entities, inflating the frontier for genuinely new entities never
seen locally. Remote ops for these entities were incorrectly discarded
as superseded. Now only uses snapshot clock when appliedFrontier exists
for the entity.
Also improves E2E tests with navigation-based component refresh and
Playwright auto-retry assertions (toHaveCount with timeout).
Extract Argon2 params into mutable exported constant so tests can use
minimal KDF settings (8 KiB memory, 1 iteration) instead of production
values (64 MB, 3 iterations). Add batch operation creation helper and
configurable download limit to SimulatedClient, reducing test op counts
from 500-1000 to 50-100 while still exercising pagination.
Use immutable `created` timestamp instead of mutable `dueDay` for
duplicate detection in task-repeat-cfg.service.ts. The old check
used dueDay which gets mutated by planTasksForToday when users
reschedule overdue tasks, causing false-positive duplicate matches.
Replace filter-and-drop with waitForSyncWindow operator in all three
TaskDueEffects so day-change emissions during hydration/sync are
deferred rather than permanently lost.
Add waitForSyncWindow reusable RxJS operator and expose isInSyncWindow
as a computed signal + observable on HydrationStateService.
Use inline-flex centering on the mat-icon to align the font glyph
to the geometric center of its bounding box, and promote the spinning
element to a GPU compositing layer via translateZ(0) to prevent
sub-pixel anti-aliasing shifts during rotation.
Closes#6318
exitBreakToPlanning resets focus session state but had no effect to stop
tracking, leaving it running orphaned. Add effect to dispatch
unsetCurrentTask() when isSyncSessionWithTracking is enabled.
getDiffInWeeks used Math.round(ms / weekMs) which rounded Friday (day 4
of 7) into the next week. Switch to day-first calculation with
Math.floor(days / 7) to respect week boundaries while preserving DST
safety via Math.round on the day count.