fix(gate): give each step its own log and stop grep eating it #723

Merged
coilyco-ops merged 1 commit from test/pin-names-the-issue-that-owns-it into main 2026-08-13 20:46:50 +00:00
Member

ward exec gate reported test FAIL on a clean tree and printed this instead of the reason:

test           FAIL
Binary file /tmp/ward-gate.log matches
exit status 1

The next run passed. I never learned which test failed, and that is the defect: the gate is the one habit AGENTS.md asks everyone to run, and it can fail without saying why.

Two causes, both in gate_step

if "$@" >/tmp/ward-gate.log 2>&1; then
  ...
  grep -ivE 'Passed|Skipped' /tmp/ward-gate.log >&2 || tail -20 /tmp/ward-gate.log >&2

A fixed path. Every concurrent gate on the host writes the same file. Four seats share this machine, and two overlapping runs interleave into one log.

grep without -a. One NUL byte and grep prints Binary file ... matches, suppressing every real line. It exits 0, so the || tail -20 fallback never fires and nothing readable survives.

Reproduced both ways, same input:

old form:  probe  FAIL
           Binary file /tmp/ward-gate-probe.log matches

new form:  probe  FAIL
           FAIL: the real reason

The change

mktemp per step instead of one path, grep -a, and remove the log after. No change to what the gate checks or to its exit status.

What I am not claiming

That concurrency caused my failing run. The log was destroyed, so the original test FAIL is unexplained and stays that way. It was either a flaky test or cross-run interference, and I would rather leave that open than pick one. This change means the next occurrence is readable.

Acceptance

  • Two gates running at once cannot corrupt each other's diagnostic.
  • A step whose output contains a NUL still prints its reason.
  • ward exec gate passes end to end, unchanged.

Next owner

Engineer. Closed by the pull request that lands the change.

ward exec gate PASS on all six steps after the change.

closes #722

`ward exec gate` reported `test FAIL` on a clean tree and printed this instead of the reason: ``` test FAIL Binary file /tmp/ward-gate.log matches exit status 1 ``` The next run passed. **I never learned which test failed**, and that is the defect: the gate is the one habit `AGENTS.md` asks everyone to run, and it can fail without saying why. ## Two causes, both in `gate_step` ```sh if "$@" >/tmp/ward-gate.log 2>&1; then ... grep -ivE 'Passed|Skipped' /tmp/ward-gate.log >&2 || tail -20 /tmp/ward-gate.log >&2 ``` **A fixed path.** Every concurrent gate on the host writes the same file. Four seats share this machine, and two overlapping runs interleave into one log. **`grep` without `-a`.** One NUL byte and grep prints `Binary file ... matches`, suppressing every real line. It exits **0**, so the `|| tail -20` fallback never fires and nothing readable survives. Reproduced both ways, same input: ``` old form: probe FAIL Binary file /tmp/ward-gate-probe.log matches new form: probe FAIL FAIL: the real reason ``` ## The change `mktemp` per step instead of one path, `grep -a`, and remove the log after. No change to what the gate checks or to its exit status. ## What I am not claiming **That concurrency caused my failing run.** The log was destroyed, so the original `test FAIL` is unexplained and stays that way. It was either a flaky test or cross-run interference, and I would rather leave that open than pick one. This change means the next occurrence is readable. ## Acceptance - Two gates running at once cannot corrupt each other's diagnostic. - A step whose output contains a NUL still prints its reason. - `ward exec gate` passes end to end, unchanged. ## Next owner Engineer. Closed by the pull request that lands the change. `ward exec gate` PASS on all six steps after the change. closes #722
fix(gate): give each step its own log and stop grep eating it
All checks were successful
ci / image-build (pull_request) Successful in 4s
ci / test (pull_request) Successful in 36s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
8e39c1a00a
ward exec gate reported test FAIL on a clean tree and printed "Binary file
/tmp/ward-gate.log matches" instead of the reason. The next run passed and the
failing run is unexplained, because its diagnostic was destroyed.

Two causes. The log path is fixed, so concurrent gates on a host four seats
share write the same file. And grep without -a turns one NUL into "Binary file
matches", exiting 0, so the || tail fallback never fires.

mktemp per step, grep -a, remove the log after. What the gate checks and what
it exits with are unchanged.

closes #722

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!723
No description provided.