From 11ca26d9fd49ededd8dd04b59ce2db652c31c957 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 2 Sep 2026 08:56:50 +0000 Subject: [PATCH] test(repo-hygiene): pin batch_read_lines_into under ulimit -n 10 The fixed fd 3 open was added for a low nofile ceiling, but no case exercised that limit. A future {fd} allocator would regress silently. No linked issue Co-authored-by: ksextonmelodic --- .../repo-hygiene/.claude-plugin/plugin.json | 2 +- plugins/repo-hygiene/CHANGELOG.md | 9 ++++++ .../clean/scripts/lib/batch-common.test.sh | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/plugins/repo-hygiene/.claude-plugin/plugin.json b/plugins/repo-hygiene/.claude-plugin/plugin.json index f4e117faa3..ba198f3f2f 100644 --- a/plugins/repo-hygiene/.claude-plugin/plugin.json +++ b/plugins/repo-hygiene/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "repo-hygiene", - "version": "0.10.20", + "version": "0.10.23", "description": "Repo hygiene action-router: /repo-hygiene:clean sweeps reclaimable caches, build artifacts, and stale git metadata, and can realign the working tree to a fresh-pull state — dry-run-first, with destructive tiers gated behind explicit confirmation and a session-scoped destructive-command guard. Ecosystem targets are detected at runtime; secrets, runtime dependencies, and skill data are preserved by default.", "author": { "name": "Melodic Software", diff --git a/plugins/repo-hygiene/CHANGELOG.md b/plugins/repo-hygiene/CHANGELOG.md index d72ef61895..12c4a2152e 100644 --- a/plugins/repo-hygiene/CHANGELOG.md +++ b/plugins/repo-hygiene/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to the `repo-hygiene` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.10.23] + +### Fixed + +- **`clean`: `batch_read_lines_into` now has a `ulimit -n 10` regression case.** The helper + opens named sources on fixed fd 3 so a low nofile ceiling still works. The prior + `{fd}` allocator started at 10 and failed that limit; the case was missing from the + test matrix on #3641. + ## [0.10.20] ### Fixed diff --git a/plugins/repo-hygiene/skills/clean/scripts/lib/batch-common.test.sh b/plugins/repo-hygiene/skills/clean/scripts/lib/batch-common.test.sh index 5a1433227e..99ac7506b0 100755 --- a/plugins/repo-hygiene/skills/clean/scripts/lib/batch-common.test.sh +++ b/plugins/repo-hygiene/skills/clean/scripts/lib/batch-common.test.sh @@ -185,5 +185,36 @@ else fi chmod 644 "$UNREAD" 2>/dev/null || true +# Fixed fd 3 (not Bash `{fd}`, which allocates from 10 up) so a named source +# still opens when the runner's soft nofile ceiling is 10. Codex flagged the +# missing case on #3641 after `{fd}` failed under that ulimit. +printf 'keep\n' >"$TEST_TMPDIR/lowfd.txt" +if (ulimit -n 10) >/dev/null 2>&1; then + LINES=() + rc=0 + out="$( + bash -c ' + ulimit -n 10 || exit 125 + # shellcheck source=batch-common.sh + source "$1" + LINES=() + batch_read_lines_into LINES "$2" || exit $? + printf "%s\n" "${LINES[0]}" + ' bash "$SCRIPT_DIR/batch-common.sh" "$TEST_TMPDIR/lowfd.txt" + )" || rc=$? + if [[ $rc -eq 125 ]]; then + skip_case "ulimit -n 10 refused on this host" + else + assert_exit "named source opens under ulimit -n 10" 0 "$rc" + if [[ "$out" == "keep" ]]; then + pass "low-fd read yields the line" + else + fail "low-fd read yields the line" "keep" "$out" + fi + fi +else + skip_case "cannot lower ulimit -n on this host" +fi + [[ $FAILED -eq 0 ]] || exit 1 echo "batch-common.test.sh: all passed"