Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
103 lines
5.9 KiB
Markdown
103 lines
5.9 KiB
Markdown
# Nested dismissal isolation — 2026-09-26
|
|
|
|
Status: controlled follow-up to [boundary recovery](BoundaryRecoveryExperiment.md),
|
|
Codex editorial analysis. Same pinned React/Radix fixture, now compared across
|
|
Chromium 151.0.7922.34 and Firefox 155.0, development and production builds.
|
|
No package upgrade, deployment, model call or accessibility certification.
|
|
|
|
## Design and provenance
|
|
|
|
[isolation.mjs](../experiments/boundary-recovery/isolation.mjs) bundles the unchanged
|
|
fixture with four variants, three fresh-page trials each, in fixed order. The
|
|
[48-trial receipt](../experiments/boundary-recovery/isolation-results.json) retains
|
|
successes, failures, focus snapshots, open/close transitions and layer event traces.
|
|
It hashes runner, fixture, lockfile, inspected dependency source and every bundle.
|
|
[Additional provenance](../experiments/boundary-recovery/isolation-provenance.json)
|
|
records Firefox build/executable hash and the initial sandbox launch failure.
|
|
|
|
- **raw:** unmodified dependencies, no layer tracing, immediate browser Escape
|
|
after focus arrives and a before-event snapshot is captured.
|
|
- **traced:** in-memory instrumentation logs layer registration, listener changes
|
|
and Escape handling; no intended change to vendor control flow.
|
|
- **ready:** same instrumentation; additionally waits until only the inner layer's
|
|
Escape listener is installed. This uses private instrumentation, not a public API.
|
|
- **guarded:** traced build adds a current-top-layer check at event handling time;
|
|
stale listeners return without dismissing. This is experimental modified behavior.
|
|
|
|
All variants retain keyboard Enter/Tab/Escape interaction and assert inner return
|
|
followed by outer return. No fixed settling sleep or hidden retry. Extra snapshots,
|
|
tracing and readiness observation can change scheduling. Results are exploratory
|
|
counts, not failure rates. Fixed ordering and three trials do not establish browser
|
|
or build superiority. Production mode changes React build selection, not the fixture
|
|
into a production application. The historical eight-case runner/results are unchanged.
|
|
|
|
## Results
|
|
|
|
Pass means both expected return targets were reached in order.
|
|
|
|
| Browser | Build | raw | traced | ready | guarded |
|
|
| --- | --- | --- | --- | --- | --- |
|
|
| Chromium | development | 2/3 | 2/3 | 3/3 | 3/3 |
|
|
| Chromium | production | 3/3 | 1/3 | 3/3 | 2/3 |
|
|
| Firefox | development | 3/3 | 3/3 | 3/3 | 3/3 |
|
|
| Firefox | production | 3/3 | 3/3 | 3/3 | 3/3 |
|
|
|
|
43/48 obligations met. Keep conditions separate: a readiness wait changes the
|
|
precondition, and the guard changes the implementation. An unmodified production
|
|
failure was not observed in these three Chromium trials; failures with tracing
|
|
show the timing problem is not restricted to a development bundle, but instrumentation
|
|
may influence whether its window is hit. Firefox's passes do not prove immunity.
|
|
|
|
## Captured mechanism
|
|
|
|
Chromium/development/traced trial 1 records this order:
|
|
|
|
1. Outer Escape listener is installed.
|
|
2. Inner layer is registered; focus reaches its close button.
|
|
3. Escape invokes the **outer** listener while the registered layer stack already
|
|
ends in the inner layer.
|
|
4. The outer listener is removed and the inner listener installed afterward.
|
|
5. Outer-close transition removes both dialogs; focus returns to the outer invoker.
|
|
|
|
This directly locates a stale Escape-owner interval in the instrumented fixture.
|
|
The shipped dismissable-layer module selects its listener using render-time
|
|
`isHighestLayer` and effect registration; event-time handling does not recheck the
|
|
current layer stack. Source hash matches the earlier inspected package. This
|
|
explains the captured wrong-owner dismissal; it is not a universal diagnosis of
|
|
all focus bugs or a claim about every Radix version/application.
|
|
|
|
Chromium/production/guarded trial 1 rejects the stale outer handler while focus is
|
|
inside the inner dialog. The inner listener is installed later. Both dialogs remain
|
|
open: the guard preserves the outer task but loses this Escape action. A check that
|
|
prevents a wrong transition is insufficient when it cannot deliver the valid action.
|
|
|
|
The readiness variant passes 12/12 by waiting for observed ownership before Escape.
|
|
It supports distinguishing focus arrival from event-owner readiness. It does not
|
|
establish a product solution: users cannot query this private trace, and a product
|
|
must define how input during the ownership transition is accepted, routed or deferred.
|
|
|
|
## Pattern disposition and next work
|
|
|
|
Refine [Focus Return](../candidates/FocusReturn.md): test both **which task may close**
|
|
and **where focus returns**, including input during activation and teardown. Neither
|
|
visibility nor focus alone proves the dismissal handler belongs to the active task.
|
|
Avoid arbitrary sleeps and avoid treating ignored input as successful recovery.
|
|
Keep hypothesis maturity; this is still one synthetic implementation family.
|
|
|
|
No new pattern is needed yet. The broader question is whether temporal ownership
|
|
belongs in the containing modal/interaction contract. A production repair would need
|
|
stable ownership/routing plus tests for opening, nesting, removal and teardown;
|
|
this study has not supplied or deployed such a repair. No upstream issue was sent.
|
|
|
|
WP-0003 T01 retains a bounded residual: evaluate a lifecycle-safe ownership strategy
|
|
without arbitrary delay and verify ordinary/nested dismissal in both browsers before
|
|
recommending it. Feature/import versus release-boundary research and navigation
|
|
checks remain open; this focused investigation does not complete those tasks or M2.
|
|
|
|
## Routing follow-up
|
|
|
|
[Experimental routing](NestedOwnershipRouting.md) now supplies a mechanism that
|
|
passes the tested ordinary/nested/cancel/removal/reopen/teardown cases without a
|
|
settling delay. It changes the owner-selection architecture, not just the stale
|
|
handler guard. Broader lifecycle coverage is still required for a recommendation;
|
|
this does not overwrite the failed isolation or guard results above.
|