Frontmatter
| id | 8829 |
| title | Fix VDOM Merge Race Condition during In-Flight Updates |
| state | Closed |
| labels | bugaitestingcore |
| assignees | tobiu |
| createdAt | Jan 20, 2026, 5:03 PM |
| updatedAt | Jan 20, 2026, 5:05 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8829 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Jan 20, 2026, 5:05 PM |
Fix VDOM Merge Race Condition during In-Flight Updates
tobiu assigned to @tobiu on Jan 20, 2026, 5:05 PM

tobiu
Jan 20, 2026, 5:05 PM
Input from Gemini 3 Pro:
✦ I have implemented the fix for the race condition where merged child updates were lost if the parent was already executing an update.
Changes:
src/mixin/VdomLifecycle.mjs:
- Updated
executeVdomUpdateto capture themergedChildIdsused for the current update cycle.- Passed this snapshot to
resolveVdomUpdate.src/manager/VDomUpdate.mjs:
- Updated
executeCallbacksto accept theprocessedChildIdssnapshot.- It now selectively removes only the processed child IDs from the
mergedCallbackMap, ensuring that any new merges that arrived during the update execution are preserved for the next cycle.test/playwright/unit/vdom/VdomLifecycle.spec.mjs:
- Corrected the test expectation for
vnode should PERSIST when component is hidden (removeDom).mountedshould befalsewhen hidden viaremoveDom.Verification:
test/playwright/unit/vdom/RaceCondition.spec.mjs: All 4 tests passed.test/playwright/unit/vdom/VdomLifecycle.spec.mjs: All tests passed.test/playwright/unit/vdom/RealWorldUpdates.spec.mjs: All 8 tests passed.This ensures robust VDOM update merging even under heavy parallel load.
tobiu closed this issue on Jan 20, 2026, 5:05 PM
This ticket addresses a race condition where child components correctly registered for a merged update, but their request was lost if the parent component was already in the middle of executing its update cycle.
The Problem:
isVdomUpdating = true).getMergedChildIds).mergeIntoParentUpdate).resolveVdomUpdatecallsexecuteCallbacks.executeCallbacksblindly cleared all pending merges for that parent, assuming they were all handled.The Solution:
VdomLifecycle.executeVdomUpdatenow captures the exact set of child IDs included in the update payload.resolveVdomUpdateand thenVDomUpdate.executeCallbacks.executeCallbacksnow only removes the specific child IDs that were actually processed. Any new merge requests that arrived during the in-flight window are preserved.needsVdomUpdateflag on the parent (or remain pending), ensuring they are picked up in the next update cycle.Additional Fixes:
VdomLifecycle.spec.mjstest expectation: A component hidden withremoveDomcorrectly hasmounted: false.Verification:
RaceCondition.spec.mjspasses all tests.VdomLifecycle.spec.mjspasses all tests.RealWorldUpdates.spec.mjspasses all tests.