fix(calendar): reject repeated instance page tokens - #1084
Conversation
Events.Instances paging in resolveRecurringInstanceID rebuilt the call with the next token and no seen-set. A repeated Google token could hang calendar edit and delete when --scope single or future resolves an instance by original start. Walk instances through collectAllPages so a repeated token fails closed before any instance delete or patch. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: blocked before merge. Reviewed September 5, 2026, 5:01 AM ET / 09:01 UTC. ClawSweeper reviewWhat this changesThe PR adds repeated-token protection to recurring Calendar instance lookup and tests loop rejection, later-page matches, and deletion suppression. Regression provenancePossible regression — suspected (reviewed change). No predecessor PR is attributed. Merge readiness⛔ Blocked before merge - 3 items remain The fix remains necessary on main and v0.39.0, but the earlier first-match correctness blocker remains unresolved. The supplied fault-injection evidence supports the repeated-token guard. Priority: P2 Review scores
Verification
How this fits togetherCalendar update and delete commands resolve a recurring occurrence from its original start time before modifying Google Calendar. This lookup consumes paginated Instances responses and returns either an event ID or an error. flowchart TD
A[Calendar update or delete] --> B[Resolve recurrence scope]
B --> C[Fetch Google instance pages]
C --> D[Pagination guard]
D --> E[Match original start]
D --> F[Return lookup error]
E --> G[Modify selected occurrence]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Copy recommended automerge instructionTechnical reviewBest possible solution: Instance lookup should stop at the first matching occurrence and reject token cycles only while the search remains unresolved, preserving existing scoped mutations. Do we have a high-confidence way to reproduce the issue? Yes, from source: repeating a nonempty Instances token with no matching occurrence keeps main paging; a matching page followed by an error exposes the PR's compatibility regression. Neither scenario was executed during this read-only review. Is this the best way to solve the issue? No, collecting all pages changes successful lookup behavior unnecessarily; the existing collector can still be reused if the callback terminates collection immediately upon finding the occurrence. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 25703c789da5. LabelsLabel justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (1 earlier review cycle)
|
govet shadow failed make lint on the collectAllPages callback. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
Superseded by #1087, which incorporates recurring-instance cycle protection while preserving immediate success when the requested occurrence is found. Failed lookup performs no event deletion. Thanks @SebTardif. Superseded by #1087, which incorporates cycle protection for Drive tree, inventory, and disk-usage scans. All three stock CLI commands were verified to fail without partial success output. Thanks @SebTardif. Superseded by #1087, which incorporates Gmail query-cycle protection, including repeated empty pages, while retaining existing result limits. Failure occurs before downstream message changes. Thanks @SebTardif. |
What Problem This Solves
gog calendar deleteandgog calendar updatewith--scope singleor--scope futureresolve the target instance throughEvents.Instances. That helper rebuilt each page request fromNextPageTokenand never recorded tokens it had already used. If Google returned the same token again, instance lookup never finished, so the command never deleted or patched the event.The same unguarded rebuild has already been fixed for CalendarList (
#1004) and othercmdlist helpers. Recurring instance lookup was still on the old loop, introduced with calendar recurrence parity in#38(1d595747, 2026-01-08).Evidence
Public path:
CalendarDeleteCmd.Runand the update/edit commands callresolveRecurringScopeResolution, which callsresolveRecurringInstanceIDwhenever--scopeissingleorfutureand--original-startis set.A local Calendar Instances peer that always returns
nextPageToken=stuck(and a non-matching item) shows the hang versus the fail-closed walk. The unguarded rebuild kept requesting until the peer refused after 40 calls. The seen-token walk stopped after two calls.The same peer through
CalendarDeleteCmdwith--scope singleand--original-start 2025-01-02T10:00:00Znow returns that pagination error, makes two instance list calls, writes no JSON, and never sends DELETE.Real behavior proof
Behavior or issue addressed: Recurring instance lookup for calendar edit and delete hangs if
Events.Instancesrepeats a page token.Real environment tested: Windows, Go 1.27.1, openclaw/gogcli at
25703c78plus this patch, generated Calendar client against a local Instances peer.Exact steps or command run after this patch:
Evidence after fix: terminal output from the patched walk:
Observed result after fix: The unguarded rebuild issued 41 instance list requests. After the patch, the same peer stops after two requests with
pagination loop: repeated page token "stuck".calendar delete --scope singledoes not emit a result or send DELETE once lookup fails.What was not tested: A live Google Calendar account returning a repeated Instances token.
Related: #1004, #38, #1066.