Repository navigation
Fix three intermittent CI failures (one is a real stale-misread race) - #8
Merged
Merged
Conversation
…an async assert
1. cli.test.js "detached run + status + result --wait" (`run flo_…: stale`) exposed a
real bug in deriveRunState: it read result.json first and run.lock last, with the
control-socket probe (≤300 ms) between, so a run that finished inside that window
read as "no result, no lock, journal present" — a completed run classified stale.
The engine writes result.json before releasing run.lock, so derivation now
re-derives once when a result has appeared by the time the lock is seen released.
Reproduced 10/10 with a stalled reader + slow engine start (CI's interleaving);
0/10 after. Pinned by a deterministic mcp.test.js case that completes a fake
engine on the reader's own probe connection.
2. viewer-search.test.js "SSE keepalive stays on schedule during a 64 MiB search"
measured wall-clock gaps (≤ 60 ms) in the same process as the search, so a single
preemption or GC pause failed it (0/25 under CPU contention). It now proves
DESIGN §5.4.7's contract ("the loop breathes every ≤1 MiB") by event-loop ORDER:
a 1 ms keepalive made due at every turn by an injected ≥1.1 ms-per-check clock,
keepalive writes and per-chunk deadline checks recorded on one thread. 25/25 under
the same contention on Node 18.17.1 and 24, and it now also catches 8 MiB chunks,
which the old budget missed on fast hardware.
3. cockpit.test.tsx show-args: waited for argsFn to be *called* (synchronous in the
click) and then asserted the panel before the promise's render committed. It now
waits for the rendered value, then asserts exactly one read.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three tests failed intermittently on GitHub-hosted runners on PRs that don't touch the code under test (PR #6 at 7ee1e3f, PR #7 at 76cc047). Each one is fixed below. #1 was a real production bug, not a test bug.
1.
cli.test.js› detached run + status + result --wait —run flo_…: stale(root · node 18.17.1)Cause (production).
deriveRunStatereadsresult.jsonfirst andrun.locklast, with the control-socket probe (≤300 ms) in between. A run that finishes inside that window is seen as "no result, no lock, journal present", and that gets classifiedstale. The engine closes its socket, writesresult.json, and only then releases the lock. The mock workflow goes from lock to result in about 15 ms. CI's failing test ran for 235 ms, so the very firstresult --waitpoll got the verdict.result --wait,flowition status, MCPflowition_result/flowition_statusand the viewer all treatstaleas a crash.Fix. After the lock is seen released, if
result.jsonhas appeared, derive again from it, once (src/run-state.js). This relies on the engine's existing order: result first, then lock release.Repro. I simulated CI's interleaving on Linux with Node 18.17.1: the engine starts 300 ms late and the reader stalls after its heartbeat read. Base: 10/10
stale. Fixed: 0/10. On macOS the reader stall alone gave 10/10 before and 0/20 after.Regression test (
test/mcp.test.js): a fake engine finishes on the reader's own probe connection, which fixes the interleaving deterministically. It fails withstalebefore the fix.The same misread also showed up once under
docker --cpus=1asseed-from: MCP flowition_run accepts and forwards seedFrom→actual: 'stale'. That is a fast-failing engine with no heartbeat, hitting the same race.2.
viewer-search.test.js› SSE keepalive stays on schedule during a 64 MiB search (root · node lts/*)Cause (test). The test required gaps of at most 60 ms (3 × a 20 ms keepalive) between pings, measured in the same process as the search. One preemption or GC pause breaks that on its own. CI saw a single 99 ms gap while every other gap was ≤46 ms. Under CPU contention it failed 0/25.
Fix. The test now checks DESIGN §5.4.7's actual contract, "the event loop breathes every ≤1 MiB", by event-loop order instead of milliseconds:
res.write) and per-chunk deadline checks are recorded on one thread.truncated: falseis now asserted).The test still uses a real SSE stream, and the keepalives must reach the real client.
Stress and mutation results. The new test passed 25/25 under the same contention on Node 18.17.1 and 24. Mutation checks:
readFilethen sync scan3.
cockpit.test.tsx› show-args disclosure —expected 'reading args…' to contain '"repo": "flowition"'(viewer · node 18.17.1)Cause (test). The test ran
waitFor(argsFn called), but that call happens synchronously inside the click. So the wait returned at once, and the panel was asserted before the promise'ssetLoadedrender had committed. I reproduced the exact CI error deterministically by delayingargsFnby 2 ms.Fix. The test now waits for the rendered value, then asserts
argsFnwas called exactly once for this run. It passes with 2, 50 and 300 ms of args latency, and 8/8 under load on Node 18.17.1/Linux.Verification
npm test(root): 549/549 on macOS. On Linux (Node 18.17.1 and 24,--cpus=4) the only failures were the twops-based pid-reuse tests, because thenode:*-slimimage has nops. GitHub's runners have it.npm --prefix viewer test: 73 files / 1166 tests, plus the walkthrough and perf suites, all green.