Skip to content

ci: run the money-path suite in its own job (#271) - #276

Merged
orveth merged 1 commit into
devfrom
fix/271-decouple-money-path-ci
Jul 30, 2026
Merged

ci: run the money-path suite in its own job (#271)#276
orveth merged 1 commit into
devfrom
fix/271-decouple-money-path-ci

Conversation

@orveth

@orveth orveth commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes the blinding half of #271. Unblinds money CI; does not fix the acp flake — that is deliberate and stays open on the issue.

The defect

Test mobee-core (money-path suite) was step 8 of the acp job, behind Test mobee-core (acp) at step 7. When step 7 dies, step 8 is marked skipped and the job reports failure. The check list then shows one red row that cannot distinguish "the money suite failed" from "the money suite never ran" — and since the acp step has been dying intermittently on dev, main, and every PR, that ambiguity was on every money-path signal in the repo.

This is worth stating precisely because the usual framing ("a skipped row looks like a passing row") is not quite what happens here. It is worse: the row goes red, so a reader may well believe the money suite ran and failed.

The fix

money-path is now its own job — own runner, no needs: — so nothing else in the workflow can take it down or absorb its result.

Why a separate job rather than if: always()

The issue offered both. I took the separate job, and one reason I expected to give turned out to be wrong, so I am not giving it:

  • Not "if: always() cannot run because the runner is dead." The job records a conclusion of failure, so the runner was alive. if: always() probably would have executed. I withdrew that argument.
  • Shared runner means shared fate. if: always() keeps the suite on the same runner as the fault it is meant to outlive. It papers over one instance instead of removing the shared-fate surface.
  • Its own resource budget. The leading hypothesis for the acp kill is that the test's ACP-subprocess peak lands at completion and crosses a runner limit. Running the money suite on that same runner is precisely the exposure to avoid.
  • Independently readable, independently requireable. As a distinct Money-path tests check it can be made a required context on its own. Inside the acp job its result is unreadable from the check list.

Evidence

Job isolation survives this exact fault — measured, not assumed. Run 30487009981 attempt 2, the red one:

conclusion job
SUCCESS Release workflow gates
FAILURE Build (acp) + money-path tests
SUCCESS Build & test (default features)

Two sibling jobs completed successfully while that job died ⇒ the kill is job-scoped, so a separate job is not collaterally killed. This is evidence from the real failure rather than a synthetic control.

Also verified locally before pushing:

  • actionlint clean (rc=0) — with a positive control: the same binary returns rc=1 and names both defects on a deliberately broken workflow, so the silence on this file means "passed", not "never ran".
  • The money-path cargo test invocation is byte-for-byte unchanged (diffed against HEAD).
  • No needs: anywhere in the workflow.
  • Job/step map: build-acp → build, build, Test mobee-core (acp); money-pathTest mobee-core (money-path suite).

Rename, and a thing to confirm

build-acp's display name becomes Build & test (acp), since it no longer runs money-path tests. The job id is unchanged. I checked before renaming: classic branch protection is absent on main and dev, and ruleset 20000440 carries no required status checks, so no required context is named after this job. Worth a second pair of eyes — if any config I cannot see pins the old display name, that pin needs updating with this.

Not in scope

  • The acp flake itself. Bounded on the issue: the kill lands 1s past the passing duration, so it is coupled to test completion, not a wall-clock budget; leading suspect is the conjunction of teardown child-process peak and runner-to-runner resource variance. Probes named there.
  • A test-count floor (feature-gated suites can print ok having run nothing). Real, separately valuable, not this PR.
  • Making Money-path tests a required check — needs a protection config that does not currently exist.

The money-path tests are the only tests in CI carrying money teeth, and they
ran as the final step of the acp job. When the acp concurrency test dies they
are marked `skipped` while the job reports `failure` — a single red check that
cannot distinguish "the money suite failed" from "the money suite never ran".
Every money-path signal in the repo carried that ambiguity.

They now run in their own job, on their own runner, with no `needs:`. Job
isolation is what empirically survives this fault: on run 30487009981 attempt 2
both sibling jobs passed while the acp job died.

`if: always()` is the cheaper edit but a weaker guarantee — it leaves the suite
on the same runner as the fault it is meant to outlive, and still buries its
result inside another job's conclusion. The split gives up no build sharing:
this suite compiles its own feature set (--no-default-features --features
gateway,git-delivery,wallet, in release) and reused none of the acp job's build
output. The cargo invocation is byte-for-byte unchanged.

The acp job keeps its build coverage and is named for what it runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mobee Ready Ready Preview Jul 30, 2026 12:03am

Request Review

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant