Skip to content

Fix master: flaky drop test and the cargo audit job - #6

Merged
pathscale merged 3 commits into
masterfrom
fix/ci-audit-and-flaky-drop-test
Jul 28, 2026
Merged

pathscale merged 3 commits into
masterfrom
fix/ci-audit-and-flaky-drop-test

Conversation

@pathscale

Copy link
Copy Markdown
Owner

master is currently red. PR #5 merged before two problems were caught.

1. dropping_a_run_kills_the_agent_and_its_children is flaky

It asserted the grandchild was gone after a fixed 300ms sleep. Passed locally and on the PR runner, failed on master's.

The bet was wrong in principle rather than unlucky: Drop cannot await, so it aborts the driver task and teardown happens when the runtime next polls it. Prompt, but not synchronous, and a loaded 2-vCPU runner beat the sleep.

The contract is "killed promptly", so the test polls for that with a 10s ceiling. A genuine leak still fails it.

The cancel test keeps its immediate, unpolled assertion, and that asymmetry is deliberate: cancel awaits its own teardown, so if the tree is not gone when it returns, the contract is broken. Documented the distinction in Run's docs and the README, since it is a real semantic difference callers should know: both kill the tree, only cancel tells you when.

2. cargo audit cannot find a lockfile

Cargo.lock is not committed, per library convention, so the job failed with "Couldn't load ./Cargo.lock". This fix was pushed to #5 about a minute after it merged, so it never landed.

Resolving a lockfile in CI is also the more meaningful check for a library: consumers resolve their own graph, so what matters is whether a fresh resolution pulls an advisory, not whether some pinned snapshot did.

Also swapped rustsec/audit-check for a prebuilt cargo-audit. The action compiles it from source on every run, which took 2m53s against a ~40s build for the crate itself. On a runner billed by vCPU-minute, that was most of the job's cost spent on the tool rather than the work.

Verified locally: 42 dependencies, no advisories.

Confirmed working

Ubicloud runners picked up #5's jobs and the check job passed on them in 44s, so the runner change itself is good.

meh added 3 commits July 29, 2026 02:00
Two problems with the job as first written.

Cargo.lock is not committed here, per library convention, so cargo audit had
nothing to read and failed with "Couldn't load ./Cargo.lock". Resolving one in
CI is also the more meaningful check for a library: consumers resolve their own
graph, so what matters is whether a fresh resolution pulls in an advisory, not
whether some pinned snapshot did.

rustsec/audit-check compiles cargo-audit from source on every run, which took
2m53s against a ~40s build for the crate itself. On a runner billed by
vCPU-minute that is most of the job's cost spent on the tool rather than the
work, so this installs a prebuilt binary instead.

Verified locally first: 42 dependencies, no advisories, so the original failure
was the missing lockfile and not a real vulnerability.
`dropping_a_run_kills_the_agent_and_its_children` asserted the grandchild was
gone after a fixed 300ms sleep. That held locally and on the PR runner, and
failed on master's, which is exactly the shape of a timing bet rather than a
test.

The bet was wrong in principle, not just unlucky. `Drop` cannot await, so it
aborts the driver task and the teardown runs when the runtime next polls it:
prompt, but not synchronous. A loaded 2-vCPU runner beat the sleep. The contract
is "killed promptly", so the test now polls for that with a 10s ceiling, which
still fails a genuine leak rather than hanging on it.

The cancel test keeps its immediate, unpolled assertion. That asymmetry is the
point: `cancel` awaits its own teardown, so if the tree is not already gone when
it returns, the contract really is broken.

Documented the distinction where callers will read it, in `Run`'s docs and the
README: both kill the tree, only `cancel` tells you when.
My previous commit diagnosed this as flaky timing and added polling. That was
wrong: it failed the same way on the next run, deterministically on Linux while
passing on macOS, which is a platform difference rather than a race.

The liveness check was `kill -0`, which succeeds for a zombie: a process that
has exited but whose parent has not reaped it. On a developer machine init
reaps orphans immediately so the distinction never shows. A CI container's PID 1
is frequently not a real init, so an orphaned grandchild sits as a zombie and
`kill -0` reports it alive indefinitely, long after the kill worked.

So the process-group teardown was correct the whole time and the test was
measuring the wrong thing. Now it reads the state from `ps` and treats `Z` as
dead, which it is: a killed process is dead whether or not anyone collected its
exit status.

Failures now report the actual process state, so the next surprise here
diagnoses itself instead of costing another round of guessing.

The polling from the previous commit stays. It was aimed at the wrong cause but
is still correct on its own terms, since Drop cannot await and its teardown is
prompt rather than synchronous.
@pathscale
pathscale merged commit 735a993 into master Jul 28, 2026
2 checks passed
@pathscale
pathscale deleted the fix/ci-audit-and-flaky-drop-test branch July 28, 2026 19:06
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