LearnNewsExamplesServices
Frontmatter
id12191
titlegh-workflow syncer: needsUpdate reads wrong field (always re-renders) + O(N²) #planBuckets in reconcile loop
stateClosed
labels
bugaiperformance
assigneesneo-opus-ada
createdAtMay 30, 2026, 3:15 AM
updatedAtMay 30, 2026, 8:33 AM
githubUrlhttps://github.com/neomjs/neo/issues/12191
authorneo-opus-ada
commentsCount0
parentIssue12186
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 30, 2026, 8:33 AM

gh-workflow syncer: needsUpdate reads wrong field (always re-renders) + O(N²) #planBuckets in reconcile loop

neo-opus-ada
neo-opus-ada commented on May 30, 2026, 3:15 AM

Context

Sub of #12186 (P2). Two IssueSyncer efficiency/correctness bugs, grounded against the code. (The wgr9t499x investigation mislocated the O(N²) at :990; corrected here to :1007.)

Findings (grounded)

1. needsUpdate reads a non-existent field → every issue re-rendered every sync. IssueSyncer.mjs:624 compares oldIssue.updated !== issue.updatedAt, but the persisted metadata field is updatedAt (MetadataManager.mjs:83; IssueSyncer.mjs:156/664/830/1013 all write updatedAt, never updated). So oldIssue.updated is always undefinedneedsUpdate is always true → every delta issue is re-formatted, re-hashed and re-written every run; the content-hash short-circuit never engages. → Fix: :624oldIssue.updatedAt !== issue.updatedAt.

2. #planBuckets recomputed per-iteration in the reconcile loop (loop-invariant → O(N²)). IssueSyncer.mjs:1007 calls this.#planBuckets(metadata) inside the per-issue reconcile loop, but its only input (metadata) is loop-invariant, so the identical plan is rebuilt for every archived issue. The main pull path is already correct (:572 precomputes once; the loop does O(1) planBuckets.get()) — the reconcile path should mirror it. → Fix: hoist the :1007 #planBuckets(metadata) above its loop. (:808 in refetchIssuesByNumber also calls per-iteration, but with a changing [issue] arg and typically small K — minor; verify at implementation.)

Acceptance Criteria

  • :624 compares oldIssue.updatedAt; unchanged issues skip re-render/re-hash (content-hash short-circuit verified to engage).
  • #planBuckets(metadata) computed once per reconcile run (:1007 hoisted), not per issue.
  • Main pull path (:572) unchanged.
  • A regression test covers the updatedAt short-circuit (unchanged issue → not re-pulled).

Related

Retrieval Hint: grep planBuckets + needsUpdate + oldIssue.updated in IssueSyncer.mjs.

tobiu closed this issue on May 30, 2026, 8:33 AM
tobiu referenced in commit d6ffb8e - "fix(github-workflow): needsUpdate compares persisted updatedAt field (#12191) (#12195) on May 30, 2026, 8:33 AM