@opengsd/gsd-core 1.6.0-rc.3 → 1.6.1
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/plugin.json +1 -1
- package/agents/gsd-advisor-researcher.md +2 -0
- package/agents/gsd-ai-researcher.md +2 -0
- package/agents/gsd-assumptions-analyzer.md +2 -0
- package/agents/gsd-doc-classifier.md +2 -0
- package/agents/gsd-doc-synthesizer.md +2 -0
- package/agents/gsd-domain-researcher.md +2 -0
- package/agents/gsd-eval-auditor.md +6 -9
- package/agents/gsd-phase-researcher.md +2 -0
- package/agents/gsd-project-researcher.md +2 -0
- package/agents/gsd-research-synthesizer.md +2 -0
- package/agents/gsd-ui-researcher.md +2 -0
- package/bin/install.js +219 -5
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +11 -1
- package/gsd-core/bin/lib/capability-registry.cjs +48 -48
- package/gsd-core/bin/lib/command-aliases.cjs +10 -1
- package/gsd-core/bin/lib/decisions.cjs +27 -0
- package/gsd-core/bin/lib/eval-command-router.cjs +21 -0
- package/gsd-core/bin/lib/eval.cjs +60 -0
- package/gsd-core/bin/lib/frontmatter.cjs +132 -13
- package/gsd-core/bin/lib/init.cjs +131 -26
- package/gsd-core/bin/lib/io.cjs +1 -0
- package/gsd-core/bin/lib/milestone.cjs +8 -0
- package/gsd-core/bin/lib/phase.cjs +29 -3
- package/gsd-core/bin/lib/plan-scan.cjs +2 -2
- package/gsd-core/bin/lib/roadmap.cjs +12 -1
- package/gsd-core/bin/lib/shell-command-projection.cjs +31 -1
- package/gsd-core/bin/lib/state.cjs +34 -8
- package/gsd-core/bin/lib/uat-predicate.cjs +13 -6
- package/gsd-core/bin/lib/verification.cjs +67 -6
- package/gsd-core/bin/lib/verify.cjs +8 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +3 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -1
- package/gsd-core/bin/shared/model-catalog.json +8 -8
- package/gsd-core/references/untrusted-input-boundary.md +13 -0
- package/gsd-core/workflows/autonomous.md +53 -46
- package/gsd-core/workflows/complete-milestone.md +27 -8
- package/gsd-core/workflows/execute-phase.md +1 -1
- package/gsd-core/workflows/manager.md +17 -7
- package/gsd-core/workflows/new-project.md +78 -12
- package/gsd-core/workflows/profile-user.md +6 -2
- package/gsd-core/workflows/progress.md +37 -4
- package/gsd-core/workflows/quick.md +3 -1
- package/gsd-core/workflows/settings-advanced.md +10 -10
- package/gsd-core/workflows/ship.md +3 -1
- package/gsd-core/workflows/spec-phase.md +3 -1
- package/gsd-core/workflows/transition.md +14 -12
- package/gsd-core/workflows/ui-review.md +2 -6
- package/gsd-core/workflows/verify-work.md +44 -0
- package/hooks/dist/gsd-read-injection-scanner.js +49 -25
- package/hooks/gsd-read-injection-scanner.js +49 -25
- package/hooks/hooks.json +1 -1
- package/package.json +1 -1
- package/scripts/check-alias-drift.cjs +5 -0
- package/scripts/prompt-injection-scan.sh +5 -0
|
@@ -72,27 +72,44 @@ If user chooses [A] (Acknowledge):
|
|
|
72
72
|
...
|
|
73
73
|
```
|
|
74
74
|
Sanitize all slug and status values via `sanitizeForDisplay()` before writing. Never inject raw file content into STATE.md.
|
|
75
|
-
3.
|
|
75
|
+
3. Set `closeout_type=override_closeout` and record `Known verification overrides: {count} (see STATE.md Deferred Items)` in the MILESTONES.md entry.
|
|
76
76
|
4. Proceed with milestone close.
|
|
77
77
|
|
|
78
|
-
If output shows all clear (no open items): print `All artifact types clear
|
|
78
|
+
If output shows all clear (no open items): set `closeout_type=verified_closeout`, print `All artifact types clear.`, and proceed.
|
|
79
79
|
|
|
80
80
|
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. When writing to STATE.md, item slugs and descriptions are sanitized via `sanitizeForDisplay()` before inclusion. Never inject raw user-supplied content into STATE.md without sanitization.
|
|
81
81
|
</step>
|
|
82
82
|
|
|
83
83
|
<step name="verify_readiness">
|
|
84
84
|
|
|
85
|
-
**Use `
|
|
85
|
+
**Use `init.manager` for canonical readiness check:**
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
|
|
88
|
+
INIT_MANAGER=$(gsd_run query init.manager)
|
|
89
|
+
if [[ "$INIT_MANAGER" == @file:* ]]; then INIT_MANAGER=$(cat "${INIT_MANAGER#@file:}"); fi
|
|
89
90
|
```
|
|
90
91
|
|
|
91
|
-
This returns all phases with
|
|
92
|
+
This returns all phases with implementation and verification projection. Use this to verify:
|
|
92
93
|
- Which phases belong to this milestone?
|
|
93
|
-
-
|
|
94
|
+
- `all_phases_verified`: all milestone phases have `phase_complete === true` and `verification_status === 'passed'`.
|
|
94
95
|
- `progress_percent` should be 100%.
|
|
95
96
|
|
|
97
|
+
Compute readiness from `INIT_MANAGER`, not from roadmap counts:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
ALL_PHASES_VERIFIED=$(printf '%s' "$INIT_MANAGER" | jq -r '[
|
|
101
|
+
.phases[] | select((.number | tostring | test("^999(\\.|$)") | not))
|
|
102
|
+
| (.phase_complete == true and .verification_status == "passed")
|
|
103
|
+
] | all')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If not all_phases_verified, verified_closeout must not proceed. Set `closeout_type=override_closeout`, show each phase whose `phase_complete !== true` or `verification_status !== 'passed'`, and require an explicit user choice:
|
|
107
|
+
1. **Proceed anyway** — record verification overrides in MILESTONES.md/STATE.md
|
|
108
|
+
2. **Run verification first** — `/gsd:verify-work {phase}` or `/gsd:execute-phase {phase}`
|
|
109
|
+
3. **Abort** — return to development
|
|
110
|
+
|
|
111
|
+
Only set `closeout_type=verified_closeout` when `ALL_PHASES_VERIFIED` is `true`.
|
|
112
|
+
|
|
96
113
|
**Requirements completion check (REQUIRED before presenting):**
|
|
97
114
|
|
|
98
115
|
Parse REQUIREMENTS.md traceability table:
|
|
@@ -110,7 +127,9 @@ Includes:
|
|
|
110
127
|
- Phase 3: Core Features (3/3 plans complete)
|
|
111
128
|
- Phase 4: Polish (1/1 plan complete)
|
|
112
129
|
|
|
113
|
-
Total: {phase_count} phases, {total_plans} plans
|
|
130
|
+
Total: {phase_count} phases, {total_plans} plans
|
|
131
|
+
Verification: {all_phases_verified ? "all phases verified" : "override needed"}
|
|
132
|
+
Closeout type: {closeout_type}
|
|
114
133
|
Requirements: {N}/{M} v1 requirements checked off
|
|
115
134
|
```
|
|
116
135
|
|
|
@@ -128,7 +147,7 @@ MUST present 3 options:
|
|
|
128
147
|
2. **Run audit first** — `/gsd:audit-milestone` to assess gap severity
|
|
129
148
|
3. **Abort** — return to development
|
|
130
149
|
|
|
131
|
-
If user selects "Proceed anyway": note incomplete requirements in MILESTONES.md under `### Known Gaps` with REQ-IDs and descriptions.
|
|
150
|
+
If user selects "Proceed anyway": set `closeout_type=override_closeout`; note incomplete requirements in MILESTONES.md under `### Known Gaps` with REQ-IDs and descriptions.
|
|
132
151
|
|
|
133
152
|
<config-check>
|
|
134
153
|
|
|
@@ -580,7 +580,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
|
|
|
580
580
|
DISPATCH_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
581
581
|
EXPECTED_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
582
582
|
if [ "${USE_WORKTREES_FOR_PLAN:-true}" != "false" ] && [ -z "${WAVE_WORKTREE_MANIFEST:-}" ]; then
|
|
583
|
-
|
|
583
|
+
M=$(mktemp "${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX") && mv "$M" "$M.json" && WAVE_WORKTREE_MANIFEST="$M.json" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)
|
|
584
584
|
# Persist the dispatch-time orchestrator worktree root so wave-cleanup can pin back to the
|
|
585
585
|
# orchestrator's OWN worktree — NOT `git worktree list`'s first entry (always the main
|
|
586
586
|
# checkout), which pins a non-primary (per-phase lane) orchestrator off its branch (#630).
|
|
@@ -72,6 +72,7 @@ Build dashboard from JSON. Symbols: `✓` done, `◆` active, `○` pending, `·
|
|
|
72
72
|
**Status mapping** (disk_status → D P E Status):
|
|
73
73
|
|
|
74
74
|
- `complete` → `✓ ✓ ✓` `✓ Complete`
|
|
75
|
+
- `executed` → `✓ ✓ ◆` `◆ Verification required`
|
|
75
76
|
- `partial` → `✓ ✓ ◆` `◆ Executing...`
|
|
76
77
|
- `planned` → `✓ ✓ ○` `○ Ready to execute`
|
|
77
78
|
- `discussed` → `✓ ○ ·` `○ Ready to plan`
|
|
@@ -135,7 +136,7 @@ If `all_complete` is true:
|
|
|
135
136
|
║ MILESTONE COMPLETE ║
|
|
136
137
|
╚══════════════════════════════════════════════════════════════╝
|
|
137
138
|
|
|
138
|
-
All {phase_count} phases
|
|
139
|
+
All {phase_count} phases verified complete. Ready for final steps:
|
|
139
140
|
→ /gsd:verify-work — run acceptance testing
|
|
140
141
|
→ /gsd:complete-milestone — archive and wrap up
|
|
141
142
|
```
|
|
@@ -158,8 +159,9 @@ Handle responses:
|
|
|
158
159
|
**Building options:**
|
|
159
160
|
|
|
160
161
|
1. Collect all background actions (execute and plan recommendations) — there can be multiple of each.
|
|
161
|
-
2. Collect
|
|
162
|
-
3.
|
|
162
|
+
2. Collect verification actions (`verify`) for implementation-complete phases whose canonical verification has not passed.
|
|
163
|
+
3. Collect the inline action (discuss recommendation, if any — there will be at most one since discuss is sequential).
|
|
164
|
+
4. Build compound options:
|
|
163
165
|
|
|
164
166
|
**If there are ANY recommended actions (background, inline, or both):**
|
|
165
167
|
Create ONE primary "Continue" option that dispatches ALL of them together:
|
|
@@ -169,10 +171,11 @@ Handle responses:
|
|
|
169
171
|
Continue:
|
|
170
172
|
→ Execute Phase 32 (background)
|
|
171
173
|
→ Plan Phase 34 (background)
|
|
174
|
+
→ Verify Phase 33
|
|
172
175
|
→ Discuss Phase 35 (inline)
|
|
173
176
|
```
|
|
174
|
-
- This dispatches all background agents first, then runs the inline discuss (if any).
|
|
175
|
-
- If there is no inline discuss, the dashboard refreshes after spawning background agents.
|
|
177
|
+
- This dispatches all background agents first, runs verification actions inline, then runs the inline discuss (if any).
|
|
178
|
+
- If there is no inline discuss, the dashboard refreshes after spawning background agents and inline verification.
|
|
176
179
|
|
|
177
180
|
**Important:** The Continue option must include EVERY action from `recommended_actions` — not just 2. If there are 3 actions, list 3. If there are 5, list 5.
|
|
178
181
|
|
|
@@ -221,8 +224,15 @@ Go to exit step.
|
|
|
221
224
|
|
|
222
225
|
When the user selects a compound option, behavior depends on the runtime — the Plan Phase N / Execute Phase N handlers below resolve it via `gsd_run query config-get runtime`:
|
|
223
226
|
|
|
224
|
-
- **On Codex:** **Spawn all background agents first** (plan/execute) — dispatch them in parallel using the Plan Phase N / Execute Phase N handlers below — then run the inline discuss; the background agents continue while you discuss.
|
|
225
|
-
- **
|
|
227
|
+
- **On Codex:** **Spawn all background agents first** (plan/execute) — dispatch them in parallel using the Plan Phase N / Execute Phase N handlers below — then run verification actions, then run the inline discuss; the background agents continue while you verify/discuss.
|
|
228
|
+
- **On Claude Code or any other non-Codex runtime:** run the chosen plan/execute step(s) **inline** via their handlers below (in order), then run verification actions, then run the inline discuss. There is no overlap.
|
|
229
|
+
|
|
230
|
+
Inline verification:
|
|
231
|
+
|
|
232
|
+
For each verification recommendation, dispatch by the recommended action's `command`:
|
|
233
|
+
- If `command` contains `execute-phase`, run `Skill(skill="gsd-execute-phase", args="{PHASE_NUM} {manager_flags.execute}")`.
|
|
234
|
+
- If `command` contains `verify-work`, run `Skill(skill="gsd-verify-work", args="{PHASE_NUM}")`.
|
|
235
|
+
- If `command` is missing or unrecognized, stop and show the recommendation row instead of guessing.
|
|
226
236
|
|
|
227
237
|
Inline discuss:
|
|
228
238
|
|
|
@@ -230,19 +230,52 @@ AskUserQuestion([
|
|
|
230
230
|
{ label: "Yes (Recommended)", description: "Resolve symbol references against live source during plan review — catches hallucinated names before execution" },
|
|
231
231
|
{ label: "No", description: "Skip symbol grounding — plan review proceeds without source verification" }
|
|
232
232
|
]
|
|
233
|
-
}
|
|
233
|
+
}
|
|
234
|
+
])
|
|
235
|
+
|
|
236
|
+
// Model profile uses a two-question split because AskUserQuestion enforces a hard
|
|
237
|
+
// 4-option cap and there are 5 valid profiles (quality, balanced, budget, adaptive,
|
|
238
|
+
// inherit). Q1 routes between adaptive/standard-tier/inherit; Q2 (shown only when
|
|
239
|
+
// Q1 = "Standard tier…") picks among the three standard profiles. Mirrors the
|
|
240
|
+
// /gsd:settings split (#3784, #1516).
|
|
241
|
+
AskUserQuestion([
|
|
234
242
|
{
|
|
235
243
|
header: "AI Models",
|
|
236
244
|
question: "Which AI models for planning agents?",
|
|
237
245
|
multiSelect: false,
|
|
238
246
|
options: [
|
|
239
|
-
{ label: "
|
|
240
|
-
{ label: "
|
|
241
|
-
{ label: "
|
|
242
|
-
{ label: "Inherit", description: "Use the current session model for all agents (OpenCode /model)" }
|
|
247
|
+
{ label: "Adaptive (Recommended)", description: "Role-based cost optimization: heavy roles use the highest-tier model available on the active runtime, light roles use the cheapest. Best balance of quality and cost across all supported runtimes (Claude, Codex, Gemini, OpenRouter, local)." },
|
|
248
|
+
{ label: "Standard tier…", description: "Choose Quality, Balanced, or Budget — flat tier applied to all agents" },
|
|
249
|
+
{ label: "Inherit", description: "Use the current session model for all agents (required for non-Claude runtimes: Codex, Gemini CLI, OpenCode /model, OpenRouter, local models)" }
|
|
243
250
|
]
|
|
244
251
|
}
|
|
245
252
|
])
|
|
253
|
+
|
|
254
|
+
**Conditional visibility — model_profile (Q2):**
|
|
255
|
+
Only ask this question when Q1's answer is "Standard tier…".
|
|
256
|
+
If Q1 = "Adaptive (Recommended)" → write model_profile=adaptive and SKIP Q2.
|
|
257
|
+
If Q1 = "Inherit" → write model_profile=inherit and SKIP Q2.
|
|
258
|
+
If user cancels Q2 after picking "Standard tier…" → leave existing model_profile value unchanged.
|
|
259
|
+
|
|
260
|
+
AskUserQuestion([
|
|
261
|
+
{
|
|
262
|
+
question: "Which standard profile? (Quality / Balanced / Budget)",
|
|
263
|
+
header: "Model Tier",
|
|
264
|
+
multiSelect: false,
|
|
265
|
+
options: [
|
|
266
|
+
{ label: "Quality", description: "Opus everywhere except verification (highest cost) — Claude only" },
|
|
267
|
+
{ label: "Balanced", description: "Opus for planning, Sonnet for research/execution/verification — Claude only" },
|
|
268
|
+
{ label: "Budget", description: "Sonnet for writing, Haiku for research/verification (lowest cost) — Claude only" }
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
])
|
|
272
|
+
|
|
273
|
+
// Map UI choices → config values:
|
|
274
|
+
// Q1 "Adaptive (Recommended)" → model_profile = "adaptive"
|
|
275
|
+
// Q1 "Inherit" → model_profile = "inherit"
|
|
276
|
+
// Q1 "Standard tier…" + Q2 "Quality" → model_profile = "quality"
|
|
277
|
+
// Q1 "Standard tier…" + Q2 "Balanced" → model_profile = "balanced"
|
|
278
|
+
// Q1 "Standard tier…" + Q2 "Budget" → model_profile = "budget"
|
|
246
279
|
```
|
|
247
280
|
|
|
248
281
|
**Round 3 — PR body onboarding:**
|
|
@@ -273,7 +306,7 @@ Create `.planning/config.json` with all settings (CLI fills in remaining default
|
|
|
273
306
|
|
|
274
307
|
```bash
|
|
275
308
|
mkdir -p .planning
|
|
276
|
-
gsd_run query config-new-project '{"mode":"yolo","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":true|false,"auto_advance":true},"plan_review":{"source_grounding":true|false},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}'
|
|
309
|
+
gsd_run query config-new-project '{"mode":"yolo","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|adaptive|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":true|false,"auto_advance":true},"plan_review":{"source_grounding":true|false},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}'
|
|
277
310
|
```
|
|
278
311
|
|
|
279
312
|
**If commit_docs = No:** Add `.planning/` to `.gitignore`.
|
|
@@ -745,19 +778,52 @@ questions: [
|
|
|
745
778
|
{ label: "Yes (Recommended)", description: "Confirm deliverables match phase goals" },
|
|
746
779
|
{ label: "No", description: "Trust execution, skip verification" }
|
|
747
780
|
]
|
|
748
|
-
}
|
|
781
|
+
}
|
|
782
|
+
]
|
|
783
|
+
|
|
784
|
+
// Model profile uses a two-question split because AskUserQuestion enforces a hard
|
|
785
|
+
// 4-option cap and there are 5 valid profiles (quality, balanced, budget, adaptive,
|
|
786
|
+
// inherit). Q1 routes between adaptive/standard-tier/inherit; Q2 (shown only when
|
|
787
|
+
// Q1 = "Standard tier…") picks among the three standard profiles. Mirrors the
|
|
788
|
+
// /gsd:settings split (#3784, #1516).
|
|
789
|
+
questions: [
|
|
749
790
|
{
|
|
750
791
|
header: "AI Models",
|
|
751
792
|
question: "Which AI models for planning agents?",
|
|
752
793
|
multiSelect: false,
|
|
753
794
|
options: [
|
|
754
|
-
{ label: "
|
|
755
|
-
{ label: "
|
|
756
|
-
{ label: "
|
|
757
|
-
{ label: "Inherit", description: "Use the current session model for all agents (OpenCode /model)" }
|
|
795
|
+
{ label: "Adaptive (Recommended)", description: "Role-based cost optimization: heavy roles use the highest-tier model available on the active runtime, light roles use the cheapest. Best balance of quality and cost across all supported runtimes (Claude, Codex, Gemini, OpenRouter, local)." },
|
|
796
|
+
{ label: "Standard tier…", description: "Choose Quality, Balanced, or Budget — flat tier applied to all agents" },
|
|
797
|
+
{ label: "Inherit", description: "Use the current session model for all agents (required for non-Claude runtimes: Codex, Gemini CLI, OpenCode /model, OpenRouter, local models)" }
|
|
758
798
|
]
|
|
759
799
|
}
|
|
760
800
|
]
|
|
801
|
+
|
|
802
|
+
**Conditional visibility — model_profile (Q2):**
|
|
803
|
+
Only ask this question when Q1's answer is "Standard tier…".
|
|
804
|
+
If Q1 = "Adaptive (Recommended)" → write model_profile=adaptive and SKIP Q2.
|
|
805
|
+
If Q1 = "Inherit" → write model_profile=inherit and SKIP Q2.
|
|
806
|
+
If user cancels Q2 after picking "Standard tier…" → leave existing model_profile value unchanged.
|
|
807
|
+
|
|
808
|
+
questions: [
|
|
809
|
+
{
|
|
810
|
+
question: "Which standard profile? (Quality / Balanced / Budget)",
|
|
811
|
+
header: "Model Tier",
|
|
812
|
+
multiSelect: false,
|
|
813
|
+
options: [
|
|
814
|
+
{ label: "Quality", description: "Opus everywhere except verification (highest cost) — Claude only" },
|
|
815
|
+
{ label: "Balanced", description: "Opus for planning, Sonnet for research/execution/verification — Claude only" },
|
|
816
|
+
{ label: "Budget", description: "Sonnet for writing, Haiku for research/verification (lowest cost) — Claude only" }
|
|
817
|
+
]
|
|
818
|
+
}
|
|
819
|
+
]
|
|
820
|
+
|
|
821
|
+
// Map UI choices → config values:
|
|
822
|
+
// Q1 "Adaptive (Recommended)" → model_profile = "adaptive"
|
|
823
|
+
// Q1 "Inherit" → model_profile = "inherit"
|
|
824
|
+
// Q1 "Standard tier…" + Q2 "Quality" → model_profile = "quality"
|
|
825
|
+
// Q1 "Standard tier…" + Q2 "Balanced" → model_profile = "balanced"
|
|
826
|
+
// Q1 "Standard tier…" + Q2 "Budget" → model_profile = "budget"
|
|
761
827
|
```
|
|
762
828
|
|
|
763
829
|
**PR body onboarding:** Ask which optional PRD-style sections `/gsd:ship` should append to generated PR bodies. Use the same `ship.pr_body_sections` mapping as Step 2a: selected sections get `enabled: true`, seeded-but-unselected sections get `enabled: false`, and selecting none writes an empty list. Prefer lean/agile PRD sections that make user value, acceptance criteria, Definition of Done, and stakeholder traceability explicit.
|
|
@@ -773,7 +839,7 @@ Create `.planning/config.json` with all settings (CLI fills in remaining default
|
|
|
773
839
|
|
|
774
840
|
```bash
|
|
775
841
|
mkdir -p .planning
|
|
776
|
-
gsd_run query config-new-project '{"mode":"[yolo|interactive]","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":[false if granularity=coarse, true otherwise]},"plan_review":{"source_grounding":true|false},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}'
|
|
842
|
+
gsd_run query config-new-project '{"mode":"[yolo|interactive]","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|adaptive|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":[false if granularity=coarse, true otherwise]},"plan_review":{"source_grounding":true|false},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}'
|
|
777
843
|
```
|
|
778
844
|
|
|
779
845
|
**Note:** Run `/gsd:settings` anytime to update model profile, workflow agents, branching strategy, and other preferences.
|
|
@@ -218,7 +218,9 @@ Collect all answers into an answers JSON object mapping dimension keys to select
|
|
|
218
218
|
|
|
219
219
|
**Save answers to temp file:**
|
|
220
220
|
```bash
|
|
221
|
-
|
|
221
|
+
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
222
|
+
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
223
|
+
ANSWERS_PATH=$(mktemp "${TMPDIR:-/tmp}/gsd-profile-answers-XXXXXX") && mv "$ANSWERS_PATH" "${ANSWERS_PATH}.json" && ANSWERS_PATH="${ANSWERS_PATH}.json" || exit 1
|
|
222
224
|
```
|
|
223
225
|
|
|
224
226
|
Write the answers JSON to `$ANSWERS_PATH`.
|
|
@@ -232,7 +234,9 @@ Parse the analysis JSON from the result.
|
|
|
232
234
|
|
|
233
235
|
Save analysis JSON to a temp file:
|
|
234
236
|
```bash
|
|
235
|
-
|
|
237
|
+
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
238
|
+
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
239
|
+
ANALYSIS_PATH=$(mktemp "${TMPDIR:-/tmp}/gsd-profile-analysis-XXXXXX") && mv "$ANALYSIS_PATH" "${ANALYSIS_PATH}.json" && ANALYSIS_PATH="${ANALYSIS_PATH}.json" || exit 1
|
|
236
240
|
```
|
|
237
241
|
|
|
238
242
|
Write the analysis JSON to `$ANALYSIS_PATH`.
|
|
@@ -273,7 +273,7 @@ This is a WARNING, not a blocker — routing proceeds normally. The debt is visi
|
|
|
273
273
|
|
|
274
274
|
**Step 1.7: Check verification status for the current phase**
|
|
275
275
|
|
|
276
|
-
A phase whose verification
|
|
276
|
+
A phase whose verification is missing, unknown, `gaps_found`, or `human_needed` is NOT complete, even when every PLAN.md has a matching SUMMARY.md. The count-based status (`roadmap.analyze`) only sees plans/summaries, so without this check such a phase is reported complete and routing skips straight to the next phase. When the phase appears count-complete (`summaries = plans AND plans > 0`), consult the verification report (the same `verification.status` gate `ship` and `execute-phase` use, from #651):
|
|
277
277
|
|
|
278
278
|
```bash
|
|
279
279
|
PHASE_DIR=".planning/phases/[current-phase-dir]"
|
|
@@ -282,7 +282,7 @@ VERIFICATION_STATUS=$(printf '%s' "$VERIFICATION" | jq -r '.status' 2>/dev/null
|
|
|
282
282
|
VERIFICATION_NEXT_ACTION=$(printf '%s' "$VERIFICATION" | jq -r '.next_action' 2>/dev/null || echo "")
|
|
283
283
|
```
|
|
284
284
|
|
|
285
|
-
Track: `verification_status` — the `.status` field (`passed | gaps_found | human_needed | missing | unknown`). The query
|
|
285
|
+
Track: `verification_status` — the `.status` field (`passed | stale | gaps_found | human_needed | missing | unknown`). The query/projection handles a missing VERIFICATION.md (`missing`), unexpected values, and stale verification (`stale`, when summaries are newer than verification). Only `passed` routes as phase complete (Step 3); every other status routes back to close verification debt (Step 2).
|
|
286
286
|
|
|
287
287
|
**Step 2: Route based on counts**
|
|
288
288
|
|
|
@@ -291,12 +291,15 @@ Track: `verification_status` — the `.status` field (`passed | gaps_found | hum
|
|
|
291
291
|
| uat_partial > 0 | UAT testing incomplete | Go to **Route E.2** |
|
|
292
292
|
| uat_with_gaps > 0 | UAT gaps need fix plans | Go to **Route E** |
|
|
293
293
|
| summaries < plans | Unexecuted plans exist | Go to **Route A** |
|
|
294
|
+
| summaries = plans AND plans > 0 AND verification_status = missing | Phase executed; verification report missing | Go to **Route V.missing** |
|
|
295
|
+
| summaries = plans AND plans > 0 AND verification_status = unknown | Phase executed; verification status unknown | Go to **Route V.unknown** |
|
|
296
|
+
| summaries = plans AND plans > 0 AND verification_status = stale | Phase executed; verification is stale | Go to **Route V.stale** |
|
|
294
297
|
| summaries = plans AND plans > 0 AND verification_status = gaps_found | Phase executed; verification found gaps | Go to **Route V.gaps** |
|
|
295
298
|
| summaries = plans AND plans > 0 AND verification_status = human_needed | Phase executed; awaiting human verification | Go to **Route V.human** |
|
|
296
|
-
| summaries = plans AND plans > 0 | Phase complete (verification passed
|
|
299
|
+
| summaries = plans AND plans > 0 AND verification_status = passed | Phase complete (verification passed) | Go to Step 3 |
|
|
297
300
|
| plans = 0 | Phase not yet planned | Go to **Route B** |
|
|
298
301
|
|
|
299
|
-
Rows are evaluated top to bottom; the first matching row wins. The
|
|
302
|
+
Rows are evaluated top to bottom; the first matching row wins. The `verification_status` rows must precede the passed row so non-`passed` verification is not reported as complete.
|
|
300
303
|
|
|
301
304
|
---
|
|
302
305
|
|
|
@@ -448,6 +451,36 @@ UAT.md exists with `status: partial` — testing session ended before all items
|
|
|
448
451
|
|
|
449
452
|
---
|
|
450
453
|
|
|
454
|
+
**Route V.missing: verification report missing**
|
|
455
|
+
|
|
456
|
+
All plans have summaries, but canonical verification has not passed. The phase is implementation-complete, not phase-complete.
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
`/gsd:execute-phase {phase} ${GSD_WS}` — re-run execution verification
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
**Route V.unknown: verification status unknown**
|
|
465
|
+
|
|
466
|
+
VERIFICATION.md has an unexpected status. The phase is implementation-complete, not phase-complete.
|
|
467
|
+
|
|
468
|
+
```
|
|
469
|
+
`/gsd:execute-phase {phase} ${GSD_WS}` — regenerate verification
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
**Route V.stale: verification is stale**
|
|
475
|
+
|
|
476
|
+
VERIFICATION.md has `status: passed`, but one or more SUMMARY.md files are newer than the verification report. The phase is implementation-complete, not phase-complete.
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
`/gsd:verify-work {phase} ${GSD_WS}` — re-run verification against the latest summaries
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
451
484
|
**Route V.gaps: verification found gaps (gaps_found)**
|
|
452
485
|
|
|
453
486
|
VERIFICATION.md exists with `status: gaps_found` — verification identified gaps that need fix plans. The phase is NOT complete.
|
|
@@ -675,7 +675,9 @@ Capture current HEAD before spawning (used for worktree branch check):
|
|
|
675
675
|
```bash
|
|
676
676
|
EXPECTED_BASE=$(git rev-parse HEAD)
|
|
677
677
|
if [ "${USE_WORKTREES:-true}" != "false" ]; then
|
|
678
|
-
|
|
678
|
+
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
679
|
+
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
680
|
+
QUICK_WORKTREE_MANIFEST=$(mktemp "${TMPDIR:-/tmp}/gsd-quick-worktree-XXXXXX") && mv "$QUICK_WORKTREE_MANIFEST" "${QUICK_WORKTREE_MANIFEST}.json" && QUICK_WORKTREE_MANIFEST="${QUICK_WORKTREE_MANIFEST}.json" || exit 1
|
|
679
681
|
printf '{"worktrees":[]}\n' > "$QUICK_WORKTREE_MANIFEST"
|
|
680
682
|
export QUICK_WORKTREE_MANIFEST
|
|
681
683
|
fi
|
|
@@ -353,13 +353,13 @@ Built-in tier defaults by runtime:
|
|
|
353
353
|
|
|
354
354
|
| Runtime | `opus` | `sonnet` | `haiku` |
|
|
355
355
|
|------------|-------------------------------|---------------------------------|-------------------------------|
|
|
356
|
-
| `claude` | `claude-opus-4-8` | `claude-sonnet-
|
|
356
|
+
| `claude` | `claude-opus-4-8` | `claude-sonnet-5` | `claude-haiku-4-5` |
|
|
357
357
|
| `codex` | `gpt-5.5` | `gpt-5.4` | `gpt-5.4-mini` |
|
|
358
358
|
| `gemini` | `gemini-3.1-pro-preview` | `gemini-3-flash` | `gemini-2.5-flash-lite` |
|
|
359
359
|
| `qwen` | `qwen3-max-2026-01-23` | `qwen3-coder-plus` | `qwen3-coder-next` |
|
|
360
|
-
| `opencode` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-
|
|
361
|
-
| `copilot` | `claude-opus-4-8` | `claude-sonnet-
|
|
362
|
-
| `hermes` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-
|
|
360
|
+
| `opencode` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
361
|
+
| `copilot` | `claude-opus-4-8` | `claude-sonnet-5` | `claude-haiku-4-5` |
|
|
362
|
+
| `hermes` | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
363
363
|
| Group B (`kilo`, `cline`, `cursor`, `windsurf`, `augment`, `trae`, `codebuddy`, `antigravity`) | (no built-in default — your runtime handles model selection) | | |
|
|
364
364
|
|
|
365
365
|
Display a table to the user showing the effective configuration:
|
|
@@ -623,8 +623,8 @@ AskUserQuestion([
|
|
|
623
623
|
header: "Provider",
|
|
624
624
|
multiSelect: false,
|
|
625
625
|
options: [
|
|
626
|
-
{ label: "anthropic", description: "claude-opus-4-8 / claude-sonnet-
|
|
627
|
-
{ label: "anthropic-fable", description: "claude-fable-5 / claude-sonnet-
|
|
626
|
+
{ label: "anthropic", description: "claude-opus-4-8 / claude-sonnet-5 / claude-haiku-4-5 (Anthropic / Claude)" },
|
|
627
|
+
{ label: "anthropic-fable", description: "claude-fable-5 / claude-sonnet-5 / claude-haiku-4-5 (Anthropic / Claude Fable opt-in)" },
|
|
628
628
|
{ label: "openai", description: "gpt-5.5 / gpt-5.4 / gpt-5.4-mini (OpenAI / Codex)" },
|
|
629
629
|
{ label: "Other known provider", description: "Type google or qwen; both still use the canonical tier mapping." }
|
|
630
630
|
]
|
|
@@ -654,11 +654,11 @@ Canonical tier mappings by provider and budget:
|
|
|
654
654
|
|
|
655
655
|
| Provider | Budget | high | medium | low |
|
|
656
656
|
|-----------|--------|----------------------------|----------------------------|----------------------------|
|
|
657
|
-
| anthropic | high | claude-opus-4-8 | claude-opus-4-8 | claude-sonnet-
|
|
658
|
-
| anthropic | medium | claude-opus-4-8 | claude-sonnet-
|
|
657
|
+
| anthropic | high | claude-opus-4-8 | claude-opus-4-8 | claude-sonnet-5 |
|
|
658
|
+
| anthropic | medium | claude-opus-4-8 | claude-sonnet-5 | claude-haiku-4-5 |
|
|
659
659
|
| anthropic | low | claude-haiku-4-5 | claude-haiku-4-5 | claude-haiku-4-5 |
|
|
660
|
-
| anthropic-fable | high | claude-fable-5 | claude-fable-5 | claude-sonnet-
|
|
661
|
-
| anthropic-fable | medium | claude-opus-4-8 | claude-sonnet-
|
|
660
|
+
| anthropic-fable | high | claude-fable-5 | claude-fable-5 | claude-sonnet-5 |
|
|
661
|
+
| anthropic-fable | medium | claude-opus-4-8 | claude-sonnet-5 | claude-haiku-4-5 |
|
|
662
662
|
| anthropic-fable | low | claude-haiku-4-5 | claude-haiku-4-5 | claude-haiku-4-5 |
|
|
663
663
|
| openai | high | gpt-5.5 | gpt-5.5 | gpt-5.5 |
|
|
664
664
|
| openai | medium | gpt-5.5 | gpt-5.4 | gpt-5.4-mini |
|
|
@@ -280,7 +280,9 @@ Use the exact key order `skill=`, `fallback=`, `exempt=`, `missing=` so downstre
|
|
|
280
280
|
Create the PR using the generated body. Write the body to a temp file first so large generated PRD sections do not hit shell argument limits:
|
|
281
281
|
|
|
282
282
|
```bash
|
|
283
|
-
|
|
283
|
+
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
284
|
+
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
285
|
+
PR_BODY_FILE=$(mktemp "${TMPDIR:-/tmp}/gsd-pr-body-XXXXXX") && mv "$PR_BODY_FILE" "${PR_BODY_FILE}.md" && PR_BODY_FILE="${PR_BODY_FILE}.md" || exit 1
|
|
284
286
|
trap 'rm -f "${PR_BODY_FILE:-}"' EXIT
|
|
285
287
|
printf '%s\n' "${PR_BODY}" > "${PR_BODY_FILE}"
|
|
286
288
|
|
|
@@ -235,7 +235,9 @@ fi
|
|
|
235
235
|
# canonical coverage compute. Populate the heredoc from the SPEC's Requirements — one object
|
|
236
236
|
# per requirement: {"id","text","shapes"?}. This is the load-bearing step: an empty file makes
|
|
237
237
|
# the probe a no-op, so the guard below fails loud rather than silently skipping (RR-04).
|
|
238
|
-
|
|
238
|
+
# BSD/macOS mktemp only randomizes XXXXXX when it is the final path component, so make a
|
|
239
|
+
# suffixless temp then append the extension — portable across BSD + GNU (#1520).
|
|
240
|
+
REQS_JSON=$(mktemp "${TMPDIR:-/tmp}/edge-probe-reqs-XXXXXX") && mv "$REQS_JSON" "${REQS_JSON}.json" && REQS_JSON="${REQS_JSON}.json" || exit 1
|
|
239
241
|
cat > "$REQS_JSON" <<'JSON'
|
|
240
242
|
[
|
|
241
243
|
{ "id": "R1", "text": "<replace: requirement text from the SPEC>" }
|
|
@@ -77,26 +77,28 @@ cat .planning/config.json 2>/dev/null || true
|
|
|
77
77
|
**Check for verification debt in this phase:**
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
# Run a preliminary frontmatter check via awk — the runtime launcher is not yet
|
|
81
|
+
# defined at this step, so avoid any runtime tool calls here.
|
|
82
|
+
# awk extracts only the status: field between the two --- fences to avoid
|
|
83
|
+
# false positives from historical body text (e.g. previous_status: gaps_found).
|
|
84
|
+
VERIFY_STATUS=$(awk 'NR==1&&/^---$/{in_fm=1;next}in_fm&&/^---$/{exit}in_fm&&/^status: /{print $2}' \
|
|
85
|
+
.planning/phases/XX-current/*-VERIFICATION.md 2>/dev/null | head -1)
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
**If
|
|
88
|
+
**If VERIFY_STATUS is not `passed`:**
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
Stop before confirming:
|
|
91
91
|
|
|
92
92
|
```
|
|
93
|
-
|
|
94
|
-
{list filenames}
|
|
93
|
+
Verification incomplete: ${VERIFY_STATUS:-missing}
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
Resolve before transition. Review: `/gsd:audit-uat`
|
|
97
96
|
```
|
|
98
97
|
|
|
99
|
-
This
|
|
98
|
+
This preliminary check blocks obviously unresolved verification before the
|
|
99
|
+
launcher is available. `gsd-tools.cjs query phase.complete` remains the
|
|
100
|
+
authoritative stale-aware gate and fail-closes unless canonical verification
|
|
101
|
+
status is `passed`.
|
|
100
102
|
|
|
101
103
|
**If all plans complete:**
|
|
102
104
|
|
|
@@ -143,13 +143,9 @@ Full review: {path to UI-REVIEW.md}
|
|
|
143
143
|
|
|
144
144
|
## ▶ Next
|
|
145
145
|
|
|
146
|
-
`/clear` then
|
|
146
|
+
`/clear` then:
|
|
147
147
|
|
|
148
|
-
- `/gsd:verify-work {N}` — UAT testing
|
|
149
|
-
- `/gsd:plan-phase {N+1}` — plan next phase
|
|
150
|
-
|
|
151
|
-
- `/gsd:verify-work {N}` — UAT testing
|
|
152
|
-
- `/gsd:plan-phase {N+1}` — plan next phase
|
|
148
|
+
- `/gsd:verify-work {N}` — UAT testing before phase completion
|
|
153
149
|
|
|
154
150
|
───────────────────────────────────────────────────────────────
|
|
155
151
|
```
|
|
@@ -527,6 +527,50 @@ If an active secure-phase step hook exists AND `SECURITY_FILE` exists: check fro
|
|
|
527
527
|
|
|
528
528
|
If no active secure-phase step hook exists OR (`SECURITY_FILE` exists AND `threats_open` is `0`):
|
|
529
529
|
|
|
530
|
+
If execution verification is waiting only on human UAT and this session recorded zero issues, canonicalize the report before the shared completion predicate:
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
PHASE_DIR=$(printf '%s' "$INIT" | jq -r '.phase_dir // empty')
|
|
534
|
+
VERIFICATION_FILE=$(ls "${PHASE_DIR}"/*-VERIFICATION.md 2>/dev/null | head -1)
|
|
535
|
+
VERIFICATION_STATUS=$(gsd_run query verification.status "$PHASE_DIR" 2>/dev/null)
|
|
536
|
+
VERIFICATION_STATUS_VALUE=$(printf '%s' "$VERIFICATION_STATUS" | jq -r '.status // empty' 2>/dev/null || echo "")
|
|
537
|
+
PHASE_VERIFICATION_STATUS="$VERIFICATION_STATUS_VALUE"
|
|
538
|
+
if [ "$VERIFICATION_STATUS_VALUE" = "human_needed" ]; then
|
|
539
|
+
gsd_run query frontmatter.set "$VERIFICATION_FILE" --field status --value passed
|
|
540
|
+
fi
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
If `PHASE_VERIFICATION_STATUS` is `stale`, stop before phase advancement and present:
|
|
544
|
+
|
|
545
|
+
```
|
|
546
|
+
All UAT tests passed, but phase advancement is blocked until canonical verification is fresh.
|
|
547
|
+
|
|
548
|
+
Blocking completion:
|
|
549
|
+
verification is stale
|
|
550
|
+
|
|
551
|
+
- `/gsd:verify-work {phase}` — re-run verification against the latest summaries
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Otherwise, check the shared UAT-plus-verification completion predicate before transition:
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
PHASE_COMPLETE=$(gsd_run phase uat-passed "{phase}" --require-verification)
|
|
558
|
+
PHASE_COMPLETE_PASSED=$(printf '%s' "$PHASE_COMPLETE" | jq -r '.passed' 2>/dev/null || echo "false")
|
|
559
|
+
PHASE_COMPLETE_BLOCKERS=$(printf '%s' "$PHASE_COMPLETE" | jq -r '.blockers[]?' 2>/dev/null || true)
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
If `PHASE_COMPLETE_PASSED` is not `true`, stop before phase advancement and present:
|
|
563
|
+
|
|
564
|
+
```
|
|
565
|
+
All UAT tests passed, but phase advancement is blocked until canonical verification passes.
|
|
566
|
+
|
|
567
|
+
Blocking completion:
|
|
568
|
+
{PHASE_COMPLETE_BLOCKERS}
|
|
569
|
+
|
|
570
|
+
- `/gsd:execute-phase {phase}` — regenerate execution verification
|
|
571
|
+
- `/gsd:verify-work {phase}` — resume UAT if blockers remain
|
|
572
|
+
```
|
|
573
|
+
|
|
530
574
|
**Auto-transition: mark phase complete in ROADMAP.md and STATE.md**
|
|
531
575
|
|
|
532
576
|
Execute the transition workflow inline (do NOT use Task — the orchestrator context already holds the UAT results and phase data needed for accurate transition):
|