Skip to content

feat(calendar): bootstrap race guard + os.Logger observability#27

Merged
Periicles merged 14 commits into
mainfrom
feat/authorization-recovery
Jul 13, 2026
Merged

feat(calendar): bootstrap race guard + os.Logger observability#27
Periicles merged 14 commits into
mainfrom
feat/authorization-recovery

Conversation

@Periicles

@Periicles Periicles commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Why

Stack-continuation PR. #21 was merged into main without deleting feat/authorization-recovery, so #22 (os.Logger) was merged into that branch instead of auto-retargeting to main. As a result, main is currently missing:

This PR brings both to main and re-anchors the open stack (#23#24#25#26).

⚠️ Merge procedure for the rest of the stack

Merge in order and check “Delete branch” at every merge — that's what makes GitHub retarget the next PR automatically:

  1. this PR (delete feat/authorization-recovery) → refactor(calendar): extract SnapshotBuilder #23 retargets to main
  2. refactor(calendar): extract SnapshotBuilder #23 (delete branch) → feat(panel): Join button for meeting links #24 retargets
  3. feat(panel): Join button for meeting links #24 (delete branch) → feat(calendar): multi-calendar tracking #25 retargets
  4. feat(calendar): multi-calendar tracking #25 (delete branch) → feat(l10n): French localization #26 retargets
  5. feat(l10n): French localization #26 (delete branch)

Periicles and others added 14 commits July 11, 2026 12:37
An EKEventStoreChanged notification firing during the await in
requestAccessIfNeeded() could let handleStoreChanged complete the
not-granted→granted setup before bootstrap resumes, causing it to
unconditionally repeat the same setup. Short-circuit if authorization
is already granted when the await returns.
feat(logging): os.Logger observability
Joining a meeting is the highest-value action available during
startingSoon/inProgress, so surface it directly in the notch instead
of requiring a context switch to Calendar. Detection is pure and
https-only (Zoom /j//my/, Meet, Teams, Webex subdomains), preferring
the event's URL field over location/notes.
Single-calendar selection was a v1 constraint; the legacy migration
chain (array -> single -> set) shows multi-select was the original
design intent, and the snapshot model already merges/sorts events
across sources, so absorbing multiple calendars costs nothing there.

Preferences.selectedCalendarIdentifiers replaces the single-value
selection with a Set<String>, migrating both legacy keys (idempotent,
preserves "never selected" vs "deliberately empty" distinction).
SnapshotBuilder, CalendarManager, and EventProgressModel thread the
Set through; SettingsView swaps radio rows for checkboxes.
Add os.Logger info lines in Preferences.migrateIfNeeded when a legacy-key
migration actually writes the new key, restoring observability for
diagnosing post-upgrade calendar selection changes. Add regression tests
for single-vs-legacy-array precedence and empty legacy array handling.
The landing page has been bilingual FR/EN since launch, but the app itself
was English-only. Follow system language per macOS convention: a String
Catalog carries en/fr translations, threaded through SnapshotBuilder and
the views, with a build tool plugin to compile it for swift build/test
(SwiftPM's own build system copies .xcstrings verbatim instead of
compiling it, unlike Xcode's build system).
SwiftPM's own build system doesn't compile .xcstrings catalogs, so the
prior approach shelled out to xcstringstool via a custom build plugin
and leaked the raw JSON catalog into the shipped app bundle. Convert
the catalog to en.lproj/fr.lproj Localizable.strings, which SwiftPM
processes natively, and drop the plugin entirely. Localized.string
now resolves .lproj sub-bundles directly via Bundle(path:) for
explicit non-current locales, deferring to Bundle.module's standard
search order otherwise.
refactor(calendar): extract SnapshotBuilder
feat(panel): Join button for meeting links
feat(calendar): multi-calendar tracking
@Periicles Periicles self-assigned this Jul 13, 2026
@Periicles
Periicles merged commit e25260c into main Jul 13, 2026
3 checks passed
@Periicles
Periicles deleted the feat/authorization-recovery branch July 13, 2026 07:39
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