Skip to content

feat(dom): B1.2d-i — MutationObserver transient registered observers (DOM §4.3)#413

Merged
send merged 13 commits into
mainfrom
b1.2d-range-transient
Jun 27, 2026
Merged

feat(dom): B1.2d-i — MutationObserver transient registered observers (DOM §4.3)#413
send merged 13 commits into
mainfrom
b1.2d-range-transient

Conversation

@send

@send send commented Jun 27, 2026

Copy link
Copy Markdown
Owner

B1.2d-i — MutationObserver transient registered observers (DOM §4.3)

Per-PR slice of the B1.2 umbrella (Program B / F3 mutation-path), plan-reviewed clean. Implements the §4.3 transient-registered-observer machinery so a node removed from a subtree observed by an ancestor's subtree:true observer keeps delivering records for mutations in the now-detached subtree until the next microtask delivery clears it.

What

  • elidex-api-observers (mutation.rs): MutationObservation gains transient; free fns add_transient_observers (§4.2.3 "remove" step 15 — walk parent's inclusive ancestors, append transient copies of subtree:true observers to removed nodes) and clear_transient_observers (§4.3 "notify mutation observers" step 6.3), both over the per-node MutationObservedBy ECS component (registry owns only record queues — ECS-native, no observer→nodes reverse index; shared retain_observations scaffold with disconnect). observe() re-observe clears transients (§4.3.1 step 7.1, source→observer-id collapse).
  • notify refactored to the §4.3.2 interestedObservers per-observer map-collapse (one record per observer). Required for this PR's own correctness — a removed node can hold a permanent + transient (or multi-ancestor) registration for one observer, which the old per-entry push would deliver as duplicate records. Incidentally fixes a pre-existing multi-ancestor duplicate-record bug.
  • VM (vm/host/mutation_observer.rs): notify_one creates transients for ChildList removals (eager, during the remove, in JS-execution order); the deliver loop clears per-observer interleaved (spec step 6.3, between 6.2 emptying the queue and 6.4 the callback).

Layering / ECS-native

Algorithm lives entirely in the engine-independent crate; the VM host only orchestrates at the record-drain (api-observers depends on script-session, so creation can't live in apply_*). Transients are marked component entries participating in the existing notify ancestor-walk — zero walk-structure change.

Tests

46 api-observers unit tests (8 transient + collapse/old-value-union/deep-descendant) + 3 VM integration tests (headline detached-subtree delivery + clear, move-adopt, re-observe) + full 6024-test elidex-js suite green; boa compiles.

Slots

Closes #11-mutation-transient-observers. Carves #11-mutation-transient-source-fidelity (observe() step-7.1 over-clear in the contrived multi-ancestor corner; within the sanctioned observer-id collapse). Standalone follow-up: split mutation.rs inline test module (file crossed 1000 via tests; source-only 494).

Pre-push gate

6-stage gate green (fmt → CI → /code-review high → /simplify → /review → /elidex-review). elidex-review: Axes 1–4 clean, Axis 5 IMP+2MIN addressed → 0 CRIT / 0 IMP. As-built spec re-verification deltas documented in plan §9 (notify collapse, free-fn placement, interleaved clear, citation-scope correction).

🤖 Generated with Claude Code

send and others added 4 commits June 27, 2026 09:38
B1.2d-i = MutationObserver transient registered observers (DOM §4.3): creation
(§4.2.3 remove step 15) hooked in notify_one (eager/synchronous per record);
clearing (§4.3 notify step 6.3) in deliver_pending_mutation_records via one ECS
query. Transient = a `transient:bool`-marked MutationObservedBy component entry
(ECS-native, participates in the existing notify-walk by construction). Layers:
VM + elidex-api-observers only (no script-session/dom-api change).

Decomposes the handoff's "B1.2d = Range + transient + live-range":
- live-range fixup = ALREADY DONE (LiveRangeBridge), not in scope.
- B1.2d-i (this) = transient observers (foundational chokepoint feature).
- B1.2d-ii (carved, own plan-review) = Range mutation records → apply_*.

/elidex-plan-review 5-agent: 0C / 2I (both fixed) / ~6 MIN (fixed) / 14 FP.
Approach validated (layering-clean, ECS-native, decomposition sound, algorithm
spec-accurate). IMPs caught: (1) my timing-model misdescription — notify_one is
EAGER/synchronous per-mutation, not a deferred microtask drain (the §7 FIFO race
evaporates; spec "during remove" by construction); (2) §4.3.1→§4.3 def citation
drift. Preflight + propagation re-verified. Closes #11-mutation-transient-observers
at landing.

IMPL PENDING (next session): implement per §5 → pre-push 6-stage → /external-converge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(DOM §4.3)

Implements §4.2.3 "remove" step-15 transient registered-observer creation +
§4.3 "notify mutation observers" step-6.3 clearing, so a node removed from a
subtree observed by an ancestor's subtree:true observer keeps delivering
records for mutations in the detached subtree until the next microtask.

- api-observers: MutationObservation gains `transient`; free fns
  add_transient_observers / clear_transient_observers — transients live on the
  per-node MutationObservedBy component (ECS-native; registry owns only record
  queues), cleared via one retain-query (shared retain_observations helper).
  observe() re-observe clears the observer's transients (step 7.1, source→
  observer-id collapse).
- notify refactored to the §4.3.2 interestedObservers per-observer map-collapse
  (one record per observer) — required so a removed node holding a permanent +
  transient (or multi-ancestor) registration for one observer collapses to a
  single record; also fixes a pre-existing multi-ancestor duplicate-record bug.
- VM: notify_one creates transients for ChildList removals (eager, during the
  remove, in JS-execution order); deliver loop clears per-observer interleaved
  (spec step 6.3, between 6.2 emptying the queue and 6.4 the callback).

Closes #11-mutation-transient-observers. Carves
#11-mutation-transient-source-fidelity (observe() step-7.1 over-clear in the
contrived multi-ancestor corner; within the sanctioned observer-id collapse).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- §8: ship-time registration commitment for the carved
  #11-mutation-transient-source-fidelity slot (register in
  project_open-defer-slots.md SoT at landing, alongside the
  #11-mutation-transient-observers close).
- §9: record the mutation.rs 1000-line crossing (618→1179, source-only 494;
  the inline test module is the standalone-split candidate, carried as a
  follow-up per the tree.rs-1019 precedent, not bundled here).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the §4.3.2 step-3.2.3 invariant (a non-requesting match never resets a
value a requesting registration set) — the one documented behavioral claim in
the notify map-collapse with no prior direct coverage (/review nit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57e1af1625

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/script/elidex-js/src/vm/host/mutation_observer.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
F1 (P2, mutation_observer.rs:512) — the §4.3 notifySet was derived from
record-queue non-emptiness (`observers_with_records`), so `mo.takeRecords()`
before the microtask dropped the observer and its step-6.3 transient clear
never ran (transient leaked → detached-subtree mutations kept notifying the
stale observer). Add the spec's "pending mutation observers" set (`pending`,
appended in queue-a-record step 4.3, drained by `take_pending_observers` =
notify step 2 clone + step 3 empty). Both VM and boa delivery switch to it;
the now-dead `observers_with_records` is removed.

F3 (P2, mutation.rs:164) — the re-observe step-7.1 predicate counted a
*transient* entry as an existing registration, so `observe(firstRemoved)`
before the microtask fired the whole-tree transient clear and discarded an
unrelated removed subtree's transients. Gate the predicate (and the
ensure-permanent find) on `!transient`: only a permanent registration is a
step-7.1 source under the source→observer-id collapse.

Regression tests: pending_observer_survives_take_records,
observe_on_transient_only_node_keeps_other_transients (api-observers) +
take_records_before_microtask_still_clears_transient (VM integration).

F2 (P3, test-module split) deferred to the standalone split task per CLAUDE.md
"split は単独 commit" + the #409 tree.rs-1019 precedent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R1 — 3 findings, all addressed (commit ac7cd3fd):

  • F1 (P2, takeRecords/notifySet) ✅ fixed — added the spec's "pending mutation observers" set (pending, drained by take_pending_observers) as the §4.3 notifySet, independent of record-queue contents, so step-6.3 transient clearing runs even when the page drained the queue via takeRecords(). VM + boa both switched; dead observers_with_records removed. +regression tests.
  • F3 (P2, transient-only re-observe) ✅ fixed — gated the step-7.1 predicate (and ensure-permanent find) on !transient, so observing a node that only carries a pending transient no longer wipes an unrelated removed subtree's transients. +regression test.
  • F2 (P3, split inline test module) — deferred to a standalone split task, per CLAUDE.md "1000-line debt … split は単独 PR / 単独 commit" (don't bundle the split into a feature PR) + the immediately-prior feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 tree.rs-1019 → task_2d979473 precedent in this same program (source-only is 494 lines; the file is >1000 only via the test module, which is itself the clean standalone unit).

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: ac7cd3fda3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac7cd3fda3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/api/elidex-api-observers/src/mutation.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs
Comment thread crates/script/elidex-js-boa/src/runtime/observers.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
…ind + source-keyed observe)

G1 (P2, vm_api.rs unbind) — clear_pending_records scrubbed only registry state,
leaving transient MutationObservedBy entries in the DOM; a same-DOM rebind could
deliver future detached-subtree mutations through a stale transient. Added
clear_all_transient_observers(dom), called in the bound Vm::unbind block before
dom_ptr is zeroed (permanent registrations untouched — they despawn with the
outgoing world or legitimately persist for a same-DOM rebind).

G4 (P2, mutation.rs observe step 7.1) — the observe-time clear was observer-keyed,
over-clearing transients sourced from a different inclusive-ancestor registration
of the same observer. Added `source: Option<Entity>` (the ancestor entity that
spawned each transient) + clear_transient_observers_by_source (source == target);
the notify clear (step 6.3) stays observer-keyed, clear_all (unbind) drops all —
three spec-distinct clears via the shared retain_observations. CLOSES the former
#11-mutation-transient-source-fidelity carve (the source key is the ancestor
entity, available at creation — no per-registration identity needed).

G3 (P2, boa observers.rs) — boa delivery lacks the transient lifecycle; scoped
out (boa deletion-bound, transients become the sole path at boa removal).
G2 (P3, test split) — deferred to the standalone split task (task_b3cd18da).

Regression tests: reobserve_preserves_other_source_transient,
clear_all_transient_observers_scrubs_transients_keeps_permanent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R3 — 4 findings addressed (commit 52d7a00d):

  • G1 (P2, unbind transient scrub) ✅ fixed — clear_pending_records scrubbed only registry state, leaving transient MutationObservedBy entries; added clear_all_transient_observers(dom) at the bound Vm::unbind block (before dom_ptr is zeroed) so a same-DOM rebind can't deliver through a stale transient. Permanent registrations untouched. +regression test.
  • G4 (P2, source-keyed observe step 7.1) ✅ fixed — added source: Option<Entity> (the ancestor entity that spawned each transient) + clear_transient_observers_by_source (source == target); the notify clear (step 6.3) stays observer-keyed, the unbind clear drops all — three spec-distinct clears via the shared retain_observations. This closes the prior provisional #11-mutation-transient-source-fidelity carve (the source key is the ancestor entity, available at creation). +two-ancestor regression test.
  • G3 (P2, boa transient lifecycle) — scoped out: boa is deletion-bound (D-26 PR7 / S5); the entire B-program targets MO delivery at the VM, with boa transitional. The transient lifecycle becomes the sole path when boa is removed. Per [[feedback_boa-findings-light-touch]] + plan §0.OUT(e).
  • G2 (P3, test-module split) — deferred to the standalone split task (task_b3cd18da), CLAUDE.md "split は単独 commit" + feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 tree.rs-1019 precedent (same as R1-F2).

A cumulative design re-gate over the R-loop delta (R1+R3) confirmed the lifecycle is coherent (one retain_observations primitive, three spec-keyed clears) — not an ad-hoc edifice.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52d7a00df3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
send and others added 2 commits June 27, 2026 12:41
…pend-order delivery

H1 (P2, observe step 7.1) — the ancestor-entity `source` key could not
distinguish multiple registrations of one observer on a single node (a permanent
+ a chained transient), so re-observing that node over-cleared a transient
sourced from a *different* registration (e.g. a grandparent-derived one on a
doubly-removed descendant). Replaced with the spec's registered-observer
identity: `MutationObservation` gains a `reg_id` (allocated from a registry
counter), `source` becomes `Option<u64>` (the originating registration's reg_id),
and observe step 7.1 clears by source reg_id. `add_transient_observers` is now a
registry method (it allocates reg_ids); it walks permanent AND transient ancestor
registrations (spec chained transients) tagging each transient with its source.

H2 (P2, pending delivery order) — `pending` was a `BTreeSet` delivering callbacks
in observer-id order; WHATWG DOM §4.3 iterates the pending **ordered set** in
append order (the order each observer first received a record this cycle). Made
`pending` an append-ordered `Vec` (dedup on insert); also made notify's
§4.3.2 `interestedObservers` an insertion-ordered Vec (walk order) so the per-
record append order is spec-faithful end-to-end (sibling-sweep — preempts the
intra-record ordering facet). Preserves B1/#213's determinism goal with the
spec-correct order.

Closes the source-fidelity theme (the former #11-mutation-transient-source-fidelity
is now fully resolved, not carved). Regression tests:
reobserve_distinguishes_chained_transient_sources_on_one_node,
pending_observers_preserve_append_order_not_id_order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pend-order contract

The cumulative design re-gate flagged take_pending_observers_is_id_sorted's
name/comment as stale after R4 made delivery append-order (it passed only
coincidentally for a single target). Rename to ..._drains_in_append_order and
assert registration/append order; the id-vs-append divergence stays covered by
pending_observers_preserve_append_order_not_id_order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R4 — 2 findings, both fixed at the root (commit 573df553):

  • H1 (P2, observe step 7.1 source identity) ✅ — the ancestor-entity source key couldn't distinguish multiple registrations of one observer on a single node (permanent + chained transient), so re-observe over-cleared a foreign-sourced transient. Replaced with the spec's registered-observer identity: MutationObservation gains reg_id (registry counter), source becomes Option<u64> (originating registration's reg_id), observe step 7.1 clears by source reg_id. add_transient_observers is now a registry method (allocates reg_ids) and walks permanent and transient ancestor entries (spec step-15 chained transients). +regression test (chained-source on one node). This closes the source-fidelity theme — the former provisional carve is fully resolved.
  • H2 (P2, pending delivery order) ✅ — pending was a BTreeSet (observer-id order); §4.3 iterates the pending ordered set in append order. Made pending an append-ordered Vec; also made notify's interestedObservers an insertion-ordered Vec (walk order) so the per-record append order is spec-faithful end-to-end (sibling-sweep). Preserves B1/refactor(observers): ECS-native component-on-entity for the 3 observer registries #213's determinism, now with the spec-correct order. +regression test.

A cumulative design re-gate over the full R-loop delta (R1–R4) confirmed the reg_id/source/pending/interested model is the spec's literal data model expressed ECS-native (fields on the component, no reverse index) — coherent, not an edifice.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 573df55337

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/plans/2026-06-b1.2d-transient-observers-plan.md Outdated
Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
…model

The §0.OUT(d)/§8/§9 as-built notes still described the R3 ancestor-entity
`source: Option<Entity>` / `source == target` model, which R4 superseded with
per-registration identity (`reg_id` + `source: Option<u64>`). Since this plan is
the B1.2 handoff, the stale notes could send follow-up observer/Range work back
toward the over-clear design R4 removed. Corrected §0.OUT(d), the closed-slot
note, and §9 (delta 9 now flags itself superseded; new deltas 11/12/13 record
R4-H1 reg_id, R4-H2 append-order, R5).

R5-I2 (test-module split, P3) = the recurring split MIN, deferred to task_b3cd18da.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R5 — 2 findings addressed (commit 200e92b5):

  • I1 (P2, stale as-built plan) ✅ — the plan §0.OUT(d)/§8/§9 still described the R3 ancestor-entity source model; R4 replaced it with per-registration identity (reg_id + source: Option<u64>). Updated the handoff notes to the reg_id final model so follow-up B1.2 work isn't misdirected toward the over-clear design (delta 9 flagged superseded; new deltas 11/12/13 record R4/R5).
  • I2 (P3, test-module split) — the recurring split MIN, deferred to the standalone task (task_b3cd18da) per CLAUDE.md "split は単独 commit" + feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 precedent (unchanged disposition; the split lands as its own PR).

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 200e92b559

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/plans/2026-06-b1.2d-transient-observers-plan.md Outdated
… source model

R5-I1 fixed §0/§8/§9 but left the pre-impl §3 spec-coverage table + §4 Design
"Data" bullet describing the superseded observer-id-collapse / "no source field"
model — which the B1.2d-ii handoff would follow back into the over-clear bug.
Swept the whole plan: §3 table rows (52/53) + §4 Data (65, marked SUPERSEDED
with the as-built reg_id model) now point at per-registration identity; also
cross-referenced §9-delta-1's BTreeMap→Vec change (R4-H2). Whole-doc sweep
rather than per-section patch to end the doc-staleness recurrence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R6 — 1 finding fixed (commit bf8df081):

  • J1 (P2, stale plan §4/§5 source model) ✅ — R5-I1 fixed §0/§8/§9 but the pre-impl §3 spec-coverage table + §4 Design "Data" bullet still described the superseded observer-id-collapse / "no source field" model, which the B1.2d-ii handoff could follow back into the over-clear bug. Swept the whole plan to the as-built reg_id model (§3 rows + §4 marked SUPERSEDED with the per-registration-identity model; cross-referenced §9-delta-1's BTreeMap→Vec). Whole-doc sweep to end the doc-staleness recurrence (vs the section-by-section patch in R5).

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf8df0812a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/plans/2026-06-b1.2d-transient-observers-plan.md
Comment thread docs/plans/2026-06-b1.2d-transient-observers-plan.md Outdated
…er (§9 authoritative)

R5-I1/R6-J1/R7-K1/K2 are the same recurring shape: a pre-implementation design
section (§4 Design / §5 Implementation) still describes the original model the
R-loop superseded. Patching bullet-by-bullet (§0→§3→§4→§5.1→§5.2) is #374
corner-hopping. Structural fix: a top-of-doc banner + §4/§5 banners declaring
§9 "As-built deltas" the single authoritative record for the B1.2d-ii handoff,
plus inline as-built pointers on the two flagged §5.1/§5.2 bullets (reg_id
source / pending notifySet / interleaved step-6.3 clear / mandatory unbind
scrub). Where §0–§8 conflicts with §9, §9 wins — so follow-up work cannot
re-derive the over-clear / takeRecords-leak / stale-unbind models from the
pre-impl prose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R7 — 2 findings (K1 §5.2, K2 §5.1), fixed structurally (commit b10b6b1c):

Both are the same recurring shape as R5-I1/R6-J1 — a pre-implementation plan section (§4 Design / §5 Implementation) still describing the original model the R-loop superseded. Rather than patch the prose bullet-by-bullet (the §0→§3→§4→§5 corner-hopping pattern), I neutralized the generating layer: a top-of-doc banner + §4/§5 banners declare §9 "As-built deltas" the single authoritative record for the B1.2d-ii / Range handoff (reg_id source / pending append-ordered notifySet / per-observer interleaved step-6.3 clear / mandatory unbind scrub), with inline as-built pointers on the two flagged §5.1/§5.2 bullets. Where §0–§8 prose conflicts with §9, §9 wins — so follow-up work can't re-derive the over-clear / takeRecords-leak / stale-unbind models from the pre-impl sketch.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b10b6b1c5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/api/elidex-api-observers/src/mutation.rs Outdated
Comment thread docs/plans/2026-06-b1.2d-transient-observers-plan.md Outdated
…ransient registrations)

L1 (P2, observe step 7/8) — the `!o.transient` predicate (R1-F3) treated a node
holding ONLY a transient registration for the observer as "not registered", so
step 8 added a spurious PERMANENT registration that outlived the next microtask's
step-6.3 transient clear (over-observation). Per webref, §4.3.1 step 7 matches
EVERY registration for `this` (a transient registered observer is a registered
observer); step 8 ("Otherwise") adds a permanent only if none matched. Rewrote
observe() to literal step 7/8: collect all matching reg_ids on target, clear by
each (step 7.1), set options on each (step 7.2), add permanent only if none
matched. Removes the `!transient` approximation entirely. R4-H1's two-ANCESTOR
case is unaffected (the re-observed node holds only a permanent → matches it,
preserves the other-ancestor-sourced transient); the chained permanent+transient
test now clears both (literal step-7 matches the transient too) — updated.

L2 (P2, doc) — §9-delta-2 still said add_transient_observers is a free fn;
corrected to the registry `&mut self` method (allocates reg_ids, R4).

Regression tests updated: observe_on_transient_only_node_keeps_other_transients
(no spurious permanent; transient updated in place) +
reobserve_matching_both_registrations_clears_both_chained_sources (renamed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R8 — 2 findings fixed (commit 63b0823a):

  • L1 (P2, observe() step 7/8) ✅ — the !o.transient predicate (from R1-F3) treated a node holding ONLY a transient registration as unregistered, so step 8 added a spurious permanent that outlived the microtask's step-6.3 clear. Per webref, §4.3.1 step 7 matches every registration for this (a transient IS a registered observer); step 8 adds a permanent only if none matched. Rewrote observe() to literal step 7/8 (collect all matched reg_ids → clear-by-source each → set-options each → step-8 only if none). Removes the !transient approximation. R4-H1's two-ancestor case is unaffected (re-observed node holds only a permanent); the chained permanent+transient case now correctly clears both. +tests updated.
  • L2 (P2, doc) ✅ — §9-delta-2 still called add_transient_observers a free fn; corrected to the registry &mut self method (it allocates reg_ids).

observe() is now literal §4.3.1 step 7/8 — the source-fidelity / re-observe area should be exhausted.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63b0823a52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/script/elidex-js-boa/src/runtime/observers.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R9 — 0 new findings (both already-dispositioned repeats):

  • boa transient lifecycle (P2) — repeat of R3-G3. Scoped out: boa is deletion-bound (D-26 PR7 / S5); the whole B-program targets MO delivery at the VM with boa transitional. The transient algorithm is engine-independent (elidex-api-observers); only boa's call sites are unwired, and per the boa-findings-light-touch policy boa-specific wiring on deletion-bound code is out of scope (transients become boa's sole path at its removal).
  • test-module split (P3) — repeat of R1-F2/R3-G2/R5-I2. Deferred to the standalone split task per CLAUDE.md "split は単独 commit" + feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 tree.rs precedent.

No new real findings → dry round (1/2 toward TERMINAL).

@codex review

@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R9 disposition (both = genuine cross-PR scope boundaries, no in-PR change):

  • boa `observers.rs:40` (P2) — same as the R3 G3 boa transient-lifecycle gap. boa-specific and boa-deletion-bound (D-26 PR7 / S5); the canonical VM path (VmInner::notify_one / deliver_pending_mutation_records) carries the §4.3 transient semantics. boa runtime is scoped out per the dual-runtime caveat and closes at boa removal, not patched here.
  • `mutation.rs:166` 1000-line split (P3) — real, but CLAUDE.md mandates the >1000-line split be a standalone PR / commit, not bundled into the feature PR (precedent feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 tree.rs → standalone follow-up). Tracked as a standalone split slot; deferred there rather than bundled here.

Resolving both threads on these dispositions.

@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63b0823a52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/api/elidex-api-observers/src/mutation.rs
…ep-7.1 scope-equivalence note

The post-Codex TERMINAL fix-delta /elidex-review pass (5-agent, over
`dfc07b76..HEAD`) caught two doc-only gaps the Codex R9/R10 dry rounds
missed (mirrors #409 where the TERMINAL fix-delta caught a citation drift):

- F1 (IMP, Axis 5): plan §9 "as-built deltas" (the declared SINGLE
  AUTHORITATIVE handoff record) stopped at delta 13 and left delta 7's
  `!transient`-gating claim stale — R8 reversed exactly that. Added delta
  14 (R8-L1 literal §4.3.1 step 7/8) and annotated delta 7 as superseded
  (mirrors the deltas 9→11 supersession). No code change.

- F2 (MIN, Axis 4): noted in the step-7.1 comment that the tree-wide
  `clear_transient_observers_by_source` sweep is equivalent to the spec's
  "for each node of this's node list" scope by construction (any node
  carrying a transient with `source == reg_id` necessarily carries a
  registration for this observer → it is in the query-derived node list).
  Comment-only; webref-verified observe() step 7.1 + notify step 6.3 are
  both node-list-scoped and equivalent here.

Axis 1/2/3 clean (0/0/0). All §4.3.1 step-7/8 + notify-6.3 citations
webref-verified correct (no #409-style drift). elidex-api-observers
52 tests green; elidex-js compiles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22545c90fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/api/elidex-api-observers/src/mutation.rs
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22545c90fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/script/elidex-js-boa/src/runtime/observers.rs
Comment thread crates/api/elidex-api-observers/src/mutation.rs
@send

send commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Codex R12 disposition — convergence reached (2 consecutive dry rounds on head `22545c90`, R11 + R12). Both remaining findings are pre-existing, already-seen genuine cross-PR scope boundaries (not new gaps):

  • boa `observers.rs:40` (P2) — boa runtime transient lifecycle (= the R3 G3 finding). boa-specific and boa-deletion-bound (D-26 PR7 / S5); the canonical VM path carries the §4.3 transient semantics. Scoped out per the dual-runtime caveat; closes at boa removal.
  • `mutation.rs` 1000-line split (P3) — real, but CLAUDE.md mandates the >1000-line split be a standalone PR/commit, not bundled into this feature PR (precedent feat(dom): B1.2b-3 — fold core Node insert methods onto canonical §4.2.3 pre-insertion-validity #409 tree.rs). Tracked as a standalone follow-up split slot.

R1–R8 spec-fidelity findings were all fixed at root; the post-Codex TERMINAL /elidex-review fix-delta additionally reconciled the §9 as-built record (added delta 14) and a step-7.1 scope-equivalence note. Ready to merge pending maintainer approval.

@send send merged commit bcee298 into main Jun 27, 2026
6 checks passed
@send send deleted the b1.2d-range-transient branch June 27, 2026 06:19
send added a commit that referenced this pull request Jun 27, 2026
…nsient}.rs (#417)

Standalone touch-time 1000-line-debt split (CLAUDE.md discipline).

mutation.rs (1629 lines) → directory module with source + two test files by scenario seam:

- mutation/mod.rs (610 lines): source body
- mutation/tests_core.rs (354 lines): notify/observe/disconnect/subtree/pending tests
- mutation/tests_transient.rs (687 lines): transient registered observers suite (DOM §4.3)

Mirrors script-session mutation/tests.rs + tests_replace_all.rs sibling pattern. Pure split — 52/52 tests pass, clippy clean, CI green (3 OS).

Surfaced by /elidex-review Axis 5 on PR #413 (B1.2d-i); kept as standalone per split discipline.
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