LearnNewsExamplesServices
Frontmatter
id15410
titleTear-out popup reaped at birth: post-exit geometry jump reads as re-entry
stateClosed
labels
bugai
assigneesneo-fable, neo-fable-clio
createdAtJul 18, 2026, 5:28 AM
updatedAtJul 18, 2026, 6:32 AM
githubUrlhttps://github.com/neomjs/neo/issues/15410
authorneo-fable-clio
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 18, 2026, 6:32 AM

Tear-out popup reaped at birth: post-exit geometry jump reads as re-entry

neo-fable-clio
neo-fable-clio commented on Jul 18, 2026, 5:28 AM

Context

Found and rate-confirmed by the #15243 portability-matrix witnesses on the LANDED tear-out grammar (the colors surface, pre-G1): the mid-gesture popup is nondeterministically closed ~2 ms after birth — silently, before pointer-up, before any deliberate continued movement. Reproduction rate under the headed witness: 5/6 reaps (--repeat-each=6; session total ~8 reaps across 12 same-choreography runs) — the dominant outcome, not a flake. Receipts + the full record: learn/guides/specificfeatures/TearOutPortabilityMatrix.md footnote ³ (commits f12b9c7c91611adb7fb7bbc9e66db3 on the #15243 branch).

The race predates G1 (#15244 / PR #15408 references it, correctly not gated on it) and silently violates the epic's gesture-continuity universal invariant when it fires; the revalidationTrigger question is with the D#15204 round (my recommendation on record: no pause — this ticket IS the re-evaluation path).

The Problem

Sequence when the reap fires:

  1. Boundary-exit converts proxy → real popup mid-gesture (SortZone#checkWindowBoundarydashboard.Container#onDragBoundaryExitopenWidgetInPopupNeo.Main.windowOpen). The popup is born.
  2. ≥1 additional pointer move lands inside the acquisition race window (a real-user hand always keeps moving; the witness reproduces it whenever its acquisition loop admits one extra move).
  3. The popup closes ~2 ms after birth: closedBeforeUp: true, closedAfterMoveMs negative relative to deliberate post-acquisition movement, zero console captured on the page.

Instrument-blindness correction (negative-claims discipline): earlier receipts said "no re-entry involvement" — RETRACTED. The colors app runs on a SharedWorker, whose console page.on('console') cannot observe, so onDragBoundaryEntry's own log line was invisible to the witness. The sweep scope was the page console only; the re-entry path was never exonerated.

The Architectural Reality (the hypothesis, source-anchored)

The boundary-EXIT reconfigures the exact geometry the hysteresis reads:

  • src/draggable/container/SortZone.mjs:270 checkWindowBoundary — direction-aware: isMovingIn = intersectionRatio > me.lastIntersectionRatio; re-entry fires when isMovingIn && intersectionRatio > reattachThreshold (0.6) while isWindowDragging.
  • On exit, startWindowDrag hides the drag placeholder and expands the remaining items (the documented choreography) — the proxy/boundary rects the NEXT move's ratio is computed from are no longer the pre-exit rects. A geometry-driven ratio JUMP reads as "moving in" above 0.6 → false dragBoundaryEntry.
  • src/dashboard/Container.mjs:152-175 onDragBoundaryEntry:167 await Neo.Main.windowClose({names: widgetName})src/Main.mjs:507 closes the named window. The ~2 ms reap, end to end.

The executed falsifier (run distribution): survivals correlate exactly with zero post-birth moves (witness stops at acquisition — 3 early greens + the 1/6); reaps with ≥1 extra move inside the ~50 ms race window (5/6). One deliberate post-birth move should reproduce deterministically; zero moves should survive deterministically — the confirming experiment for whoever takes this.

The Fix (candidates — decided at implementation with witness evidence)

  1. Reset lastIntersectionRatio at exit (cheapest): the first post-exit move then computes direction against post-exit geometry, killing the false jump.
  2. Require N consecutive moving-in samples before re-entry fires (hysteresis in time, not just ratio).
  3. Gate re-entry on the live proxy rect rather than post-exit layout geometry (the proxy is hidden post-exit — a hidden proxy should never satisfy re-entry).

Whichever lands: a headed regression witness on the matrix runner (deliberate post-birth move → popup survives) + the SharedWorker-visible diagnostic channel (BroadcastChannel, per the established worker→page pattern) so the next investigation is not instrument-blind.

Acceptance Criteria

  • The mechanism is confirmed or corrected via the deliberate-post-birth-move experiment (deterministic reproduction) + a SharedWorker-visible re-entry diagnostic.
  • The chosen fix lands with the false re-entry eliminated: repeat-each=6 headed shows 6/6 popup survival with post-birth movement.
  • The genuine re-entry path (a REAL drag back above 0.6 moving in) still works — witnessed.
  • The matrix doc footnote ³ updated from hypothesis to attributed mechanism; row 3's moveTo sampling unblocks.
  • The D#15204 round's revalidationTrigger question is re-evaluated with the attribution (expected: resolved as fixed, no reopen).

Out of Scope

G1 dock semantics (#15244/#15408 — proceeds in parallel, referencing this) · the matrix's remaining rows (#15243) · popup-over-popup (G3, #15395/#15396).

Decision Record impact

none — a defect fix inside the landed grammar; ADR 0029's outcome machine is unaffected (the false re-entry BYPASSES the machine's intent, which is the bug).

Related

#15243 (the discovering witness + receipts) · #15239 epic · #15244 / PR #15408 (G1, references this race) · D#15204 (the trigger question) · #15247 (vessel close policy — the legitimate close path this false path impersonates).

Live latest-open sweep: latest 8 checked at 2026-07-18T03:29Z; no equivalent (nearest: #15407 G1 contract tier — disjoint). A2A: no competing claim; the attribution successor was announced unclaimed in my 53ffd96c broadcast.

Origin Session ID: abce4d75-7dcb-4145-8afc-b0ff2cdc51e6

Retrieval Hint: query_raw_memories("birth race false re-entry geometry jump lastIntersectionRatio windowClose reap")