@opengsd/gsd-core 1.18.0 → 1.19.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 +2 -1
- package/.opencode/plugins/gsd-core.js +2 -3
- package/agents/gsd-code-fixer.compact.md +2 -2
- package/agents/gsd-code-fixer.md +4 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +422 -103
- package/gsd-core/bin/gsd-tools.cjs +106 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
- package/gsd-core/bin/lib/args-terminator.cjs +114 -0
- package/gsd-core/bin/lib/broken-windows.cjs +59 -1
- package/gsd-core/bin/lib/capability-lock.cjs +13 -2
- package/gsd-core/bin/lib/capability-registry.cjs +156 -74
- package/gsd-core/bin/lib/capability-state.cjs +14 -8
- package/gsd-core/bin/lib/capability-validator.cjs +17 -0
- package/gsd-core/bin/lib/config-loader.cjs +10 -0
- package/gsd-core/bin/lib/config.cjs +256 -58
- package/gsd-core/bin/lib/core-utils.cjs +34 -0
- package/gsd-core/bin/lib/decision-coverage-support.cjs +74 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +6 -1
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +6 -1
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +63 -22
- package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
- package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -3
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
- package/gsd-core/bin/lib/host-integration.cjs +13 -6
- package/gsd-core/bin/lib/init.cjs +65 -1
- package/gsd-core/bin/lib/install-engine.cjs +246 -32
- package/gsd-core/bin/lib/install-profiles.cjs +9 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
- package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
- package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
- package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
- package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
- package/gsd-core/bin/lib/milestone.cjs +43 -1
- package/gsd-core/bin/lib/model-catalog.cjs +8 -0
- package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
- package/gsd-core/bin/lib/phase-id.cjs +21 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
- package/gsd-core/bin/lib/phase.cjs +115 -26
- package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
- package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
- package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
- package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
- package/gsd-core/bin/lib/roadmap.cjs +33 -25
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +381 -14
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
- package/gsd-core/bin/lib/shell-command-projection.cjs +121 -16
- package/gsd-core/bin/lib/smart-entry.cjs +13 -0
- package/gsd-core/bin/lib/state-contract.cjs +29 -9
- package/gsd-core/bin/lib/state-document.cjs +12 -4
- package/gsd-core/bin/lib/state-transition.cjs +119 -24
- package/gsd-core/bin/lib/state.cjs +50 -28
- package/gsd-core/bin/lib/surface.cjs +9 -0
- package/gsd-core/bin/lib/task-command-router.cjs +5 -25
- package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
- package/gsd-core/bin/lib/verification.cjs +96 -9
- package/gsd-core/bin/lib/verify.cjs +2 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/references/git-integration.md +11 -0
- package/gsd-core/references/loop-hook-dispatch.md +13 -6
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/tdd.md +2 -2
- package/gsd-core/templates/DEBUG.md +16 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/audit-fix.md +2 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
- package/gsd-core/workflows/code-review.md +61 -7
- package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
- package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
- package/gsd-core/workflows/complete-milestone.md +37 -150
- package/gsd-core/workflows/diagnose-issues.md +29 -5
- package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +33 -2
- package/gsd-core/workflows/discuss-phase-power.md +19 -2
- package/gsd-core/workflows/discuss-phase.md +6 -10
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +7 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
- package/gsd-core/workflows/execute-phase.md +9 -5
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +2 -2
- package/gsd-core/workflows/plan-phase.md +13 -13
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
- package/gsd-core/workflows/quick.md +1 -1
- package/gsd-core/workflows/review.md +16 -13
- package/gsd-core/workflows/section-manifest.json +5 -0
- package/gsd-core/workflows/settings.md +1 -0
- package/gsd-core/workflows/ship.md +3 -4
- package/gsd-core/workflows/spec-phase.md +3 -6
- package/gsd-core/workflows/verify-work.md +4 -3
- package/hooks/dist/gsd-agent-isolation-guard.js +11 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
- package/hooks/dist/gsd-path-export.js +95 -0
- package/hooks/dist/gsd-secret-read-guard.js +172 -39
- package/hooks/dist/gsd-statusline.js +35 -2
- package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
- package/hooks/dist/gsd-workflow-guard.js +1 -1
- package/hooks/dist/gsd-worktree-path-guard.js +28 -1
- package/hooks/dist/lib/isolation-sentinel.js +44 -0
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +11 -1
- package/hooks/gsd-cursor-subagent-start.js +6 -2
- package/hooks/gsd-path-export.js +95 -0
- package/hooks/gsd-secret-read-guard.js +172 -39
- package/hooks/gsd-statusline.js +35 -2
- package/hooks/gsd-windsurf-pre-write.js +28 -1
- package/hooks/gsd-workflow-guard.js +1 -1
- package/hooks/gsd-worktree-path-guard.js +28 -1
- package/hooks/hooks.json +1 -0
- package/hooks/lib/isolation-sentinel.js +44 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +13 -6
- package/pi/gsd.cjs +1047 -10
- package/pi/package-agents/gsd-advisor-researcher.md +113 -0
- package/pi/package-agents/gsd-ai-researcher.md +111 -0
- package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
- package/pi/package-agents/gsd-code-fixer.md +769 -0
- package/pi/package-agents/gsd-code-reviewer.md +402 -0
- package/pi/package-agents/gsd-codebase-mapper.md +850 -0
- package/pi/package-agents/gsd-debug-session-manager.md +416 -0
- package/pi/package-agents/gsd-debugger.md +1274 -0
- package/pi/package-agents/gsd-doc-classifier.md +269 -0
- package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
- package/pi/package-agents/gsd-doc-verifier.md +212 -0
- package/pi/package-agents/gsd-doc-writer.md +626 -0
- package/pi/package-agents/gsd-dom-verifier.md +164 -0
- package/pi/package-agents/gsd-domain-researcher.md +144 -0
- package/pi/package-agents/gsd-eval-auditor.md +185 -0
- package/pi/package-agents/gsd-eval-planner.md +149 -0
- package/pi/package-agents/gsd-executor.md +894 -0
- package/pi/package-agents/gsd-framework-selector.md +159 -0
- package/pi/package-agents/gsd-integration-checker.md +476 -0
- package/pi/package-agents/gsd-intel-updater.md +338 -0
- package/pi/package-agents/gsd-mempalace-curator.md +49 -0
- package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
- package/pi/package-agents/gsd-pattern-mapper.md +340 -0
- package/pi/package-agents/gsd-phase-researcher.md +897 -0
- package/pi/package-agents/gsd-plan-checker.md +1077 -0
- package/pi/package-agents/gsd-planner.md +1003 -0
- package/pi/package-agents/gsd-project-researcher.md +611 -0
- package/pi/package-agents/gsd-research-synthesizer.md +259 -0
- package/pi/package-agents/gsd-roadmapper.md +779 -0
- package/pi/package-agents/gsd-security-auditor.md +171 -0
- package/pi/package-agents/gsd-ui-auditor.md +581 -0
- package/pi/package-agents/gsd-ui-checker.md +417 -0
- package/pi/package-agents/gsd-ui-researcher.md +469 -0
- package/pi/package-agents/gsd-user-profiler.md +174 -0
- package/pi/package-agents/gsd-verifier.md +963 -0
- package/pi/package-agents/manifest.json +39 -0
- package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
- package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
- package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
- package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
- package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
- package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
- package/pi/package-skills/gsd-capture/SKILL.md +68 -0
- package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
- package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
- package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
- package/pi/package-skills/gsd-config/SKILL.md +60 -0
- package/pi/package-skills/gsd-debug/SKILL.md +64 -0
- package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
- package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
- package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-explore/SKILL.md +26 -0
- package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
- package/pi/package-skills/gsd-fast/SKILL.md +33 -0
- package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
- package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
- package/pi/package-skills/gsd-health/SKILL.md +36 -0
- package/pi/package-skills/gsd-help/SKILL.md +37 -0
- package/pi/package-skills/gsd-import/SKILL.md +46 -0
- package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
- package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
- package/pi/package-skills/gsd-manager/SKILL.md +46 -0
- package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
- package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
- package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
- package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
- package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
- package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
- package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
- package/pi/package-skills/gsd-next/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
- package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
- package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
- package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
- package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
- package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
- package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
- package/pi/package-skills/gsd-phase/SKILL.md +61 -0
- package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
- package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
- package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
- package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
- package/pi/package-skills/gsd-progress/SKILL.md +51 -0
- package/pi/package-skills/gsd-quick/SKILL.md +179 -0
- package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
- package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
- package/pi/package-skills/gsd-review/SKILL.md +50 -0
- package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
- package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-settings/SKILL.md +30 -0
- package/pi/package-skills/gsd-ship/SKILL.md +27 -0
- package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
- package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
- package/pi/package-skills/gsd-spike/SKILL.md +53 -0
- package/pi/package-skills/gsd-stats/SKILL.md +22 -0
- package/pi/package-skills/gsd-surface/SKILL.md +177 -0
- package/pi/package-skills/gsd-thread/SKILL.md +29 -0
- package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
- package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
- package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
- package/pi/package-skills/gsd-undo/SKILL.md +38 -0
- package/pi/package-skills/gsd-update/SKILL.md +51 -0
- package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
- package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
- package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
- package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
- package/scripts/build-hooks.js +4 -0
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +20 -7
- package/scripts/gen-health-docs.cjs +13 -1
- package/scripts/gen-pi-package-skills.cjs +217 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +11 -1
- package/scripts/lib/platform-conformance-tier.generated.cjs +26 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
- package/scripts/lint-retired-runtime-name.cjs +5 -0
- package/scripts/npm-audit-baseline.cjs +41 -7
- package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
- package/scripts/select-docs-guards.cjs +1 -1
- package/scripts/self-test-report-policy.cjs +350 -0
- package/vscode/package.json +1 -1
- package/scripts/diagnose-validate-commit-in-tier.cjs +0 -270
- package/scripts/diagnose-validate-commit-phases.cjs +0 -348
- package/scripts/xtrace-phase-timing.cjs +0 -205
|
@@ -11,18 +11,33 @@ This workflow executes when `--power` flag is present in ARGUMENTS to `/gsd:disc
|
|
|
11
11
|
|
|
12
12
|
The caller (discuss-phase.md) has already:
|
|
13
13
|
- Validated the phase exists
|
|
14
|
-
- Provided init context: `phase_dir`, `padded_phase`, `phase_number`, `phase_name`, `phase_slug`
|
|
14
|
+
- Provided init context: `phase_dir`, `padded_phase`, `phase_number`, `phase_name`, `phase_slug`, `has_spec`, `spec_path`
|
|
15
15
|
|
|
16
16
|
Begin at **Step 1** immediately.
|
|
17
17
|
</trigger>
|
|
18
18
|
|
|
19
|
+
<step name="check_spec">
|
|
20
|
+
Check whether the phase has a SPEC.md (from the spec-phase workflow). SPEC.md locks requirements before implementation decisions. Init already resolved it: use `has_spec` and `spec_path`, which come from one shared definition of "the phase SPEC" (a plain `*-SPEC.md`, never `*-AI-SPEC.md` or `*-UI-SPEC.md`). Do not glob for it.
|
|
21
|
+
|
|
22
|
+
**If `has_spec` is true:**
|
|
23
|
+
1. Read the SPEC.md file at `spec_path`.
|
|
24
|
+
2. Count requirements (numbered items in `## Requirements`).
|
|
25
|
+
3. Display: `Found SPEC.md — {N} requirements locked. Focusing on implementation decisions.`
|
|
26
|
+
4. Set `spec_loaded = true`.
|
|
27
|
+
5. Store requirements, boundaries, and acceptance criteria as `<locked_requirements>` — these flow directly into CONTEXT.md without re-asking.
|
|
28
|
+
|
|
29
|
+
**If `has_spec` is false:** Continue with `spec_loaded = false`.
|
|
30
|
+
|
|
31
|
+
**Note:** `*-AI-SPEC.md` (from the ai-integration-phase workflow) and `*-UI-SPEC.md` (from the ui-phase workflow) are different artifacts and never count as the phase SPEC.
|
|
32
|
+
</step>
|
|
33
|
+
|
|
19
34
|
<step name="analyze">
|
|
20
35
|
Run the same gray area identification as standard discuss-phase mode.
|
|
21
36
|
|
|
22
37
|
1. Load prior context (PROJECT.md, REQUIREMENTS.md, STATE.md, prior CONTEXT.md files)
|
|
23
38
|
2. Scout codebase for reusable assets and patterns relevant to this phase
|
|
24
39
|
3. Read the phase goal from ROADMAP.md
|
|
25
|
-
4. Identify ALL gray areas — specific implementation decisions the user should weigh in on
|
|
40
|
+
4. Identify ALL gray areas — specific implementation decisions the user should weigh in on. If `spec_loaded = true`, the locked requirements are pre-answered: identify gray areas about HOW to implement only, never about WHAT to build or WHY
|
|
26
41
|
5. For each gray area, generate 2–4 concrete options with tradeoff descriptions
|
|
27
42
|
|
|
28
43
|
Group questions by topic into sections (e.g., "Visual Style", "Data Model", "Interactions", "Error Handling"). Each section should have 2–6 questions.
|
|
@@ -257,6 +272,8 @@ Process all answered questions from the JSON file and generate CONTEXT.md.
|
|
|
257
272
|
- Status: "Decided" if fully answered, "Needs clarification" if only chat_more with no option selected
|
|
258
273
|
|
|
259
274
|
5. Write CONTEXT.md using the standard context template format:
|
|
275
|
+
- `<spec_lock>` section immediately after `<domain>` when `spec_loaded = true` (template: `discuss-phase/templates/context.md`); do NOT copy SPEC.md requirements into `<decisions>`
|
|
276
|
+
- the SPEC.md file in `<canonical_refs>` with the note "Locked requirements — MUST read before planning" when `spec_loaded = true`
|
|
260
277
|
- `<decisions>` section with all answered questions grouped by section
|
|
261
278
|
- `<deferred_ideas>` section for unanswered questions (carry forward for future discussion)
|
|
262
279
|
- `<specifics>` section for any chat_more content that adds nuance
|
|
@@ -125,7 +125,7 @@ INIT=$(gsd_run query init.phase-op ${GSD_WS:+--ws=${GSD_WS##* }} "${PHASE}"); [[
|
|
|
125
125
|
AGENT_SKILLS_ADVISOR=$(gsd_run query agent-skills gsd-advisor-researcher ${GSD_WS:+--ws=${GSD_WS##* }})
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`, `response_language`.
|
|
128
|
+
Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`, `has_spec`, `spec_path`, `response_language`.
|
|
129
129
|
|
|
130
130
|
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
131
131
|
|
|
@@ -183,22 +183,18 @@ Write these answers inline before continuing. If a blocking anti-pattern cannot
|
|
|
183
183
|
</step>
|
|
184
184
|
|
|
185
185
|
<step name="check_spec">
|
|
186
|
-
Check
|
|
186
|
+
Check whether the phase has a SPEC.md (from the spec-phase workflow). SPEC.md locks requirements before implementation decisions. Init already resolved it: use `has_spec` and `spec_path`, which come from one shared definition of "the phase SPEC" (a plain `*-SPEC.md`, never `*-AI-SPEC.md` or `*-UI-SPEC.md`). Do not glob for it.
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
**If SPEC.md is found:**
|
|
193
|
-
1. Read the SPEC.md file.
|
|
188
|
+
**If `has_spec` is true:**
|
|
189
|
+
1. Read the SPEC.md file at `spec_path`.
|
|
194
190
|
2. Count requirements (numbered items in `## Requirements`).
|
|
195
191
|
3. Display: `Found SPEC.md — {N} requirements locked. Focusing on implementation decisions.`
|
|
196
192
|
4. Set `spec_loaded = true`.
|
|
197
193
|
5. Store requirements, boundaries, and acceptance criteria as `<locked_requirements>` — these flow directly into CONTEXT.md without re-asking.
|
|
198
194
|
|
|
199
|
-
**If
|
|
195
|
+
**If `has_spec` is false:** Continue with `spec_loaded = false`.
|
|
200
196
|
|
|
201
|
-
**Note:** SPEC.md
|
|
197
|
+
**Note:** `*-AI-SPEC.md` (from the ai-integration-phase workflow) and `*-UI-SPEC.md` (from the ui-phase workflow) are different artifacts and never count as the phase SPEC.
|
|
202
198
|
</step>
|
|
203
199
|
|
|
204
200
|
<step name="check_existing">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Per-plan worktree decision (#2772)
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Per-plan worktree decision (#2772) and per-dispatch isolation record (#3045, #5516)
|
|
2
|
+
## Part 1 — Decide (run for each plan in the wave, up front, at `execute_waves` step 2.5)
|
|
3
|
+
This gate has two parts that run at **different times**. **Part 1** (this part) decides, for every plan in the wave, whether it uses worktree isolation, and stores each plan's answer; it runs for the whole wave before any dispatch. **Part 2** (below) writes the plan-scoped isolation record and runs once per plan, immediately before that plan's `Agent()` dispatch in step 3. The output `USE_WORKTREES_FOR_PLAN` gates the dispatch branch (worktree mode vs sequential mode) for that plan only — other plans in the same wave can still take the worktree path.
|
|
4
4
|
|
|
5
5
|
`SUBMODULE_PATHS` is computed once in the `initialize` step (parsed from `.gitmodules`).
|
|
6
6
|
|
|
@@ -115,23 +115,29 @@ fi
|
|
|
115
115
|
|
|
116
116
|
After running this for the plan, the dispatch branches in `execute_waves` step 3 MUST gate on `USE_WORKTREES_FOR_PLAN` for the current plan, not on the project-level `USE_WORKTREES`. Track which plans in this wave actually used worktrees (append `plan_id` to a `WAVE_WORKTREE_PLANS` accumulator when `USE_WORKTREES_FOR_PLAN != false`) — the post-wave cleanup step (5.5) uses this to decide whether worktree-merge cleanup is needed at all.
|
|
117
117
|
|
|
118
|
-
**
|
|
118
|
+
**Store the decision per plan (#5516).** `USE_WORKTREES_FOR_PLAN` is one shared value: the next plan's decision overwrites it. Keep each plan's answer as `plan_id → value` (for example `WAVE_PLAN_ISOLATION="03-01-api=false 03-02-docs=true"`) so step 3 can restore the dispatched plan's own value just before its dispatch (the value after `<plan_id>=`). `PLAN_FILES` and `PLAN_DELETIONS` above are shared the same way, and step 3 passes them to `worktree.record-agent` / `worktree.create`: re-run the extraction block above on the dispatched plan's JSON to restore them. This part does **not** write the isolation record.
|
|
119
|
+
|
|
120
|
+
## Part 2 — Re-record the dispatch-isolation sentinel, scoped to THIS plan (#3045 BLOCKER 1, #5516)
|
|
121
|
+
|
|
122
|
+
Run this in `execute_waves` step 3, **immediately before dispatching THIS plan**, after restoring that plan's **stored decision** from Part 1 (`plan_id` := this plan's `id`, `USE_WORKTREES_FOR_PLAN` := the value stored for it, and `PLAN_FILES` / `PLAN_DELETIONS` re-extracted from this plan's JSON). Never run it at step 2.5 and never for a plan other than the one about to dispatch: the sentinel is a single slot, so recording every plan up front leaves only the wave's last plan in it, and every earlier plan is dispatched against a record naming a different plan (the isolation guard discards it and its registry fallback denies a sequential dispatch the plan's own decision allowed, #5516).
|
|
119
123
|
|
|
120
|
-
The phase-level sentinel (written by the "Resolve ISOLATION" step, before any per-plan decision exists) authorizes/denies at the PHASE level.
|
|
124
|
+
The phase-level sentinel (written by the "Resolve ISOLATION" step, before any per-plan decision exists) authorizes/denies at the PHASE level. The per-plan decision can override that (submodule intersection forcing `USE_WORKTREES_FOR_PLAN=false` on an otherwise harness-worktree phase) — without a fresh, plan-scoped record at dispatch time, the isolation guard hooks would still be reading the STALE phase-level `harness-worktree` sentinel when this plan's dispatch omits the isolation kwarg (correctly, since it isn't worktree-isolated), producing a false DENY; or, symmetrically, a plan-level degrade elsewhere in the wave could leave a stale `none` sentinel that a LATER, genuinely harness-worktree plan's own dispatch could be misread against. Running it right before the dispatch keeps the sentinel always fresh and always keyed to the plan it authorizes:
|
|
121
125
|
|
|
122
126
|
```bash
|
|
123
127
|
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { set -- "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}" "$HOME/.gemini/antigravity-ide" "$HOME/.gemini/antigravity-cli" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}" "${CLINE_CONFIG_DIR:-$HOME/.cline}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}" "${CODEX_HOME:-$HOME/.codex}" "${COPILOT_CONFIG_DIR:-${COPILOT_HOME:-$HOME/.copilot}}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}" "${HERMES_HOME:-$HOME/.hermes}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}" "${KIMI_CONFIG_DIR:-$HOME/.config/agents}" "$HOME/.agents" "${KIMI_CODE_HOME:-$HOME/.kimi-code}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}" "${TRAE_CONFIG_DIR:-$HOME/.trae}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}" "${ZCODE_CONFIG_DIR:-$HOME/.zcode}" "${GROK_AGENTS_HOME:-$HOME/.agents}"; for _h; do _gsd_at "$_h/gsd-core/bin/${_GSD_SHIM_NAME}" && return 0; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
124
|
-
if [ "$USE_WORKTREES_FOR_PLAN" = "false" ]; then
|
|
128
|
+
if [ "${USE_WORKTREES_FOR_PLAN:-}" = "false" ]; then
|
|
125
129
|
# Submodule intersection (or an inherited USE_WORKTREES=false) forces
|
|
126
130
|
# sequential dispatch for this plan specifically — force the resolver's
|
|
127
131
|
# single write path to record `none`, scoped to this plan, even though the
|
|
128
132
|
# phase/registry would otherwise resolve harness-worktree.
|
|
129
133
|
gsd_run query dispatch-isolation --raw --phase "${PHASE_NUMBER:-}" --plan "$plan_id" --force-isolation none >/dev/null 2>&1 || true
|
|
130
|
-
|
|
134
|
+
elif [ -n "${USE_WORKTREES_FOR_PLAN:-}" ]; then
|
|
131
135
|
# No plan-level override — re-resolve normally, still scoped to this plan,
|
|
132
136
|
# so the sentinel's `plan` field always matches the plan about to dispatch.
|
|
133
137
|
gsd_run query dispatch-isolation --raw --phase "${PHASE_NUMBER:-}" --plan "$plan_id" >/dev/null 2>&1 || true
|
|
134
138
|
fi
|
|
139
|
+
# An EMPTY value (the plan state was lost with an earlier tool call's shell) writes
|
|
140
|
+
# nothing, so a recorded phase-level degrade is never re-persisted as harness-worktree (#5479).
|
|
135
141
|
```
|
|
136
142
|
|
|
137
143
|
**`PLAN_FILES` is reused after dispatch (#2596):** pass it as `--files "$PLAN_FILES"` on the step-3 `worktree.record-agent` call (and on `worktree.create` in the orchestrator-worktree path) so the post-wave cleanup gauntlet can compare each plan branch's actual committed diff against the scope the plan declared, and report any path outside it. That check is advisory — it warns, it never blocks the merge — and omitting the flag simply skips it for that plan.
|
|
@@ -55,7 +55,10 @@ if [ -z "$BUILD_CMD" ]; then
|
|
|
55
55
|
elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
|
|
56
56
|
BUILD_CMD="python -m py_compile $(find . -name '*.py' -not -path './.planning/*' -not -path './node_modules/*' | head -20 | tr '\n' ' ')"
|
|
57
57
|
elif [ -f "package.json" ] && grep -q '"build"' package.json; then
|
|
58
|
-
|
|
58
|
+
# #5346: the project's own package manager (packageManager field, then lockfile), npm if unresolved.
|
|
59
|
+
BUILD_CMD=$(gsd_run query resolve-package-manager build --cwd . 2>/dev/null || echo "npm run build")
|
|
60
|
+
[ -n "$BUILD_CMD" ] || BUILD_CMD="npm run build"
|
|
61
|
+
echo "⚠ Build command not configured — running this project's build script (${BUILD_CMD}). Set workflow.build_command to pin it."
|
|
59
62
|
else
|
|
60
63
|
BUILD_CMD=""
|
|
61
64
|
echo "⚠ No build command detected — skipping build gate"
|
|
@@ -122,7 +125,9 @@ if [ -z "$TEST_CMD" ]; then
|
|
|
122
125
|
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
|
123
126
|
TEST_CMD="just test"
|
|
124
127
|
elif [ -f "package.json" ]; then
|
|
125
|
-
|
|
128
|
+
# #5346: same resolver as the build gate.
|
|
129
|
+
TEST_CMD=$(gsd_run query resolve-package-manager test --cwd . 2>/dev/null || echo "npm test")
|
|
130
|
+
[ -n "$TEST_CMD" ] || TEST_CMD="npm test"
|
|
126
131
|
elif [ -f "Cargo.toml" ]; then
|
|
127
132
|
TEST_CMD="cargo test"
|
|
128
133
|
elif [ -f "go.mod" ]; then
|
|
@@ -29,7 +29,8 @@ if [ -z "$REG_TEST_CMD" ]; then
|
|
|
29
29
|
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
|
30
30
|
REG_TEST_CMD="just test"
|
|
31
31
|
elif [ -f "package.json" ]; then
|
|
32
|
-
REG_TEST_CMD
|
|
32
|
+
REG_TEST_CMD=$(gsd_run query resolve-package-manager test --cwd . 2>/dev/null || echo "npm test")
|
|
33
|
+
[ -n "$REG_TEST_CMD" ] || REG_TEST_CMD="npm test"
|
|
33
34
|
elif [ -f "Cargo.toml" ]; then
|
|
34
35
|
REG_TEST_CMD="cargo test"
|
|
35
36
|
elif [ -f "go.mod" ]; then
|
|
@@ -89,7 +89,7 @@ advisory throughout: it never blocks.
|
|
|
89
89
|
|
|
90
90
|
**Error handling:** If the Skill invocation fails or throws, catch the error, display "Code review encountered an error (non-blocking): {error}" and proceed to gate dispatch. Review failures must never block execution.
|
|
91
91
|
|
|
92
|
-
**Execute:post gate hook dispatch.** After code review, dispatch all active gate hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "gate"`. ⚠ **Validate `check` before shell use** (third-party manifest input) — `loop-hook-dispatch.md` § `gate`. For each, run the form below, or — for a `predicate` gate (ADR-2008 / #2008) — `gsd_run check predicate --predicate '<predicate JSON>' --phase-number "${PHASE_NUMBER}" --raw`:
|
|
92
|
+
**Execute:post gate hook dispatch.** After code review, dispatch all active gate hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "gate"`. ⚠ **Validate `check` before shell use** (third-party manifest input; wherever `${hook.check.query}` appears, write the dot-normalized query, each `.` as `-`, and validate and pass that same value) — `loop-hook-dispatch.md` § `gate`. For each, run the form below, or — for a `predicate` gate (ADR-2008 / #2008) — `gsd_run check predicate --predicate '<predicate JSON>' --phase-dir "${PHASE_DIR}" --phase-number "${PHASE_NUMBER}" --raw`:
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
95
|
GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_NUMBER}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
@@ -99,7 +99,7 @@ GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_NUMBER}" --raw) && CHEC
|
|
|
99
99
|
|
|
100
100
|
**Gate evaluation** uses the same two-step contract as the `execute:wave:post` gates (`execute-phase/steps/wave-post-gate-hooks.md`).
|
|
101
101
|
|
|
102
|
-
**TDD review escalation (overrides the advisory default for the `tdd.review-checkpoint` gate only).** The tdd `execute:post` gate is declared `blocking: false`, so by the generic contract above it displays its `message`/table and continues. There is ONE documented exception (see `~/.claude/gsd-core/references/execute-mvp-tdd.md`): when `TDD_MODE=true` AND `GATE_RESULT.block == true` (one or more TDD plans miss a RED or GREEN gate commit; #4011 — no MVP condition), the end-of-phase TDD review escalates from advisory to **blocking under TDD** — refuse to mark the phase complete and present:
|
|
102
|
+
**TDD review escalation (overrides the advisory default for the `tdd.review-checkpoint` gate only).** The tdd `execute:post` gate is declared `blocking: false`, so by the generic contract above it displays its `message`/table and continues. There is ONE documented exception (see `~/.claude/gsd-core/references/execute-mvp-tdd.md`): when `TDD_MODE=true` AND `GATE_RESULT.block == true` (one or more TDD plans miss a RED or GREEN gate commit, or have no GREEN commit that follows a RED commit — `reason: green_before_red`, #5275; #4011 — no MVP condition), the end-of-phase TDD review escalates from advisory to **blocking under TDD** — refuse to mark the phase complete and present:
|
|
103
103
|
|
|
104
104
|
```
|
|
105
105
|
Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under TDD.
|
|
@@ -2,15 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Detail for the `kind == "gate"` dispatch at the execute:wave:post hook point, extracted from the host step 5.7 (#3606 — the host file carries a frozen pre-phase-6 byte ceiling, #1168; evaluation detail lives here).
|
|
4
4
|
|
|
5
|
-
⚠ **Validate `check` before shell use** (third-party manifest input) — `gsd-core/references/loop-hook-dispatch.md` § `gate`.
|
|
5
|
+
⚠ **Validate `check` before shell use** (third-party manifest input; wherever `${hook.check.query}` appears, write the dot-normalized query, each `.` as `-`, and validate and pass that same value) — `gsd-core/references/loop-hook-dispatch.md` § `gate`.
|
|
6
6
|
|
|
7
|
-
**For each active entry where `kind == "gate"`** (process in array order), run the gate check — a `predicate` gate (ADR-2008 / #2008) uses the check CLI's `predicate` form with the predicate JSON and phase number (shown in the block below):
|
|
7
|
+
**For each active entry where `kind == "gate"`** (process in array order), run the gate check — a `predicate` gate (ADR-2008 / #2008) uses the check CLI's `predicate` form with the predicate JSON, phase directory and phase number (shown in the second block below):
|
|
8
|
+
|
|
9
|
+
When `check.query` is set (a named-query gate):
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { set -- "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}" "$HOME/.gemini/antigravity-ide" "$HOME/.gemini/antigravity-cli" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}" "${CLINE_CONFIG_DIR:-$HOME/.cline}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}" "${CODEX_HOME:-$HOME/.codex}" "${COPILOT_CONFIG_DIR:-${COPILOT_HOME:-$HOME/.copilot}}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}" "${HERMES_HOME:-$HOME/.hermes}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}" "${KIMI_CONFIG_DIR:-$HOME/.config/agents}" "$HOME/.agents" "${KIMI_CODE_HOME:-$HOME/.kimi-code}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}" "${TRAE_CONFIG_DIR:-$HOME/.trae}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}" "${ZCODE_CONFIG_DIR:-$HOME/.zcode}" "${GROK_AGENTS_HOME:-$HOME/.agents}"; for _h; do _gsd_at "$_h/gsd-core/bin/${_GSD_SHIM_NAME}" && return 0; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
11
13
|
GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_NUMBER}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
12
14
|
```
|
|
13
15
|
|
|
16
|
+
When `check.predicate` is set (a predicate gate), pass every phase value this step holds (`phase_dir` and `phase_number` from the init bundle) (#5290):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# same shell as the block above: gsd_run is already defined by its preamble
|
|
20
|
+
GATE_RESULT=$(gsd_run check predicate --predicate '<predicate JSON>' --phase-dir "${PHASE_DIR}" --phase-number "${PHASE_NUMBER}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
21
|
+
```
|
|
22
|
+
|
|
14
23
|
**Step 1 — did the CHECK COMMAND itself succeed?**
|
|
15
24
|
|
|
16
25
|
If the check command failed (non-zero `CHECK_EXIT`, empty output, or unparseable JSON):
|
|
@@ -605,11 +605,13 @@ increases monotonically across waves. `{status}` is `complete` (success),
|
|
|
605
605
|
- Bad: "Executing terrain generation plan"
|
|
606
606
|
- Good: "Procedural terrain generator using Perlin noise — creates height maps and biome zones. Required before vehicle physics."
|
|
607
607
|
|
|
608
|
-
2.5. **Per-plan worktree decision (run for each plan in this wave BEFORE
|
|
608
|
+
2.5. **Per-plan worktree decision (run for each plan in this wave BEFORE any dispatch):**
|
|
609
609
|
|
|
610
|
-
Read and execute `gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md` for each plan. It extracts `PLAN_FILES` from the plan's JSON, intersects against `SUBMODULE_PATHS` (with normalization, bidirectional matching, and glob-prefix handling), and sets `USE_WORKTREES_FOR_PLAN` to `false` when the plan touches a submodule path. Append `plan_id` to a `WAVE_WORKTREE_PLANS` accumulator when `USE_WORKTREES_FOR_PLAN != false`.
|
|
610
|
+
Read and execute **Part 1** of `gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md` for each plan. It extracts `PLAN_FILES` from the plan's JSON, intersects against `SUBMODULE_PATHS` (with normalization, bidirectional matching, and glob-prefix handling), and sets `USE_WORKTREES_FOR_PLAN` to `false` when the plan touches a submodule path. Append `plan_id` to a `WAVE_WORKTREE_PLANS` accumulator when `USE_WORKTREES_FOR_PLAN != false`. **Store each plan's decision** (`plan_id → USE_WORKTREES_FOR_PLAN`): the shared `USE_WORKTREES_FOR_PLAN` value is overwritten by the next plan's decision.
|
|
611
611
|
|
|
612
|
-
The dispatch
|
|
612
|
+
The plan-scoped dispatch-isolation record is **not written here**. It is a single slot, so it is written in step 3, immediately before each plan's own dispatch (Part 2 of the gate, #5516).
|
|
613
|
+
|
|
614
|
+
The dispatch branches in step 3 gate on both `USE_WORKTREES` and the dispatched plan's own stored `USE_WORKTREES_FOR_PLAN` (#2474).
|
|
613
615
|
|
|
614
616
|
2.75. **Execute:wave:pre capability dispatch:**
|
|
615
617
|
|
|
@@ -632,6 +634,8 @@ increases monotonically across waves. `{status}` is `complete` (success),
|
|
|
632
634
|
|
|
633
635
|
**Substitute `{plan_id}` in the prompt below with this plan's `id` field** from the `phase-plan-index` JSON loaded in step 1 (the same field referred to elsewhere in this workflow as `plan.id`) — unmodified and un-truncated, never a paraphrase. The guard hooks compare this value verbatim against the sentinel the per-plan gate wrote (`per-plan-worktree-gate.md`'s `plan_id`); a paraphrase or an omission costs the dispatch its recorded isolation decision.
|
|
634
636
|
|
|
637
|
+
**Record this plan's isolation immediately before its dispatch (#5516).** Restore the dispatched plan's **stored decision** from step 2.5 (`plan_id` := this plan's `id`, `USE_WORKTREES_FOR_PLAN` := the value stored for that plan, and `PLAN_FILES` / `PLAN_DELETIONS` re-extracted from this plan's JSON, since the later plans' decisions overwrote them) and run **Part 2** of `gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md`, so the single-slot sentinel names the plan being dispatched. Do not run it for any other plan, and do not batch it ahead of the dispatches.
|
|
638
|
+
|
|
635
639
|
**Executor routing (#1689/#3370).** Per plan, run `gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md` to set `EXECUTOR_TYPE` for `subagent_type="{EXECUTOR_TYPE}"` below.
|
|
636
640
|
|
|
637
641
|
**TDD-applicability resolution (#4266/#4272).** Run `gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md`.
|
|
@@ -1114,8 +1118,8 @@ When executor returns a checkpoint AND `AUTO_MODE` is `true`:
|
|
|
1114
1118
|
[Awaiting section from agent return]
|
|
1115
1119
|
```
|
|
1116
1120
|
5. User responds: "approved"/"done" | issue description | decision selection
|
|
1117
|
-
6. **Spawn continuation agent (NOT resume)**
|
|
1118
|
-
- `{completed_tasks_table}`: From checkpoint return
|
|
1121
|
+
6. **Spawn continuation agent (NOT resume)** with a prompt built from these placeholders (there is no separate template file; this list is the contract):
|
|
1122
|
+
- `{completed_tasks_table}`: From checkpoint return, wrapped in a `<completed_tasks>` tag (the executor's continuation handling keys on it)
|
|
1119
1123
|
- `{resume_task_number}` + `{resume_task_name}`: Current task
|
|
1120
1124
|
- `{user_response}`: What user provided
|
|
1121
1125
|
- `{resume_instructions}`: Based on checkpoint type
|
|
@@ -249,7 +249,7 @@ Report final status.
|
|
|
249
249
|
| W027 | warning | Stale git worktree (not modified in a long time) | No |
|
|
250
250
|
| W028 | warning | A GSD-owned install scope shadows another on this machine | No |
|
|
251
251
|
| W029 | warning | .planning/ matches a gitignore rule but is still tracked by git (gitignore has no effect on already-tracked files) | No |
|
|
252
|
-
| W030 | warning | Phase verification report status is outside the closed set |
|
|
252
|
+
| W030 | warning | Phase verification report status is outside the closed set | Yes (known legacy statuses only) |
|
|
253
253
|
| I001 | info | Plan without SUMMARY (may be in progress) | No |
|
|
254
254
|
| I010 | info | Resolved CWD reported alongside the E010 home-directory guard | No |
|
|
255
255
|
|
|
@@ -266,6 +266,7 @@ Note: this table is **generated** — do not hand-edit it. It is produced by `no
|
|
|
266
266
|
| addNyquistKey | Add workflow.nyquist_validation: true to config.json | None — matches existing default |
|
|
267
267
|
| addAiIntegrationPhaseKey | Add workflow.ai_integration_phase: true to config.json | None — matches existing default |
|
|
268
268
|
| backfillMilestones | Synthesize missing MILESTONES.md entries from `.planning/milestones/vX.Y-ROADMAP.md` snapshots | None — additive only; triggered by `--backfill` flag |
|
|
269
|
+
| repairVerificationStatus | Rewrite a known legacy verification `status` (`pass_with_caveats`) to `passed`, keeping the original as `legacy_status` | None — only the `status` line changes; unknown statuses are never touched |
|
|
269
270
|
|
|
270
271
|
**Not repairable (too risky):**
|
|
271
272
|
- PROJECT.md, ROADMAP.md content
|
|
@@ -227,7 +227,7 @@ Agent({
|
|
|
227
227
|
|
|
228
228
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
229
229
|
|
|
230
|
-
Handle the checker return by severity, never by the sentinel alone: count BLOCKER + WARNING entries in the YAML issues block; an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If the return is `## VERIFICATION PASSED
|
|
230
|
+
Handle the checker return by severity, never by the sentinel alone: count BLOCKER + WARNING entries in the YAML issues block; an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). A `## VERIFICATION PASSED` return that lists an entry whose severity is BLOCKER or WARNING, in the YAML issues block or listed in prose (a mention such as "no warnings" or a zero count is not an entry) is counted as `## ISSUES FOUND`, the prose entries counted as BLOCKER/WARNING entries (#5578). If the return is `## VERIFICATION PASSED` with no such entry, or the count is zero — every entry is explicitly INFO — display `ℹ advisory — {dimension}: {description}` per INFO entry and treat the plan as imported; INFO is advisory and never blocks an import (#3724). Otherwise:
|
|
231
231
|
- Display the blocking issues to the user
|
|
232
232
|
- Ask the user to resolve issues before the plan is considered imported
|
|
233
233
|
- Do not delete the written file — the user can fix and re-validate manually
|
|
@@ -50,7 +50,7 @@ Display:
|
|
|
50
50
|
Spawn the planner in **outline-only** mode — it must write only the outline manifest, not any
|
|
51
51
|
PLAN.md files:
|
|
52
52
|
|
|
53
|
-
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED
|
|
53
|
+
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED` (config key `planner.stall_detection_enabled`, resolved in `plan-phase/steps/stall-detection-helpers.md`):**
|
|
54
54
|
- **`true` (default):** use `run_in_background=true` in the Agent() call below, then use `gsd_stall_watch` after it.
|
|
55
55
|
|
|
56
56
|
```javascript
|
|
@@ -146,7 +146,7 @@ GSD_ARGS=${GSD_ARGS%$'\n'}
|
|
|
146
146
|
4. Spawn the planner in **single-plan** mode — it must write exactly one PLAN.md file. The prompt
|
|
147
147
|
is unchanged per plan; what changes is whether the runnable set's Agent() calls are issued one
|
|
148
148
|
at a time (serial) or together in one message (concurrent, every call still carrying
|
|
149
|
-
`run_in_background=true` exactly as today when `PLANNER_STALL_DETECTION_ENABLED` is `true`
|
|
149
|
+
`run_in_background=true` exactly as today when `PLANNER_STALL_DETECTION_ENABLED` (config key `planner.stall_detection_enabled`) is `true`
|
|
150
150
|
(default)):
|
|
151
151
|
```javascript
|
|
152
152
|
Agent(
|
|
@@ -528,7 +528,7 @@ Read the `activeHooks` array directly from `PLAN_PRE_HOOKS_JSON` / `HOOKS_JSON`
|
|
|
528
528
|
- In pipeline / `--auto` mode, invoke the hook's `ref.skill` via `Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")`.
|
|
529
529
|
- In manual mode, display the existing non-blocking `/gsd:ai-integration-phase {N}` recommendation and let the user continue planning without AI-SPEC or stop to run the capability workflow first.
|
|
530
530
|
|
|
531
|
-
Run the UI deterministic gate whenever **any** `plan:pre` UI hook is active — including the step-only case (`workflow.ui_safety_gate` off). (`check.query` = `"ui.plan-gate"
|
|
531
|
+
Run the UI deterministic gate whenever **any** `plan:pre` UI hook is active — including the step-only case (`workflow.ui_safety_gate` off). (`check.query` = `"ui.plan-gate"`, dot-normalized to `ui-plan-gate` per `loop-hook-dispatch.md` § `gate`.)
|
|
532
532
|
|
|
533
533
|
```bash
|
|
534
534
|
GATE=$(gsd_run check ui-plan-gate "${PHASE}" --raw) && GATE_EXIT=0 || GATE_EXIT=$?
|
|
@@ -635,10 +635,10 @@ SKETCH_FINDINGS_PATH=$(ls ./.claude/skills/sketch-findings-*/SKILL.md 2>/dev/nul
|
|
|
635
635
|
# Resolve the phase SPEC (carries the ## Edge Coverage section the planner lifts resolved
|
|
636
636
|
# edges from). UNCONDITIONAL — must NOT live in §4.5 Check AI-SPEC, which is skipped
|
|
637
637
|
# on non-AI phases; gating it there silently starves the planner of the SPEC (#550 review).
|
|
638
|
-
#
|
|
638
|
+
# init resolves the plain phase SPEC (never the -AI-SPEC.md / -UI-SPEC.md variants) through the one shared predicate.
|
|
639
639
|
PHASE_DIR_FOR_SPEC=$(_gsd_field "$INIT" phase_dir)
|
|
640
|
-
|
|
641
|
-
|
|
640
|
+
SPEC_PATH=$(_gsd_field "$INIT" spec_path)
|
|
641
|
+
SPEC_FILE="${SPEC_PATH}"
|
|
642
642
|
# Resolve the phase UI-SPEC separately (the glob above excludes -UI-SPEC.md); it carries the
|
|
643
643
|
# ## UI Considerations section the planner lifts by the same rule as ## Edge Coverage (#1867).
|
|
644
644
|
UI_SPEC_FILE=$(ls "${PHASE_DIR_FOR_SPEC}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
|
@@ -960,7 +960,7 @@ Every task MUST include these fields — they are NOT optional:
|
|
|
960
960
|
|
|
961
961
|
**If `CHUNKED_MODE` is `false` (default):** Spawn the planner as a single long-lived Agent:
|
|
962
962
|
|
|
963
|
-
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED
|
|
963
|
+
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED` (config key `planner.stall_detection_enabled`, resolved in `plan-phase/steps/stall-detection-helpers.md`):**
|
|
964
964
|
- **`true` (default):** use `run_in_background=true` in the Agent() call shown below, then use `gsd_stall_watch` as specified after it.
|
|
965
965
|
|
|
966
966
|
```text
|
|
@@ -1109,7 +1109,7 @@ Agent(
|
|
|
1109
1109
|
)
|
|
1110
1110
|
```
|
|
1111
1111
|
|
|
1112
|
-
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED
|
|
1112
|
+
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED` (config key `planner.stall_detection_enabled`, resolved in `plan-phase/steps/stall-detection-helpers.md`):**
|
|
1113
1113
|
- **`true` (default):** use `run_in_background=true` in the Agent() call above, then use `gsd_stall_watch` below.
|
|
1114
1114
|
|
|
1115
1115
|
**ORCHESTRATOR RULE — ALL RUNTIMES (when `PLANNER_STALL_DETECTION_ENABLED` is `true`):** `TS=$(date +%s)`; repeat `CHECKER_STALL_RESULT=$(gsd_stall_watch "$TS" "{outputFile}" "${PHASE_DIR}"'/*-PLAN.md' "## VERIFICATION PASSED" "## ISSUES FOUND")` while waiting/active.
|
|
@@ -1118,7 +1118,7 @@ Agent(
|
|
|
1118
1118
|
|
|
1119
1119
|
## 11. Handle Checker Return
|
|
1120
1120
|
|
|
1121
|
-
- **`marker_received` + `## VERIFICATION PASSED`:**
|
|
1121
|
+
- **`marker_received` + `## VERIFICATION PASSED`:** If the return lists an entry whose severity is BLOCKER or WARNING, in the YAML issues block or listed in prose (a mention such as "no warnings" or a zero count is not an entry), treat it as `## ISSUES FOUND` instead: display issues, check iteration count, proceed to step 12, which counts those prose entries as BLOCKER/WARNING entries (the no-YAML-block shortcut there does not apply). The sentinel never decides alone, and an entry with a missing or unrecognized severity counts as a BLOCKER (#5578). Otherwise display confirmation, proceed to step 13.
|
|
1122
1122
|
- **`marker_received` + `## ISSUES FOUND`:** Display issues, check iteration count, proceed to step 12.
|
|
1123
1123
|
- **`stalled`:** Automatically surface 11a's recovery choice (Accept verification / Retry checker / Stop) — no manual interrupt needed.
|
|
1124
1124
|
- **Empty / truncated / no recognized marker:** → Filesystem fallback (step 11a).
|
|
@@ -1143,7 +1143,7 @@ Track `stall_reentry_count` (starts at 0; incremented each time "Adjust approach
|
|
|
1143
1143
|
|
|
1144
1144
|
**If iteration_count < 3:**
|
|
1145
1145
|
|
|
1146
|
-
Parse issue count from checker return: count BLOCKER + WARNING entries in the YAML issues block (structured output from gsd-plan-checker); an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If the checker's return contains no YAML issues block (i.e., the plan was approved with no issues), treat `issue_count` as 0 and skip the stall check — the plan passed. Proceed to step 13 — likewise when every entry in the block is explicitly INFO (display them as advisories). Advisory format: `ℹ advisory — {dimension}: {description}` per INFO entry, listed once before the step-13 output.
|
|
1146
|
+
Parse issue count from checker return: count BLOCKER + WARNING entries in the YAML issues block (structured output from gsd-plan-checker); an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). Entries a `## VERIFICATION PASSED` return lists in prose count the same way (#5578). If the checker's return contains no YAML issues block and lists no BLOCKER or WARNING entry in prose (i.e., the plan was approved with no issues), treat `issue_count` as 0 and skip the stall check — the plan passed. Proceed to step 13 — likewise when every entry in the block is explicitly INFO (display them as advisories). Advisory format: `ℹ advisory — {dimension}: {description}` per INFO entry, listed once before the step-13 output.
|
|
1147
1147
|
|
|
1148
1148
|
Display (only when entering the revision loop — skip if the paragraph above already proceeded to step 13): `Revision iteration {N}/3 -- {blocker_count} blockers, {warning_count} warnings`
|
|
1149
1149
|
|
|
@@ -1206,7 +1206,7 @@ Agent(
|
|
|
1206
1206
|
)
|
|
1207
1207
|
```
|
|
1208
1208
|
|
|
1209
|
-
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED
|
|
1209
|
+
**Dispatch/wait gate — `PLANNER_STALL_DETECTION_ENABLED` (config key `planner.stall_detection_enabled`, resolved in `plan-phase/steps/stall-detection-helpers.md`):**
|
|
1210
1210
|
- **`true` (default):** use `run_in_background=true` in the Agent() call above, then use `gsd_stall_watch` below.
|
|
1211
1211
|
|
|
1212
1212
|
**ORCHESTRATOR RULE — ALL RUNTIMES (when `PLANNER_STALL_DETECTION_ENABLED` is `true`):** (7.99; no marker, mtimes only) `TS=$(date +%s)`; repeat `PLANNER_STALL_RESULT=$(gsd_stall_watch "$TS" "{outputFile}" "${PHASE_DIR}"'/*-PLAN.md')` while waiting/active — `stalled` -> 1) Accept as revised, to step 13, 2) Retry, 3) Stop.
|
|
@@ -1288,7 +1288,7 @@ Spawn checker again (step 10), then increment `iteration_count`.
|
|
|
1288
1288
|
|
|
1289
1289
|
**If iteration_count >= 3:**
|
|
1290
1290
|
|
|
1291
|
-
Recount BLOCKER + WARNING by the same rule — an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If `issue_count` is 0 — PASSED, or every entry in the block is explicitly INFO — display any advisories and proceed to step 13; the gate below fires on everything else (#3724).
|
|
1291
|
+
Recount BLOCKER + WARNING by the same rule — an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If `issue_count` is 0 — PASSED with no BLOCKER/WARNING entry in the YAML block or in prose, or every entry in the block is explicitly INFO — display any advisories and proceed to step 13; the gate below fires on everything else (#3724).
|
|
1292
1292
|
|
|
1293
1293
|
Display: `Max iterations reached. {N} issues remain:` + issue list
|
|
1294
1294
|
|
|
@@ -1478,7 +1478,7 @@ every other registered hook at this point).
|
|
|
1478
1478
|
|
|
1479
1479
|
**Step and contribution dispatch:** dispatch every `kind == "step"` hook and inject every `kind == "contribution"` fragment per @gsd-core/references/loop-hook-dispatch.md (skip each kind silently when none), before gate evaluation below.
|
|
1480
1480
|
|
|
1481
|
-
⚠ **Validate `check` before shell use** (third-party manifest input) — `loop-hook-dispatch.md` § `gate`.
|
|
1481
|
+
⚠ **Validate `check` before shell use** (third-party manifest input; wherever `${hook.check.query}` appears, write the dot-normalized query, each `.` as `-`, and validate and pass that same value) — `loop-hook-dispatch.md` § `gate`.
|
|
1482
1482
|
|
|
1483
1483
|
**For each active entry where `kind == "gate"`** (process in array order). **Dispatch by check shape** (the registry validates exactly one of `query`/`predicate`/`agentVerdict`):
|
|
1484
1484
|
|
|
@@ -1486,9 +1486,9 @@ every other registered hook at this point).
|
|
|
1486
1486
|
# named-query gate:
|
|
1487
1487
|
GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_DIR}" "${PHASE_REQ_IDS}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
1488
1488
|
```
|
|
1489
|
-
OR, for a generic `predicate` gate (ADR-2008 / #2008), inline the predicate as compact JSON (note the `--phase-dir`/`--phase-req-ids` flags feed `${PHASE_DIR}`/`${PHASE_REQ_IDS}` interpolation):
|
|
1489
|
+
OR, for a generic `predicate` gate (ADR-2008 / #2008), inline the predicate as compact JSON (note the `--phase-dir`/`--phase-number`/`--phase-req-ids` flags feed `${PHASE_DIR}`/`${PHASE_NUMBER}`/`${PHASE_REQ_IDS}` interpolation):
|
|
1490
1490
|
```bash
|
|
1491
|
-
GATE_RESULT=$(gsd_run check predicate --predicate '<hook.check.predicate as JSON>' --phase-dir "${PHASE_DIR}" --phase-req-ids "${PHASE_REQ_IDS}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
1491
|
+
GATE_RESULT=$(gsd_run check predicate --predicate '<hook.check.predicate as JSON>' --phase-dir "${PHASE_DIR}" --phase-number "${PHASE_NUMBER}" --phase-req-ids "${PHASE_REQ_IDS}" --raw) && CHECK_EXIT=0 || CHECK_EXIT=$?
|
|
1492
1492
|
```
|
|
1493
1493
|
(Read the hook's `check` object in-context to pick the branch; a gate with neither is a malformed registry entry — skip with a warning.)
|
|
1494
1494
|
|
|
@@ -82,7 +82,7 @@ Agent(
|
|
|
82
82
|
|
|
83
83
|
**Handle checker return:**
|
|
84
84
|
|
|
85
|
-
- **`## VERIFICATION PASSED`:**
|
|
85
|
+
- **`## VERIFICATION PASSED`:** If the return lists an entry whose severity is BLOCKER or WARNING, in the YAML issues block or listed in prose (a mention such as "no warnings" or a zero count is not an entry), handle it as `## ISSUES FOUND` below, counting the prose entries as BLOCKER/WARNING entries; the sentinel never decides alone, and an entry with a missing or unrecognized severity counts as a BLOCKER (#5578). Otherwise display confirmation, proceed to step 6.
|
|
86
86
|
- **`## ISSUES FOUND`:** Count BLOCKER + WARNING entries in the YAML issues block; an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If zero — every entry is explicitly INFO — display `ℹ advisory — {dimension}: {description}` per entry and proceed to step 6; INFO is advisory and never enters the loop (#3724). Otherwise display issues, check iteration count, enter revision loop.
|
|
87
87
|
|
|
88
88
|
**Revision loop (max 2 iterations):**
|
|
@@ -16,7 +16,6 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
|
|
|
16
16
|
QUICK_PLAN_PARENT=""
|
|
17
17
|
QUICK_PLAN_COMMIT=""
|
|
18
18
|
if [ "${USE_WORKTREES}" != "false" ]; then
|
|
19
|
-
QUICK_PLAN_PARENT=$(git rev-parse HEAD)
|
|
20
19
|
COMMIT_DOCS=$(gsd_run query config-get commit_docs --raw 2>/dev/null || echo "true")
|
|
21
20
|
if [ "$COMMIT_DOCS" != "false" ]; then
|
|
22
21
|
# pre-dispatch plan commit — PLAN.md is always in scope. CONTEXT.md/RESEARCH.md
|
|
@@ -52,5 +51,13 @@ if [ "${USE_WORKTREES}" != "false" ]; then
|
|
|
52
51
|
if [ -z "$QUICK_PLAN_COMMIT" ]; then
|
|
53
52
|
QUICK_PLAN_COMMIT=$(git rev-parse HEAD)
|
|
54
53
|
fi
|
|
54
|
+
# #5209: the alternate base is the PLAN commit's immediate parent, read AFTER the
|
|
55
|
+
# commit attempt so it holds whether the planner already committed the plan or this
|
|
56
|
+
# step just did. Empty when docs commits are off and for a root commit.
|
|
57
|
+
if [ "$COMMIT_DOCS" != "false" ]; then
|
|
58
|
+
_GSD_PLAN_AT=$(git log -1 --format=%H -- "${QUICK_DIR}/${quick_id}-PLAN.md" 2>/dev/null || true)
|
|
59
|
+
[ -n "$_GSD_PLAN_AT" ] || _GSD_PLAN_AT="$QUICK_PLAN_COMMIT"
|
|
60
|
+
QUICK_PLAN_PARENT=$(git rev-parse --verify --quiet "${_GSD_PLAN_AT}^" 2>/dev/null || true)
|
|
61
|
+
fi
|
|
55
62
|
fi
|
|
56
63
|
```
|
|
@@ -73,7 +73,8 @@ that require a ROADMAP phase goal.
|
|
|
73
73
|
counts as BLOCKER, fail closed; pure INFO entries are advisory only and never
|
|
74
74
|
enter the revision loop):
|
|
75
75
|
|
|
76
|
-
- **`## VERIFICATION PASSED`** or all-INFO: proceed to the next item.
|
|
76
|
+
- **`## VERIFICATION PASSED`** (with no BLOCKER/WARNING entry) or all-INFO: proceed to the next item.
|
|
77
|
+
- **`## VERIFICATION PASSED` that nevertheless lists an entry whose severity is BLOCKER or WARNING, in the YAML issues block or listed in prose (a mention such as "no warnings" or a zero count is not an entry):** handled as `## ISSUES FOUND`, counting the prose entries as BLOCKER/WARNING entries; the sentinel never decides alone (#5578).
|
|
77
78
|
- **Any BLOCKER/WARNING:** revision loop, max 2 iterations total for this item.
|
|
78
79
|
|
|
79
80
|
**Revision (iteration < 2):**
|
|
@@ -541,7 +541,7 @@ SUMMARY.md and stop — the user must rerun with worktrees disabled.
|
|
|
541
541
|
|
|
542
542
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
543
543
|
|
|
544
|
-
If the executor ran isolated (`ISOLATION = "harness-worktree"` at dispatch), append its returned `{agent_id, worktree_path, branch, expected_base, allowed_bases}` metadata to `QUICK_WORKTREE_MANIFEST` before cleanup. Set `expected_base` to `${EXPECTED_BASE}` and `allowed_bases` to `["${EXPECTED_BASE}", "${QUICK_PLAN_PARENT}"]` with duplicates removed. If any required field is unavailable, stop and ask for recovery; do not discover global worktrees.
|
|
544
|
+
If the executor ran isolated (`ISOLATION = "harness-worktree"` at dispatch), append its returned `{agent_id, worktree_path, branch, expected_base, allowed_bases}` metadata to `QUICK_WORKTREE_MANIFEST` before cleanup. Set `expected_base` to `${EXPECTED_BASE}` and `allowed_bases` to `["${EXPECTED_BASE}", "${QUICK_PLAN_PARENT}"]` with duplicates and empty values removed. If any required field is unavailable, stop and ask for recovery; do not discover global worktrees.
|
|
545
545
|
|
|
546
546
|
After executor returns:
|
|
547
547
|
1. **Worktree cleanup:** If the executor ran isolated (`ISOLATION = "harness-worktree"` at dispatch), merge the worktree branch back and clean up:
|
|
@@ -27,18 +27,9 @@ command -v cursor-agent >/dev/null 2>&1 && echo "cursor:available" || echo "curs
|
|
|
27
27
|
command -v agy >/dev/null 2>&1 && echo "antigravity:available" || echo "antigravity:missing"
|
|
28
28
|
command -v kimi >/dev/null 2>&1 && echo "kimi-code:available" || echo "kimi-code:missing"
|
|
29
29
|
|
|
30
|
-
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
curl -s --max-time 2 "${OLLAMA_HOST}/v1/models" >/dev/null 2>&1 && echo "ollama:available" || echo "ollama:missing"
|
|
34
|
-
|
|
35
|
-
LM_STUDIO_HOST=$(gsd_run query config-get review.lm_studio_host --raw 2>/dev/null || echo "")
|
|
36
|
-
if [ -z "$LM_STUDIO_HOST" ] || [ "$LM_STUDIO_HOST" = "null" ]; then LM_STUDIO_HOST="http://localhost:1234"; fi
|
|
37
|
-
curl -s --max-time 2 "${LM_STUDIO_HOST}/v1/models" >/dev/null 2>&1 && echo "lm_studio:available" || echo "lm_studio:missing"
|
|
38
|
-
|
|
39
|
-
LLAMA_CPP_HOST=$(gsd_run query config-get review.llama_cpp_host --raw 2>/dev/null || echo "")
|
|
40
|
-
if [ -z "$LLAMA_CPP_HOST" ] || [ "$LLAMA_CPP_HOST" = "null" ]; then LLAMA_CPP_HOST="http://localhost:8080"; fi
|
|
41
|
-
curl -s --max-time 2 "${LLAMA_CPP_HOST}/v1/models" >/dev/null 2>&1 && echo "llama_cpp:available" || echo "llama_cpp:missing"
|
|
30
|
+
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required);
|
|
31
|
+
# hosts and defaults come from each lane's descriptor
|
|
32
|
+
gsd_run review-lane availability || { echo "WARNING: review-lane availability failed or is unsupported by this gsd-tools; treating local lanes as missing" >&2; printf 'ollama:missing\nlm_studio:missing\nllama_cpp:missing\n'; }
|
|
42
33
|
|
|
43
34
|
# jq prerequisite (#2589). The config/model/budget lookups in this workflow no
|
|
44
35
|
# longer need jq — they use the native --raw/--pick flags. But the lanes listed
|
|
@@ -665,6 +656,18 @@ done
|
|
|
665
656
|
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
666
657
|
# `$DISPATCH_SLUGS` word-splits under bash but not zsh, collapsing every
|
|
667
658
|
# slug onto one iteration there whenever 2+ reviewers were selected.
|
|
659
|
+
# gsd-resolve-lib begin pattern.cjs (#5640): load helpers from the installed runtime, not the cwd
|
|
660
|
+
_gsd_lib_probe="pattern.cjs"
|
|
661
|
+
_gsd_rt="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
662
|
+
_gsd_gr="$(command -v gsd_run 2>/dev/null || true)"
|
|
663
|
+
case "$_gsd_gr" in /*) ;; *) _gsd_gr="" ;; esac # a gsd_run shell function prints its bare name: not a path
|
|
664
|
+
[ -n "$_gsd_gr" ] && _gsd_gr="$(dirname "$(node -p "require('fs').realpathSync(process.argv[1])" "$_gsd_gr" 2>/dev/null || echo "$_gsd_gr")")/lib"
|
|
665
|
+
GSD_LIB_DIR=""
|
|
666
|
+
_gsd_pick() { for _gsd_d; do if [ -n "$_gsd_d" ] && [ -f "$_gsd_d/$_gsd_lib_probe" ]; then GSD_LIB_DIR="$_gsd_d"; return 0; fi; done; return 1; }
|
|
667
|
+
_gsd_pick "${GSD_TOOLS:+${GSD_TOOLS%/*}/lib}" "$_gsd_rt/gsd-core/bin/lib" "$_gsd_rt/.claude/gsd-core/bin/lib" "$_gsd_rt/.codex/gsd-core/bin/lib" "$_gsd_gr" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib" || true
|
|
668
|
+
if [ -z "$GSD_LIB_DIR" ]; then echo "ERROR: pattern.cjs not found in the GSD runtime. Looked in: ${GSD_TOOLS:+${GSD_TOOLS%/*}/lib, }${_gsd_rt}/gsd-core/bin/lib (and its .claude and .codex forms), ${_gsd_gr:-next to gsd_run (not on PATH)}, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/lib, ${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/lib. Reinstall: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
669
|
+
export GSD_LIB_DIR
|
|
670
|
+
# gsd-resolve-lib end
|
|
668
671
|
for SLUG in $(printf '%s' "$DISPATCH_SLUGS"); do
|
|
669
672
|
[ "$SLUG" = "coderabbit" ] && continue
|
|
670
673
|
REVIEW_FILE="$RUN_DIR/gsd-review-$SLUG.md"
|
|
@@ -675,7 +678,7 @@ for SLUG in $(printf '%s' "$DISPATCH_SLUGS"); do
|
|
|
675
678
|
|
|
676
679
|
node -e '
|
|
677
680
|
const fs = require("fs");
|
|
678
|
-
const { escapeRegex } = require("
|
|
681
|
+
const { escapeRegex } = require(require("path").join(process.env.GSD_LIB_DIR, "pattern.cjs"));
|
|
679
682
|
const manifest = fs.readFileSync(process.argv[1], "utf8");
|
|
680
683
|
const review = fs.readFileSync(process.argv[2], "utf8");
|
|
681
684
|
const ids = manifest.split("\n")
|
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"complete-milestone": [
|
|
43
|
+
{
|
|
44
|
+
"id": "project-md-evolution-review",
|
|
45
|
+
"when": "state:flat-mode",
|
|
46
|
+
"read": "gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md"
|
|
47
|
+
},
|
|
43
48
|
{
|
|
44
49
|
"id": "git-tag",
|
|
45
50
|
"when": "state:git-create-tag",
|
|
@@ -59,6 +59,7 @@ Parse current values (default to `true` if not present):
|
|
|
59
59
|
- `graphify.auto_update` — opt-in: auto-rebuild graph after main HEAD advances (#3347) (default: `false`)
|
|
60
60
|
- `model_profile` — which model each agent uses (default: `balanced`)
|
|
61
61
|
- `git.branching_strategy` — branching approach (default: `"none"`)
|
|
62
|
+
- `git.repo_tagging` — milestone tagging mode: `"single"` (one `v[X.Y]` tag, default) or `"per_repo"` (record a release map and tag each `planning.sub_repos` repository separately; set via `gsd_run query config-set git.repo_tagging per_repo`, #3628)
|
|
62
63
|
- `workflow.use_worktrees` — whether parallel executor agents run in worktree isolation (honored when the runtime declares a `dispatch.isolation` primitive — `harness-worktree` or `orchestrator-worktree`; runtimes declaring `none` default it to `false` and fail closed on an explicit `true` — #1521, #2486, #2584)
|
|
63
64
|
- `workflow.compact_content` — load token-minimized instruction variants where they exist, trading rarely-needed elaboration for a smaller always-loaded instruction window (default: false if absent; #4139)
|
|
64
65
|
- `model_policy.provider` — provider slug for model policy (default: `null`; known values: anthropic, openai, google, qwen; set via /gsd:config --advanced)
|
|
@@ -160,7 +160,7 @@ Verify the work is ready to ship:
|
|
|
160
160
|
|
|
161
161
|
- **Every other `capId`** — run the gate's own declared check through the generic evaluator. This arm is what makes a third-party capability's declared gate enforceable at all (#3559); before it existed, a gate whose `capId` was not named above was resolved and then silently dropped.
|
|
162
162
|
|
|
163
|
-
⚠ **Validate `check` before shell use** (third-party manifest input) — `loop-hook-dispatch.md` § `gate`.
|
|
163
|
+
⚠ **Validate `check` before shell use** (third-party manifest input; wherever `${hook.check.query}` appears, write the dot-normalized query, each `.` as `-`, and validate and pass that same value) — `loop-hook-dispatch.md` § `gate`.
|
|
164
164
|
|
|
165
165
|
For a named-query gate (only a value that has passed validation is run):
|
|
166
166
|
```bash
|
|
@@ -477,11 +477,10 @@ Report the PR URL and suggest: "Review the diff at {url}/files"
|
|
|
477
477
|
</step>
|
|
478
478
|
|
|
479
479
|
<step name="track_shipping">
|
|
480
|
-
Update STATE.md to reflect the shipping action
|
|
480
|
+
Update STATE.md to reflect the shipping action. Write the activity line only, with its description; do not write `Status`. At ship time the Current Position block already describes the next phase, and `Status` feeds the frontmatter `status` field, so a free-text value such as "Phase N shipped" does not belong there (#5165).
|
|
481
481
|
|
|
482
482
|
```bash
|
|
483
|
-
gsd_run query state.update "Last Activity" "$(date +%Y-%m-%d)"
|
|
484
|
-
gsd_run query state.update "Status" "Phase ${PHASE_NUMBER} shipped — PR #${PR_NUMBER}"
|
|
483
|
+
gsd_run query state.update "Last Activity" "$(date +%Y-%m-%d) -- Phase ${PHASE_NUMBER} shipped as PR #${PR_NUMBER}"
|
|
485
484
|
```
|
|
486
485
|
|
|
487
486
|
If `commit_docs` is true, commit the ship-note AND push it onto the PR branch so
|