Skip to content

Fix overlapping MutationObserver registrations, with credit to #68 - #83

Merged
byteface merged 2 commits into
masterfrom
fix/mutation-observer-pr68
Sep 9, 2026
Merged

byteface merged 2 commits into
masterfrom
fix/mutation-observer-pr68

Conversation

@byteface

@byteface byteface commented Sep 9, 2026

Copy link
Copy Markdown
Owner

When one MutationObserver watches a child directly and its ancestor with subtree and old-value capture enabled, the direct registration previously hid the ancestor's old-value request. Combine all matching registrations and deliver one record with the requested old value for attributes and character data.

Adapted from 7HR4IZ3's interestedObservers aggregation in #68, with credit in the code and tests and a verified Co-authored-by trailer.

Also reject contradictory observe options, infer omitted mutation types from option presence, and release inactive observers from the global registry. Synchronous delivery is documented; browser microtask batching remains unimplemented.

Validation: 248 tests and 89 subtests passed across tests/test_dom_mutation_observer.py, tests/test_dom.py, and tests/test_dom_insertion_ownership.py. The 22 new cases produce 11 failures against the unchanged baseline and all pass after the fix. The principal regression is test_overlapping_observations_preserve_old_value, covering attributes and character data, both registration orders, and old-value requests on either registration.

Follow-up to #68.

Adapt the interested-observer aggregation from #68 so matching ancestor
registrations can request old values without producing duplicate records.
Credit 7HR4IZ3 beside the implementation and in the regression tests.

Validate contradictory observer options, infer omitted mutation types from
option presence, and release inactive observers from the global registry.
Document the existing synchronous callback behavior.

Validation: 248 passed, 89 subtests passed across the observer, DOM and
insertion ownership tests. The 22 new cases produce 11 failures against
the unchanged baseline and all pass with this change.

Co-authored-by: 7HR4IZ3 <90985774+7HR4IZ3@users.noreply.github.com>
@byteface
byteface marked this pull request as ready for review September 9, 2026 20:34
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Preserve old values across overlapping MutationObserver registrations

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Aggregate overlapping observer registrations into one record while preserving requested old
 values.
• Normalize and validate observation options, and release disconnected observers from global
 tracking.
• Add mutation regressions and make Git tests independent of checkout branch state.
Diagram

graph TD
  A["DOM Mutation"] --> B["Observer Registry"] --> C{"Matching registration?"}
  C -->|Yes| D["Aggregate options"] --> E["Single record"] --> F["Sync callback"]
  C -->|No| G["Ignore mutation"]
Loading
High-Level Assessment

The PR uses the appropriate registration-aggregation strategy: evaluate every eligible direct and ancestor registration, combine old-value requirements, and emit one observer-level record. First-match delivery would retain the original ordering bug, while emitting per-registration records would introduce duplicates. Explicit removal from the strong global registry also preserves active delivery while allowing disconnected observers to be collected; a weak-only registry could prematurely lose active observers.

Files changed (3) +212 / -35

Bug fix (1) +49 / -33
dom.pyCorrect MutationObserver aggregation, validation, and lifecycle behavior +49/-33

Correct MutationObserver aggregation, validation, and lifecycle behavior

• Combines all matching direct and ancestor registrations before creating one MutationRecord, preserving an old value requested by any eligible registration without duplicate delivery. It also infers mutation types from present dependent options, rejects contradictory options, tracks only active observers globally, and documents synchronous callback delivery.

domonic/dom.py

Tests (2) +163 / -2
test_dom_mutation_observer.pyAdd comprehensive MutationObserver regression coverage +141/-0

Add comprehensive MutationObserver regression coverage

• Adds parameterized tests for overlapping registrations, registration ordering, old-value aggregation, subtree and filter exclusions, option inference and validation, disconnect reuse, and garbage collection. The tests credit the interested-observer approach adapted from PR #68.

tests/test_dom_mutation_observer.py

test_terminal.pyMake Git terminal tests safe for detached HEAD checkouts +22/-2

Make Git terminal tests safe for detached HEAD checkouts

• Replaces the assumption that the project checkout uses the master branch with an isolated temporary Git repository. The test now verifies clean and untracked status output in both attached and detached HEAD states.

tests/test_terminal.py

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@byteface
byteface merged commit 96582b9 into master Sep 9, 2026
11 checks passed
Sign up for free to 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