enhance(#2142): archive quick tasks at milestone close-out (#3592)

* test(#2142): failing-first coverage for quick-task archival at milestone close-out

* enhance(#2142): archive quick tasks at milestone close-out

* fix(#2142): resolve review findings — readme injection, move/reset ordering, owned state write

* fix(#2142): fold archival under milestone namespace, expose index IR, dedupe reset decision

* test(#2142): assert archive-dir-relative summary path in index IR

* docs(#2142): backfill changeset pr number to 3592

* test(#2142): skip newline-fixture injection test on windows (control chars illegal in path names)

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-17 14:51:00 -04:00
committed by GitHub
parent b08af152e4
commit 98ecb2ba8c
18 changed files with 1776 additions and 22 deletions

View File

@@ -182,6 +182,9 @@
- [External-Job Capability](#155-external-job-capability)
- [API-Coverage Gate](#156-api-coverage-gate)
- [State Rebuild & Configurable Graph Path](#157-state-rebuild--configurable-graph-path)
- [Broken-Windows Ledger](#158-broken-windows-ledger)
- [Complexity-Triggered Refactor](#159-complexity-triggered-refactor)
- [Archive Quick Tasks at Milestone Close](#160-archive-quick-tasks-at-milestone-close)
---
@@ -3384,3 +3387,24 @@ The load-bearing wire is the `plan-phase` lift into `must_haves.prohibitions`, s
**Config:** `refactor.trigger_enabled` (master gate, default `false`), `refactor.complexity_threshold` (default `15`), `refactor.complexity_jump_delta` (default `5`), `refactor.trigger_strict` (default `false`). See [Configuration Reference](CONFIGURATION.md#refactor-trigger-settings).
**Backward compatibility:** Off by default. When `refactor.trigger_enabled` is `false` the hook never runs and writes nothing; a project that never enables it is completely unaffected.
---
### 160. Archive Quick Tasks at Milestone Close
**Command:** `/gsd-complete-milestone` (forward path), `/gsd-cleanup` (retroactive path), `gsd-tools milestone complete --archive-quick` / `gsd-tools milestone archive-quick <version>` (#2142)
**Behavior:** `.planning/quick/` otherwise accumulates one directory per `/gsd-quick` task forever. `/gsd-complete-milestone` now offers a Yes/Skip prompt — when accepted, it moves every directory under `.planning/quick/` into `.planning/milestones/<version>-quick/`, (re)writes that archive directory's `README.md` (an index built by scanning the archive directory, one entry per task, linked to its `SUMMARY.md` when one exists), and clears the data rows of `STATE.md`'s `### Quick Tasks Completed` table while preserving its header and detected column variant. `/gsd-cleanup` offers the same archival retroactively, for milestones that were already closed before their quick tasks were swept, via the narrower `milestone archive-quick <version>` command — identical move/index/reset behavior, but without touching `ROADMAP.md`, `REQUIREMENTS.md`, `MILESTONES.md`, or milestone-completion guards, so it can be re-run safely against an already-completed milestone.
**Why opt-in.** Phase-directory archival is default-ON (#1871) — omitting a phase directory from an archive would silently leave stale execution history in the way of the next milestone's roadmap. Quick tasks carry no such downstream conflict, so archival here defaults OFF: a user who never passes `--archive-quick` sees zero behavior change. This is a deliberate asymmetry with phase archival, not an oversight.
**Why bucket-all, not per-milestone.** `.planning/quick/` is a flat directory with no on-disk record of which milestone a given task belongs to. Splitting tasks per milestone was considered and rejected — inferring provenance from dates (creation time vs. a milestone's shipped date) is a proxy, not a fact, and a wrong inference on a one-way `mv` is silently irreversible. Archival instead buckets everything currently in `.planning/quick/` into the one milestone being completed (or, on the retroactive path, the one milestone chosen), and says so in the confirmation prompt.
**Why the index is built from disk, not from `STATE.md`'s table.** The `### Quick Tasks Completed` table is a running log a workflow step appends to — it demonstrably drifts from what's actually in `.planning/quick/` (the motivating case: 53 rows against 49 directories, ~22 rows pointing at directories that no longer existed, 18 directories with no row at all). Building the archive's `README.md` index by scanning the archive directory itself, rather than trusting the table, means the index can never inherit that drift; a re-run's index also naturally includes entries a prior run already archived, since it's re-derived from what's physically present.
**Known limits:**
- No per-milestone provenance — bucket-all is the only option (see above).
- A `### Quick Tasks Completed` table whose columns match neither registered variant (with/without a Status column) is left untouched with a warning rather than reset, since clearing it would risk destroying rows under a schema GSD doesn't recognize.
- A `STATE.md` with no `### Quick Tasks Completed` section at all is a normal, silent no-op for the reset step — the section is created lazily by `/gsd-quick`, not present in the project template.
See [Archiving quick tasks](how-to/handle-quick-and-fast-tasks.md#archiving-quick-tasks) for the full walkthrough.