@opengsd/gsd-core 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-debug-session-manager.md +11 -0
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-executor.md +5 -5
- package/agents/gsd-mempalace-curator.md +5 -2
- package/agents/gsd-phase-researcher.md +20 -1
- package/agents/gsd-plan-checker.md +37 -0
- package/agents/gsd-planner.md +44 -46
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +12 -3
- package/bin/install.js +841 -971
- package/bin/lib/ui-safety-gate.cjs +2 -0
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/quick.md +1 -1
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +469 -88
- package/gsd-core/bin/lib/active-workstream-store.cjs +138 -22
- package/gsd-core/bin/lib/agent-install-check.cjs +230 -32
- package/gsd-core/bin/lib/api-coverage.cjs +3 -5
- package/gsd-core/bin/lib/artifacts.cjs +3 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +876 -240
- package/gsd-core/bin/lib/broken-windows.cjs +1 -1
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-registry.cjs +575 -101
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +495 -22
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +71 -37
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/commands.cjs +651 -86
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
- package/gsd-core/bin/lib/config-loader.cjs +75 -0
- package/gsd-core/bin/lib/config.cjs +10 -1
- package/gsd-core/bin/lib/core-utils.cjs +127 -29
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +155 -20
- package/gsd-core/bin/lib/gap-checker.cjs +68 -7
- package/gsd-core/bin/lib/git-base-branch.cjs +102 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init.cjs +321 -129
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +745 -258
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
- package/gsd-core/bin/lib/install-profiles.cjs +134 -57
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +138 -31
- package/gsd-core/bin/lib/io.cjs +10 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +133 -20
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +754 -70
- package/gsd-core/bin/lib/model-catalog.cjs +59 -1
- package/gsd-core/bin/lib/model-resolver.cjs +183 -40
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
- package/gsd-core/bin/lib/phase-id.cjs +444 -36
- package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
- package/gsd-core/bin/lib/phase-locator.cjs +125 -18
- package/gsd-core/bin/lib/phase.cjs +646 -143
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +86 -2
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -6
- package/gsd-core/bin/lib/probe-core.cjs +1 -1
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +13 -4
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +34 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +943 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +385 -94
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +608 -46
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +426 -55
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +115 -3
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +275 -3
- package/gsd-core/bin/lib/smart-entry.cjs +142 -22
- package/gsd-core/bin/lib/state-command-router.cjs +5 -1
- package/gsd-core/bin/lib/state-document.cjs +152 -8
- package/gsd-core/bin/lib/state-transition.cjs +371 -117
- package/gsd-core/bin/lib/state.cjs +1794 -357
- package/gsd-core/bin/lib/surface.cjs +23 -9
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +9 -3
- package/gsd-core/bin/lib/uat.cjs +399 -56
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
- package/gsd-core/bin/lib/unusable-input.cjs +24 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +37 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +258 -8
- package/gsd-core/bin/lib/verify.cjs +368 -888
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
- package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +176 -9
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +7 -1
- package/gsd-core/references/agent-contracts.md +43 -26
- package/gsd-core/references/checkpoints.md +2 -2
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/execute-mvp-tdd.md +3 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +6 -2
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-planning-commit.md +2 -1
- package/gsd-core/references/loop-hook-dispatch.md +39 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planning-config.md +8 -6
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +3 -3
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +22 -6
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +2 -4
- package/gsd-core/templates/state.md +4 -4
- package/gsd-core/templates/verification-report.md +9 -1
- package/gsd-core/workflows/ai-integration-phase.md +9 -11
- package/gsd-core/workflows/autonomous.md +1 -1
- package/gsd-core/workflows/cleanup.md +62 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +13 -3
- package/gsd-core/workflows/code-review-fix.md +37 -10
- package/gsd-core/workflows/code-review.md +38 -12
- package/gsd-core/workflows/complete-milestone.md +141 -18
- package/gsd-core/workflows/debug.md +7 -5
- package/gsd-core/workflows/diagnose-issues.md +35 -9
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +2 -1
- package/gsd-core/workflows/edit-phase.md +26 -1
- package/gsd-core/workflows/eval-review.md +3 -5
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +31 -6
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +2 -0
- package/gsd-core/workflows/execute-phase.md +38 -50
- package/gsd-core/workflows/execute-plan.md +36 -4
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/health.md +73 -4
- package/gsd-core/workflows/import.md +4 -4
- package/gsd-core/workflows/ingest-docs.md +5 -5
- package/gsd-core/workflows/mvp-phase.md +6 -3
- package/gsd-core/workflows/new-milestone.md +14 -9
- package/gsd-core/workflows/new-project.md +14 -14
- package/gsd-core/workflows/next.md +12 -0
- package/gsd-core/workflows/plan-phase.md +41 -17
- package/gsd-core/workflows/plan-review-convergence.md +50 -2
- package/gsd-core/workflows/progress.md +34 -6
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -4
- package/gsd-core/workflows/quick/steps/quick-verification.md +27 -6
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -2
- package/gsd-core/workflows/quick.md +35 -15
- package/gsd-core/workflows/review.md +26 -5
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings.md +66 -2
- package/gsd-core/workflows/ship.md +104 -44
- package/gsd-core/workflows/spec-phase.md +30 -12
- package/gsd-core/workflows/sync-skills.md +63 -8
- package/gsd-core/workflows/transition.md +46 -11
- package/gsd-core/workflows/ui-phase.md +5 -5
- package/gsd-core/workflows/ui-review.md +2 -2
- package/gsd-core/workflows/update.md +1 -1
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +9 -7
- package/hooks/dist/gsd-agent-isolation-guard.js +103 -14
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
- package/hooks/dist/gsd-cursor-subagent-start.js +77 -2
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/dist/gsd-prompt-guard.js +21 -20
- package/hooks/dist/gsd-read-injection-scanner.js +38 -24
- package/hooks/dist/gsd-statusline.js +18 -0
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-workflow-guard.js +134 -36
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +9 -0
- package/hooks/gsd-agent-isolation-guard.js +103 -14
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-cursor-pre-tool.js +0 -3
- package/hooks/gsd-cursor-subagent-start.js +77 -2
- package/hooks/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/gsd-prompt-guard.js +21 -20
- package/hooks/gsd-read-injection-scanner.js +38 -24
- package/hooks/gsd-statusline.js +18 -0
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-workflow-guard.js +134 -36
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +9 -0
- package/package.json +21 -9
- package/pi/gsd.cjs +19 -5
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/changeset/lint.cjs +60 -5
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/ci-test-scope.cjs +19 -2
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +3 -15
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +4 -24
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/drift-scan.cjs +278 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-phase-enumeration-drift.cjs +479 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +434 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +320 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +1045 -0
- package/scripts/lint-test-file-count.allowlist.json +21 -10
- package/scripts/lint-unreachable-guard-drift.cjs +843 -0
- package/scripts/lint-vendored-deps.cjs +124 -0
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +25 -0
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/state-write-path-drift-baseline.json +19 -0
- package/scripts/sync-runtime-launcher.cjs +2 -4
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +0 -1
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +1 -1
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -574
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<purpose>
|
|
2
2
|
|
|
3
|
-
Archive accumulated phase directories from completed milestones into `.planning/milestones/v{X.Y}-phases/`. Identifies which phases belong to each completed milestone, shows a dry-run summary, and moves directories on confirmation.
|
|
3
|
+
Archive accumulated phase directories from completed milestones into `.planning/milestones/v{X.Y}-phases/`. Identifies which phases belong to each completed milestone, shows a dry-run summary, and moves directories on confirmation. Also offers retroactive archival of `.planning/quick/` (#2142) when it is non-empty.
|
|
4
4
|
|
|
5
5
|
</purpose>
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ Archive accumulated phase directories from completed milestones into `.planning/
|
|
|
9
9
|
1. `.planning/MILESTONES.md`
|
|
10
10
|
2. `.planning/milestones/` directory listing
|
|
11
11
|
3. `.planning/phases/` directory listing
|
|
12
|
+
4. `.planning/quick/` directory listing
|
|
12
13
|
|
|
13
14
|
</required_reading>
|
|
14
15
|
|
|
@@ -69,6 +70,26 @@ Match phase directories to milestone membership. Only include directories that s
|
|
|
69
70
|
|
|
70
71
|
</step>
|
|
71
72
|
|
|
73
|
+
<step name="identify_quick_tasks">
|
|
74
|
+
|
|
75
|
+
Check whether `.planning/quick/` has anything to retroactively archive (#2142):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ls -d .planning/quick/*/ 2>/dev/null || true
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**If no directories are found:** `.planning/quick/` is empty (or absent) — say nothing about quick-task archival and do not offer the step. Skip straight to `show_dry_run` with no quick-task summary or prompt.
|
|
82
|
+
|
|
83
|
+
**If at least one directory is found:** determine the target milestone. Unlike phase directories — whose milestone membership is derivable from the archived ROADMAP snapshot each completed milestone already has — quick tasks carry **no on-disk provenance** at all; there is no way to tell which milestone any given quick task directory belongs to. The target is therefore the single most recent completed milestone (from `.planning/MILESTONES.md`, already read in `identify_completed_milestones`, listed newest-first) that does not yet have a `-quick` archive directory:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
ls -d .planning/milestones/v*-quick 2>/dev/null || true
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Walk `.planning/MILESTONES.md`'s entries newest-first and pick the first version with no matching `v{version}-quick` directory above. If every completed milestone already has a `-quick` archive, or `.planning/MILESTONES.md` has no entries, there is no valid target — say so and skip the quick-task step entirely (do not prompt).
|
|
90
|
+
|
|
91
|
+
</step>
|
|
92
|
+
|
|
72
93
|
<step name="show_dry_run">
|
|
73
94
|
|
|
74
95
|
Present a dry-run summary for each milestone:
|
|
@@ -92,6 +113,19 @@ These phase directories will be archived:
|
|
|
92
113
|
Destination: .planning/milestones/v{X.Z}-phases/
|
|
93
114
|
```
|
|
94
115
|
|
|
116
|
+
**If a quick-task target milestone was determined in `identify_quick_tasks`**, add:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
### Quick tasks — bucket-all into v{X.Y}
|
|
120
|
+
{N} directories under .planning/quick/ will ALL be archived into this ONE milestone
|
|
121
|
+
(v{X.Y} — {Milestone Name}), regardless of when each was actually completed.
|
|
122
|
+
Quick tasks carry no on-disk record of which milestone they belong to, so this is
|
|
123
|
+
a bucket-all, not a per-milestone split — unlike the phase archival above, which
|
|
124
|
+
is derived per-milestone from each archived ROADMAP snapshot.
|
|
125
|
+
|
|
126
|
+
Destination: .planning/milestones/v{X.Y}-quick/
|
|
127
|
+
```
|
|
128
|
+
|
|
95
129
|
**Stale local branches (upstream gone):**
|
|
96
130
|
|
|
97
131
|
First, update remote-tracking refs so the candidate list matches the execution list exactly:
|
|
@@ -112,11 +146,12 @@ Show each branch name. If none, show:
|
|
|
112
146
|
No stale local branches detected.
|
|
113
147
|
```
|
|
114
148
|
|
|
115
|
-
If no phase directories remain to archive (all already moved or deleted) AND no stale branches exist:
|
|
149
|
+
If no phase directories remain to archive (all already moved or deleted) AND no stale branches exist AND no quick-task target milestone was determined:
|
|
116
150
|
|
|
117
151
|
```
|
|
118
152
|
No phase directories found to archive. Phases may have been removed or archived previously.
|
|
119
153
|
No stale local branches detected either.
|
|
154
|
+
No quick tasks to archive either.
|
|
120
155
|
```
|
|
121
156
|
|
|
122
157
|
Stop here.
|
|
@@ -127,6 +162,12 @@ AskUserQuestion: "Proceed with archiving and pruning?" with options: "Yes — ar
|
|
|
127
162
|
|
|
128
163
|
If "Cancel": Stop.
|
|
129
164
|
|
|
165
|
+
**If a quick-task target milestone was determined in `identify_quick_tasks`**, ask a separate, explicit question — this is a distinct, bucket-all action and must not be silently folded into the "Yes" above:
|
|
166
|
+
|
|
167
|
+
AskUserQuestion: "Archive ALL {N} quick-task directories into v{X.Y} — {Milestone Name}? This buckets every remaining quick task into this ONE milestone; there is no way to split them per-milestone." with options: "Yes — archive quick tasks into v{X.Y}" | "Skip"
|
|
168
|
+
|
|
169
|
+
If "Skip": do not run `archive_quick_tasks` — proceed to `archive_phases` (or `report`, if there were no phase directories to archive) with quick-task archival omitted.
|
|
170
|
+
|
|
130
171
|
</step>
|
|
131
172
|
|
|
132
173
|
<step name="archive_phases">
|
|
@@ -147,6 +188,20 @@ Repeat for all milestones in the cleanup set.
|
|
|
147
188
|
|
|
148
189
|
</step>
|
|
149
190
|
|
|
191
|
+
<step name="archive_quick_tasks">
|
|
192
|
+
|
|
193
|
+
Only run this step when the "Yes — archive quick tasks into v{X.Y}" option was confirmed in `show_dry_run`.
|
|
194
|
+
|
|
195
|
+
Uses the narrow `milestone.archive-quick` command (#2142 escalation) rather than `milestone.complete --archive-quick`: cleanup runs against milestones that are typically ALREADY completed, and `milestone.complete` is the full close-out — it archives ROADMAP/REQUIREMENTS and writes a MILESTONES.md entry, so re-running it against an already-completed milestone would clobber that milestone's archived ROADMAP/REQUIREMENTS snapshot (the very snapshot this cleanup depends on) and duplicate its MILESTONES.md entry. `milestone.archive-quick` shares the same move/README-index/table-reset logic as `milestone.complete --archive-quick` (same underlying helper) without any of that.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
gsd_run query milestone.archive-quick "v{X.Y}"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
This moves every directory under `.planning/quick/` into `.planning/milestones/v{X.Y}-quick/`, (re)writes that directory's `README.md` index, and clears STATE.md's `### Quick Tasks Completed` table rows — identical move/index/reset behavior to the `--archive-quick` flag documented in `complete-milestone.md`'s `archive_milestone` step, without touching ROADMAP.md, REQUIREMENTS.md, MILESTONES.md, or milestone-completion guards. Extract `archived` from the result to confirm.
|
|
202
|
+
|
|
203
|
+
</step>
|
|
204
|
+
|
|
150
205
|
<step name="prune_local_branches">
|
|
151
206
|
|
|
152
207
|
After phase archival, prune local branches whose upstream has been deleted. Use the same filter as the dry-run so the execution list matches exactly what the user confirmed:
|
|
@@ -168,7 +223,7 @@ Notes:
|
|
|
168
223
|
Commit the changes:
|
|
169
224
|
|
|
170
225
|
```bash
|
|
171
|
-
gsd_run query commit "chore: archive phase directories from completed milestones" --files .planning/milestones/ .planning/phases/
|
|
226
|
+
gsd_run query commit "chore: archive phase directories from completed milestones" --files .planning/milestones/ .planning/phases/ .planning/quick/ .planning/STATE.md
|
|
172
227
|
```
|
|
173
228
|
|
|
174
229
|
</step>
|
|
@@ -179,6 +234,8 @@ gsd_run query commit "chore: archive phase directories from completed milestones
|
|
|
179
234
|
Archived:
|
|
180
235
|
{For each milestone}
|
|
181
236
|
- v{X.Y}: {N} phase directories → .planning/milestones/v{X.Y}-phases/
|
|
237
|
+
{If quick-task archival ran}
|
|
238
|
+
- v{X.Y}: {N} quick-task directories → .planning/milestones/v{X.Y}-quick/ (bucket-all — see known limit)
|
|
182
239
|
|
|
183
240
|
Pruned: {N} local branches whose upstream is gone.
|
|
184
241
|
|
|
@@ -196,6 +253,8 @@ Pruned: {N} local branches whose upstream is gone.
|
|
|
196
253
|
- [ ] Dry-run summary shown and user confirmed (covers both archival and pruning)
|
|
197
254
|
- [ ] Phase directories moved to `.planning/milestones/v{X.Y}-phases/`
|
|
198
255
|
- [ ] Stale local branches pruned (branches whose upstream is gone)
|
|
256
|
+
- [ ] `.planning/quick/` checked; quick-task archival offered only when non-empty
|
|
257
|
+
- [ ] When offered and confirmed, ALL remaining quick-task directories archived into the single named target milestone (bucket-all, not per-milestone) via `milestone.archive-quick`
|
|
199
258
|
- [ ] Changes committed
|
|
200
259
|
|
|
201
260
|
</success_criteria>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
When `FALLOW_ENABLED=true`:
|
|
2
2
|
|
|
3
|
-
1) Resolve binary via
|
|
3
|
+
1) Resolve binary via `node_modules/.bin/fallow` first, then PATH.
|
|
4
4
|
```bash
|
|
5
5
|
FALLOW_BIN=$(FALLOW_CWD="$(pwd)" node -e "
|
|
6
6
|
const { resolveFallowBinary } = require('./gsd-core/bin/lib/fallow-runner.cjs');
|
|
@@ -26,10 +26,20 @@ FALLOW_STDERR_TMP=$(mktemp)
|
|
|
26
26
|
|
|
27
27
|
# Phase scope uses fallow's native changed-files scoping (--changed-since <base>).
|
|
28
28
|
# Derive the phase base commit; if none is found, fall back to repo scope (fallow
|
|
29
|
-
# auto-detects the base branch).
|
|
29
|
+
# auto-detects the base branch). #3191/#3503: the grep is the SAME anchored,
|
|
30
|
+
# POSIX-portable conventional-commit-scope derivation the workflow's Tier-3
|
|
31
|
+
# scope step uses (subject-line `type((phase-)?N(-plan)?):`, padded or unpadded
|
|
32
|
+
# phase spelling). Free prose in commit bodies — "deferred to Phase N per
|
|
33
|
+
# D-09", "### Phase N" format examples — never captures the base, and a bare
|
|
34
|
+
# digit substring matches version strings, dates, and other phases; the oldest
|
|
35
|
+
# such false match would silently widen --changed-since far past the phase.
|
|
30
36
|
FALLOW_SCOPE_ARGS=()
|
|
31
37
|
if [ \"$FALLOW_SCOPE\" = \"phase\" ]; then
|
|
32
|
-
|
|
38
|
+
PHASE_SCOPE_NUM=\"${PADDED_PHASE}\"
|
|
39
|
+
case \"$PADDED_PHASE\" in
|
|
40
|
+
0[0-9]*) PHASE_SCOPE_NUM=\"${PADDED_PHASE#0}|${PADDED_PHASE}\" ;;
|
|
41
|
+
esac
|
|
42
|
+
FALLOW_PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep=\"^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:\" --format=\"%H\" 2>/dev/null)
|
|
33
43
|
if [ -n \"$FALLOW_PHASE_COMMITS\" ]; then
|
|
34
44
|
FALLOW_BASE=$(echo \"$FALLOW_PHASE_COMMITS\" | tail -1)^
|
|
35
45
|
FALLOW_SCOPE_ARGS=(--changed-since \"$FALLOW_BASE\")
|
|
@@ -207,9 +207,9 @@ Use Agent() to spawn agent:
|
|
|
207
207
|
|
|
208
208
|
```text
|
|
209
209
|
Agent(subagent_type="gsd-code-fixer", model="{FIXER_MODEL}", prompt="
|
|
210
|
-
<
|
|
210
|
+
<required_reading>
|
|
211
211
|
${REVIEW_PATH}
|
|
212
|
-
</
|
|
212
|
+
</required_reading>
|
|
213
213
|
|
|
214
214
|
<config>
|
|
215
215
|
phase_dir: ${PHASE_DIR}
|
|
@@ -256,7 +256,11 @@ if [ "$AUTO_MODE" = "true" ]; then
|
|
|
256
256
|
# Total fix passes = MAX_ITERATIONS. Loop uses -lt (not -le) intentionally.
|
|
257
257
|
ITERATION=1
|
|
258
258
|
MAX_ITERATIONS=3
|
|
259
|
-
|
|
259
|
+
# #3190: track whether the loop converged (re-review came back clean) vs
|
|
260
|
+
# degraded (hit the cap). Convergence determines whether the .iterN.md backups
|
|
261
|
+
# are spent scratch (cleaned below) or retained for post-mortem analysis.
|
|
262
|
+
CONVERGED=false
|
|
263
|
+
|
|
260
264
|
while [ $ITERATION -lt $MAX_ITERATIONS ]; do
|
|
261
265
|
ITERATION=$((ITERATION + 1))
|
|
262
266
|
|
|
@@ -315,6 +319,7 @@ ${AGENT_SKILLS_REVIEWER}")
|
|
|
315
319
|
" 2>/dev/null)
|
|
316
320
|
|
|
317
321
|
if [ "$NEW_STATUS" = "clean" ]; then
|
|
322
|
+
CONVERGED=true
|
|
318
323
|
echo ""
|
|
319
324
|
echo "✓ All issues resolved after iteration ${ITERATION}."
|
|
320
325
|
break
|
|
@@ -324,9 +329,9 @@ ${AGENT_SKILLS_REVIEWER}")
|
|
|
324
329
|
echo "Issues remain. Applying fixes for iteration ${ITERATION}..."
|
|
325
330
|
|
|
326
331
|
Agent(subagent_type="gsd-code-fixer", model="{FIXER_MODEL}", prompt="
|
|
327
|
-
<
|
|
332
|
+
<required_reading>
|
|
328
333
|
${REVIEW_PATH}
|
|
329
|
-
</
|
|
334
|
+
</required_reading>
|
|
330
335
|
|
|
331
336
|
<config>
|
|
332
337
|
phase_dir: ${PHASE_DIR}
|
|
@@ -353,14 +358,24 @@ ${AGENT_SKILLS_FIXER}")
|
|
|
353
358
|
echo ""
|
|
354
359
|
echo "⚠ Reached maximum iterations (${MAX_ITERATIONS}). Remaining issues documented in REVIEW-FIX.md."
|
|
355
360
|
fi
|
|
361
|
+
|
|
362
|
+
# #3190: on convergence the .iterN.md backups are spent scratch — their
|
|
363
|
+
# stated purpose is post-mortem analysis "if iterations degrade", and
|
|
364
|
+
# convergence means no degradation. Remove them so the phase directory is
|
|
365
|
+
# clean (no dirty REVIEW.md or backup files after the run). They are RETAINED
|
|
366
|
+
# when the loop degraded (hit MAX_ITERATIONS / fixer failure) so the
|
|
367
|
+
# post-mortem trail survives. Backup CREATION (cp … .iterN.md) is unchanged.
|
|
368
|
+
if [ "$CONVERGED" = "true" ]; then
|
|
369
|
+
rm -f "${REVIEW_PATH%.md}.iter"*.md "${FIX_REPORT_PATH%.md}.iter"*.md 2>/dev/null || true
|
|
370
|
+
fi
|
|
356
371
|
fi
|
|
357
372
|
```
|
|
358
373
|
|
|
359
374
|
Key design decisions for --auto (addresses ALL review HIGH concerns):
|
|
360
375
|
1. **Re-review scope**: Uses REVIEW_FILES_ARRAY from original REVIEW.md frontmatter, falling back to full phase scope. Scope is NOT lost between iterations. Uses portable while-read loop (bash 3.2+ compatible, handles spaces in paths).
|
|
361
376
|
2. **Artifact semantics**: REVIEW.md is overwritten by each re-review (latest review state). REVIEW-FIX.md is overwritten by each fixer iteration (latest fix state with iteration count). There is ONE final version of each artifact, not per-iteration copies.
|
|
362
|
-
Backup files (.iterN.md) preserve history for post-mortem analysis if iterations degrade.
|
|
363
|
-
3. **Commit timing**: Fix commits happen per-finding inside the agent. REVIEW-FIX.md is NOT committed until step 7 (after ALL iterations complete). Only ONE docs commit
|
|
377
|
+
Backup files (.iterN.md) preserve history for post-mortem analysis if iterations degrade. On successful convergence (#3190) the backups are spent scratch and removed; on degradation (hit MAX_ITERATIONS / fixer failure) they are retained for post-mortem.
|
|
378
|
+
3. **Commit timing**: Fix commits happen per-finding inside the agent. REVIEW-FIX.md is NOT committed until step 7 (after ALL iterations complete). Only ONE docs commit, not one per iteration. In --auto that single commit also stages the converged REVIEW.md alongside REVIEW-FIX.md (#3190), so the two committed artifacts agree — the initial code-review commit held iteration-1 REVIEW.md content, and the --auto re-review loop overwrote it each iteration.
|
|
364
379
|
</step>
|
|
365
380
|
|
|
366
381
|
<step name="commit_fix_report">
|
|
@@ -369,7 +384,8 @@ After ALL iterations complete (or single pass in non-auto mode), validate and co
|
|
|
369
384
|
```bash
|
|
370
385
|
if [ -f "${FIX_REPORT_PATH}" ]; then
|
|
371
386
|
# Validate REVIEW-FIX.md has valid YAML frontmatter with status field
|
|
372
|
-
|
|
387
|
+
# #3190: export FIX_REPORT_PATH (the var the body reads), not REVIEW_PATH.
|
|
388
|
+
HAS_STATUS=$(FIX_REPORT_PATH="${FIX_REPORT_PATH}" node -e "
|
|
373
389
|
const fs = require('fs');
|
|
374
390
|
const content = fs.readFileSync(process.env.FIX_REPORT_PATH, 'utf-8');
|
|
375
391
|
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -380,9 +396,19 @@ if [ -f "${FIX_REPORT_PATH}" ]; then
|
|
|
380
396
|
echo "REVIEW-FIX.md created at ${FIX_REPORT_PATH}"
|
|
381
397
|
|
|
382
398
|
if [ "$COMMIT_DOCS" = "true" ]; then
|
|
399
|
+
# #3190: --auto's re-review loop overwrote REVIEW.md each iteration
|
|
400
|
+
# (auto_iteration_loop), but the only prior REVIEW.md commit is the
|
|
401
|
+
# initial code-review pass (iteration-1 content). Stage the converged
|
|
402
|
+
# REVIEW.md alongside REVIEW-FIX.md in this single docs commit so the two
|
|
403
|
+
# committed artifacts agree. Non-auto single-pass runs never rewrite
|
|
404
|
+
# REVIEW.md, so it is left untouched (guarded on AUTO_MODE).
|
|
405
|
+
COMMIT_FILES=("${FIX_REPORT_PATH}")
|
|
406
|
+
if [ "$AUTO_MODE" = "true" ] && [ -f "${REVIEW_PATH}" ]; then
|
|
407
|
+
COMMIT_FILES+=("${REVIEW_PATH}")
|
|
408
|
+
fi
|
|
383
409
|
gsd_run query commit \
|
|
384
410
|
"docs(${PADDED_PHASE}): add code review fix report" \
|
|
385
|
-
--files "${
|
|
411
|
+
--files "${COMMIT_FILES[@]}"
|
|
386
412
|
fi
|
|
387
413
|
else
|
|
388
414
|
echo "Warning: REVIEW-FIX.md has invalid frontmatter (no status field). Not committing."
|
|
@@ -426,7 +452,8 @@ Extract frontmatter fields:
|
|
|
426
452
|
|
|
427
453
|
```bash
|
|
428
454
|
# Extract only the YAML frontmatter block (between first two --- lines)
|
|
429
|
-
|
|
455
|
+
# #3190: export FIX_REPORT_PATH (the var the body reads), not REVIEW_PATH.
|
|
456
|
+
FIX_FRONTMATTER=$(FIX_REPORT_PATH="${FIX_REPORT_PATH}" node -e "
|
|
430
457
|
const fs = require('fs');
|
|
431
458
|
const content = fs.readFileSync(process.env.FIX_REPORT_PATH, 'utf-8');
|
|
432
459
|
const match = content.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -237,12 +237,26 @@ against the diff and warn about (then add) any changed files the SUMMARY extract
|
|
|
237
237
|
surface — so a partial SUMMARY result can no longer silently mask the rest of the phase.
|
|
238
238
|
```bash
|
|
239
239
|
# Compute diff base from phase commits — fail closed if no reliable base found.
|
|
240
|
-
# #
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
#
|
|
245
|
-
|
|
240
|
+
# #3503: anchor the grep to GSD's own conventional-commit phase scopes — the
|
|
241
|
+
# subject-line formats this system itself emits (docs(phase-N): from
|
|
242
|
+
# execute-phase.md, plan scopes feat(N-MM):/test(N-MM): from references/tdd.md,
|
|
243
|
+
# bare phase scopes docs(N):). The #2989/#3191 prose anchor "[Pp]hase N"
|
|
244
|
+
# matched free prose in ANY commit body — planning commits forward-reference
|
|
245
|
+
# later phases ("deferred to Phase N per D-09"), doc commits use "### Phase N"
|
|
246
|
+
# as a format example — and tail -1 (oldest match) turned each false positive
|
|
247
|
+
# into a base unboundedly before the phase, while GSD's own scope commits
|
|
248
|
+
# never contain the literal "Phase N" at all. The ^ anchor makes this a
|
|
249
|
+
# subject-line match, so commit-body prose can never capture the base.
|
|
250
|
+
# Workflows emit the UNPADDED roadmap phase number (docs(phase-6):) while
|
|
251
|
+
# PADDED_PHASE is zero-padded ("06") — accept both spellings.
|
|
252
|
+
# #3191: stay POSIX-ERE portable — the boundary is the closing paren + colon,
|
|
253
|
+
# never \b (not a POSIX ERE token; under --extended-regexp it silently matches
|
|
254
|
+
# nothing on macOS regex(3), making this fallback dead on Apple platforms).
|
|
255
|
+
PHASE_SCOPE_NUM="${PADDED_PHASE}"
|
|
256
|
+
case "${PADDED_PHASE}" in
|
|
257
|
+
0[0-9]*) PHASE_SCOPE_NUM="${PADDED_PHASE#0}|${PADDED_PHASE}" ;;
|
|
258
|
+
esac
|
|
259
|
+
PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep="^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:" --format="%H" 2>/dev/null)
|
|
246
260
|
DIFF_BASE=""
|
|
247
261
|
if [ -n "$PHASE_COMMITS" ]; then
|
|
248
262
|
DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)^
|
|
@@ -306,7 +320,7 @@ fi
|
|
|
306
320
|
|
|
307
321
|
**Post-processing (all tiers):**
|
|
308
322
|
|
|
309
|
-
1. **Expand tilde paths:** SUMMARY.md `key-files` entries may record a `~/...`-prefixed path (e.g. `~/.claude/gsd-core/workflows/verify-
|
|
323
|
+
1. **Expand tilde paths:** SUMMARY.md `key-files` entries may record a `~/...`-prefixed path (e.g. `~/.claude/gsd-core/workflows/verify-work.md`). Bash only tilde-expands a literal `~` written in source text, never one arriving as the value of an already-expanded variable, so every later `[ -f "$file" ]` check must see a real, expanded path or it misclassifies the file as deleted.
|
|
310
324
|
```bash
|
|
311
325
|
EXPANDED_FILES=()
|
|
312
326
|
for file in "${REVIEW_FILES[@]}"; do
|
|
@@ -423,17 +437,29 @@ Compute the review output path:
|
|
|
423
437
|
REVIEW_PATH="${PHASE_DIR}/${PADDED_PHASE}-REVIEW.md"
|
|
424
438
|
```
|
|
425
439
|
|
|
426
|
-
Compute DIFF_BASE for agent context (in case agent needs it):
|
|
440
|
+
Compute DIFF_BASE for agent context (in case agent needs it). #3191/#3503: this
|
|
441
|
+
must be the SAME anchored, POSIX-portable conventional-commit-scope derivation
|
|
442
|
+
the Tier-3 scope step uses — the reviewer agent consumes `diff_base` exactly
|
|
443
|
+
when `files:` is empty, i.e. the same fail-closed scenario Tier 3 protects, so
|
|
444
|
+
a divergent recomputation here re-arms the mis-scoping one tier down:
|
|
427
445
|
```bash
|
|
428
|
-
|
|
446
|
+
PHASE_SCOPE_NUM="${PADDED_PHASE}"
|
|
447
|
+
case "${PADDED_PHASE}" in
|
|
448
|
+
0[0-9]*) PHASE_SCOPE_NUM="${PADDED_PHASE#0}|${PADDED_PHASE}" ;;
|
|
449
|
+
esac
|
|
450
|
+
PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep="^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:" --format="%H" 2>/dev/null)
|
|
429
451
|
if [ -n "$PHASE_COMMITS" ]; then
|
|
430
452
|
DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)^
|
|
453
|
+
# Verify the parent commit exists (first commit in repo has no parent)
|
|
454
|
+
if ! git rev-parse "${DIFF_BASE}" >/dev/null 2>&1; then
|
|
455
|
+
DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)
|
|
456
|
+
fi
|
|
431
457
|
else
|
|
432
458
|
DIFF_BASE=""
|
|
433
459
|
fi
|
|
434
460
|
```
|
|
435
461
|
|
|
436
|
-
Build
|
|
462
|
+
Build required_reading block for agent:
|
|
437
463
|
```bash
|
|
438
464
|
FILES_TO_READ=""
|
|
439
465
|
for file in "${REVIEW_FILES[@]}"; do
|
|
@@ -488,9 +514,9 @@ Print: `◆ Spawning code reviewer... (runs in a subagent — no output until it
|
|
|
488
514
|
|
|
489
515
|
```
|
|
490
516
|
Agent(subagent_type="gsd-code-reviewer", model="{REVIEWER_MODEL}", prompt="
|
|
491
|
-
<
|
|
517
|
+
<required_reading>
|
|
492
518
|
${FILES_TO_READ}
|
|
493
|
-
</
|
|
519
|
+
</required_reading>
|
|
494
520
|
|
|
495
521
|
${STRUCTURAL_FINDINGS_BLOCK}
|
|
496
522
|
|
|
@@ -61,26 +61,135 @@ These items are open. Choose an action:
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
If user chooses [A] (Acknowledge):
|
|
64
|
-
1. Re-run `gsd-tools.cjs query audit-open --json` to get structured data
|
|
65
|
-
2.
|
|
64
|
+
1. Re-run `gsd-tools.cjs query audit-open --json` to get structured data.
|
|
65
|
+
2. Acknowledge every open item through the `audit-open acknowledge` CLI writer — this is what actually suppresses each item starting at the NEXT `audit-open` scan; the STATE.md table in step 3 is a disclosure record only, it is no longer the suppression mechanism. Every acknowledge call's exit status is accumulated (`ACK_FAILURES`); the step HALTS before closing if any failed — a refusal (`unsupported_heading_shape`, `ambiguous`, `not_found`, missing file, etc.) must never be silently discarded and let the close proceed as if everything were suppressed. `AUDIT_JSON` uses the same `@file:` large-payload sentinel handling `INIT_MANAGER` uses in `verify_readiness` below — `io.output` swaps any JSON payload over 50000 chars for a `@file:<path>` marker, and feeding that literal string to `jq` would silently make every loop body below iterate zero times:
|
|
66
|
+
```bash
|
|
67
|
+
AUDIT_JSON=$(gsd_run query audit-open --json)
|
|
68
|
+
if [[ "$AUDIT_JSON" == @file:* ]]; then AUDIT_JSON=$(cat "${AUDIT_JSON#@file:}"); fi
|
|
69
|
+
MILESTONE_VERSION="v[X.Y]" # already known from ROADMAP.md's active milestone header — the same identifier `milestone.complete` uses in the archive_milestone step
|
|
70
|
+
|
|
71
|
+
ACK_FAILURES=0
|
|
72
|
+
ACK_FAILURE_LOG=""
|
|
73
|
+
record_ack_failure() {
|
|
74
|
+
ACK_FAILURES=$((ACK_FAILURES + 1))
|
|
75
|
+
ACK_FAILURE_LOG="${ACK_FAILURE_LOG}
|
|
76
|
+
- $1"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# debug_sessions / threads (--slug)
|
|
80
|
+
# NOTE: `< <(...)` process substitution, not `... | while`, so the loop
|
|
81
|
+
# runs in THIS shell — a `| while` pipeline puts the loop in a subshell
|
|
82
|
+
# and any ACK_FAILURES/ACK_FAILURE_LOG update inside it is lost the
|
|
83
|
+
# moment the pipeline exits.
|
|
84
|
+
for cat in debug_sessions threads; do
|
|
85
|
+
while IFS= read -r slug; do
|
|
86
|
+
[ -z "$slug" ] && continue
|
|
87
|
+
if ! gsd_run query audit-open acknowledge --category "$cat" --milestone "$MILESTONE_VERSION" --slug "$slug"; then
|
|
88
|
+
record_ack_failure "$cat slug=$slug"
|
|
89
|
+
fi
|
|
90
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -r --arg cat "$cat" '.items[$cat][] | select(.scan_error | not) | .slug')
|
|
91
|
+
done
|
|
92
|
+
|
|
93
|
+
# seeds (--seed-id)
|
|
94
|
+
while IFS= read -r seed_id; do
|
|
95
|
+
[ -z "$seed_id" ] && continue
|
|
96
|
+
if ! gsd_run query audit-open acknowledge --category seeds --milestone "$MILESTONE_VERSION" --seed-id "$seed_id"; then
|
|
97
|
+
record_ack_failure "seeds seed_id=$seed_id"
|
|
98
|
+
fi
|
|
99
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -r '.items.seeds[] | select(.scan_error | not) | .seed_id')
|
|
100
|
+
|
|
101
|
+
# todos (--filename) — the scanner caps its list to 5 entries per scan
|
|
102
|
+
# (remainder items carry `_remainder_count`, no `filename`, and are skipped)
|
|
103
|
+
while IFS= read -r filename; do
|
|
104
|
+
[ -z "$filename" ] && continue
|
|
105
|
+
if ! gsd_run query audit-open acknowledge --category todos --milestone "$MILESTONE_VERSION" --filename "$filename"; then
|
|
106
|
+
record_ack_failure "todos filename=$filename"
|
|
107
|
+
fi
|
|
108
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -r '.items.todos[] | select((.scan_error or ._remainder_count) | not) | .filename')
|
|
109
|
+
|
|
110
|
+
# quick_tasks (--dir) — the scanner's `slug` strips a leading
|
|
111
|
+
# YYYYMMDD-/YYYY-MM-DD- date prefix for display; `--dir` needs the
|
|
112
|
+
# ORIGINAL .planning/quick/<dir>/ name, so reconstruct it from `date`+`slug`.
|
|
113
|
+
while IFS= read -r dir; do
|
|
114
|
+
[ -z "$dir" ] && continue
|
|
115
|
+
if ! gsd_run query audit-open acknowledge --category quick_tasks --milestone "$MILESTONE_VERSION" --dir "$dir"; then
|
|
116
|
+
record_ack_failure "quick_tasks dir=$dir"
|
|
117
|
+
fi
|
|
118
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -r '.items.quick_tasks[] | select(.scan_error | not) | if .date != "" then "\(.date)-\(.slug)" else .slug end')
|
|
119
|
+
|
|
120
|
+
# uat_gaps / verification_gaps / context_questions — phase-scoped
|
|
121
|
+
# (--phase --file [--archived-milestone] when the item was found in an archived phase)
|
|
122
|
+
for cat in uat_gaps verification_gaps context_questions; do
|
|
123
|
+
while IFS= read -r item; do
|
|
124
|
+
[ -z "$item" ] && continue
|
|
125
|
+
phase=$(printf '%s' "$item" | jq -r '.phase')
|
|
126
|
+
file=$(printf '%s' "$item" | jq -r '.file')
|
|
127
|
+
archived=$(printf '%s' "$item" | jq -r '.archived_milestone // empty')
|
|
128
|
+
if [ -n "$archived" ]; then
|
|
129
|
+
if ! gsd_run query audit-open acknowledge --category "$cat" --milestone "$MILESTONE_VERSION" --phase "$phase" --file "$file" --archived-milestone "$archived"; then
|
|
130
|
+
record_ack_failure "$cat phase=$phase file=$file archived-milestone=$archived"
|
|
131
|
+
fi
|
|
132
|
+
else
|
|
133
|
+
if ! gsd_run query audit-open acknowledge --category "$cat" --milestone "$MILESTONE_VERSION" --phase "$phase" --file "$file"; then
|
|
134
|
+
record_ack_failure "$cat phase=$phase file=$file"
|
|
135
|
+
fi
|
|
136
|
+
fi
|
|
137
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -c --arg cat "$cat" '.items[$cat][] | select(.scan_error | not)')
|
|
138
|
+
done
|
|
139
|
+
|
|
140
|
+
# deferred_items — same phase-scoped identification, plus --text (the
|
|
141
|
+
# exact bullet the audit read, which uniquely identifies the entry)
|
|
142
|
+
while IFS= read -r item; do
|
|
143
|
+
[ -z "$item" ] && continue
|
|
144
|
+
phase=$(printf '%s' "$item" | jq -r '.phase')
|
|
145
|
+
file=$(printf '%s' "$item" | jq -r '.file')
|
|
146
|
+
text=$(printf '%s' "$item" | jq -r '.text')
|
|
147
|
+
archived=$(printf '%s' "$item" | jq -r '.archived_milestone // empty')
|
|
148
|
+
if [ -n "$archived" ]; then
|
|
149
|
+
if ! gsd_run query audit-open acknowledge --category deferred_items --milestone "$MILESTONE_VERSION" --phase "$phase" --file "$file" --text "$text" --archived-milestone "$archived"; then
|
|
150
|
+
record_ack_failure "deferred_items phase=$phase file=$file archived-milestone=$archived"
|
|
151
|
+
fi
|
|
152
|
+
else
|
|
153
|
+
if ! gsd_run query audit-open acknowledge --category deferred_items --milestone "$MILESTONE_VERSION" --phase "$phase" --file "$file" --text "$text"; then
|
|
154
|
+
record_ack_failure "deferred_items phase=$phase file=$file"
|
|
155
|
+
fi
|
|
156
|
+
fi
|
|
157
|
+
done < <(printf '%s' "$AUDIT_JSON" | jq -c '.items.deferred_items[] | select(.scan_error | not)')
|
|
158
|
+
|
|
159
|
+
if [ "$ACK_FAILURES" -gt 0 ]; then
|
|
160
|
+
echo "ERROR: $ACK_FAILURES acknowledge call(s) failed — HALTING before milestone close. Resolve each listed item manually (e.g. edit the file directly for unsupported_heading_shape/ambiguous, or re-run the audit if a --text/--file target has since changed) and re-run /gsd:complete-milestone:" >&2
|
|
161
|
+
printf '%s\n' "$ACK_FAILURE_LOG" >&2
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
```
|
|
165
|
+
`todos` is the only category the scanner caps (5 entries per scan, with a remainder count for the rest). Re-run `gsd-tools.cjs query audit-open --json` (through the same `@file:` handling above) and repeat the `todos` block until it reports no `todos` items — every other category always returns its full open set in one pass.
|
|
166
|
+
3. Re-run `gsd-tools.cjs query audit-open --json` once more and write the items just acknowledged as new rows to STATE.md under `## Deferred Items` — append to the existing table (creating the section if absent) rather than overwriting it, preserving rows recorded at earlier milestone closes:
|
|
66
167
|
```markdown
|
|
67
168
|
## Deferred Items
|
|
68
169
|
|
|
69
|
-
Items acknowledged and deferred at milestone close
|
|
70
|
-
|
|
71
|
-
| Category | Item | Status |
|
|
72
|
-
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
170
|
+
Items acknowledged and deferred at milestone close, most recent first:
|
|
171
|
+
|
|
172
|
+
| Category | Item | Status | Deferred At | Milestone |
|
|
173
|
+
|----------|------|--------|-------------|-----------|
|
|
174
|
+
| debug_sessions | {slug} | {status} | {date} | {milestone} |
|
|
175
|
+
| quick_tasks | {slug} | {status} | {date} | {milestone} |
|
|
176
|
+
| threads | {slug} | {status} | {date} | {milestone} |
|
|
177
|
+
| seeds | {seed_id} | {status} | {date} | {milestone} |
|
|
178
|
+
| todos | {filename} | (presence-only) | {date} | {milestone} |
|
|
179
|
+
| uat_gaps | {phase}/{file} | {status} | {date} | {milestone} |
|
|
180
|
+
| verification_gaps | {phase}/{file} | {status} | {date} | {milestone} |
|
|
181
|
+
| context_questions | {phase}/{file} | {question_count} questions | {date} | {milestone} |
|
|
182
|
+
| deferred_items | {phase}/{file}: {text} | acknowledged | {date} | {milestone} |
|
|
76
183
|
```
|
|
77
|
-
Sanitize all slug
|
|
78
|
-
|
|
79
|
-
|
|
184
|
+
One row per item actually acknowledged in step 2 (omit categories with nothing to disclose this close). `{date}` is today's date; `{milestone}` is `MILESTONE_VERSION`. Sanitize all slug/status/text values via `sanitizeForDisplay()` before writing. Never inject raw file content into STATE.md.
|
|
185
|
+
4. Set `closeout_type=override_closeout` and record in the MILESTONES.md entry: `Known verification overrides: {N} newly acknowledged, {M} carried forward from a prior close (see STATE.md Deferred Items)` — `{N}` is the count of items acknowledged in step 2 (the pre-acknowledgment audit JSON's `counts.total`) and `{M}` is that same audit JSON's `acknowledged.total` (items a PRIOR close already suppressed and still are).
|
|
186
|
+
5. Proceed with milestone close.
|
|
80
187
|
|
|
81
|
-
|
|
188
|
+
Acknowledging is verdict-preserving and self-invalidating: it never rewrites the artifact's own `status:` field (except `deferred_items`, whose entry has no other meaning for that field), and the suppression it grants lapses automatically the moment the artifact's observed state changes again — a reopened debug session, an edited UAT gap, a re-triggered seed, etc. resurfaces on its own at the next audit and must be acknowledged again.
|
|
82
189
|
|
|
83
|
-
|
|
190
|
+
If output shows all clear (no open items): set `closeout_type=verified_closeout`. If the audit JSON's `acknowledged.total` is `0`, print `All artifact types clear.` and proceed. Otherwise the close is clean only because `{acknowledged.total}` item(s) acknowledged at an earlier milestone close are still being suppressed, not because everything was fixed this time — print `All artifact types clear ({acknowledged.total} previously acknowledged item(s) still suppressed — see STATE.md Deferred Items).` and record `Known verification overrides: 0 newly acknowledged, {acknowledged.total} carried forward from a prior close (see STATE.md Deferred Items)` in the MILESTONES.md entry before proceeding.
|
|
191
|
+
|
|
192
|
+
SECURITY: Audit JSON output is structured data from the `audit-open` query handler (same JSON contract as legacy `gsd-tools.cjs audit-open`) — validated and sanitized at source. The `audit-open acknowledge` writer is the only path that sets the `audit_acknowledged` suppression marker — it snapshots each artifact's current state itself from the identifiers passed on the command line, so this workflow never hand-authors the marker. When writing the STATE.md disclosure table, item identifiers, statuses, and deferred-item text are sanitized via `sanitizeForDisplay()` before inclusion. Never inject raw user-supplied content into STATE.md without sanitization.
|
|
84
193
|
</step>
|
|
85
194
|
|
|
86
195
|
<step name="verify_readiness">
|
|
@@ -257,7 +366,8 @@ Full PROJECT.md evolution review at milestone completion.
|
|
|
257
366
|
Read all phase summaries:
|
|
258
367
|
|
|
259
368
|
```bash
|
|
260
|
-
|
|
369
|
+
_SUMMARIES=( .planning/phases/*-*/*-SUMMARY.md )
|
|
370
|
+
if [ -e "${_SUMMARIES[0]}" ]; then cat "${_SUMMARIES[@]}"; fi
|
|
261
371
|
```
|
|
262
372
|
|
|
263
373
|
**Full review checklist:**
|
|
@@ -397,10 +507,20 @@ Initial user testing showed demand for shape tools.
|
|
|
397
507
|
|
|
398
508
|
<step name="archive_milestone">
|
|
399
509
|
|
|
510
|
+
**Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
|
|
511
|
+
|
|
512
|
+
**Quick-task archival (opt-in — NOT symmetrical with phase archival below, #2142):** unlike phase archival, quick-task archival is **opt-in, default OFF**. Doing nothing leaves `.planning/quick/` untouched, exactly like today's behavior. Decide this BEFORE calling `milestone complete` below, so the flag can be folded into that single invocation rather than issuing a second, redundant call.
|
|
513
|
+
|
|
514
|
+
If `.planning/quick/` contains at least one directory, ask:
|
|
515
|
+
|
|
516
|
+
AskUserQuestion: "Archive completed quick tasks into this milestone too?" with options: "Yes — archive quick tasks into v[X.Y]" | "Skip"
|
|
517
|
+
|
|
518
|
+
If "Yes": set `ARCHIVE_QUICK_FLAG="--archive-quick"`. If "Skip" (or `.planning/quick/` is empty): set `ARCHIVE_QUICK_FLAG=""`.
|
|
519
|
+
|
|
400
520
|
**Delegate archival to `gsd-tools.cjs query milestone.complete`:**
|
|
401
521
|
|
|
402
522
|
```bash
|
|
403
|
-
ARCHIVE=$(gsd_run query milestone.complete "v[X.Y]" --name "[Milestone Name]")
|
|
523
|
+
ARCHIVE=$(gsd_run query milestone.complete "v[X.Y]" --name "[Milestone Name]" $ARCHIVE_QUICK_FLAG)
|
|
404
524
|
```
|
|
405
525
|
|
|
406
526
|
The CLI handles:
|
|
@@ -410,11 +530,16 @@ The CLI handles:
|
|
|
410
530
|
- Moving audit file to milestones if it exists
|
|
411
531
|
- Creating/appending MILESTONES.md entry with accomplishments from SUMMARY.md files
|
|
412
532
|
- Updating STATE.md (status, last activity)
|
|
533
|
+
- When `ARCHIVE_QUICK_FLAG` is `--archive-quick`: moving every directory under `.planning/quick/` into `.planning/milestones/v[X.Y]-quick/`, writing a `README.md` index into that archive directory (generated by scanning the archive directory itself), and clearing the data rows of STATE.md's `### Quick Tasks Completed` table — preserving the table's header and whichever column variant (with/without a Status column) was detected
|
|
413
534
|
|
|
414
535
|
Extract from result: `version`, `date`, `phases`, `plans`, `tasks`, `accomplishments`, `archived`.
|
|
415
536
|
|
|
416
537
|
Verify: `✅ Milestone archived to .planning/milestones/`
|
|
417
538
|
|
|
539
|
+
**Known limit (quick-task archival):** there is no on-disk provenance recording which milestone a given quick task belonged to. Archival buckets **all** remaining `.planning/quick/*` into the completing milestone — a quick task that predates an earlier, unarchived milestone lands in the current bucket regardless.
|
|
540
|
+
|
|
541
|
+
Verify after `--archive-quick` was passed: `✅ Quick tasks archived to .planning/milestones/v[X.Y]-quick/`
|
|
542
|
+
|
|
418
543
|
**Phase archival (default-on):** `milestone complete` archives phase directories to `milestones/v[X.Y]-phases/` by default (#1871), so the next `/gsd:new-milestone` never inherits un-archived dirs. No manual `mkdir`/`mv` or `--archive-phases` flag is needed.
|
|
419
544
|
|
|
420
545
|
If the user explicitly wants to keep phase directories in place as raw execution history, invoke `milestone complete` with `--no-archive-phases`:
|
|
@@ -425,8 +550,6 @@ gsd_run query milestone complete v[X.Y] --no-archive-phases
|
|
|
425
550
|
|
|
426
551
|
Verify after a default (archived) completion: `✅ Phase directories archived to .planning/milestones/v[X.Y]-phases/`
|
|
427
552
|
|
|
428
|
-
**Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
|
|
429
|
-
|
|
430
553
|
After archival, the AI still handles:
|
|
431
554
|
- Reorganizing ROADMAP.md with milestone grouping (requires judgment) — overwrite in place after extracting Backlog section, with the write-guard's single-use sentinel armed first (a per-step env var cannot reach a hook — see the reorganize step for the sentinel mechanics)
|
|
432
555
|
- Full PROJECT.md evolution review (requires understanding)
|
|
@@ -140,13 +140,14 @@ specialist_dispatch_enabled: true
|
|
|
140
140
|
""",
|
|
141
141
|
subagent_type="gsd-debug-session-manager",
|
|
142
142
|
model="{debugger_model}",
|
|
143
|
-
description="Continue debug session {SLUG}"
|
|
143
|
+
description="Continue debug session {SLUG}",
|
|
144
|
+
run_in_background=false
|
|
144
145
|
)
|
|
145
146
|
```
|
|
146
147
|
|
|
147
148
|
Display the compact summary returned by the session manager.
|
|
148
149
|
|
|
149
|
-
**Return handling — exhaustive, no fallthrough (#2257).** Apply the same three-way classification as Section 4 "Session Management" below: `DEBUG SESSION COMPLETE` and `ABANDONED` are the only two terminal shapes. ANYTHING ELSE — including the explicit `## CONTINUE_REQUIRED` marker and any unrecognized or malformed summary that is not one of the two terminal markers — is non-terminal. Read `.planning/debug/{SLUG}.md` for the current `status`/`next_action` and AUTO-RESUME by re-spawning `gsd-debug-session-manager` with the SAME `SLUG
|
|
150
|
+
**Return handling — exhaustive, no fallthrough (#2257).** Apply the same three-way classification as Section 4 "Session Management" below: `DEBUG SESSION COMPLETE` and `ABANDONED` are the only two terminal shapes. ANYTHING ELSE — including the explicit `## CONTINUE_REQUIRED` marker and any unrecognized or malformed summary that is not one of the two terminal markers — is non-terminal. Read `.planning/debug/{SLUG}.md` for the current `status`/`next_action` and AUTO-RESUME by re-spawning `gsd-debug-session-manager` with the SAME `SLUG`/`debug_file_path` and the same `session_params` as the spawn above PLUS the resume parameters (#3448): `resume: true`, `resume_status: {status}`, `resume_next_action: {next_action}`, both sourced from `.planning/debug/{SLUG}.md`. The respawn must NOT be parameter-identical to a cold start: identical params drop the recorded next action and the disposition that any earlier checkpoint in the session was already answered, so the debugger re-derives — or stalls before — the very step the checkpoint already names (the #3448 auto-resume stall). Do NOT return control to the user, and do NOT report the session as complete.
|
|
150
151
|
|
|
151
152
|
**Anti-loop guard.** Same two-stop policy as Section 4 "Session Management": (1) a no-progress heuristic keyed on `next_action` ALONE from `.planning/debug/{SLUG}.md` — never `updated`, which is overwritten on every checkpoint write (`agents/gsd-debugger.md`: "Update the file BEFORE taking action"), so it changes every cycle and can never signal no-progress. Two consecutive auto-resumes with `next_action` UNCHANGED stop the loop and print a blocker report to the user (checkpoint path, status, next_action, "N auto-resumes made no progress"). And (2) an absolute hard cap, independent of content: the orchestrator tracks a running total of auto-resume spawns for this `SLUG` within the current `/gsd:debug` invocation; after **3** total auto-resumes for the slug, STOP auto-resuming and emit the blocker report REGARDLESS of whether `next_action` changed. The hard cap is the guaranteed termination bound; the no-progress heuristic is only a faster early exit before the cap is reached.
|
|
152
153
|
|
|
@@ -203,7 +204,7 @@ Create `.planning/debug/{slug}.md` with initial state using the Write tool (neve
|
|
|
203
204
|
|
|
204
205
|
After initial context setup, spawn the session manager to handle the full checkpoint/continuation loop. The session manager handles specialist_hint dispatch internally: when gsd-debugger returns ROOT CAUSE FOUND it extracts the specialist_hint field and invokes the matching skill (e.g. typescript-expert, swift-concurrency) before offering fix options.
|
|
205
206
|
|
|
206
|
-
> **Foreground, blocking spawn — #2196.** The `Agent(subagent_type="gsd-debug-session-manager", …)` call below
|
|
207
|
+
> **Foreground, blocking spawn — #2196.** The `Agent(subagent_type="gsd-debug-session-manager", …)` call below MUST carry `run_in_background: false` — Claude Code backgrounds subagents by default, and only that flag makes the spawn return the compact session summary directly. Wait for it; do not background it, and do not poll for it. Never pass an agent or session identifier to `TaskOutput` — an agent ID is NOT a task ID, so `TaskOutput <agent-id>` always returns `No task found with ID`. If the spawn returns no usable result (the handoff is lost), do NOT claim the session is still running: preserve the checkpoint at `.planning/debug/{slug}.md`, report the failed handoff plainly, and resume by re-spawning the session manager or via `/gsd:debug continue {slug}`.
|
|
207
208
|
|
|
208
209
|
Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
|
|
209
210
|
```
|
|
@@ -229,7 +230,8 @@ specialist_dispatch_enabled: true
|
|
|
229
230
|
""",
|
|
230
231
|
subagent_type="gsd-debug-session-manager",
|
|
231
232
|
model="{debugger_model}",
|
|
232
|
-
description="Debug session {slug}"
|
|
233
|
+
description="Debug session {slug}",
|
|
234
|
+
run_in_background=false
|
|
233
235
|
)
|
|
234
236
|
```
|
|
235
237
|
|
|
@@ -239,7 +241,7 @@ Display the compact summary returned by the session manager.
|
|
|
239
241
|
|
|
240
242
|
1. **Terminal — complete.** Summary shows `DEBUG SESSION COMPLETE` (without an `ABANDONED` status line): the session is finished. Stop.
|
|
241
243
|
2. **Terminal — abandoned.** Summary shows `ABANDONED`: note session saved at `.planning/debug/{slug}.md` for later `/gsd:debug continue {slug}`. Stop.
|
|
242
|
-
3. **Non-terminal — auto-resume.** ANYTHING ELSE — including the explicit `## CONTINUE_REQUIRED` marker and any unrecognized or malformed summary that is not one of the two terminal markers above — is non-terminal. Read `.planning/debug/{slug}.md` for the current `status` and `next_action`, then AUTO-RESUME by re-spawning `gsd-debug-session-manager` with the SAME `slug`/`debug_file_path` and
|
|
244
|
+
3. **Non-terminal — auto-resume.** ANYTHING ELSE — including the explicit `## CONTINUE_REQUIRED` marker and any unrecognized or malformed summary that is not one of the two terminal markers above — is non-terminal. Read `.planning/debug/{slug}.md` for the current `status` and `next_action`, then AUTO-RESUME by re-spawning `gsd-debug-session-manager` with the SAME `slug`/`debug_file_path` and the same `session_params` as the spawn above PLUS the resume parameters (#3448): `resume: true`, `resume_status: {status}`, `resume_next_action: {next_action}`, both read from `.planning/debug/{slug}.md`. The respawn must NOT be parameter-identical to a cold start: identical params drop the recorded next action and the disposition that any earlier checkpoint in the session was already answered, so the debugger re-derives — or stalls before — the very step the checkpoint already names (the #3448 auto-resume stall). Do NOT return control to the user; do NOT report the session as complete.
|
|
243
245
|
|
|
244
246
|
**Anti-loop guard.** Two independent stops apply; the orchestrator honors whichever trips first:
|
|
245
247
|
|