Multi-account support and correct live-store selection#4
Open
joshthomp wants to merge 1 commit into
Open
Conversation
Reminders keeps each account in its own SQLite store. RemCTL picked the
store by file size, which on multi-account setups selected a bloated
Exchange store instead of the live iCloud one — so the wrong account's
reminders were shown. Select the active store by reminder count and
file-group recency instead, with a REMCTL_DB env / config `dbPath`
override for pinning a specific file.
Building on that, add opt-in multi-account support. The default stays
single-account and its output is byte-for-byte unchanged:
- `--all-accounts` reads every connected account; `--account NAME` scopes
to one. A default scope can be set via the REMCTL_ACCOUNT_SCOPE env var
or the `accountScope` config key ("all" or an account name).
- Multi-account output labels each item by source: bold per-account
headers in human output, `account`/`accountType` fields in JSON, and an
Account column in tables.
- Reminder IDs (Z_PK) are per-account. When the scope spans more than one
account, a bare ID or list name present in multiple accounts produces a
disambiguation error and requires `--account`.
- New `accounts` command lists connected accounts; new `config` command
gets/sets `accountScope`, `storeDir`, and `dbPath`.
- Writes (add/done/edit/delete/flag/...) can target any connected account.
The EventKit bridge gains a `list_calendars` action and calendar-identifier
targeting, so a (list, account) pair maps to a stable calendar rather than
an arbitrary same-named list in another account.
NOTE: the bridge must be recompiled via install.sh.
- export/import stay single-account by design (IDs collide across
accounts): they accept `--account` but refuse an all-accounts scope
rather than silently writing a partial backup.
Also fix `stats` overdue counting, which compared against the current
time and so counted reminders due earlier today as overdue — disagreeing
with the `overdue` command, which lists none. Count from the start of day
so the two agree.
Docs updated; adds multi-account test coverage (discovery, scope
resolution, addressing, and single-account back-compat).
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.
Summary
RemCTL currently reads from a single Reminders store chosen by file size.
On setups with more than one account (iCloud + Exchange/CalDAV + on-device),
the largest file is often a bloated Exchange store rather than the live
iCloud one, so RemCTL silently operates on the wrong account.
This PR fixes store selection and, on top of that, adds opt-in
multi-account support: read from every connected account, see which account
each item belongs to, and create/modify/delete in any of them. The default
behavior is unchanged and single-account output is byte-for-byte identical.
Motivation
find_main_db_path()selected the store with the largest file on disk.Exchange stores accumulate size independent of how many live reminders they
hold, so the heuristic can pick a stale/secondary account. The result is
confusing:
today,lists, etc. show an account the user didn't expect.What changed
Store selection
REMCTL_DBenv var /dbPathconfig key to pin a specific file;REMCTL_STORE_DIR/storeDirto point at a Stores directory.Reading across accounts (opt-in)
--all-accountsincludes every connected account;--account NAMErestricts to one. A personal default can be set with
REMCTL_ACCOUNT_SCOPEor theaccountScopeconfig key (allor a name).account/accountTypefields (JSON), an Account column (table).Z_PK) are per-account; when the scope spans accounts, an ID orlist name found in more than one produces a disambiguation error that
lists candidates and asks for
--account.accountscommand (lists connected accounts) andconfigcommand(
accountScope/storeDir/dbPath).Writing to a specific account
list_calendarsaction and targets lists bystable calendar identifier, so a
(list, account)pair resolves to theright calendar instead of an arbitrarily-chosen same-named list.
--accountonadd/done/edit/delete/flag, etc../install.sh(runsswiftc -O).Correctness fix
statscounted overdue against the current time, so reminders due earliertoday were reported as overdue even though
overdueitself lists none.It now counts from the start of the day, matching
overdueandtoday.Deliberate scope limit
export/importoperate on a single account (reminder IDs collideacross accounts). They accept
--accountbut refuse an all-accountsscope with a clear error rather than writing a silently partial backup.
Backward compatibility
Single-account behavior is the default. With no flags/config, output is
byte-for-byte identical to the previous release — verified by diffing every
read command × format (plain/table/json) against
main, for both thedefault scope and an explicit
--account. The only intended output changeis the
statsoverdue fix above.Testing
python3 -m pytest tests/test_cli.py-> 273 passing, plus coverage foraccount discovery, scope precedence, cross-account addressing/ambiguity,
and single-account back-compat.
test_info_json_keeps_due_date_separate_from_display_alarm_date, isnot introduced here — it fails identically on unmodified
mainbecause it hard-codes a UTC+2 expected value and only passes in that
timezone. Happy to fix it (force a fixed TZ) in a separate change if you'd
like.
Notes for review
account-targeted writes need both.