* feat(#3587): add a per-phase commit_docs override Delivers epic #2292's second user story: commit an architecture phase's artifacts while execution phases stay local. commit_docs was project-wide and binary, so the only choices were all phases or none. Shape is a config dynamic key phase_commit_docs.<phase-id>, following the 14 existing dynamicKeyPatterns precedents rather than inventing a PLAN.md frontmatter spec -- which #2292 itself flags as becoming its own maintenance surface. Tier 1 resolves in cmdCommit, NOT in loadConfig: loadConfig has no phase context and is called by nearly every command, so threading one through it to serve a single caller would be a far larger blast radius for no gain. The phase comes from detectPhaseNumberFromFiles, which cmdCommit already computes for branch naming and which is already hardened against the #2539 project-code bug. Suppression by the per-phase tier returns its own reason rather than reusing skipped_commit_docs_false -- telling a user their project setting is false when it is true would be actively misleading. Additive; the two existing reason strings that agents/gsd-executor.md matches on are unchanged. The manifest's phase-id pattern is a hand-copy of PHASE_NUMBER_TOKEN_SOURCE because the manifest is hand-maintained JSON, so a behavioral parity test asserts both surfaces accept and reject the same token shapes. * fix(#3587): fold tests, close review findings, update reference docs Fold: the new tests were added as their own file, which required loosening a grandfathered lint-test-file-count bucket 5-to-6. A ratchet exists to go down only. commit-docs-bypass.test.cjs is the established commit_docs test home and already hosts two folded suites, so the tests fold there as a third block and the allowlist is reverted untouched. Standards review: CONTEXT.md and the test header both cited a phase-commit-docs-manifest-parity.test.cjs that never existed; a repo-wide sweep found a fourth stale cite in the schema manifest description. All four now name the real location. Spec review: the issue's Scope of changes named planning-config.md and git-planning-commit.md and neither was touched. Both now document the four-tier precedence and the new skip reason. Security review, minor and unproven: detectPhaseNumberFromFiles returns the FIRST matching path's phase, so a --files list spanning two phases resolves the override against whichever comes first. That helper is hardened and widely used, so it is not changed; the behavior is pinned by a named test and disclosed in the design and user docs. A pinned behavior is not a bug; an unpinned surprise is. * chore(#3587): backfill changeset pr number to 3601 --------- Co-authored-by: sim <sim@local>
142 lines
5.7 KiB
Markdown
142 lines
5.7 KiB
Markdown
# Keep planning docs out of a shared repo
|
|
|
|
You are working in a team repo and want GSD's `.planning/` artifacts — PLAN.md, SUMMARY.md,
|
|
ROADMAP.md, STATE.md — to stay on your machine instead of appearing in commits your teammates read.
|
|
|
|
This takes four steps, and the third is the one people miss.
|
|
|
|
## 1. Turn off doc commits
|
|
|
|
```bash
|
|
gsd-tools config-set planning.commit_docs false
|
|
```
|
|
|
|
`gsd-tools query commit` now returns a `skipped` envelope instead of committing, and every workflow
|
|
that writes a planning artifact honors it.
|
|
|
|
## 2. Ignore the directory
|
|
|
|
Add to `.gitignore`:
|
|
|
|
```
|
|
.planning/
|
|
```
|
|
|
|
This is also enough on its own: when `.planning/` is gitignored and `config.json` sets no explicit
|
|
value, GSD auto-resolves `commit_docs` to `false`. Setting it explicitly in step 1 is clearer, and
|
|
it survives someone later editing `.gitignore`.
|
|
|
|
## 3. Untrack what git is already tracking
|
|
|
|
**This is the step that catches people out.** `.gitignore` only stops git picking up *new* files.
|
|
It has no effect on files already committed — git keeps tracking those, so `git add -A` keeps
|
|
staging them even though steps 1 and 2 are both done.
|
|
|
|
Because GSD's default is `commit_docs: true`, most existing projects already have `.planning/`
|
|
in history, which makes this the common case rather than an edge case.
|
|
|
|
```bash
|
|
git rm -r --cached .planning/
|
|
git commit -m "chore: stop tracking planning docs"
|
|
```
|
|
|
|
`--cached` removes the files from the index only — your files on disk are untouched.
|
|
|
|
To check whether this applies to you before running it:
|
|
|
|
```bash
|
|
git ls-files .planning
|
|
```
|
|
|
|
Any output means git is still tracking those paths.
|
|
|
|
## 4. Keep search working
|
|
|
|
With `.planning/` ignored, tools that respect `.gitignore` stop searching it — including GSD's own
|
|
broad searches, which is rarely what you want, since the planning docs are exactly what you want an
|
|
agent to read.
|
|
|
|
```bash
|
|
gsd-tools config-set planning.search_gitignored true
|
|
```
|
|
|
|
This adds `--no-ignore` to broad searches so `.planning/` is still found locally.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
gsd-tools validate health
|
|
```
|
|
|
|
A clean result means you are done. If you skipped step 3, you will see:
|
|
|
|
```
|
|
W029 .planning/ is gitignored but N file(s) are still tracked by git
|
|
Fix: git rm -r --cached .planning/ && git commit -m "chore: stop tracking planning docs"
|
|
```
|
|
|
|
`W029` is advisory. GSD will not untrack files for you, and `--repair` deliberately does not act on
|
|
it — removing files from the index is destructive and the timing is yours.
|
|
|
|
## Notes
|
|
|
|
- **A deliberate force-add also raises `W029`.** If you intentionally keep one file tracked under an
|
|
otherwise-ignored `.planning/` (`git add -f .planning/decisions.md`), the warning still appears.
|
|
There is no reliable way to tell an intentional force-add from the accidental case, so the warning
|
|
is expected there too.
|
|
- **Teammates who have already pulled the tracked files** will see them deleted by your step-3
|
|
commit. That is the intended effect — the files leave the repo, not their working copies of your
|
|
branch — but say so in the commit message or PR description so it is not a surprise.
|
|
|
|
## Per-phase override
|
|
|
|
You just made the whole project local-only in step 1. If instead you want ONE phase's artifacts —
|
|
say, an architecture or ADR phase whose PLAN.md and REQUIREMENTS.md are worth sharing with the
|
|
team — committed while every other phase stays local, set a `phase_commit_docs` entry for that
|
|
phase's number instead of (or on top of) the project-wide switch:
|
|
|
|
```bash
|
|
gsd-tools config-set planning.commit_docs false
|
|
gsd-tools config-set phase_commit_docs.03 true
|
|
```
|
|
|
|
```json
|
|
{
|
|
"planning": { "commit_docs": false },
|
|
"phase_commit_docs": { "03": true }
|
|
}
|
|
```
|
|
|
|
Now `gsd-tools query commit` commits phase 03's artifacts normally, and skips (with the
|
|
`skipped_commit_docs_phase_false`-or-`skipped_commit_docs_false` reason depending on which tier
|
|
decided) every other phase's — the project-wide setting from step 1 still governs everything
|
|
`phase_commit_docs` does not name.
|
|
|
|
A few things worth knowing before you rely on this:
|
|
|
|
- **The phase-id form doesn't matter.** `phase_commit_docs.3`, `phase_commit_docs.03`, and (if your
|
|
project uses a `project_code`) `phase_commit_docs.PROJ-03` all resolve to the same entry — GSD
|
|
normalizes the phase number before lookup, the same way it does everywhere else phase numbers are
|
|
compared.
|
|
- **It only applies to a commit that names a phase-scoped file.** `gsd-tools query commit` resolves
|
|
the phase from the `--files` paths you pass it (via the `.planning/phases/<phase-dir>/…`
|
|
segment). A commit that names no phase file — e.g. a bare `ROADMAP.md` update — has no phase to
|
|
look up, so `phase_commit_docs` never applies to it and the project-wide setting governs, same as
|
|
before this feature existed.
|
|
- **It's per phase, not per artifact.** You cannot commit a phase's ADR but suppress its SUMMARY
|
|
within the same commit; the override applies to the whole phase.
|
|
- **Reverse direction works too.** With the project-wide default (`commit_docs: true`), set
|
|
`phase_commit_docs.<phase-id> false` to suppress just one noisy execution phase while everything
|
|
else commits normally.
|
|
|
|
Full precedence order (highest wins): `phase_commit_docs.<phase-id>` → explicit `commit_docs` /
|
|
`planning.commit_docs` → `.gitignore` auto-detect → the manifest default. See
|
|
[Configuration reference — per-phase override](../CONFIGURATION.md#per-phase-override-phase_commit_docs)
|
|
for the complete rules, including how a non-boolean value is handled.
|
|
|
|
## Related
|
|
|
|
- [Configuration reference — `planning.commit_docs`](../CONFIGURATION.md#planning-settings)
|
|
- [Configuration reference — auto-detection and the tracked-files caveat](../CONFIGURATION.md#auto-detection)
|
|
- [Configuration reference — per-phase override](../CONFIGURATION.md#per-phase-override-phase_commit_docs)
|