Skip to content

test: fix two base-gate flake races (mcp-inject pre-start kill; session-handoff wait-depth) - #814

Merged
danshapiro merged 2 commits into
mainfrom
fix/mcp-inject-pre-start-kill
Sep 20, 2026
Merged

danshapiro merged 2 commits into
mainfrom
fix/mcp-inject-pre-start-kill

Conversation

@danshapiro

Copy link
Copy Markdown
Owner

What

Two more load-race flakes surfaced by the origin/main base gate, both fixed test-side with structural reasoning, no widened timeouts:

1. mcp_inject: the pre-start kill of a timed-out conversion IS the reap

live_wslpath_timeout_falls_back_and_reaps_the_child read the child's pid file unconditionally after the conversion's 3s-deadline fallback. Under heavy parallel load (the workspace gate; WSL fork latency) the deadline can kill the child BEFORE its fork+exec runs — the pid file legitimately never exists, and the read panicked (mcp_inject_tests.rs:505, the rust-phase failure of the 2026-09-19 base gate).

The pid file is written as the script's FIRST statement, so its absence at read time deterministically means the child never started: a pre-start kill+wait IS the reap, while the leak this test guards against (a started sleep surviving) always leaves the file for the kill -0 assertion. The Err arm now returns as a valid outcome.

Mutation pair: with the conversion deadline forced to zero (the deterministic pre-start kill), the old test panics at :505 — the exact gate failure — and the fixed test passes. Under the real 3s deadline the normal path is unchanged.

2. session-handoff: wait for the SETTLED under-ticket binding row

the_claude_handoff_target_binding_carries_the_handoff_generation polled until ANY matching binding row existed, but an interim unfenced row (observed pair None) can land before the runner's under-ticket adoption — the row the assertions read. When the interim row won, the test asserted None against Some(generation) and panicked (isolated ~13% failure rate, 4/30; it blocked this branch's first pre-push gate).

The poll now requires the row that satisfies the contract (stamped with the supplied handoff pair). The r27 regression the test guards against still fails at the deadline — now with a full bindings dump. Post-fix: 0/40 isolated runs (pre-fix ~13%).

Evidence

  • freshell-platform: 236/236 green; freshell-freshagent targeted set green; cargo fmt clean; pre-push gate passed.

t and others added 2 commits September 19, 2026 19:47
… reap

The timeout test read the child's pid file unconditionally after the
conversion's 3s-deadline fallback — but under heavy parallel load (the
workspace gate; WSL fork latency) the deadline can kill the child
BEFORE its fork+exec ever runs, so the pid file legitimately never
exists and the read panicked (the third origin/main base-gate flake,
2026-09-19 rust phase, mcp_inject_tests.rs:505).

The pid file is written as the script's FIRST statement, so its
absence at read time deterministically means the child never started:
a pre-start kill+wait IS the reap (the property under test holds by
construction), while the leak this test guards against (a started
sleep surviving the timeout) always leaves the file behind for the
kill -0 assertion. The Err arm returns as a valid outcome instead of
panicking.

Mutation pair: with the conversion deadline forced to zero (the
deterministic pre-start kill), the old test panics at :505 — the exact
gate failure — and the fixed test passes; under the real 3s deadline
the normal timeout+reap+kill-0 path is unchanged (3.01s).
… not the first match

The r27 F2 test's bounded-poll broke on ANY matching binding row, but an
interim unfenced row (observed pair None) can land before the runner's
under-ticket adoption — the row the assertions read. When the interim
row won the race the test asserted None against Some(generation) and
panicked (isolated ~13% failure rate; the pre-push/base-gate flake).

Wait for the row that actually satisfies the contract — one stamped
with the supplied handoff (epoch, generation) pair — so the assertions
never read an interim row. The regression the test guards against (the
adoption writing None and never the pair) still fails at the deadline,
now with the full bindings dump. Post-fix: 0/40 isolated runs.
@danshapiro
danshapiro merged commit 8255c0f into main Sep 20, 2026
7 checks passed
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