Two async-timing tests fail intermittently on CI. Same bytes in, different outcome each run — so a red check on a PR currently carries no information about the PR.
Evidence
Three CI runs of the same tree (commits differ only by amend; git diff between them is empty), PR #218:
| run |
commit |
result |
| 1 |
b90645b |
FAIL — packages/e2e-tests › bridges back to a stale Opus cache after more than 20 Fable blocks |
| 2 |
4dfbf7f |
FAIL — packages/opencode › writes the manifest before clearing a migrated legacy handle |
| 3 |
e2af7f6 |
PASS |
Two different tests, then green, from identical source.
The two failures
bridges back to a stale Opus cache… — waitForSessionText gives up after ~36–42 s waiting for the Fable recovery window complete. Returning to Fable 5. notice (packages/opencode/src/index.ts:783). It passed on another CI run in 16 s, so the wait is racing notice delivery rather than observing a stuck one.
writes the manifest before clearing a migrated legacy handle (packages/opencode/src/tests/index.test.ts:2451) — asserts on stateAtManifestWrite, captured inside an fs.rename spy. It failed with Received value must be an array type…, i.e. the capture was still undefined: the startup migration had not reached its manifest write by the time getPlugin returned and the assertion ran.
Both are the same shape — an assertion racing detached async work, with no barrier tying the two together.
Not reproducible locally
writes the manifest… passes 5/5 in isolation and inside full-suite runs (1874/1874, repeatedly). The e2e test fails consistently on my machine — but it fails identically on a clean detached worktree at main, so that is a local environment issue, not a signal about either PR.
Suggested fix
Same treatment as #176: replace the implicit timing assumption with an explicit barrier. For the migration test, expose or await the startup migration's completion rather than relying on it finishing before getPlugin resolves. For the e2e test, wait on the notice being queued rather than on its rendered text, or raise the bound with a named timeout that says what it was waiting for.
Happy to take either if useful — filing first since both are pre-existing and neither is related to what I am working on.
Two async-timing tests fail intermittently on CI. Same bytes in, different outcome each run — so a red
checkon a PR currently carries no information about the PR.Evidence
Three CI runs of the same tree (commits differ only by amend;
git diffbetween them is empty), PR #218:b90645bpackages/e2e-tests›bridges back to a stale Opus cache after more than 20 Fable blocks4dfbf7fpackages/opencode›writes the manifest before clearing a migrated legacy handlee2af7f6Two different tests, then green, from identical source.
The two failures
bridges back to a stale Opus cache…—waitForSessionTextgives up after ~36–42 s waiting for theFable recovery window complete. Returning to Fable 5.notice (packages/opencode/src/index.ts:783). It passed on another CI run in 16 s, so the wait is racing notice delivery rather than observing a stuck one.writes the manifest before clearing a migrated legacy handle(packages/opencode/src/tests/index.test.ts:2451) — asserts onstateAtManifestWrite, captured inside anfs.renamespy. It failed withReceived value must be an array type…, i.e. the capture was stillundefined: the startup migration had not reached its manifest write by the timegetPluginreturned and the assertion ran.Both are the same shape — an assertion racing detached async work, with no barrier tying the two together.
Not reproducible locally
writes the manifest…passes 5/5 in isolation and inside full-suite runs (1874/1874, repeatedly). The e2e test fails consistently on my machine — but it fails identically on a clean detached worktree atmain, so that is a local environment issue, not a signal about either PR.Suggested fix
Same treatment as #176: replace the implicit timing assumption with an explicit barrier. For the migration test, expose or await the startup migration's completion rather than relying on it finishing before
getPluginresolves. For the e2e test, wait on the notice being queued rather than on its rendered text, or raise the bound with a named timeout that says what it was waiting for.Happy to take either if useful — filing first since both are pre-existing and neither is related to what I am working on.