Two contract suites fail under scripts/run-plugin-tests.sh --jobs 4 in CI, pass serially and pass locally, and no hypothesis so far explains why. Both are on the serial allowlist as a fail-toward-running measure so the parallel runner can land; this issue holds the debt so the allowlist entries do not become permanent by default.
Evidence
Run 33787030286 on melodic-software/claude-code-plugins, plugin-gate job, Run plugin contract tests step, branch ci-perf/phase-2-scripts, head 68f18b483, runner ubuntu-24.04.
plugins/discovery/agents/tool-honesty.test.sh — two assertions failed:
FAIL - explorer.md: the return payload has no `persistence:` field — a completed run whose write was refused cannot be told apart from one that never ran
FAIL - researcher.md: the return payload has no `persistence:` field — a completed run whose write was refused cannot be told apart from one that never ran
The identical assertion passed for intent-tracer.md in the same run. The check is body "$agent" | grep -q '^persistence: ' at plugins/discovery/agents/tool-honesty.test.sh:147. Check 6 immediately below it (scope_as_received/topic_as_received) uses the same body() helper on the same files and passed for all three, so body() produced output at least once per file.
plugins/work-items/tools/work-item-tracker/conformance/bindings/jira.test.sh — case [4] failed:
FAIL: [4] conformance --binding jira exit 0 — expected 0 got 1
Case [5] is the same conformance run under a PATH shim that makes gh and curl exit 1, and it passed. Case [4] is therefore the only one of the pair that runs with real network tools on PATH.
What is not the cause
- Not a pre-existing failure.
main's own most recent run at the same parent SHA (33706296925) passed both suites. That run failed only plugins/performance/scripts/ab.test.sh, a wall-clock benchmark already on the serial allowlist.
- Not a
pipefail plus grep -q SIGPIPE race. This was the first hypothesis: tool-honesty.test.sh sets set -uo pipefail, and grep -q exits on its first match, which can leave awk writing into a closed pipe and turn a successful match into a non-zero pipeline status. Two hundred iterations of the exact pipeline under load produced zero failures, and the file body fits inside the pipe buffer, so awk finishes writing before grep -q can exit. Rejected.
- Not visible resource exhaustion. The run's log was searched for
fork, Resource temporarily unavailable, Cannot allocate, out of memory, No space left, too many open files and Killed. Only ordinary test prose matched. If a fork or allocation failure is behind this, it left no message.
- Not reproducible locally on a developer box. Both suites pass on Windows Git Bash on this branch. That box reports 32 cores against the hosted runner's 4, so it cannot reproduce contention on a 4-vCPU runner; local reproduction is the wrong instrument here and a local pass is not evidence.
Standing hypothesis
The suites are spawn-bound, and four concurrent ones on a four-vCPU hosted runner is the aggressive end of the range docs/topics/ci-perf/research/PROFILE-ccp-scripts.md predicted. The jira case is the more legible half: it is the one case in that file that runs with real gh and curl reachable, so network or rate-limit contention under concurrency is a plausible mechanism. tool-honesty.test.sh has no clock, no network and no shared state, and remains unexplained.
Done means
Either the mechanism is identified and the underlying defect fixed, at which point both entries come off scripts/run-plugin-tests-serial.txt, or this issue records why the entries stay with the reason stated as something other than "unexplained".
A --jobs 3 measurement is planned on the same branch and will be recorded here: if the failures disappear at three concurrent suites, that is evidence for the contention hypothesis and the job count, not the allowlist, is the lever.
Refs melodic-software/github-iac#385
Two contract suites fail under
scripts/run-plugin-tests.sh --jobs 4in CI, pass serially and pass locally, and no hypothesis so far explains why. Both are on the serial allowlist as a fail-toward-running measure so the parallel runner can land; this issue holds the debt so the allowlist entries do not become permanent by default.Evidence
Run 33787030286 on
melodic-software/claude-code-plugins,plugin-gatejob,Run plugin contract testsstep, branchci-perf/phase-2-scripts, head68f18b483, runnerubuntu-24.04.plugins/discovery/agents/tool-honesty.test.sh— two assertions failed:The identical assertion passed for
intent-tracer.mdin the same run. The check isbody "$agent" | grep -q '^persistence: 'atplugins/discovery/agents/tool-honesty.test.sh:147. Check 6 immediately below it (scope_as_received/topic_as_received) uses the samebody()helper on the same files and passed for all three, sobody()produced output at least once per file.plugins/work-items/tools/work-item-tracker/conformance/bindings/jira.test.sh— case [4] failed:Case [5] is the same conformance run under a PATH shim that makes
ghandcurlexit 1, and it passed. Case [4] is therefore the only one of the pair that runs with real network tools on PATH.What is not the cause
main's own most recent run at the same parent SHA (33706296925) passed both suites. That run failed onlyplugins/performance/scripts/ab.test.sh, a wall-clock benchmark already on the serial allowlist.pipefailplusgrep -qSIGPIPE race. This was the first hypothesis:tool-honesty.test.shsetsset -uo pipefail, andgrep -qexits on its first match, which can leaveawkwriting into a closed pipe and turn a successful match into a non-zero pipeline status. Two hundred iterations of the exact pipeline under load produced zero failures, and the file body fits inside the pipe buffer, soawkfinishes writing beforegrep -qcan exit. Rejected.fork,Resource temporarily unavailable,Cannot allocate,out of memory,No space left,too many open filesandKilled. Only ordinary test prose matched. If a fork or allocation failure is behind this, it left no message.Standing hypothesis
The suites are spawn-bound, and four concurrent ones on a four-vCPU hosted runner is the aggressive end of the range
docs/topics/ci-perf/research/PROFILE-ccp-scripts.mdpredicted. The jira case is the more legible half: it is the one case in that file that runs with realghandcurlreachable, so network or rate-limit contention under concurrency is a plausible mechanism.tool-honesty.test.shhas no clock, no network and no shared state, and remains unexplained.Done means
Either the mechanism is identified and the underlying defect fixed, at which point both entries come off
scripts/run-plugin-tests-serial.txt, or this issue records why the entries stay with the reason stated as something other than "unexplained".A
--jobs 3measurement is planned on the same branch and will be recorded here: if the failures disappear at three concurrent suites, that is evidence for the contention hypothesis and the job count, not the allowlist, is the lever.Refs melodic-software/github-iac#385