Frontmatter
| id | 10092 |
| title | [bug] IssueSyncer delta-sync is blind to comment deletions — updatedAt does not bump |
| state | Closed |
| labels | bugairegressionarchitecture |
| assignees | tobiu |
| createdAt | Apr 19, 2026, 1:44 PM |
| updatedAt | May 15, 2026, 2:42 PM |
| githubUrl | https://github.com/neomjs/neo/issues/10092 |
| author | tobiu |
| commentsCount | 0 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Apr 19, 2026, 2:03 PM |
[bug] IssueSyncer delta-sync is blind to comment deletions — updatedAt does not bump
tobiu assigned to @tobiu on Apr 19, 2026, 1:49 PM
tobiu cross-referenced by PR #10093 on Apr 19, 2026, 2:00 PM
tobiu closed this issue on Apr 19, 2026, 2:03 PM
tobiu cross-referenced by #10094 on Apr 19, 2026, 2:20 PM
tobiu cross-referenced by #10095 on Apr 19, 2026, 2:20 PM
tobiu cross-referenced by #10096 on Apr 19, 2026, 2:20 PM
tobiu cross-referenced by #10097 on Apr 19, 2026, 2:25 PM
tobiu cross-referenced by PR #10098 on Apr 19, 2026, 2:29 PM
tobiu cross-referenced by PR #10099 on Apr 19, 2026, 3:10 PM
tobiu cross-referenced by #10110 on Apr 19, 2026, 11:40 PM
tobiu cross-referenced by PR #10111 on Apr 19, 2026, 11:53 PM
tobiu cross-referenced by PR #10114 on Apr 20, 2026, 1:11 AM
The Problem
IssueSyncer's delta-sync relies onissue.updatedAtas the invalidation signal, viafilterBy: {since: $since}inFETCH_ISSUES_FOR_SYNC. This gate is blind to comment deletions: GitHub does not bumpissue.updatedAtwhen a user deletes a comment. The sync engine never revisits the affected issue, and the local markdown retains:commentsCountfrozen at the pre-delete valueConcrete reproducer, found during the detector sweep for #10090: issue #9535. Local frontmatter at time of detection:
commentsCount: 11. Live GraphQLissue.comments.totalCount: 10. LocalupdatedAt: 2026-04-01T02:28:35Zmatched GitHub exactly — but a comment had been deleted post-sync and the local file stayed frozen for weeks. Silent disagreement with upstream.This is a distinct bug class from #10090. That ticket ensured full event retrieval when we DO fetch an issue (
timelineItemspagination). This ticket is about deciding when to fetch in the first place. The recovery primitive from #10090 —GH_SyncService.refetchIssuesByNumber— is the right healing endpoint here; what's missing is the detection trigger.Architectural Reality
FETCH_ISSUES_FOR_SYNCusesfilterBy: {since: $since}— GitHub filters onupdatedAt >= since. Deleted-comment drift never crosses that gate.runFullSyncalready has the timeline-scan workaround from #7948 for relationship events that don't bumpupdatedAt(sub-issues, blocking). But GraphQL exposes noISSUE_COMMENT_DELETED_EVENT— comment deletions can't be detected the same way; the timeline only shows the surviving nodes.comments { totalCount }on every sync, but when delta-sync skips an issue, that totalCount check never runs./issues/N/timelineDOES exposeDeletedCommentEvent, but adding a parallel REST surface for a single edge case is the wrong trade.Options Considered
A) Full-scan sweep periodically — drop the
since:filter every Nth sync. Simple, but O(all issues) cost on a timer that's hard to tune.B) Totals-only sentinel pass — add a lightweight query
FETCH_ISSUE_TOTALS_BATCHthat returns{number, comments{totalCount}}for all tracked issues with nosince:filter, no body, no timelineItems. Compare against stored metadata; mismatches feed intorefetchIssuesByNumber. ~1 rate-limit unit per 100 issues. Recommended.C) Per-repo events API polling — listen for
IssueCommentEvent.action=deleted. New infra surface; not justified for a deletion-detection corner case.Fix Approach (option B)
FETCH_ISSUE_TOTALS_BATCH(numbers[])toissueQueries.mjs: returns only{number, comments{totalCount}}per issue. No body, no timelineItems, nosince:filter.MetadataManagermetadata shape to persistcommentsTotalper issue alongside existingupdatedAt,contentHash.IssueSyncer.detectStaleCommentsCounts(metadata)that runs insiderunFullSyncafter the delta pull:metadata.issuesinto batches (100/query).comments.totalCountper batch.refetchIssuesByNumber.staleCommentsCountcount inrunFullSynclogs and return-stats, mirroring the #10090 pagination-warn pattern.Avoided Traps
timelineItems.Acceptance Criteria
FETCH_ISSUE_TOTALS_BATCHquery fetches{number, comments{totalCount}}with nosince:filterMetadataManagerpersistscommentsTotalper issue in the sync-metadata fileIssueSyncer.detectStaleCommentsCounts(metadata)runs insiderunFullSyncafter the delta pull; mismatches are fed intorefetchIssuesByNumberrunFullSynclogs + return-stats expose astaleCommentsCountcountRelated
timelineItemspagination fix (same session discovered both bugs)updatedAtblind spotOrigin Session ID
d9eb5e76-5430-45f7-b3ea-8600664d28f9