A custom element waits one microtask, attaches shadow DOM, reads
scrollHeight, then sets data-state="opening" to
start a 0s animation. This mirrors the original repro. The shadow CSS
animates :host([data-state="opening"]) div. The handler sets
data-state="done" when animationend fires.
The 0s animation gets its start time at kPaintClean, but finish
events only dispatch on the next animation-frame timing update. If an
on-demand partial lifecycle update lands in that gap and samples the
animation as finished, affected builds drop it from servicing and the
finish/animationend event is never dispatched. The timing is
frame-scheduling dependent, so the miss rate varies by platform.
PASS: every case reaches data-state="done" after animationend.
FAIL: a case remains data-state="opening" after the timeout.