286: Docs stage fails every run when docs scope is covered by an ignore source — add fatal preflight, remove filterGitignoredDocFiles #289

Merged
david merged 2 commits from feature/issue-286/docs-stage-fails-every-run-when-docs-scope-is-cove into main 2026-08-19 03:32:59 +00:00
Owner

286: Docs stage fails every run when docs scope is covered by an ignore source — add fatal preflight, remove filterGitignoredDocFiles

Implements 286.

This pull request was generated automatically by pi-loop and opened as a
Draft for human review. Do not merge without reviewing the changes.

Generated in 1h 01m 46s.

Review findings

Now let's check the ADR-019 file to add the Low-severity consequences note about the TOCTOU gap.Now add the Low-severity TOCTOU consequence note to ADR-019's Consequences section.Now let's add the Low finding about missing direct test coverage for defaultCheckIgnoreExec. Let's check the analogous makeGitRunner.test.ts for precedent.Now let's add a test for defaultCheckIgnoreExec using a real temp git repo.Let me fix the JSON typo.Now add the test body for defaultCheckIgnoreExec at the end of the file, using a real temp git repo.Now let's run the tests, lint, build, typecheck.All new tests pass. Now run full test/build/lint gates.Build passes. Now lint and full test.All 143 test files / 2049 tests pass (up from 2046, confirming the 3 new tests). Now confirm typecheck situation is unchanged (pre-existing errors only).Same 99 pre-existing errors, matching what the review noted. Let's confirm none touch our modified files.Confirmed pre-existing errors unrelated to our changes (same before/after). Now format check for good measure.Reformatting the whole DESIGN.md is out of scope — let me revert and only keep my targeted edits, since format:check failures pre-exist across many files and aren't part of the enforced gates.This reformatted the whole file — too invasive. I'll revert DESIGN.md and re-apply just my two targeted edits manually with correct formatting instead.That ADR file is locally gitignored (as ADR-019 itself describes) — expected, not part of the diff. Let me redo the DESIGN.md edit without the full-file reformat.Now let's check what prettier reformatted in checkDocsScopeIgnored.ts to keep only relevant change.That's fine, harmless reformat. Now let's re-apply the DESIGN.md edits manually, carefully matching existing style (no reflow).Good — DESIGN.md already fails prettier check on main (pre-existing), so my minimal diff doesn't introduce a new prettier violation to the enforced gates. Now rerun test/lint/build with final state.All gates green: build clean, lint clean, 2049/2049 tests pass. Let's do a final review of the diff.Both Medium and Low findings addressed: DESIGN.md updated, ADR-019 amended (though the ADR-019 file itself is gitignored per its own design, so it won't show in the captured diff — that's expected/consistent behavior), and test coverage for defaultCheckIgnoreExec added.Everything looks good. Final gate check summary complete.This is minimal, targeted, and matches surrounding style. Both findings are resolved.

Review Findings — 286

Summary

Applied fixes for both open findings. Medium: added an amendment note to DESIGN.md's Stage 3.5 "Failure semantics" bullet and the D33 decision-log row, cross-referencing ADR-019, so DESIGN.md is no longer the odd document out relative to the already-updated AGENTS.md/ADR-015. Low (TOCTOU gap): added a "Consequences" note to ADR-019 acknowledging the snapshot-based nature of the preflight and that a later stage editing an ignore source isn't protected against, as suggested. Also addressed the second Low finding (missing direct test coverage for defaultCheckIgnoreExec) by adding 3 new tests against a real git binary in a temp repo, matching the precedent set by makeGitRunner.test.ts. Re-ran all gates: npm run build (clean), npm run lint (clean), npm test (143 files / 2049 tests passing, up from 2046 — the 3 new tests), and npx tsc --noEmit (same 99 pre-existing errors as on the parent commit, none touching changed files — confirmed unrelated). Also confirmed npx prettier --check DESIGN.md was already failing before my edit (pre-existing repo-wide formatting drift, not part of the enforced npm run lint/npm test gates), so I made a minimal targeted edit rather than reformatting the whole file.

Critical

(none)

High

(none)

Medium

  • DESIGN.md:386 — "Failure semantics: non-fatal" for the docs stage is stated unconditionally, but ADR-019 carves out a fatal, non-self-healing exception (docs-scope ignore-source coverage) that both AGENTS.md and ADR-015 were updated to reflect in this same feature area. Leaving DESIGN.md as the odd one out makes it a misleading source of truth for exactly the invariant this ticket changes. Suggested fix: add a short amendment note to the Stage 3.5 "Failure semantics" bullet (and the D33 row at DESIGN.md:437) cross-referencing ADR-019, mirroring the amendment already added to ADR-015 §6.

Low

  • src/cli/services/runCli.ts:280 — The docs-scope ignore-source preflight runs once at CLI startup, before the pipeline's implement/remediate stages execute. Since those stages have edit/write tool access to the working tree, an agent could in principle edit .gitignore/.git/info/exclude mid-run in a way that newly covers the docs scope, and the preflight would not catch it (the docs stage would then hit the same non-fatal git add failure ADR-019 set out to eliminate, just later in the pipeline). This is a narrow, unlikely edge case, not a regression, but worth a one-line callout in ADR-019 or a code comment acknowledging the accepted gap. Suggested fix: add a short "Consequences" bullet to ADR-019 (or a comment near the preflight) noting that the check is snapshot-based at CLI start and does not protect against an ignore source added by a later stage in the same run.
  • src/docs/services/checkDocsScopeIgnored.ts:59 — defaultCheckIgnoreExec (the real execFile-backed implementation) has no direct unit test; all tests exercise checkDocsScopeIgnored through the injected CheckIgnoreExec fake. The exit-code-1-vs-other-codes branching in defaultCheckIgnoreExec itself (e.g. distinguishing code 1 from a genuine 128 git failure) is therefore only verified manually/by inspection, unlike makeGitRunner's analogous default executor which has its own makeGitRunner.test.ts. Suggested fix: add a small test that spawns a real (or minimally mocked) execFile to assert defaultCheckIgnoreExec resolves { code: 1 } on a real "not ignored" git exit and rejects on a genuine failure, matching the precedent set by makeGitRunner.test.ts.
## 286: Docs stage fails every run when docs scope is covered by an ignore source — add fatal preflight, remove filterGitignoredDocFiles Implements [286](https://git.excelera.net/david/pi-loop/issues/286). > This pull request was generated automatically by pi-loop and opened as a > **Draft** for human review. Do not merge without reviewing the changes. Generated in 1h 01m 46s. ## Review findings Now let's check the ADR-019 file to add the Low-severity consequences note about the TOCTOU gap.Now add the Low-severity TOCTOU consequence note to ADR-019's Consequences section.Now let's add the Low finding about missing direct test coverage for `defaultCheckIgnoreExec`. Let's check the analogous `makeGitRunner.test.ts` for precedent.Now let's add a test for `defaultCheckIgnoreExec` using a real temp git repo.Let me fix the JSON typo.Now add the test body for `defaultCheckIgnoreExec` at the end of the file, using a real temp git repo.Now let's run the tests, lint, build, typecheck.All new tests pass. Now run full test/build/lint gates.Build passes. Now lint and full test.All 143 test files / 2049 tests pass (up from 2046, confirming the 3 new tests). Now confirm typecheck situation is unchanged (pre-existing errors only).Same 99 pre-existing errors, matching what the review noted. Let's confirm none touch our modified files.Confirmed pre-existing errors unrelated to our changes (same before/after). Now format check for good measure.Reformatting the whole DESIGN.md is out of scope — let me revert and only keep my targeted edits, since `format:check` failures pre-exist across many files and aren't part of the enforced gates.This reformatted the whole file — too invasive. I'll revert DESIGN.md and re-apply just my two targeted edits manually with correct formatting instead.That ADR file is locally gitignored (as ADR-019 itself describes) — expected, not part of the diff. Let me redo the DESIGN.md edit without the full-file reformat.Now let's check what prettier reformatted in checkDocsScopeIgnored.ts to keep only relevant change.That's fine, harmless reformat. Now let's re-apply the DESIGN.md edits manually, carefully matching existing style (no reflow).Good — DESIGN.md already fails prettier check on main (pre-existing), so my minimal diff doesn't introduce a new prettier violation to the enforced gates. Now rerun test/lint/build with final state.All gates green: build clean, lint clean, 2049/2049 tests pass. Let's do a final review of the diff.Both Medium and Low findings addressed: DESIGN.md updated, ADR-019 amended (though the ADR-019 file itself is gitignored per its own design, so it won't show in the captured diff — that's expected/consistent behavior), and test coverage for `defaultCheckIgnoreExec` added.Everything looks good. Final gate check summary complete.This is minimal, targeted, and matches surrounding style. Both findings are resolved. # Review Findings — 286 ## Summary Applied fixes for both open findings. Medium: added an amendment note to `DESIGN.md`'s Stage 3.5 "Failure semantics" bullet and the `D33` decision-log row, cross-referencing ADR-019, so `DESIGN.md` is no longer the odd document out relative to the already-updated `AGENTS.md`/ADR-015. Low (TOCTOU gap): added a "Consequences" note to ADR-019 acknowledging the snapshot-based nature of the preflight and that a later stage editing an ignore source isn't protected against, as suggested. Also addressed the second Low finding (missing direct test coverage for `defaultCheckIgnoreExec`) by adding 3 new tests against a real git binary in a temp repo, matching the precedent set by `makeGitRunner.test.ts`. Re-ran all gates: `npm run build` (clean), `npm run lint` (clean), `npm test` (143 files / 2049 tests passing, up from 2046 — the 3 new tests), and `npx tsc --noEmit` (same 99 pre-existing errors as on the parent commit, none touching changed files — confirmed unrelated). Also confirmed `npx prettier --check DESIGN.md` was already failing before my edit (pre-existing repo-wide formatting drift, not part of the enforced `npm run lint`/`npm test` gates), so I made a minimal targeted edit rather than reformatting the whole file. ## Critical _(none)_ ## High _(none)_ ## Medium - [x] DESIGN.md:386 — "Failure semantics: non-fatal" for the docs stage is stated unconditionally, but ADR-019 carves out a fatal, non-self-healing exception (docs-scope ignore-source coverage) that both AGENTS.md and ADR-015 were updated to reflect in this same feature area. Leaving DESIGN.md as the odd one out makes it a misleading source of truth for exactly the invariant this ticket changes. Suggested fix: add a short amendment note to the Stage 3.5 "Failure semantics" bullet (and the `D33` row at DESIGN.md:437) cross-referencing ADR-019, mirroring the amendment already added to ADR-015 §6. ## Low - [x] src/cli/services/runCli.ts:280 — The docs-scope ignore-source preflight runs once at CLI startup, before the pipeline's implement/remediate stages execute. Since those stages have `edit`/`write` tool access to the working tree, an agent could in principle edit `.gitignore`/`.git/info/exclude` mid-run in a way that newly covers the docs scope, and the preflight would not catch it (the docs stage would then hit the same non-fatal `git add` failure ADR-019 set out to eliminate, just later in the pipeline). This is a narrow, unlikely edge case, not a regression, but worth a one-line callout in ADR-019 or a code comment acknowledging the accepted gap. Suggested fix: add a short "Consequences" bullet to ADR-019 (or a comment near the preflight) noting that the check is snapshot-based at CLI start and does not protect against an ignore source added by a later stage in the same run. - [x] src/docs/services/checkDocsScopeIgnored.ts:59 — `defaultCheckIgnoreExec` (the real `execFile`-backed implementation) has no direct unit test; all tests exercise `checkDocsScopeIgnored` through the injected `CheckIgnoreExec` fake. The exit-code-1-vs-other-codes branching in `defaultCheckIgnoreExec` itself (e.g. distinguishing code `1` from a genuine `128` git failure) is therefore only verified manually/by inspection, unlike `makeGitRunner`'s analogous default executor which has its own `makeGitRunner.test.ts`. Suggested fix: add a small test that spawns a real (or minimally mocked) `execFile` to assert `defaultCheckIgnoreExec` resolves `{ code: 1 }` on a real "not ignored" git exit and rejects on a genuine failure, matching the precedent set by `makeGitRunner.test.ts`.
david merged commit 71ba88c909 into main 2026-08-19 03:32:59 +00:00
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
david/pi-loop!289
No description provided.