lib/hook-utils.test.sh: 'a Windows backslash path' begin case is flaky on Linux CI #4357
Description
Activity
- addedneeds-triageNot yet classified. Floor until a type and one priority tier are set.Not yet classified. Floor until a type and one priority tier are set.
on Sep 23, 2026 This was generated by AI during triage.
Additional occurrence, from #4360 (being closed as a duplicate of this issue): on PR #4210, CI run 35865887568, job
test-linux (2)(https://github.com/melodic-software/claude-code-plugins/actions/runs/35865887568/job/107197366977), twobegincases failed in the same suite:FAIL: begin: a nested path → FILE_DIR '' (want '/a'), FILE_BASE '' (want 'b.md') FAIL: begin: a Windows backslash path → FILE_DIR '' (want '.'), FILE_BASE '' (want 'x.md') PASS=505 FAIL=2Same shard and the same empty FILE_DIR/FILE_BASE signature, so the defect is not limited to the Windows backslash row: the nested path row of the same post-read loop failed too. Re-running only the failed job on the same commit passed, and an earlier head with byte-identical content passed every job.
- marked lib/hook-utils.test.sh: begin path-split cases fail intermittently on test-linux #4360 as a duplicate of this issue
on Sep 23, 2026 - addedpriority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.Fully specified and briefed; eligible for autonomous pickup from the frontier.status: readyTriaged, unblocked, and fully specified; eligible to pick up.Triaged, unblocked, and fully specified; eligible to pick up.and removedneeds-triageNot yet classified. Floor until a type and one priority tier are set.Not yet classified. Floor until a type and one priority tier are set.
on Sep 23, 2026 This was generated by AI during triage.
Agent Brief
Type: Bug
Summary: Make thehook::begintable-driven cases in the hook-utils test suite pass deterministically on Linux CI.Current behavior:
Ontest-linux (2)the post-readbegincases intermittently report emptyFILE_DIRandFILE_BASE(the "a Windows backslash path" row on runs 35858998103 and 35865887568, the "a nested path" row on 35865887568). Re-running the same commit passes. Empty values for both fields mean the driver never printed itsREACHED=1block for the row: eitherhook::beginexited before the print or the row output was lost. The rows use theBG_STUB_FILEreader stub. Root cause has not been reproduced.Desired behavior:
Everybeginrow yields its expectedFILE_DIR/FILE_BASEon every run, on Linux, including under CI-like parallel load.Key interfaces:
hook::begin(shared hook-utils library): its stdin read and path split.- The test suite driver for the
beginpost-read loop and itsBG_STUB_FILEstub.
Acceptance criteria:
- Reproduce first: a loop of the suite on Linux (under parallel load like the CI matrix shard) that shows the empty-output failure, with the observed failure rate recorded in the PR.
- The root cause is named in the PR body, backed by the reproduction.
- After the fix, the same loop runs the same number of iterations or more with zero failures, and the full hook-utils suite passes.
- If the fix is in
hook::begin, no other suite that sources the shared library regresses.
Out of scope:
- Rewriting unrelated cases in the suite.
- CI retry or rerun logic that masks the flake instead of fixing it.
Problem
On PR #4352, CI run 35858998103, job
test-linux (2), step "Run plugin contract tests", one case inlib/hook-utils.test.shfailed:When I reran the failed job on the same commit (
f43d49e), it passed, so the case is nondeterministic. PR #4352 does not touchlib/hook-utils.shor its test. The suite passes locally on Windows Git Bash with 510/0.Both fields came back empty. That means the driver never printed its
REACHED=1block for this row:hook::beginexited before the printf, or the row's output was lost. The case is the table-driven "post-read half" loop atlib/hook-utils.test.sharound line 3899, which uses theBG_STUB_FILEreader stub.Done when
hook::begin, is made deterministic.