- Update target version from 40.6.1 to 40.8.3 (E37 is EOL since Jan 2026)
- Replace Snap X11-only strategy with gnome-42-2204 plug override (Tidal HiFi
pattern) to fix the root cause while preserving Wayland support
- Fix fatal infinite recursion bug in planned protocol.handle migration code
- Add Flathub manifest upgrade section (runtime 25.08, Wayland re-enablement,
wrapper script following Signal Desktop pattern)
- Add breaking changes audit across Electron 38-40 (Node.js 22→24 is safe)
- Clarify macOS Tahoe situation (fix already in 37.6.0+, ongoing freezes are
Apple system-level memory management issues)
- Add Flathub linter-valid socket configuration
- Update ecosystem comparison table with March 2026 data
* docs: add plan for Android background sync via WorkManager
Outlines the implementation plan for using WorkManager to periodically
sync with SuperSync server in the background, cancelling stale reminders
for tasks that were completed/deleted on other devices.
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* docs: refine plan based on multi-agent architecture review
- Pin frontend hook to SyncProviderManager.currentProviderPrivateCfg$
- Add skipWhileApplyingRemoteOps() guard for selector-based effect
- Add HRX (dismiss reminder) and deadlineRemindAt to parser
- Add batch operation ds field handling
- Add ProGuard rules step for release builds
- Add error handling note for BootReceiver WorkManager enqueue
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* docs: improve plan after second review round
Key changes:
- Remove Step 5 (ReminderAlarmStore lookup) - hash-based cancellation is
sufficient, no store lookup needed
- Add BackgroundSyncProvider interface for extensibility to Dropbox/WebDAV
- Per-account lastServerSeq keyed by baseUrl hash
- Add SyncReminderScheduler helper to deduplicate scheduling logic
- Document edge cases: account switching, token expiry, force-kill,
gapDetected, notification race conditions
- Add extensibility section explaining Dropbox feasibility and architecture
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* feat(android): add background sync to cancel stale reminders via WorkManager
When a task is completed/deleted on desktop, Android reminders for that task
would still fire because the mobile app didn't know about the change. This adds
a WorkManager periodic job (every 15 min) that fetches operations from the
SuperSync server and cancels AlarmManager alarms + notifications for tasks that
are done, deleted, archived, or had their reminders dismissed.
Architecture:
- BackgroundSyncProvider interface for extensibility (Dropbox/WebDAV possible later)
- SuperSyncBackgroundProvider: lightweight HTTP client + operation parser
- SyncReminderWorker: CoroutineWorker that fetches ops and cancels reminders
- SyncReminderScheduler: helper to schedule/cancel the WorkManager job
- AndroidSyncBridgeEffects: mirrors SuperSync credentials to native SharedPreferences
- Per-account lastServerSeq prevents account-switching bugs
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* chore: update package-lock.json after npm install
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* fix(android): address review issues and add tests for background sync
Fixes from code review:
- Fix distinctUntilChanged to properly handle provider switching
(non-SuperSync emissions now treated as equal to prevent repeated clears)
- Add null-safe ops array parsing in SuperSyncBackgroundProvider
- Add write/call timeouts to OkHttpClient (30s write, 60s call)
- Remove no-op `hash and hash` line in Kotlin hash function
Tests:
- Add cross-platform parity tests for notification ID hash function
(pinned expected values that must match Kotlin implementation)
- Add AndroidSyncBridgeEffects unit tests covering:
- distinctUntilChanged comparator behavior
- credential set/clear decision logic
- observable filtering integration (dedup, null filtering)
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* fix(android): fix hash overflow and operation parser payload paths
Two critical bugs found during final review:
1. Hash function abs(Int.MIN_VALUE) bug: In Kotlin, abs(Int.MIN_VALUE)
returns Int.MIN_VALUE (still negative) due to 32-bit overflow.
Fixed by converting to Long before abs(), matching JS behavior where
Math.abs works on 64-bit floats.
2. Operation parser payload structure: The parser was looking at
p.isDone and p.task.changes directly, but the actual compact
operation format wraps everything in p.entityChanges[] and
p.actionPayload. Rewrote to use p.entityChanges as primary source
(consistent structure with entityType, entityId, changes fields)
and p.actionPayload.task.changes as secondary source.
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* docs: add long-term plan for Android background sync improvements
Covers three phases: fast app startup via cached sync seq,
push-based notification cancellation via FCM, and extending
background sync to Dropbox/WebDAV providers.
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
* fix(android): address review feedback for background reminder sync
- Remove PLAN.md from repo root (C1)
- Use EncryptedSharedPreferences for access token storage with
fallback to standard SharedPreferences on broken KeyStore (C2)
- Reset lastServerSeq when access token changes to prevent stale
seq on account switch with same server URL (I1)
- Add max iteration guard (100) to pagination loop to prevent
infinite loops from server bugs (I2)
- Use type predicate filter instead of non-null assertions (I3)
- Add exponential backoff (5min) to WorkManager schedule (S1)
- Add comments linking action type codes to frontend source (S2)
- Extract distinctUntilChanged comparator to named function with
JSDoc explaining the suppression semantics (S3)
https://claude.ai/code/session_01RkrVBB492k8RBA8zt5swwe
---------
Co-authored-by: Claude <noreply@anthropic.com>
Root cause: electron-builder auto-published unsigned files via implicit
tag-based publishing (despite release:false), and spaces in NSIS
artifact names caused naming mismatches — electron-builder sanitized
spaces to hyphens while softprops/action-gh-release converted them
to dots, resulting in three sets of exe files per architecture.
Changes:
- Hardcode NSIS artifactName with hyphens to eliminate spaces
- Add --publish never to explicitly prevent auto-publishing
- Update latest.yml with signed file hashes (preserving EB fields)
- Use lockfile-pinned app-builder-bin for blockmap regeneration
- Scope blockmap publishing to NSIS setup files only
- Fail hard if latest.yml references missing files
Extract styling rules, CSS variable reference, and design token
patterns into docs/styling-guide.md for a consistent design language.
CLAUDE.md now points to the guide for all styling changes.
Add deadline support for tasks with date-only and time-specific deadlines.
Core:
- Add deadlineDay, deadlineWithTime, deadlineRemindAt fields to task model
- Add NgRx actions (setDeadline, removeDeadline, clearDeadlineReminder)
- Add meta-reducer with mutual exclusivity and input validation
- Register deadline actions in ActionType enum and op-log codes
UI:
- Create deadline dialog with calendar, time input, and reminder options
- Add deadline badge to task list row with overdue warning color
- Add deadline item to task detail panel with flag icon
- Add deadline options to task context menu
- Show deadlines in scheduled list page
Reminders:
- Add deadline reminder effects and selectors
- Show reminder dialog with grouped deadline/schedule sections
- Handle deadline reminder clearing on dismiss, done, add-to-today
- Cancel Android native deadline notifications on delete/archive
Planner:
- Show deadline tasks in planner day view and overdue section
- Create dedicated planner-deadline-task component
- Optimize deadline grouping with O(N) single-pass selector
Other:
- Add deadline-today banner effect for unplanned deadline tasks
- Add translation keys for all deadline UI strings
- Add E2E tests for deadline reminder flows
- Add unit tests for deadline reducer and overdue utility
- Extract shared isDeadlineOverdue utility function
- Guard app-state selectors against undefined during teardown
Design document for GitHub issue #4328. Covers data model (deadlineDay,
deadlineWithTime, deadlineRemindAt), UI placement in detail panel and
task list rows, NgRx actions/reducers, and reminder integration.
The action-electron-builder omits --publish when release=false, causing
electron-builder to default to onTag on CI and publish unsigned files.
The signed files were then published separately, creating duplicates.
- Add --publish never to explicitly prevent auto-publishing
- Hardcode NSIS artifactName with hyphens to avoid SignPath converting
spaces to dots (Super.Productivity → Super-Productivity)
- Skip blockmap regeneration for portable targets, fail loudly if an
NSIS blockmap is unexpectedly missing
- Update normalization comment and docs filename reference
- Remove outdated feature requests from .github/CONTRIBUTING.md (GitLab
support already exists) and add commit message format section
- Improve PR template with type-of-change checkboxes and checklist
- Update commit guideline links in README and CONTRIBUTING.md to
reference the project's own format instead of external angular.js docs
- Add "only edit en.json" rule to TRANSLATING.md and clarify workflow
- Update add-new-integration.md provider list to match codebase (add
Trello, ClickUp, Linear, Azure DevOps, Nextcloud Deck; note GitHub
plugin migration; fix type name to BuiltInIssueProviderKey)
- Add cross-references between mac certificate docs and remove 240-line
duplicate section from update-mac-certificates.md
- Clean up update-android-app.md (specify npm version args, collapse
deprecated workflow, translate German UI labels to English)
- Add context to howto-refresh-snap-credentials.md
- Fix fine-grained token note in github-access-token-instructions.md
- Fix absolute URL to relative path in gitlab-access-token-instructions.md
- Fix grammar in i18n-script-usage.md
- Add status headers to all 19 long-term plan files (Planned, Completed,
Archived with reason, Investigation Complete)
- Fix broken relative link in hybrid-manifest-architecture.md
- Delete supersync-scenarios-simplified.md (duplicate of
supersync-scenarios.md; known issues already covered there)
- Rename vector-clock-pruning-research.md to
vector-clock-history-and-alternatives.md for clarity
Design for extending the existing CalDAV provider with VEVENT (calendar
event) support alongside existing VTODO sync. Serves privacy-focused
self-hosted calendar users with no new auth infrastructure needed.
Complements the Google Calendar provider design.
Evaluates authentication approaches for cross-platform Google Calendar
integration and documents decisions: hybrid auth proxy with user-provided
credentials option, REST API v3, and phased two-way sync rollout.
Parallel to the SuperSync flowchart, covering the file-based sync
decision tree: gap detection, snapshot hydration, rev-based upload
retry, and error handling. Verified against source code with matching
abstraction level to the SuperSync chart.
Correct the flowchart to match actual codebase behavior:
- Move fresh-client dialogs under the "has remote ops" branch (was incorrectly under "no remote ops")
- Split single password dialog into two distinct decrypt error dialogs (DecryptNoPasswordError vs DecryptError)
- Route SYNC_IMPORT conflicts to ImportConflictDialog (was incorrectly using SyncConflictDialog)
- Add encryption-only change bypass for password-change SYNC_IMPORTs
- Add LWW tie-breaking details (remote wins on tie, archive ops always win)
- Add retry limit note on re-download, correct "Cancel" to "Disable SuperSync"
- Show silent server migration path for fresh clients with local data on empty server
Rename generic "Conflict dialog" labels to SyncConflictDialog and
ImportConflictDialog to reflect the two distinct components. Add orange
action styling for key state-changing nodes (apply, force upload/download,
enable encryption, upload).
Document findings from attempted Electron upgrade including the
upstream blocker (electron-builder#9452) for Snap packaging and
a phased implementation plan for when it's resolved.
* feat: add label to heatmap for repeat task
* style(e2e): fix prettier formatting in planner spec
* fix(focus-mode): clear stale _isResumingBreak flag when isPauseTrackingDuringBreak is enabled (#6534)
When both isSyncSessionWithTracking and isPauseTrackingDuringBreak are
enabled, pausing and resuming a break left _isResumingBreak stale,
causing the next manual tracking start to dispatch clearResumingBreakFlag
instead of skipBreak. Refactor syncSessionResumeToTracking$ to explicitly
dispatch clearResumingBreakFlag in this case.
* refactor(sync): unify JWT expiry to 365 days for all auth methods
Replace separate JWT_EXPIRY_MAGIC_LINK (365d) and JWT_EXPIRY_PASSKEY (7d)
constants with a single JWT_EXPIRY (365d). The auth method only matters
during login — once a JWT is issued, it represents a verified session
regardless of how the user authenticated.
* feat(start-of-next-day): respect startOfNextDayDiff offset in today view
Thread startOfNextDayDiffMs through AppState, selectors, meta-reducers,
and task component so that "today" membership correctly accounts for the
user's configured day-start offset. When startOfNextDay=4 (4 AM), at
2:30 AM the app now correctly treats the previous calendar day as "today".
- Add isTodayWithOffset utility for offset-aware date comparison
- Store startOfNextDayDiffMs in AppState alongside todayStr
- Update all selectors (work-context, planner, task, overdue) to use offset
- Update meta-reducers with defensive fallbacks for state access
- Fix task component computed signals (isOverdue, isScheduledToday, etc.)
- Add 48 new tests covering offset boundary conditions
* style(planner): remove unused eslint-disable directive
* fix(start-of-next-day): use offset-aware date in ensureTasksDueTodayInTodayTag effect
Replace raw getDbDateStr() and getDateRangeForDay(Date.now()) with
store-derived todayStr and offset-adjusted range in task-due.effects.ts.
Without this, the effect would use the wrong day between midnight and
the configured startOfNextDay hour.
Also add selectOverdueTasks offset boundary tests.
* refactor(start-of-next-day): use DateService for offset-aware today checks
Add DateService.isToday() method that encapsulates the startOfNextDayDiff
offset logic, replacing scattered isToday()/getDbDateStr() calls across
effects, services, and components.
- Add isToday(date) to DateService for DRY offset-aware checks
- Fix task-repeat-cfg.effects.ts: 6 isToday/getDbDateStr calls
- Fix task-repeat-cfg.service.ts: isToday call
- Fix task-context-menu-inner.component.ts: 6 isToday/getDbDateStr calls
- Fix task-related-model.effects.ts: getDbDateStr call
- Fix work-context.service.ts: getDbDateStr call
- Remove duplicate planTaskForDay handler from tag.reducer.ts
(already handled by planner-shared meta-reducer with offset)
* refactor(start-of-next-day): migrate remaining isToday() calls to offset-aware DateService
Replace 6 call sites still using the non-offset isToday()/isYesterday()
with DateService methods that respect startOfNextDayDiff. Also adds
isYesterday() to DateService and uses isTodayWithOffset in legacy backup
migration. Behavior is identical at offset=0 (default).
* fix(start-of-next-day): fix offset bugs, sync regression, and code quality issues
- Fix wrong config path in legacy backup migration (misc.startOfNextDay)
- Restore sync readiness check (filter+first instead of take(1))
- Restore SYNC_AFTER_ENABLE in setInitialSyncDone conditions
- Use offset-aware dates in addAllDueToday/addAllDueTomorrow
- Make isSameDay offset-aware and pass offset through planner selectors
- Fix TagSettingsPageComponent selector from 'project-settings' to 'tag-settings'
- Hide settings link for virtual TODAY tag
- Revert direct ru.json edits (only en.json should be edited)
- Add standalone:true and use takeUntilDestroyed in settings components
- Restore Math.max(duration,1) for zero-duration overlap detection
- Remove dead code, stale CSS, and commented-out HTML
- Add input validation clamping in DateService.setStartOfNextDayDiff
* fix(start-of-next-day): fix offset bugs in overdue detection, planner display, and LWW sync
- Fix isOverdue ignoring offset for dueWithTime tasks in task.component
- Remove duplicate moveBeforeTask handler from tag.reducer (handled by meta-reducer)
- Add skip(1) and hydration guard to setTodayStr$ effect to prevent race condition
- Move side effects from map() to tap() in global-config.effects
- Fix isSameDay double-offset bug in planner.selectors for scheduled tasks/events
- Replace unsafe `as any` casts with proper PlannerState types
- Use safe optional chaining for todayStr access in meta-reducers
- Refactor handlePlanTaskForDay to use helper functions with hasChanges optimization
- Extend syncTodayTagTaskIds in LWW meta-reducer to handle dueWithTime changes
- Fix absolute import path in global-config.effects
- Add @deprecated to isToday() in favor of offset-aware alternatives
* fix(config): migrate task dueDays when startOfNextDay offset changes
When the "start of next day" offset changes and causes todayStr to shift,
existing tasks with dueDay matching the old todayStr are now migrated to
the new todayStr so they remain classified as "today" tasks.
* refactor(config): use switchMap and document archive task exclusion
Replace mergeMap with switchMap in setStartOfNextDayDiffOnChange
effect to better communicate intent (only latest emission matters).
Add comment clarifying archived tasks are intentionally excluded
from dueDay migration.
* test(sync): add LWW tests for dueWithTime → TODAY_TAG sync
Cover the dueWithTime path in syncTodayTagTaskIds that was added
but had no test coverage. Tests verify TODAY_TAG membership updates
when dueWithTime changes via LWW sync.
* docs(wiki): add new Quickstart to help with using Sync
There is a slew of notes that try to explain or show this so a
Quickstart can help bring everything into one place.
* docs(wiki): combine "First Steps" into single note with relevant links
* docs(wiki): update index notes
* docs(wiki): fix remaining broken external links
* docs(wiki): add core developer How-To guides to orient first-time devs
The majority of the documentation is currently spread across several
files ins "docs/" and READMEs. Over time these can be consolidated into
the wiki while retaining the common CONTRIBUTING.md as a valid entry
point.
* docs(wiki): add basic guides for plugins and issue integration
As with the core development docs, there is too much to add here right
now. These notes will serve as a simple entry to other resources.
* docs(wiki): add basic reference note for theming
* docs(wiki): add basic Translation guide
* docs(wiki): rename Theming and linting to clean up headings
* docs(wiki): add heading lint exception for GH-specific nav pages; rework sidebar and index pages
Sidebar should be a quick-access for the more common topics grouped
thematically with the X.00 notes simply enumerating all the notes where
appropriate.
I tried to include as much up-to-date guidance as possible but given the
dynamic nature of SuperSync at the moment this note will require some
updates as the new sync backend is rolled out to non-SuperSync
integrations.
When encryption was enabled, forceUploadLocalState (triggered by "Use local"
in conflict dialog) caused double-encryption: the upload service encrypted the
state payload, then the file adapter encrypted the entire file. On download,
only the outer layer was decrypted, leaving the state as an opaque string that
couldn't be hydrated — making "Use remote" silently fail and forcing a
ping-pong loop between clients.
Fix: _uploadSnapshot now uses getStateSnapshot() (matching _buildMergedSyncData)
instead of the passed state parameter, since file-level encryption already
handles security.
Also: clean up dead return values in _buildMergedSyncData, reset
_lastSyncTimestamps in _uploadSnapshot for consistency, and update stale
piggybacking doc reference.
Remove duplicate LegacySyncProvider enum and use SyncProviderId everywhere.
The two enums had identical values but were separate types for historical
reasons, making the "Legacy" name misleading since providers are actively used.
Add limitVectorClockSize to OperationLogCompactionService._doCompact()
which was the remaining saveStateCache caller that persisted unpruned
clocks. Update vector-clocks.md exhaustive pruning table with the three
new client-side pruning locations. Add boundary tests at exactly
MAX_VECTOR_CLOCK_SIZE for snapshot and hydrator services.
Remove references to deleted docs/ai/ files, update stale comments about
protectedClientIds and pruning-aware comparison to reflect current REPLACE
semantics, fix MAX=30→20 heading, client_0..29→19 comment, use ?? over ||,
preserve lastSeq in server clean-slate path to prevent sequence reuse, and
add clarifying comments for mock limitations and validation guards.
- Add deterministic tie-breaking test for vector clock pruning with
equal counters (shared-schema)
- Remove last isLikelyPruningArtifact reference from entity versioning doc
- Use JWT_EXPIRY_PASSKEY (7d) for replaceToken instead of 365d magic link
expiry — token replacement is a security action, shorter lifetime is safer
- Replace localeCompare with locale-independent comparator in vector clock
tie-breaking to ensure deterministic behavior across environments
- Fix 5 additional stale MAX=30 references in docs and tests (now 20)
- Update authentication.md to reflect dual JWT expiry tiers
- Clean up isLikelyPruningArtifact references in docs and LEGACY_MAX in tests
Lower the cap to leave headroom for future increases and surface
size-related edge cases earlier. All pruning logic is MAX-agnostic
so this is a safe constant change with documentation updates.
At MAX=10, pruning triggered frequently enough (11+ unique client IDs from
reinstalls/new browsers) to require 4 defense layers compensating for
information loss: pruning-aware comparison, protected client IDs with
migration, isLikelyPruningArtifact heuristic, and same-client check.
At MAX=30, pruning almost never triggers (needs 31+ unique client IDs).
A 30-entry clock is ~500 bytes — negligible bandwidth. This allows removing
most defense layers while keeping two cheap backward-compat checks for old
10-entry pruned data still on servers.
Removed:
- Pruning-aware mode in compareVectorClocks (standard comparison now)
- Protected client IDs mechanism (storage, migration, preservation)
- selectProtectedClientIds function
- Clock normalization in SyncImportFilterService
Kept temporarily (backward compat with old 10-entry data):
- isLikelyPruningArtifact with LEGACY_MAX=10
- Same-client check (always mathematically correct)
Replace the scattered, contradictory document with a coherent 13-section
architecture reference covering the full vector clock system: core
operations, pruning, conflict detection, SYNC_IMPORT filtering, defense
layers against pruning artifacts, and step-by-step scenario traces.
When a client with an established vector clock (10+ entries) received a
remote SYNC_IMPORT/BACKUP_IMPORT with a fresh clock, mergeRemoteOpClocks()
merged the import's clock into the old clock instead of replacing it.
This caused clock bloat (11+ entries), which led to server-side pruning
dropping the import's entry (lowest counter). Other clients then saw
these ops as CONCURRENT with the import and discarded them.
Fix: In mergeRemoteOpClocks(), when a full-state op is present, use its
clock as the base instead of the existing local clock. Regular ops
continue to merge normally.
The sanitizeVectorClock() DoS cap was changed to 5x MAX (50 entries) but
comments in CLAUDE.md, vector-clocks.md, sync.types.ts, and
validation.service.ts still referenced the old 3x MAX (30) value.