Skip to content

core/test: project-board-panels is order-dependent and reds merge groups at random (it ejected #1825 once) #1843

Closed

Description

@HugoXK

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.

Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: bbcd50297ba84d3dad4f26da8e7b5dae
Branch: dev/3-flaky-panel-state
Base: b4e05ac
At: 2026-10-30T15:01:10Z

Baseline

Checked on main = b4e05acf9c2785eced88e94f1b70e4f15c860c9f (2026-10-30). core/test/project-board-panels.test.js and its mirror are byte-identical there (sha256 875357b9497f34d9358a3d381199901685ff97028ad96b2eb22f3ed355aba663, 14125 bytes each). #1835 did not touch either file.

What happens

core/test/project-board-panels.test.js is order-dependent and fails intermittently in a merge group. It already cost one queue ejection on 2026-10-30:

  • 11:16:34Z #1825 entered the merge queue; the merge-group run 41046947850 (job 124033238715, ubuntu-latest · Node 24 · DSH 0.2.0-rc.2) went red on this file, and github-merge-queue[bot] removed the PR at 11:19:20Z.
  • 11:21:57Z the same PR at the same tip 33a5d463 was queued again; run 41047579302 went green. Same code, same test, different outcome.

Failing assertion (the test starts at :169, the assertion at :177):

✖ the settings panel memory save lands in the Project memory through the real endpoint
AssertionError: the panel reports the state the host answered
+ actual:  'Assistant settings saved.'
- expected: 'Memory saved.'

Why it is order-dependent

  • The panel keeps its status line in component state: core/src/client/project-board.js:349 const [status, setStatus] = useState(''), written only from run() (:351-363) after await save(...).
  • The test's React stand-in keeps hook slots in module scope and never clears them between tests: core/test/project-board-panels.test.js:33 let slots = [], :34 let index = 0, and :58 const render = (component, props) => { index = 0; return component(props) } — only the cursor is reset, not the slots.
  • The earlier test in the same file clicks project-assistant-save (:158-161), leaving 'Assistant settings saved.' in that slot. The later test re-renders, clicks project-memory-save, and settle() (:77, ten tick()s) is a fixed number of turns rather than a wait for the status to change — under CI load the async run() has not landed yet, so the stale line is what gets read.

So the defect is in the test harness (shared state + fixed-tick wait), not in the host and not in the panel.

Expected

  1. Each test starts from clean hook slots: a fresh state map per test (or per render() of a new tree), so one test's clicks cannot be read by another.
  2. The assertion waits for the condition rather than a fixed number of ticks: e.g. await waitFor(() => text(status) === 'Memory saved.') with a bounded timeout, or await Promise.resolve() chains that end when the save promise settles.
  3. The file passes in a loop and in a shuffled order: run it at least 20 times in a row, and run it with the :158 block placed after the :166 block, with no failure.
  4. Nothing about the production behaviour changes: the panel still reports the host's answer, Memory saved. on success and the host's sentence on refusal, in zh under a zh locale.

Scope

  • core/test/project-board-panels.test.js only, plus its byte-identical mirror patches/ds-bot/files/test/project-board-panels.test.js. The slot reset (around :33-58) and the wait helper (settle at :77, used at :174, :186 and :213).
  • The wait helper lives inside this test file. Do not extract it into a shared helper under core/test/: that would pull other test files into this issue's scope.
  • No production code. The change lands in the test fixture only; core/src/** and core/client.js stay untouched. If the fix appears to need a source change, stop and report instead of widening this issue.
  • No changelog fragment: test-only, not user-visible.

Acceptance

The two order criteria are one criterion, taken together — either alone proves nothing:

  • 20 consecutive runs green and the same file green with the two offending blocks swapped (the :158 block after the :166 block). Record both in the PR body: the run count and the swapped-order result.
  • npm run verify green, check's three ok lines green, build-client --check green.
  • No change to any user-visible sentence.

Duplicate check

search/issues on repo:ThinkFlowLab/FlyBot (open and closed) for flaky, merge queue, project-board-panels, settle returns no issue about this harness; the only related ones are #1820/#1823 (the panel's write path and its fix), which are about behaviour, not test order. git grep -n "slots = \[\]" b4e05acf -- core/test shows the shared slot array only in this file.

Why this is not scheduled as one of the daily four

It is a precondition for the other four: while it can red a merge group at random, any finished PR can fail to reach main. The Lead keeps it outside the daily quota and ahead of them in priority; the owner-set daily four (P-239, P-230, P-234, P-237) keep their own order.

Activity

  1. Birfy commented on Oct 30, 2026

    @Birfy
    Collaborator

    Written-by: Chief

    状态补记:agent-pr。本单已有开放 PR #1850(dev/3-flaky-panel-state,tip ed4ddb9c,正文 Fixes #1843),此前本单没有任何状态标签。CI、入队与合并由开该 PR 的那条线负责,本线不接手。

    读取时间 2026-10-30T16:35Z,来源 api.github.com。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions