fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(google-calendar): drop cancellations of never-imported events - #238

Merged
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread
Jun 27, 2026
Merged

fix(google-calendar): drop cancellations of never-imported events#238
KrisBraun merged 1 commit into
mainfrom
fix/calendar-stale-cancellation-phantom-unread

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Problem

In prod, a 3-year-old calendar event ("Product 0️⃣➡️1️⃣") suddenly appeared as unread, despite not having changed in years.

Root cause, traced in the prod DB:

  1. The Google composite-connector cutover archived the standalone "Google Calendar" twist and started a fresh sync under the new "Gmail & Calendar" twist.
  2. The calendar initial backfill imports a bounded window (history floor = Jan 1 of two years ago → future) and deliberately skips already-cancelled events. The 2023 event was both cancelled and before the floor, so it was never imported.
  3. A later incremental sync (syncToken + showDeleted: true) surfaced that old cancelled recurring master — a Google quirk where the sync token leaks cancellations from outside the initial timeMin window.
  4. The cancellation handler called saveLink. Thread dedup is keyed on (twist_id, key), and the new twist had no matching thread, so saveLinkcreated a brand-new thread with a "This event was cancelled." note. Incremental syncs don't set unread: false, so it landed unread — a phantom for an event the user never saw in Plot.

Fix

Guard both incremental cancellation paths (processCalendarEventsFn whole-event and prepareEventInstanceFn occurrence) with a new cancellationIsForUnimportedEventFn, which drops a cancellation when the event was never imported — detected by either:

  • event.updated predates when we first synced this calendar (new set-once first_sync_at_<calendarId> marker written in runCalendarInit) — it was already cancelled at backfill time, so we skipped it; or
  • the event's scheduled time is older than the import history floor (stateless fallback for connector instances initialised before the marker existed).

Real cancellations of imported, upcoming events satisfy neither signal and still surface as unread (e.g. a meeting tomorrow getting cancelled). Also de-duplicated the history-floor computation into calendarHistoryFloor().

This guard lives in the shared google-calendar sync code, so it covers both the standalone Google Calendar connector and the composite Gmail & Calendar connector.

Testing

  • TDD: 5 new tests (the 3 "drop" cases failed first, RED).
  • pnpm exec vitest run43/43 green.
  • tsc --noEmit and plot lint clean (for both google-calendar and the composite google connector).

No changeset (connector-only change). Forward-only — does not backfill the one existing phantom thread already in prod (archive it manually).

🤖 Generated with Claude Code

After a fresh (re)sync — e.g. the Google composite-connector cutover — the
calendar backfill skips already-cancelled events, then the incremental
syncToken (showDeleted) surfaces an old cancelled event from outside the
import window. The cancellation path then saveLink'd it into a brand-new
unread thread: a phantom for an event the user never saw in Plot. (Observed
in prod: a 3-year-old recurring event resurfaced as unread.)
Guard both incremental cancellation paths with
cancellationIsForUnimportedEventFn: skip when event.updated predates the
calendar's first sync (new set-once first_sync_at_<calendarId> marker) or the
event's scheduled time is older than the import history floor. Real
cancellations of imported, upcoming events are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit 944634b into mainJun 27, 2026
1 check passed
@KrisBraun
KrisBraun deleted the fix/calendar-stale-cancellation-phantom-unread branch June 27, 2026 02:05
Sign up for freeto 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

@KrisBraun