Skip to content

fix(google-calendar): export tasks created while Obsidian was closed - #2236

Open
raphaelfaouakhiri wants to merge 1 commit into
callumalpass:mainfrom
raphaelfaouakhiri:patch/gcal-sync-tasks-created-while-obsidian-closed
Open

fix(google-calendar): export tasks created while Obsidian was closed#2236
raphaelfaouakhiri wants to merge 1 commit into
callumalpass:mainfrom
raphaelfaouakhiri:patch/gcal-sync-tasks-created-while-obsidian-closed

Conversation

@raphaelfaouakhiri

Copy link
Copy Markdown
Contributor

Problem

A task file that appears while Obsidian is closed is never exported to Google Calendar, and no later startup recovers it.

This is the case reported in #2130, where task files arrive on the desktop through an external sync tool. I hit the same thing with a vault synced by git: tasks are created by a headless agent on a server at 05:00 and pulled into the vault, and they never reach the calendar. Editing them by hand later does not help either — the fingerprint already matches, so the task stays invisible to export forever.

Cause

initializeExternalFileReconciliation() baselines every task path it has never seen and then continues, skipping the eligibility and sync decision entirely:

if (previousFingerprint === undefined) {
    fingerprints.set(task.path, fingerprint);
    changed = true;
    baselineTasks++;
    continue;
}

The live path, handleExternalTaskFileUpdated(), makes the opposite decision for the same input: an unknown fingerprint falls through to isTaskCalendarEligible() and, with syncOnTaskCreate on, calls syncTaskToCalendar(). So whether a task reaches the calendar depends on whether Obsidian happened to be running when the file landed — and the startup branch also makes the miss permanent, because the baseline it writes matches on every subsequent boot.

This also answers the open question in #2130 ("a remaining TaskNotes file-change bug vs. the sync tool not producing a metadata update"): it is a TaskNotes bug, and it is in the startup branch, not in the file-change event. Reproduced on 4.12.3.

Change

Startup now makes the same decision the live path already makes: an unknown task that has no event link, is eligible, and has syncOnTaskCreate enabled gets exported instead of silently baselined.

The initial baseline is deliberately preserved. When the fingerprint map is empty, the vault has never been reconciled — every task is unknown, and exporting them all would flood the calendar the first time someone enables export. That case still baselines everything, exactly as before.

Tasks that already carry an event id still baseline without an API write, so a vault whose events were created elsewhere does not get duplicates.

Tests

Four cases added to tests/unit/issues/issue-google-calendar-external-file-reconciliation.test.ts:

  • exports a task created while Obsidian was closed — fails without the fix, passes with it
  • does not export tasks on the first reconciliation of a vault (baseline preserved)
  • does not duplicate an event when the new task already carries an event id
  • does not export an ineligible task created while Obsidian was closed
npx jest tests/unit/issues/issue-google-calendar-external-file-reconciliation.test.ts
9 passed

# same file with the src change reverted
1 failed, 8 passed   ← only "exports a task created while Obsidian was closed"

npx jest --testPathPatterns="[Cc]alendar" → 435 passed. Five UI suites fail (issue-859, issue-385, calendarMutationPlanning, issue-1377, issue-1183), but they fail identically on an unpatched checkout, so they are pre-existing and unrelated.

npx eslint src/services/TaskCalendarSyncService.ts --max-warnings=0 → clean. tsc --noEmit reports no error in this file (the errors it does report exist on main and are in other files). I left Prettier alone: it already flags both files on main, so running it would have buried the change in unrelated reformatting.

Not tested

No live Google API call — the tests use the mocked calendar service, like the surrounding suite.

Closes #2130

Startup reconciliation baselined every task path it had never seen and
skipped the rest of the loop, so a task file that arrived from an external
sync (Syncthing, git, another device) was recorded as known without ever
being exported. The fingerprint then matched on every later startup, so the
task never reached Google Calendar.

The live path (handleExternalTaskFileUpdated) already exports an unknown
eligible task; startup now makes the same decision instead of a different
one. The initial baseline is preserved: when no fingerprints exist yet, all
tasks are still baselined so enabling export never floods the calendar.
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.

[Bug]: Google Calendar won't auto-sync

1 participant