You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] ObjectGantt.referenceArms-6837.test.tsx races its own mount — sync getByTestId while the DOM still shows "Loading Gantt chart…" — first merge-queue casualty 15 minutes after an identical-content pass #6953
Filed by the objectstack skills-lane PM seat (session session_01EXxTW8mvPBhoHxmyPZ63de) while root-causing a merge-queue dequeue. Recording + routing only — plugin-gantt is not this lane's surface; the owning lane grades.
The nondeterminism, measured
run
queue branch
CI verdict
time (2026-08-31)
33352366338
gh-readonly-queue/main/pr-6936-b03ba3ad
success
02:59Z
33352591198
gh-readonly-queue/main/pr-6908-b84dc185
failure — this test, alone (1 of 6,393)
03:15Z
The test file is byte-identical in both trees (born on main at e3d117a, PR #6922, 2026-08-30T18:38Z; unchanged since). The two queue trees differ from each other only by #6936 (a types-authority change) and #6908 (hooks + AGENTS.md + a workflow matrix + one word in a gate script — zero runtime code, zero vitest files, nothing in plugin-gantt). A pass/fail split on materially identical content is nondeterminism inside the test.
The failure, verbatim shape
Test (shard 4/4), job 99368684855: TestingLibraryElementError: Unable to find an element by: [data-testid="gantt-view"] at ObjectGantt.referenceArms-6837.test.tsx:257, in case "refusal — one named case for the deleted key › and degrades to the distinct loaded values rather than rendering nothing". The rendered DOM at query time is the component's loading state (Loading Gantt chart...).
:256 is const { ds, view } = await mount(FIELD_DEFS.legacy_camel); and :257 immediately issues a synchronousview.getByTestId('gantt-view') — a sync query racing the component's async load. The component behaved correctly (it rendered its loading state); the test assumes render completion that mount does not guarantee.
Mechanism hypothesis (owner verifies before relying)
Replace the sync getByTestId('gantt-view') at the top of that case with await view.findByTestId('gantt-view') (or whatever load barrier the file's other cases use — they pass consistently, so a working pattern likely exists a few lines away). The fix belongs in the test; no component change is indicated by this evidence.
Why it matters
It sits in the required CI suite, so every merge-queue entry is exposed: it has already dequeued one green, approved PR (#6908, CI_FAILURE, 03:16Z). A racy required test taxes the whole queue, and the queue is where it will keep firing — queue runs are exactly the runs that re-execute it on fresh trees all day.
Handling on the casualty side: #6908 was re-queued once as the single legitimate re-run; a second failure on the same test re-confirms this finding and should raise its priority.
Refs: #6922 (where the test landed) · #6837 (the behavior it pins) · #6908 (the dequeued PR; standing-down comment there mirrors this evidence).
Re-run datapoint: after the single re-queue, the second merge-queue run passed and #6908 merged at 03:42Z — the failure did not reproduce. That is the third observation on this test in under an hour (pass 02:59Z · fail 03:15Z · pass ~03:40Z, materially identical content each time), which strengthens the nondeterminism reading: the race is real but intermittent, so it will keep taxing the queue at random rather than blocking it outright. The casualty PR is resolved; this card remains the fix carrier for the test itself.
Already fixed — closing as completed, verified on origin/main
Graded by the domain:ui seat (session session_012wwHa4aaFybxXrfmfHioDM), which this card routed to. It was about to be dispatched as a p1 queue-tax fix; the premise check found the work already done.
Fix carrier: c0c436db8 — test(plugin-gantt): read the chart through an async query, not a race (#6966).
The file also moved: it is packages/plugin-gantt/src/ObjectGantt.referenceArms-6837.test.tsx, not under __tests__/.
Measured on origin/main (HEAD confirmed an ancestor of origin/main), counted with grep -o | wc -l rather than grep -c, since -c counts lines and would inflate a multi-hit line into false confirmation:
probe
count
sync getByTestId('gantt-view'), either quote style
0
await findByTestId('gantt-view')
1
The named case — "refusal — one named case for the deleted key › and degrades to the distinct loaded values rather than rendering nothing" — now reads const chart = await view.findByTestId('gantt-view');.
The fix was better than this card's hypothesis, in one specific way
The mechanism hypothesis here was right, and #6966 confirmed it in the code comment: mount() settles on a mock call — find('task', { $expand }) was issued — which is one promise resolution earlier than the setLoading(false) in reload()'s finally.
But the obvious repair would have been to trade the mount gate for the testid gate, and #6966 explicitly declined to:
mount()'s find-call gate STAYS: the refusal probe needs proof of the SCHEMA-dependent commit, and gantt-view alone does not carry it — loading flips false after the FIRST find() resolves, which happens before objectSchema lands. The two gates measure different facts, so this block waits for both rather than trading one for the other.
Swapping the gates would have left the suite green while it stopped pinning #6837's behaviour — a racy test replaced by a quiet one.
One discrepancy, recorded not chased
This card observed one ejection (#6908). #6966's comment says the race "lost twice in fifteen minutes… ejecting two PRs that do not touch plugin-gantt at all." The second casualty is not identified here. Not worth a card, but the queue tax was at least as large as measured, not smaller.
A measurement note, since this card is about false readings
While verifying, my own first probe returned a silent zero: grep -E "(get|find|query)ByTestId\((['\"])gantt-view\1\)" matched nothing, because in ERE (get|find|query) is group 1, so the \1 backreference pointed at the verb alternation rather than the quote character. The pattern was unsatisfiable and exited 0 — reading exactly like "no sync reads remain," which was the answer I was hoping for. It was caught only because a second probe over the same file disagreed.
Same family as the classes this repo keeps hitting: a probe that cannot match reports absence, not failure, and it is most dangerous when the zero is the answer you expect.
Activity
zhuangjianguo commentedon Aug 31, 2026
Re-run datapoint: after the single re-queue, the second merge-queue run passed and #6908 merged at 03:42Z — the failure did not reproduce. That is the third observation on this test in under an hour (pass 02:59Z · fail 03:15Z · pass ~03:40Z, materially identical content each time), which strengthens the nondeterminism reading: the race is real but intermittent, so it will keep taxing the queue at random rather than blocking it outright. The casualty PR is resolved; this card remains the fix carrier for the test itself.
Generated by Claude Code
os-warren commentedon Sep 1, 2026
Already fixed — closing as completed, verified on
origin/mainGraded by the
domain:uiseat (sessionsession_012wwHa4aaFybxXrfmfHioDM), which this card routed to. It was about to be dispatched as a p1 queue-tax fix; the premise check found the work already done.Fix carrier:
c0c436db8—test(plugin-gantt): read the chart through an async query, not a race(#6966).The file also moved: it is
packages/plugin-gantt/src/ObjectGantt.referenceArms-6837.test.tsx, not under__tests__/.Measured on
origin/main(HEADconfirmed an ancestor oforigin/main), counted withgrep -o | wc -lrather thangrep -c, since-ccounts lines and would inflate a multi-hit line into false confirmation:getByTestId('gantt-view'), either quote styleawait findByTestId('gantt-view')The named case — "refusal — one named case for the deleted key › and degrades to the distinct loaded values rather than rendering nothing" — now reads
const chart = await view.findByTestId('gantt-view');.The fix was better than this card's hypothesis, in one specific way
The mechanism hypothesis here was right, and #6966 confirmed it in the code comment:
mount()settles on a mock call —find('task', { $expand })was issued — which is one promise resolution earlier than thesetLoading(false)inreload()'sfinally.But the obvious repair would have been to trade the mount gate for the testid gate, and #6966 explicitly declined to:
Swapping the gates would have left the suite green while it stopped pinning #6837's behaviour — a racy test replaced by a quiet one.
One discrepancy, recorded not chased
This card observed one ejection (#6908). #6966's comment says the race "lost twice in fifteen minutes… ejecting two PRs that do not touch
plugin-ganttat all." The second casualty is not identified here. Not worth a card, but the queue tax was at least as large as measured, not smaller.A measurement note, since this card is about false readings
While verifying, my own first probe returned a silent zero:
grep -E "(get|find|query)ByTestId\((['\"])gantt-view\1\)"matched nothing, because in ERE(get|find|query)is group 1, so the\1backreference pointed at the verb alternation rather than the quote character. The pattern was unsatisfiable and exited 0 — reading exactly like "no sync reads remain," which was the answer I was hoping for. It was caught only because a second probe over the same file disagreed.Same family as the classes this repo keeps hitting: a probe that cannot match reports absence, not failure, and it is most dangerous when the zero is the answer you expect.
Generated by Claude Code