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
Found while fixing #593, whose own body reports six failing tests while CI on the same commit reported one. The discrepancy is not a difference in behaviour between the two environments. It is this setting, and resolving it took a full local build to do.
The finding
Every test preset in CMakePresets.json sets stopOnFailure:
All twelve, and .github/workflows/ci.yml drives every leg through ctest --preset ${{ matrix.preset }}. So a leg with six failures reports one, and the failure it reports is whichever one ctest reached first — which depends on the -j scheduling, so it is not even stably the same one across legs.
Measured, on one commit
PR #585 head a08db4f9, CI run 35467846733. Six legs failed. Each reported exactly one failing test:
Linux / clang-asan 1663 - SocketBackend: action result delivered via then (Failed)
Linux / clang-tsan 1663 - SocketBackend: action result delivered via then (Failed)
Linux / clang-ubsan 1669 - SocketBackend: action result delivered via then (Failed)
Linux / clang-coverage 2786 - SocketBackend: action result delivered via then (Failed)
The same branch, rebased onto master a020e69c and run locally without a preset (GCC 16.2.1, Debug, -DMORPH_BUILD_QT=ON -DMORPH_BUILD_NET=ON, ctest -j4):
99% tests passed, 6 tests failed out of 1833
The following tests FAILED:
1660 - SocketBackend: action result delivered via then (Failed)
1676 - SocketBackend: executeTimeout surfaces as backend::TimeoutError, not a generic runtime_error (Failed)
1681 - SocketBackend: many concurrent in-flight executes all resolve, matched by callId (Failed)
1689 - SocketBackend: server dropping mid-call resolves the pending completion with DisconnectedError (Failed)
1692 - SocketBackend: two backends share one server with isolated model state (Failed)
1833 - SocketBackend interop: connects to a QtWebSocketServer and completes an action (Failed)
One cause, six symptoms, and CI showed one of them.
Note that the Valgrind memcheck leg on that same run, which does not go through a test preset, reported all of its five:
That is the shape of report the preset legs suppress.
Why it matters
Blast radius is invisible. "One test fails" and "every test that registers a handler over this transport fails" are different verdicts about whether a PR is one line from green. qt: move QtWebSocketBackend onto the structural registration surface #585's own PR body read the CI logs correctly and still described the failure as singular for three revisions.
Each extra symptom costs a CI cycle. Fix the first failure, push, wait 26–74 minutes, discover the second. With six symptoms that is potentially six cycles to learn what one uninterrupted run would have printed.
It interacts badly with -j. The reported test is a race, so two runs of the same red commit can name different tests and look like two different regressions.
What it is not
stopOnFailure is a defensible setting for a leg whose later tests are meaningless once an early one fails, and for one that is expensive to run to completion. This ticket is not "delete it everywhere" — it is that the twelve presets adopt it uniformly and nothing records why, while the one leg that does not use a preset produces a strictly more useful report at apparently no cost (that leg is Valgrind, the slowest in the matrix, which is evidence against "it is there to save time").
Verification status
Reproduced. The preset listing above is real output from the tree at a020e69c. The CI counts are read from run 35467846733's job logs, not inferred. The six-failure local run is measured, on the rebased branch, with the build configuration stated.
Not measured: how much wall-clock a full run costs on each leg versus a stop-at-first — i.e. the actual price of turning it off. Somebody proposing a change should measure that, per leg, before changing all twelve.
What would change the verdict
Close this if a leg-by-leg measurement shows running to completion materially lengthens the matrix and the current behaviour is a deliberate trade — but then it wants a comment in CMakePresets.json saying so, because it is currently unexplained.
Close this if ctest's --stop-on-failure can be left on while still printing the full failing set, which would make this a reporting fix rather than a policy one. I did not check whether it can.
Found while fixing #593, whose own body reports six failing tests while CI on the same commit reported one. The discrepancy is not a difference in behaviour between the two environments. It is this setting, and resolving it took a full local build to do.
The finding
Every test preset in
CMakePresets.jsonsetsstopOnFailure:All twelve, and
.github/workflows/ci.ymldrives every leg throughctest --preset ${{ matrix.preset }}. So a leg with six failures reports one, and the failure it reports is whichever onectestreached first — which depends on the-jscheduling, so it is not even stably the same one across legs.Measured, on one commit
PR #585 head
a08db4f9, CI run 35467846733. Six legs failed. Each reported exactly one failing test:The same branch, rebased onto master
a020e69cand run locally without a preset (GCC 16.2.1, Debug,-DMORPH_BUILD_QT=ON -DMORPH_BUILD_NET=ON,ctest -j4):One cause, six symptoms, and CI showed one of them.
Note that the
Valgrind memcheckleg on that same run, which does not go through a test preset, reported all of its five:That is the shape of report the preset legs suppress.
Why it matters
-j. The reported test is a race, so two runs of the same red commit can name different tests and look like two different regressions.What it is not
stopOnFailureis a defensible setting for a leg whose later tests are meaningless once an early one fails, and for one that is expensive to run to completion. This ticket is not "delete it everywhere" — it is that the twelve presets adopt it uniformly and nothing records why, while the one leg that does not use a preset produces a strictly more useful report at apparently no cost (that leg is Valgrind, the slowest in the matrix, which is evidence against "it is there to save time").Verification status
Reproduced. The preset listing above is real output from the tree at
a020e69c. The CI counts are read from run 35467846733's job logs, not inferred. The six-failure local run is measured, on the rebased branch, with the build configuration stated.Not measured: how much wall-clock a full run costs on each leg versus a stop-at-first — i.e. the actual price of turning it off. Somebody proposing a change should measure that, per leg, before changing all twelve.
What would change the verdict
CMakePresets.jsonsaying so, because it is currently unexplained.ctest's--stop-on-failurecan be left on while still printing the full failing set, which would make this a reporting fix rather than a policy one. I did not check whether it can.🤖 Generated with Claude Code
https://claude.ai/code/session_01AbwhcguQFkhvVi2AH19sWk