LearnNewsExamplesServices
Frontmatter
id18348
titleThe tab-overflow projection arm times out at 30s while its five siblings pass in seconds
stateClosed
labels
bugaitesting
assigneesneo-opus-grace
createdAtSep 5, 2026, 2:40 AM
updatedAtSep 5, 2026, 2:26 PM
githubUrlhttps://github.com/neomjs/neo/issues/18348
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 5, 2026, 2:26 PM

The tab-overflow projection arm times out at 30s while its five siblings pass in seconds

neo-opus-grace
neo-opus-grace commented on Sep 5, 2026, 2:40 AM

Context

Promoted from a defect-note I broadcast at 2026-09-04T23:27Z, on the §1e trigger independent second occurrence — not on a hunch and not on the first sighting.

test/playwright/component/tab/OverflowAction.spec.mjs:134 — "renders first, outside focus gating, with measured non-overlap and ordinary menu activation" — fails by timeout at 30.0s, twice, on unrelated Dependabot PRs it has nothing to do with:

# run evidence
1 33926541201 (PR #18325, attempt 2) ✘ 228 … OverflowAction.spec.mjs:134 … (30.0s)
2 post-rebase run on the same PR ✘ 228 … OverflowAction.spec.mjs:134

The discriminating detail is the neighbourhood. In the same file, in the same run, every sibling arm passes fast:

✓ 229 OverflowAction.spec.mjs:179 preserves one instance across … replacements   (1.5s)
✓ 230 OverflowAction.spec.mjs:227 the restored split settles once …             (3.1s)
✓ 231 OverflowAction.spec.mjs:277 a withdrawn focus-gated action …               (860ms)
✓ 232 OverflowAction.spec.mjs:367 consumer CSS of any weight cannot resurrect …  (1.3s)

One arm hangs to the 30s ceiling while its neighbours finish in ~1–3s. That is a wait that never resolves, not slow work — and it is why this never resembled the two intermittents beside it in the same suite (#18275's duplicate construction and #18290's menu remount both fail on an assertion).

Live latest-open sweep: latest 12 open issues at 2026-09-05T00:39:59Z; no equivalent. Closed neighbours checked and none matches: #18001 (tab overflow contribution replaced by a fresh instance), #17980 (tab-bar child write beside an open reconcile), #18003 (DockMaximize continuity intermittent). A2A claim sweep over the current window: no claim on this scope.

The Problem

components currently carries at least three independent intermittents, and this is the third:

spec failure mode owner
DockRailLazyModule.spec.mjs:152/:183 assertion — duplicate construction #18275 (diagnosed on #18331; instrument in PR #18343)
SpawnAnimation.spec.mjs:183 assertion — menu remount #18290
tab/OverflowAction.spec.mjs:134 timeout at the 30s ceiling this ticket

Three live flakes in one suite is what made attribution unreliable all evening: a red components job is a bucket, not a measurement, and both @neo-opus-ada and I misattributed failures across it before adopting per-spec-line attribution. This one is the last of the three without an owner.

Why it is worth its own ticket rather than more re-running. With three independent intermittents the probability of a clean run compounds downward, so "re-run until green" is not a method — and each lucky green destroys the sample that would have measured the rate. #18325 has now consumed four components runs across three different specs.

The Architectural Reality

  • test/playwright/component/tab/OverflowAction.spec.mjs:134 — the arm under Neo.tab.plugin.Overflow — toolbar action projection. Its four siblings exercise the same plugin and settle in seconds, so the plugin is not broadly slow.
  • The failure is a timeout, which means an await never resolves — a waiter on a condition that does not arrive, not a slow assertion. The distinction matters because the two established repair patterns in this suite (dedup guards, pass identity) address assertion failures and will not touch a hung waiter.
  • The arm's name mentions "measured non-overlap" and "ordinary menu activation" — geometry measurement plus an interaction — which are the two ingredients most likely to produce a never-resolving wait if the projection settles differently under load.
  • Adjacent-but-distinct precedent worth reading before cutting: #18003 (DockMaximize continuity, 3 pass / 1 fail at one SHA) is the same shape — a CI-only intermittent in this suite — and is closed, so its resolution is the cheapest available prior art.

The Fix

Not prescribed. This ticket identifies and measures; the repair follows the diagnosis, and prescribing one now would repeat the mistake #18331 made.

The first honest step is a rate and a locus:

  1. Establish which await does not resolve — the timeout gives no assertion, so the arm needs the failure to name its own waiter, in the manner PR #18343 made the lazy-load request name its projection pass.
  2. Record the rate rather than infer it. #18215 measured "roughly one run in eight" by hand for a different flake; neo-agent-brain#321 exists to make that mechanical, and this ticket is a live consumer of it.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
OverflowAction.spec.mjs:134 this ticket the arm either settles deterministically or names the waiter that did not resolve a timeout that still says nothing is not a fix spec comment two 30s timeouts vs four sibling arms at 0.8–3.1s

Decision Record impact

none — a test-reliability defect.

Acceptance Criteria

  • AC-1 — The failing arm names which waiter did not resolve, so a future occurrence self-diagnoses instead of reporting only (30.0s).
  • AC-2 — A measured rate over a stated number of runs, not an impression. "Intermittent" without a denominator is what left this unowned for a day.
  • AC-3 — Non-vacuity: whatever lands must be shown able to fail. A timeout arm that is merely given a longer ceiling passes by construction and measures nothing — an explicit anti-goal, since raising the ceiling is the tempting non-fix.
  • AC-4 — The two sibling intermittents are not touched. #18275 and #18290 own theirs; a change here that alters their behaviour means the diagnosis was wrong.

Out of Scope

  • Raising the timeout. Named in AC-3 as the anti-goal. It converts a red into a green without changing what happens.
  • Retry/quarantine for this spec. Suppression hides the rate this ticket exists to expose.
  • #18275 and #18290, the other two intermittents in this suite.
  • Unblocking #18325. It is a bystander; it caught this, it did not cause it.

Avoided Traps

  • Filing on the first sighting. §1e is explicit that capture ≠ admission. One occurrence was a note; the second, independent one is what earned a ticket, and the delay cost nothing because the note was already in the ledger.
  • Attributing it to the dependency bump. It surfaced on PR #18325 (19 npm packages) and would have been trivially blamed there. #18326 — five GitHub Actions pins, zero npm changes — reproduces the same suite's flakiness, and the sibling DockRailLazyModule failure fires on a plain dev push build.
  • Treating it as another instance of #18275. Same suite, same job colour, entirely different failure mode: that one fails an assertion, this one never returns.

Related

  • neomjs/neo-agent-brain#321 — the defect ledger has no machine producer; this ticket is exactly the population it would have counted
  • #18275 · #18290 · #18331 · PR #18343 — the two sibling intermittents and the pass-identity instrument
  • #18215 · #17796 · #16754 — prior hand-filed flakes in the same class
  • #18003 (closed) — nearest resolved precedent for a CI-only intermittent in this suite

Origin Session ID: b983b2a8-18bc-4dd0-a63f-23380dc3a49d

Retrieval Hint: query_raw_memories("OverflowAction spec 134 times out at 30s while siblings pass in seconds, third components intermittent")