Docs stage fails every run when docs scope is covered by an ignore source — add fatal preflight, remove filterGitignoredDocFiles #286
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The docs stage (ADR-015) fails non-fatally on every run when the resolved docs scope (
config.docs.paths, defaultREADME.md+docs/**/*.md) is covered by a git ignore source (.gitignore,.git/info/exclude, or a globalcore.excludesFile). This has been happening silently in this repo for multiple runs (#267, #274, #282), always producing the same buried error:Full design decided in ADR-019 (amends ADR-015 §6). ADR-019 is already merged into
docs/adr/as part of this issue's groundwork — this issue tracks the remaining code implementation.Background
discoverDocFiles()walks the filesystem directly and returns every in-scope doc file that exists, regardless of any gitignore source.runDocsGit'sfilterGitignoredDocFiles()was meant to drop paths that would make the subsequentgit add -- <paths>hard-fail, using:--othersmatches only untracked files. Any doc file that is tracked but now lives under a path present in an active ignore source is invisible to this command, so the filter treats it as "safe to stage."git add -- <path>then hard-fails, which throws insiderunDocsGit, and — per ADR-015 §6 — the docs stage swallows the error and the run continues, silently degrading every subsequent run until the misconfiguration is fixed.Reproduced empirically (git 2.54.0): a tracked+modified file under a directory added to
.git/info/excludeis invisible togit ls-files --others --ignored, butgit add -- <path>on it still fails. This repo's own.git/info/excludehas/docs/locally (unrelated to pi-loop's own.pi-loop/rule), which triggers the bug on every run.Documentation Required
docs/adr/).assertPiLoopGitignore) this new preflight follows.git check-ignoredocs: https://git-scm.com/docs/git-check-ignore (exit code semantics:0= at least one path is ignored,1= none are ignored — not an error).Implementation Details
1. New CLI-level fatal preflight (
runCli.ts).pi-loopgitignore preflight (assertPiLoopGitignore), running immediately afterloadConfig()resolvesconfig.docs(currently ~line 227, before the gitignore preflight at ~line 260).config.docs.enabled === falseor--no-docsis passed for the run.discoverDocFiles({ repoRoot: cwd, paths: config.docs.paths, exclude: config.docs.exclude })to get the exact file list the docs stage would later discover.git check-ignore -vagainst all ignore sources (.gitignore,.git/info/exclude, globalcore.excludesFile) — batch all files into one invocation.0= some paths matched (ignored → fail); exit1= no paths matched (all clear → proceed, not a runner error). This differs from thels-files-based convention used elsewhere in this codebase (non-zero exit = failure), so the seam wrapping this call needs its own invocation path that doesn't throw on exit 1.stderra plain message listing every ignored file with fullgit check-ignore -vdetail (ignore-source file, line number, pattern) — uncapped, no summarization — plus a one-line fix hint.return 1. Noerror.json(no run directory exists yet at this point, mirrors the existing.pi-loopgitignore preflight exactly).checkPiLoopGitignoreFninrunCli.ts'sdeps) so it's unit-testable without spawning real git.2. Remove
filterGitignoredDocFiles(src/docs/services/runDocsGit.ts)filterGitignoredDocFiles()entirely.docFilesdirectly:runDocsGit.tsthat reference the old filter's purpose (the "gitignored paths are filtered out first" comment above the currentgit addstep).runDocsGitnow has zero defense against an ignored doc file reachinggit add— correctness is guaranteed by the new CLI preflight being the single source of truth. Any future code path that invokesrunDocsStage/runDocsGitwithout going through the CLI preflight would reintroduce the original crash with no safety net.Acceptance Criteria
runCli.ts, runs afterloadConfig(), before origin detection/issue fetch/any pipeline stage.discoverDocFiles()+git check-ignoreacross all ignore sources (.gitignore,.git/info/exclude, global excludes) to check every discovered doc file.config.docs.enabled === falseor--no-docsis set.stderrmessage with a full, uncapped per-file listing (git check-ignore -vdetail per file) + fix hint;return 1; noerror.jsonwritten.git check-ignoreexit code1(nothing ignored) is treated as success/proceed, not a runner error.filterGitignoredDocFiles()is removed fromsrc/docs/services/runDocsGit.ts; staging simplified to a directgit add -- <docFiles>.AGENTS.md's ADR cross-reference list and M8 error-handling policy table are updated to reference ADR-019 and the new fail-fast preflight case (ADR-019 doc already merged; this issue covers the M8 table + any remaining AGENTS.md wiring notes).Test Plan
GitRunnerseam:git check-ignoreexit code1(nothing ignored) is handled as a normal "clear" result, not a thrown runner error.runCli.test.ts: assert the CLI aborts with the expectedstderrmessage and exit code1when the preflight fails.runCli.test.ts: assert the preflight is skipped whendocs.enabled: false(YAML) and when--no-docsis passed.runDocsGit.test.ts: remove/replace the obsolete "skips gitignored doc paths when staging so git add never hard-fails" test with a test asserting the simplified direct-git addbehavior (no filter step, nols-filesprobe for ignored paths).Validation is unit-tests only — no manual repro required (this repo's own
.git/info/excludemisconfiguration is already diagnosed as the real-world trigger; the unit tests exercise the same logic deterministically).pi-loop opened and merged a pull request for this issue: #289