Skip to content

cov-ci: wall-clock-bounded tests fail under llvm-cov instrumentation on a loaded machine (false-failure class) #360

Description

@hartsock

Observation

just cov-ci failed twice in a row at the same place:

thread 'main' panicked at agent-bridle-tool-shell/tests/brush_real.rs:688:10:
a confined stdin-reader must not block on the operator terminal: Elapsed(())

That is confined_stdin_reader_gets_eof_not_the_operator_terminal, whose teeth
are a 10-second tokio::time::timeout wrapped around spawning a brush
worker and running /bin/cat.

It is not a defect in the code under test. The same test passes cleanly in
the same worktree uninstrumented (cargo test -p agent-bridle-tool-shell --no-default-features --features brush --test brush_real). Both failures were
under cargo llvm-cov on a developer machine that was heavily loaded at the
time (load average in the thousands, i/o-wait bound, several concurrent
workspace builds). The bound is losing a race with i/o wait, not detecting a
hang.

Why this deserves a fix rather than a re-run

The failure is indistinguishable from a real regression at the point of
reading it: an Elapsed panic on a test whose docstring says the timeout IS
the regression detector for "the child blocked on the operator terminal". A
reviewer who sees it in CI has no way to tell "the fd-0 fix regressed" from
"the runner was busy", and the honest response — re-run it — is exactly the
habit that hides real failures.

CI's coverage job is the same shape (instrumented, shared runner), so this is
not purely a local-machine artifact.

The class, not just the instance

Any test whose assertion is a wall-clock bound has this property. At least:

  • brush_real.rs::confined_stdin_reader_gets_eof_not_the_operator_terminal (10s)
  • brush_real.rs::confined_run_is_bounded_by_the_wall_clock_ceiling
  • the #269 / AB-006 timeout-kill tests (real_timed_out_child_is_killed_and_never_writes_marker and the grandchild variant), which sleep past a deadline and assert a marker is absent

Note the repo already draws this line correctly for authority (no wall clock as a coordination primitive; caveats key on valid_for_generation). These
tests use wall-clock legitimately — they bound work — but the bounds were
chosen against an idle machine.

Options

  1. Scale the bounds under instrumentation: multiply when a coverage/profile
    env var is present (LLVM_PROFILE_FILE is set by cargo llvm-cov), so the
    uninstrumented bound stays tight and the instrumented one stays honest.
  2. Replace the bound with a causal oracle where one exists. The stdin test
    really asks "did the child get EOF", which a sentinel file or an explicit
    read() result answers without a clock; the timeout is only there to stop a
    hang. Both can coexist: assert the causal fact, keep a generous timeout as a
    hang-stop.
  3. Serialise the coverage run (--test-threads), reducing self-inflicted load
    at the cost of wall-clock.

Preference: (2) where the test has a causal oracle available, (1) as the blanket
guard for the rest. Not fixing this in-flight — filed so it is not re-discovered
later as an unexplained flake.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions