fix(skills): replace stream-based lookahead with array indexing in list-changed-files.sh#1376
fix(skills): replace stream-based lookahead with array indexing in list-changed-files.sh#1376
Conversation
…st-changed-files.sh - use mapfile to load grep output into array for index-based iteration - prevent inner read from consuming the shared input stream - add || true guards to arithmetic expressions under set -e 🐛 - Generated by Copilot
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1376 +/- ##
==========================================
- Coverage 87.66% 87.65% -0.02%
==========================================
Files 61 61
Lines 9329 9329
==========================================
- Hits 8178 8177 -1
- Misses 1151 1152 +1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Advisory review, this PR is from a maintainer. Findings are informational only.
Review Summary
✅ This PR meets initial quality standards. The fix is correct, well-scoped, and addresses the root cause of the stream-consumption bug.
Issue Alignment
✅ Fixes #1375. The PR directly targets the identified root cause: a nested read call inside a while read loop that consumed lines from the shared process-substitution stream. When two consecutive diff --git headers appeared without an intervening type-indicator line, the inner read would swallow the next header, silently dropping files from the output. The mapfile-plus-index-based approach is the canonical Bash fix for this class of problem.
PR Template Compliance
✅ All required sections are filled in. Type-of-change checkboxes (Bug fix, Script/automation) correctly reflect the change. The Tests added for new functionality item is appropriately annotated as N/A with rationale. Security and checklist items are correctly scoped.
Coding Standards
✅ The script follows the repository's Bash conventions:
#!/usr/bin/env bashshebang is present.- Copyright and SPDX headers are intact.
set -euo pipefailstrict mode is in place.[[ ... ]]and(( ... ))are used correctly.localscoping is applied to all function-local variables.
Code Quality
✅ The implementation is correct across all cases:
- Back-to-back
diff --git(no type indicator):next_linedoesn't match any type pattern, no spuriousi++is issued, and the outer(( i++ )) || trueadvances normally. - New/deleted file: The type-indicator line is consumed by the inner
(( i++ )) || true, and the outer increment advances to the nextdiff --git. Correct. - Rename (
rename fromin filtered output): The inner increment consumes therename fromline; paths come from thediff --githeader. Correct. - Last line in array (no lookahead possible): Falls through to the
elif [[ "$old_path" != "$new_path" ]]branch for path-mismatch renames. Correct. (( i++ )) || trueguards: Necessary and correct — Bash exits with status 1 when an arithmetic expression evaluates to 0 (post-increment ofi=0returns 0, which is falsy underset -e). The|| trueguard is the right idiom.- Empty input:
mapfileproduces an empty array,count=0, the while loop never executes. Correct.
Action Items
None — the PR is ready to merge.
Note
🔒 Integrity filter blocked 1 item
The following item were blocked because they don't meet the GitHub integrity level.
- #1375
issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | none|
@katriendg ... do you know if the powershell version suffers from this as well? |
I checked, and no, it does not have the same issue due to the code difference. |
There was a problem hiding this comment.
Advisory review, this PR is from a maintainer. Findings are informational only.
Review Summary
This is a well-crafted bug fix. All automated CI checks pass (43/43), the implementation is correct, and conventions are followed throughout.
✅ Issue Alignment
Fixes #1375. The root cause — a nested read inside a while read loop consuming lines from the shared input stream — is correctly identified and addressed. The mapfile array-based approach is the idiomatic Bash solution for this class of lookahead problem.
✅ PR Template Compliance
All required sections are present and accurately filled:
- Description: Clear and detailed.
- Related Issues:
Fixes #1375present. - Type of Change: Bug fix ✅ and Script/automation ✅ are both correct.
- Testing: Diff-based assessment documented; manual testing absence acknowledged.
- Checklist: All applicable items checked; N/A annotations are accurate.
✅ Coding Standards (bash.instructions.md)
- Copyright header and SPDX identifier present ✅
#!/usr/bin/env bashshebang ✅set -euo pipefailstrict mode ✅- Variables quoted, arrays used appropriately ✅
- Error output directed to
stderr✅ mapfileand(( ))arithmetic are Bash 5.x idiomatic ✅
✅ Code Quality
The fix is correct. Key implementation decisions are sound:
mapfile -t linesloads all filtered diff headers into memory before iteration, eliminating the stream contention entirely. The memory trade-off is bounded and acceptable (bounded by the number of changed files).(( i++ )) || trueguards are necessary and correctly placed. Underset -e, post-incrementing fromi=0evaluates to0and exits code1without the guard — the PR description documents this explicitly.- Restructured rename detection: separating
^rename\ frommatching from theold_path != new_pathpath-mismatch fallback is a correctness improvement over the original compound||condition. Theelifat the last-entry boundary (elif [[ "$old_path" != "$new_path" ]]) correctly handles the case where no next line exists.
💡 Informational Observations (non-blocking)
1. Regression test coverage
The PR description notes manual testing was not performed. A bash test fixture that exercises extract_files() against a mock diff containing consecutive diff --git headers (the exact regression case) would prevent this bug from silently re-entering the codebase. No bash test infrastructure currently exists in this repo, so this would require investment, but it is worth considering as a follow-up.
2. Local variable naming (next)
local next=$(( i + 1 )) uses a generic name in a function with multiple index variables. A name like next_idx would make the intent unambiguous at a glance. This is a minor readability suggestion only — the current name is unambiguous in context.
✅ Security
No sensitive data, no new dependencies, no input trust boundaries affected.
This PR meets quality standards for merge.
Note
🔒 Integrity filter blocked 1 item
The following item were blocked because they don't meet the GitHub integrity level.
- #1375
issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneThere was a problem hiding this comment.
Advisory review, this PR is from a maintainer. Findings are informational only.
Review Summary
✅ This PR continues to meet quality standards. All 43 CI checks pass, the implementation is correct, and the fix is well-scoped to the root cause.
Issue Alignment
✅ Fixes #1375. The root cause — a nested read call consuming lines from the shared process-substitution stream when consecutive diff --git headers appear without intervening type-indicator lines — is correctly addressed. The mapfile-plus-index approach is the canonical Bash solution for this class of lookahead problem.
PR Template Compliance
✅ All required sections are present and accurately filled. Type-of-change checkboxes (Bug fix, Script/automation) match the actual change. The N/A annotations for testing and backwards compatibility are accurate and properly justified.
Coding Standards (bash.instructions.md)
✅ All conventions followed:
- Copyright header and SPDX identifier present
#!/usr/bin/env bashshebangset -euo pipefailstrict modelocalscoping on all function variables[[ ... ]]and(( ... ))used correctly throughoutmapfileis Bash 5.x idiomatic
Code Quality
✅ The implementation is correct across all cases:
- Back-to-back
diff --git(no type indicator): no spuriousi++fired; outer increment advances normally. - New/deleted/renamed files: inner
(( i++ )) || trueconsumes the type-indicator line; outer increment moves to next header. - Last entry (no lookahead): falls through to the
old_path != new_pathbranch correctly. (( i++ )) || trueguards: necessary underset -e— post-increment ofi=0evaluates to0(exit 1 without the guard).- Empty input:
mapfileproduces an empty array; loop never executes.
No Action Items
This PR is ready to merge.
Note
🔒 Integrity filter blocked 1 item
The following item were blocked because they don't meet the GitHub integrity level.
- #1375
issue_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | none## Pre-Release 3.3.101 ### ✨ Features - add removed maturity tier and retire owasp-docker (#1444) - add evaluation dataset creator (#1279) - align RAI planner with guide, remove scoring, improve UX (#1287) - add PSGallery staleness check and BOM cleanup (#1379) - ISA-95 network planner agent (#1177) - auto-generate collection.md with maturity filtering (#1316) - add folder-consistency check and standardize WARN outp… (#1350) - add synth-data-generate prompt to data-science collection (#1419) - add canonical deck workflow and customer-card rendering for design thinking (#1413) - add Figma MCP integration for DT artifact export (#1222) - introduce `owasp-docker` (#1245) - replace hve-core-specific references with portable discovery-based language (#1335) - introduce `owasp-cicd` (#1246) - add secure-by-design knowledge skill (#1223) - introduce `owasp-infrastructure` (#1244) - introduce `owasp-mcp` (#1207) - add OutputPath parameter to Invoke-LinkLanguageCheck.ps1 (#1229) - add -OutputPath parameter to Validate-SkillStructure.ps1 (#1225) - add maintainer-only skip-review label guard (#1293) - add extension collections overview and integrate into getting started flow (#950) - add agentic workflows for automated issue triage, implementation, PR review, dependency review, and doc-staleness detection (#1219) - consolidate package-lock.json version sync into Update-VersionFiles.ps1 (#1240) - add standards code review agent and full review orchestrator (#1174) - standardize pytest-mock as Python mocking framework (#1170) - add Jira backlog workflows and Jira/GitLab skills (#978) - add centralized version bump script and supply-chain attestation (#1183) ### 🐛 Bug Fixes - pin PowerShell-Yaml to 0.4.7 across all install sites (#1378) - close fork-PR/workflow-file-PR secret-strip gap and normalize upload-artifact version (#1421) - replace stream-based lookahead with array indexing in list-changed-files.sh (#1376) - centralize ISO 8601 timestamp regex in CIHelpers (#1343) - update stale documentation date in release-process.md (#1363) - pin basic-ftp to 5.3.0 to resolve GHSA-rp42-5vxx-qpwr (#1374) - add bot filter to dependency PR review workflow (#1362) - resolve pip-audit findings in powerpoint, gitlab, and jira skill lock files (#1360) - standardize Timestamp JSON key casing across all lint result files (#1314) - add synchronize trigger to PR Review workflow (#1323) - standardize timestamp in Validate-SkillStructure.ps1 to use Get-StandardTimestamp (#1280) - add parallel subagent dispatch and structured JSON contracts to code-review-full (#1304) - standardize timestamp in SecurityHelpers.psm1 to use Get-StandardTimestamp (#1284) - standardize timestamps in Test-DependencyPinning.ps1 and SecurityClasses.psm1 (#1282) - derive collection artifact counts from YAML at build time (#1275) - standardize timestamp in FrontmatterValidation.psm1 to use Get-StandardTimestamp (#1285) - standardize timestamp in Markdown-Link-Check.ps1 to use Get-StandardTimestamp (#1283) - escape hyphens in Mermaid diagram on Collections page (#1262) - add summary timestamp to PSScriptAnalyzer output (#1211) - fix plugin compatibility and robustness for coding-standards code review agents (#1289) - standardize timestamp in Test-CopyrightHeaders.ps1 to use Get-StandardTimestamp (#1278) - standardize timestamp in Invoke-YamlLint.ps1 to use Get-StandardTimestamp (#1270) - standardize timestamp in Invoke-LinkLanguageCheck.ps1 to use Get-StandardTimestamp (#1264) - fix dependency-review path filters and sparse-checkout cone mode (#1259) - replace invalid bare tool names with official tool identifiers (#1198) - fix broken links and remove orphaned reference in code review docs (#1257) - exclude Python env dirs from skill validation warnings (#1255) - pin happy-dom and serialize-javascript to resolve Dependabot vulnerabilities (#1253) - remove Mermaid diagram and add missing collection cards (#1247) - disable MCP servers by default to prevent token limit errors (#1144) - sync package-lock.json after pre-release version bump (#1236) - separate mermaid node declarations and add dynamic diagram generation with tests (#1215) - replace anchor links in meeting-analyst with bold text references (#1201) - remove recursive symlinks in jira and gitlab skill directories (#1233) - validate-installation scripts now check .github/skills directory (#1010) (#1206) - resolve npm audit vulnerabilities via dependency overrides (#1200) - add post-release triggers to scorecard workflow (#1186) - add missing .md extensions to relative links in agent documentation (#1180) ### 📚 Documentation - broaden Security Review description beyond OWASP (#1385) - document maintainer advisory mode and skip-review label guard (#1386) - document ExcludePaths/OutputPath for Invoke-LinkLanguageCheck (#1383) - CLI getting-started: clarify plugin install commands as alternatives (-all vs base) (#1251) ### ♻️ Refactoring - align agent and prompt folder names to collection identifier (#1210) ### 🔧 Maintenance - pin PSScriptAnalyzer to 1.25.0 and sync stale workflow version comments (#1389) - bump lxml from 6.0.2 to 6.1.0 in /.github/skills/experimental/powerpoint (#1424) - bump @vscode/vsce from 3.7.1 to 3.9.1 in the npm-dependencies group (#1390) - bump the github-actions group across 1 directory with 7 updates (#1391) - bump follow-redirects from 1.15.11 to 1.16.0 in /docs/docusaurus (#1356) - upgrade Node.js from 20 to 24 and bump cspell to v10 (#1353) - bump basic-ftp from 5.2.0 to 5.2.1 (#1324) - update github/gh-aw-actions requirement to 536ea1bad8c6715d098a9dc1afea8d403733acfe in the github-actions group across 1 directory (#1298) - update security instruction attributions and compliance (#1294) - bump the npm-dependencies group with 2 updates (#1297) - pre-release 3.3.41 (#1252) - streamline RAI Planner phase structure and documentation (#1273) - bump happy-dom from 20.8.8 to 20.8.9 in /docs/docusaurus (#1237) - pre-release 3.3.27 (#1191) - bump pygments from 2.19.2 to 2.20.0 in /.github/skills/gitlab/gitlab (#1234) - bump path-to-regexp from 0.1.12 to 0.1.13 in /docs/docusaurus (#1226) - bump the github-actions group with 4 updates (#1231) - add missing folders and alphabetize location lists (#1193) - bump brace-expansion (#1224) - bump handlebars from 4.7.8 to 4.7.9 in /docs/docusaurus (#1217) - bump brace-expansion from 5.0.3 to 5.0.5 in /docs/docusaurus (#1213) - pre-release 3.3.10 (#1187) - bump markdownlint-cli2 from 0.21.0 to 0.22.0 in the npm-dependencies group (#1175) - bump the github-actions group with 3 updates (#1176) - pre-release 3.3.1 (#1165) --- *Managed automatically by pre-release workflow.* Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fixed a bug in the pr-reference skill's
list-changed-files.shwhere nestedreadcalls inside awhile readloop consumed lines from the shared input stream. When consecutivediff --githeaders appeared without intervening type-indicator lines, the innerreadwould swallow the next header, causing the outer loop to skip files or misclassify change types. The fix replaced the stream-based approach withmapfilearray indexing for correct lookahead behavior.Description
mapfile -t linesto load all grep output into an array before the loop, switching towhile (( i < count ))arithmetic iteration with explicit index-based lookahead vialines[i + 1]|| trueguards to all(( i++ ))arithmetic expressions to preventset -efailures when the pre-increment value evaluates as falsy in Bash^rename\ frommatching, path-mismatch checks, and a fallback for the last entry in the array where no next line existsRelated Issue(s)
Fixes #1375
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md).github/skills/*/SKILL.md)Other:
.ps1,.sh,.py)Sample Prompts (for AI Artifact Contributions)
Testing
extract_files()function's final state matches expected array-indexed iteration pattern with correct|| trueguards and rename detection branches.Checklist
Required Checks
AI Artifact Contributions
/prompt-analyzeto review contributionprompt-builderreviewRequired Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run validate:skillsnpm run lint:md-linksnpm run lint:psnpm run plugin:generatenpm run docs:testSecurity Considerations
Additional Notes
mapfileapproach trades bounded memory for iteration correctness, which is appropriate since grep output is bounded by the number of files in a diff.2>/dev/null || trueon thegrepinvocation was preserved to handle empty input files gracefully.