@opengsd/gsd-core 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-executor.md +63 -35
- package/agents/gsd-plan-checker.md +76 -57
- package/agents/gsd-planner.md +14 -0
- package/agents/gsd-ui-checker.md +19 -3
- package/agents/gsd-ui-researcher.md +29 -0
- package/agents/gsd-verifier.md +23 -1
- package/bin/install.js +239 -67
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +195 -50
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-registry.cjs +514 -114
- package/gsd-core/bin/lib/capability-state.cjs +7 -1
- package/gsd-core/bin/lib/capability-validator.cjs +120 -4
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +85 -2
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/commands.cjs +337 -13
- package/gsd-core/bin/lib/config-loader.cjs +3 -0
- package/gsd-core/bin/lib/core-utils.cjs +34 -7
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +14 -1
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +137 -23
- package/gsd-core/bin/lib/gap-checker.cjs +22 -13
- package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- package/gsd-core/bin/lib/host-integration.cjs +57 -5
- package/gsd-core/bin/lib/init-command-router.cjs +14 -0
- package/gsd-core/bin/lib/init.cjs +132 -15
- package/gsd-core/bin/lib/install-engine.cjs +184 -12
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
- package/gsd-core/bin/lib/install-profiles.cjs +22 -14
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/io.cjs +35 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +123 -0
- package/gsd-core/bin/lib/milestone.cjs +22 -2
- package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-id.cjs +251 -9
- package/gsd-core/bin/lib/phase.cjs +774 -35
- package/gsd-core/bin/lib/plan-document.cjs +10 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +147 -20
- package/gsd-core/bin/lib/planning-workspace.cjs +103 -28
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-parser.cjs +499 -26
- package/gsd-core/bin/lib/roadmap.cjs +187 -58
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +233 -33
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +286 -108
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -43
- package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
- package/gsd-core/bin/lib/smart-entry.cjs +7 -9
- package/gsd-core/bin/lib/state-document.cjs +30 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +23 -13
- package/gsd-core/bin/lib/state-transition.cjs +333 -44
- package/gsd-core/bin/lib/state.cjs +684 -125
- package/gsd-core/bin/lib/surface.cjs +23 -8
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/uat.cjs +1419 -515
- package/gsd-core/bin/lib/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +273 -12
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +346 -16
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +8 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +3 -3
- package/gsd-core/references/edge-probe.md +17 -13
- package/gsd-core/references/execute-mvp-tdd.md +18 -16
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/mvp-concepts.md +2 -2
- package/gsd-core/references/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +75 -2
- package/gsd-core/references/planning-config.md +2 -1
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/tdd.md +14 -9
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/templates/phase-prompt.md +4 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/add-backlog.md +2 -0
- package/gsd-core/workflows/add-phase.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +2 -0
- package/gsd-core/workflows/audit-uat.md +2 -0
- package/gsd-core/workflows/autonomous.md +2 -0
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +15 -13
- package/gsd-core/workflows/code-review-fix.md +2 -0
- package/gsd-core/workflows/code-review.md +73 -31
- package/gsd-core/workflows/complete-milestone.md +13 -4
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +43 -13
- package/gsd-core/workflows/docs-update.md +1 -1
- package/gsd-core/workflows/edit-phase.md +2 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +17 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +32 -14
- package/gsd-core/workflows/execute-plan.md +8 -8
- package/gsd-core/workflows/explore.md +2 -0
- package/gsd-core/workflows/extract-learnings.md +2 -0
- package/gsd-core/workflows/fast.md +6 -0
- package/gsd-core/workflows/forensics.md +2 -0
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +3 -3
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +2 -0
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +2 -0
- package/gsd-core/workflows/list-workspaces.md +2 -0
- package/gsd-core/workflows/manager.md +3 -3
- package/gsd-core/workflows/map-codebase.md +2 -0
- package/gsd-core/workflows/milestone-summary.md +2 -0
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +1 -1
- package/gsd-core/workflows/new-project.md +5 -3
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -0
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +19 -4
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
- package/gsd-core/workflows/plan-phase.md +130 -12
- package/gsd-core/workflows/plan-review-convergence.md +102 -10
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +11 -3
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +25 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
- package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +13 -3
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +2 -0
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +6 -2
- package/gsd-core/workflows/review.md +215 -10
- package/gsd-core/workflows/scan.md +2 -0
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings-integrations.md +9 -8
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +10 -10
- package/gsd-core/workflows/sketch-wrap-up.md +2 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +24 -19
- package/gsd-core/workflows/spike-wrap-up.md +2 -0
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +2 -0
- package/gsd-core/workflows/sync-skills.md +12 -4
- package/gsd-core/workflows/thread.md +2 -0
- package/gsd-core/workflows/transition.md +2 -0
- package/gsd-core/workflows/ui-phase.md +26 -5
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +2 -0
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/update.md +41 -38
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +49 -3
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-context-monitor.js +283 -12
- package/hooks/dist/gsd-node-runner.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +30 -5
- package/hooks/dist/gsd-read-guard.js +2 -0
- package/hooks/dist/gsd-read-injection-scanner.js +5 -5
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-statusline.js +7 -3
- package/hooks/dist/gsd-validate-commit.sh +444 -7
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/lib/git-cmd.js +210 -1
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-context-monitor.js +283 -12
- package/hooks/gsd-node-runner.sh +1 -0
- package/hooks/gsd-prompt-guard.js +30 -5
- package/hooks/gsd-read-guard.js +2 -0
- package/hooks/gsd-read-injection-scanner.js +5 -5
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-statusline.js +7 -3
- package/hooks/gsd-validate-commit.sh +444 -7
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/hooks.json +6 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +5 -5
- package/scripts/build-hooks.js +11 -4
- package/scripts/ci-test-scope.cjs +7 -0
- package/scripts/docs-guard-registry.cjs +10 -0
- package/scripts/gen-loop-host-contract.cjs +67 -15
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +5 -0
- package/scripts/lint-phase-enumeration-drift.cjs +24 -6
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-response-language-coverage.cjs +524 -0
- package/scripts/lint-test-file-count.allowlist.json +3 -1
- package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +8 -0
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/vscode/package.json +1 -1
|
@@ -9,6 +9,27 @@ runs (~3–5 min each), committing each plan individually for crash resilience.
|
|
|
9
9
|
For recovering plans from a prior *non-chunked* run, use step 6's "Add more plans" or
|
|
10
10
|
proceed to `/gsd:execute-phase` — don't start a fresh chunked run over them.
|
|
11
11
|
|
|
12
|
+
Set `CHUNKED_PARALLEL` from config, here rather than in `plan-phase.md`, so the two extra
|
|
13
|
+
`gsd_run` calls it costs are paid only on a run that already reached this section (#3777) —
|
|
14
|
+
`CHUNKED_MODE` is `true` at this point, per the skip-check above. STRICT equality on `"true"`
|
|
15
|
+
is deliberate, matching `review.parallel_lanes` (#3034): a mistyped or non-canonical value
|
|
16
|
+
(`"1"`, `"yes"`, `"TRUE"`) gets the conservative behavior, and any tooling failure
|
|
17
|
+
(`config-get`/`dispatch-capacity` erroring or printing nothing) fails safe to serial — never the
|
|
18
|
+
opposite polarity, since firing concurrent Agent() dispatch is the risky direction here, not the
|
|
19
|
+
safe default. `dispatch-capacity` is the same negotiated dispatch-capability query
|
|
20
|
+
`quick-batch-dispatch.cts` already consults (#3673) — a host that declares no `maxConcurrency`
|
|
21
|
+
(reason `missing`/`undocumented`) resolves to the fail-closed floor of `1`, which degrades this
|
|
22
|
+
flag to serial regardless of the config value:
|
|
23
|
+
```bash
|
|
24
|
+
_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; }; 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 unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; 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
|
|
25
|
+
CHUNKED_PARALLEL_CFG=$(gsd_run query config-get planning.chunked_parallel --raw 2>/dev/null || echo "false")
|
|
26
|
+
DISPATCH_CAPACITY=$(gsd_run query dispatch-capacity --raw 2>/dev/null || echo "1")
|
|
27
|
+
CHUNKED_PARALLEL=false
|
|
28
|
+
if [[ "$CHUNKED_PARALLEL_CFG" == "true" ]] && [[ "${DISPATCH_CAPACITY:-1}" -gt 1 ]] 2>/dev/null; then
|
|
29
|
+
CHUNKED_PARALLEL=true
|
|
30
|
+
fi
|
|
31
|
+
```
|
|
32
|
+
|
|
12
33
|
### 8.5.1 Outline Phase (outline-only mode, ~2 min)
|
|
13
34
|
|
|
14
35
|
**Resume detection:** If `${PHASE_DIR}/${PADDED_PHASE}-PLAN-OUTLINE.md` exists and contains
|
|
@@ -17,7 +38,7 @@ the `## OUTLINE COMPLETE` marker (written by the outline agent — #2762), skip
|
|
|
17
38
|
```bash
|
|
18
39
|
OUTLINE_FILE="${PHASE_DIR}/${PADDED_PHASE}-PLAN-OUTLINE.md"
|
|
19
40
|
if [[ -f "$OUTLINE_FILE" ]] && grep -q "^## OUTLINE COMPLETE" "$OUTLINE_FILE"; then
|
|
20
|
-
# reuse existing outline — skip to 8.5.2
|
|
41
|
+
: # reuse existing outline — skip to 8.5.2
|
|
21
42
|
fi
|
|
22
43
|
```
|
|
23
44
|
|
|
@@ -58,25 +79,65 @@ Handle return:
|
|
|
58
79
|
|
|
59
80
|
### 8.5.2 Per-Plan Tasks (single-plan mode, ~3-5 min each)
|
|
60
81
|
|
|
61
|
-
|
|
82
|
+
Plans are dispatched **wave by wave**, in ascending Wave order (a blank/missing Wave value on a
|
|
83
|
+
row is treated as Wave `1` — see §8.5.1's example table). Within one Wave, dispatch is either
|
|
84
|
+
serial (today's behavior, always used when `CHUNKED_PARALLEL` is `false`) or concurrent
|
|
85
|
+
(`CHUNKED_PARALLEL` is `true` — resolved above from `planning.chunked_parallel` gated on
|
|
86
|
+
`dispatch-capacity`, #3777). A Wave containing only one runnable entry always takes the serial
|
|
87
|
+
path regardless of `CHUNKED_PARALLEL` — there is nothing to batch.
|
|
62
88
|
|
|
63
|
-
|
|
64
|
-
(resume safety) — UNLESS `--reviews` is set, whose purpose is to REPLAN with review
|
|
65
|
-
feedback (§6), so existing plans are overwritten, not skipped (#2762).
|
|
89
|
+
**For each Wave, in order:**
|
|
66
90
|
|
|
91
|
+
1. **Build the batch's plan-ID list** from the outline rows sharing this Wave value, in outline
|
|
92
|
+
row order, deduplicated defensively — a malformed outline naming the same Plan ID twice must
|
|
93
|
+
never produce two concurrent Agent() calls targeting the same `{plan_id}-PLAN.md` output path
|
|
94
|
+
(mirrors `review.md`'s `DISPATCH_SLUGS` dedup, #3034):
|
|
95
|
+
```bash
|
|
96
|
+
# Rewrapped through unquoted command substitution, not consumed as a bare
|
|
97
|
+
# `$WAVE_PLAN_IDS`: bash word-splits an unquoted scalar on IFS by default,
|
|
98
|
+
# but zsh does not, so a bare re-split collapses every Plan ID onto one
|
|
99
|
+
# iteration under zsh (gsd-core#4109 — same fix review.md's DISPATCH_SLUGS
|
|
100
|
+
# loop already applies). Unquoted `$(...)` re-splits identically under
|
|
101
|
+
# both shells regardless of `SH_WORD_SPLIT`.
|
|
102
|
+
BATCH_PLAN_IDS=""
|
|
103
|
+
for PLAN_ID in $(printf '%s' "$WAVE_PLAN_IDS"); do
|
|
104
|
+
case " $BATCH_PLAN_IDS " in
|
|
105
|
+
*" $PLAN_ID "*) continue ;;
|
|
106
|
+
esac
|
|
107
|
+
BATCH_PLAN_IDS="$BATCH_PLAN_IDS $PLAN_ID"
|
|
108
|
+
done
|
|
109
|
+
```
|
|
110
|
+
`WAVE_PLAN_IDS` is the space-separated Plan ID list for this Wave, in outline row order — the
|
|
111
|
+
orchestrator (already reading the outline table to extract plan entries, per §8.5.1) populates
|
|
112
|
+
it directly from the table before this block runs.
|
|
113
|
+
|
|
114
|
+
2. **Resume check, per entry:** for each `plan_id` in `BATCH_PLAN_IDS`, skip it (remove it from
|
|
115
|
+
this batch's runnable set) if `${PHASE_DIR}/{plan_id}-PLAN.md` exists with valid frontmatter —
|
|
116
|
+
UNLESS `--reviews` is set, whose purpose is to REPLAN with review feedback (§6), so existing
|
|
117
|
+
plans are overwritten, not skipped (#2762). Unchanged from before this change, applied per entry
|
|
118
|
+
before dispatch rather than immediately before each individual spawn:
|
|
67
119
|
```bash
|
|
68
120
|
PLAN_FILE="${PHASE_DIR}/${plan_id}-PLAN.md"
|
|
69
121
|
if [[ -f "$PLAN_FILE" ]] && head -1 "$PLAN_FILE" | grep -q '^---' && [[ "$ARGUMENTS" != *"--reviews"* ]]; then
|
|
70
|
-
|
|
122
|
+
: # resume safety — skip this plan, remove from the batch's runnable set — NOT under --reviews (replan)
|
|
71
123
|
fi
|
|
72
124
|
```
|
|
125
|
+
If every entry in the Wave is resumed (runnable set empty), skip straight to the next Wave —
|
|
126
|
+
nothing to dispatch, nothing to wait on.
|
|
73
127
|
|
|
74
|
-
|
|
128
|
+
3. Display:
|
|
75
129
|
```text
|
|
76
130
|
◆ Chunked mode: planning {plan_id} ({k}/{N})... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
77
131
|
```
|
|
78
|
-
|
|
79
|
-
|
|
132
|
+
Serial dispatch (`CHUNKED_PARALLEL` is `false`, or the runnable set has exactly one entry):
|
|
133
|
+
print one line per plan, immediately before that plan's own Agent() call, exactly as before.
|
|
134
|
+
Concurrent dispatch: print one line per plan in the runnable set, immediately before issuing
|
|
135
|
+
the batch's Agent() calls together.
|
|
136
|
+
|
|
137
|
+
4. Spawn the planner in **single-plan** mode — it must write exactly one PLAN.md file. The prompt
|
|
138
|
+
is unchanged per plan; what changes is whether the runnable set's Agent() calls are issued one
|
|
139
|
+
at a time (serial) or together in one message (concurrent, every call still carrying
|
|
140
|
+
`run_in_background=true` exactly as today):
|
|
80
141
|
```javascript
|
|
81
142
|
Agent(
|
|
82
143
|
prompt="{same planning_context as step 8, plus:}
|
|
@@ -94,17 +155,38 @@ For each plan entry extracted from `PLAN-OUTLINE.md`:
|
|
|
94
155
|
run_in_background=true
|
|
95
156
|
)
|
|
96
157
|
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
158
|
+
**Serial dispatch:** issue one Agent() call, wait for it (step 5), verify and commit it
|
|
159
|
+
(steps 6-7), THEN move to the next entry in the runnable set — byte-identical to the
|
|
160
|
+
pre-#3777 loop.
|
|
161
|
+
**Concurrent dispatch:** issue every runnable entry's Agent() call together, in this one
|
|
162
|
+
message, before waiting on any of them.
|
|
163
|
+
|
|
164
|
+
5. **ORCHESTRATOR RULE — ALL RUNTIMES, per batch:** for every entry dispatched in this round,
|
|
165
|
+
`TS=$(date +%s)`; repeat `PLANNER_STALL_RESULT=$(gsd_stall_watch "$TS" "{outputFile}" "$PLAN_FILE" "## PLAN COMPLETE")`
|
|
166
|
+
while waiting/active for THAT entry. Serial dispatch waits on one entry at a time (unchanged).
|
|
167
|
+
Concurrent dispatch waits on every entry issued in step 4 before proceeding — this is the
|
|
168
|
+
"per-batch" join the config makes possible: nothing in step 6 runs until every plan dispatched
|
|
169
|
+
this round has reached `marker_received` or `stalled`. A `stalled` entry falls into step 7's
|
|
170
|
+
Retry/Stop recovery for that one plan; it does not block verifying/committing sibling entries
|
|
171
|
+
in the same batch that already reached `marker_received`.
|
|
172
|
+
|
|
173
|
+
6. **Verify disk, per entry:** check `${PHASE_DIR}/{plan_id}-PLAN.md` exists for each entry that
|
|
174
|
+
reached `marker_received`. Unchanged per-plan check.
|
|
175
|
+
|
|
176
|
+
7. **Commit, per entry, in outline row order (not completion order):** for each verified entry —
|
|
177
|
+
never one combined commit for the batch — preserving crash resilience: an interrupt mid-batch
|
|
178
|
+
leaves every already-verified entry committed, exactly as a mid-loop interrupt did before this
|
|
179
|
+
change.
|
|
103
180
|
```bash
|
|
104
|
-
_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; }; 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 unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; 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
|
|
105
181
|
gsd_run query commit "docs(${PADDED_PHASE}): plan ${plan_id} (chunked)" --files "${PHASE_DIR}/${plan_id}-PLAN.md"
|
|
106
182
|
```
|
|
107
183
|
|
|
108
|
-
|
|
109
|
-
|
|
184
|
+
8. **Recovery:** any entry that did not reach `marker_received` (missing file in step 6, or
|
|
185
|
+
`stalled` in step 5) offers 1) Retry, 2) Stop — scoped to that one plan. Sibling entries in the
|
|
186
|
+
same batch that already verified and committed keep their commits either way; only the
|
|
187
|
+
failed/stalled plan is retried or the run stopped.
|
|
188
|
+
|
|
189
|
+
Move to the next Wave only once every entry in the current Wave is committed or the run was
|
|
190
|
+
stopped. After every Wave's plans are written and committed, treat this as `## PLANNING COMPLETE`
|
|
191
|
+
and continue to step 9.
|
|
110
192
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
|
|
2
|
+
|
|
1
3
|
# PRD Express Path — generate CONTEXT.md from a PRD
|
|
2
4
|
|
|
3
5
|
Runs when `--prd <filepath>` is provided (§3.5 of `plan-phase.md`).
|
|
@@ -48,6 +48,15 @@ min), real, bounded call that reliably hands control back — the outer
|
|
|
48
48
|
threshold is enforced by `dispatch_ts` accumulating across calls, not by one
|
|
49
49
|
call's own duration.
|
|
50
50
|
|
|
51
|
+
**Never a wake-up call between cycles (#4079):** while the orchestrator waits
|
|
52
|
+
between `gsd_stall_watch` cycles, it must NOT call `ScheduleWakeup` (or any
|
|
53
|
+
host wake/sleep-scheduling tool, e.g. the `/loop` pacing surface) to
|
|
54
|
+
literalize "I'll wait". The `gsd_stall_watch` bash call IS the wait mechanism;
|
|
55
|
+
wake-up scheduling is never part of it, and a partial-args `ScheduleWakeup`
|
|
56
|
+
call surfaces the host's red validation error (`prompt` is required when
|
|
57
|
+
`stop` is not true). Just issue the next watch call (or let the blocking
|
|
58
|
+
Agent() return) — nothing else.
|
|
59
|
+
|
|
51
60
|
**Disclosed tradeoff:** the first cycle always sleeps a full
|
|
52
61
|
`PLANNER_STALL_INTERVAL_MINUTES` before its first check, so a planner that
|
|
53
62
|
completes in seconds is not observed by this path until that interval
|
|
@@ -100,7 +100,7 @@ Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_
|
|
|
100
100
|
|
|
101
101
|
**#2517:** omit the `model=` param from an `Agent()` call when its `researcher`/`planner`/`checker`_model is `"inherit"` or empty — passing `model=""` 404s on non-Claude runtimes; omitting inherits the orchestrator model (mirrors execute-phase).
|
|
102
102
|
|
|
103
|
-
**If `response_language` is set:** All user-facing orchestrator output MUST be in `{response_language}`; technical terms, code, paths, and subagent prompts stay in English. Pass `response_language: {value}` into every spawned subagent prompt.
|
|
103
|
+
**If `response_language` is set:** All user-facing orchestrator output — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be in `{response_language}`; technical terms, code, paths, and subagent prompts stay in English. Pass `response_language: {value}` into every spawned subagent prompt.
|
|
104
104
|
|
|
105
105
|
**File paths (for <required_reading> blocks):** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`, `verification_path`, `uat_path`, `reviews_path`. These are null if files don't exist.
|
|
106
106
|
|
|
@@ -287,6 +287,43 @@ fi
|
|
|
287
287
|
|
|
288
288
|
If `AI_SPEC_FILE` is non-empty, pass `AI_SPEC_PATH` and `FRAMEWORK_LINE` to the planner in step 8 so it can reference the AI design contract. If it is empty, the active `ai-integration` capability hook in step 5.6 handles any AI-system nudge or `/gsd:ai-integration-phase` dispatch.
|
|
289
289
|
|
|
290
|
+
## 4.6. Context Drift Pre-Check (drift plan:pre gate)
|
|
291
|
+
|
|
292
|
+
Capability-driven dispatch, same lazy-init pattern already used elsewhere in this file for
|
|
293
|
+
`PLAN_PRE_HOOKS_JSON`:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
if [ -z "${PLAN_PRE_HOOKS_JSON:-}" ]; then
|
|
297
|
+
PLAN_PRE_HOOKS_JSON=$(gsd_run loop render-hooks plan:pre --raw)
|
|
298
|
+
fi
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
If `activeHooks` (from `PLAN_PRE_HOOKS_JSON`) has a `kind == "gate"`, `capId == "drift"`,
|
|
302
|
+
`check.query == "verify.context-drift"` entry (`workflow.context_drift_precheck` on), run the
|
|
303
|
+
check before either the research-reuse decision (§5.1) or the pattern-mapper reuse decision
|
|
304
|
+
(§7.8) can fire — both would otherwise silently reuse a stale artifact with zero signal.
|
|
305
|
+
Otherwise skip to §5.
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
DRIFT=$(gsd_run verify context-drift "${PHASE}" 2>/dev/null || echo '{"skipped":true}')
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
If `skipped` is true, continue silently to §5 — nothing to compare (no CONTEXT.md yet, no
|
|
312
|
+
upstream artifacts yet, or the phase directory did not resolve).
|
|
313
|
+
|
|
314
|
+
If `stale_artifacts` is a non-empty array, print `message` verbatim (it names each stale
|
|
315
|
+
artifact and the command to regenerate it). Then:
|
|
316
|
+
|
|
317
|
+
- If `DRIFT.block` is `false` (the default, `workflow.context_drift_action: warn`): continue to
|
|
318
|
+
§5 — this is advisory only, exactly like the codebase-drift pre-check at §5.65.
|
|
319
|
+
- If `DRIFT.block` is `true` (opt-in `workflow.context_drift_action: block`): **exit the
|
|
320
|
+
plan-phase workflow** rather than continuing. Do not spawn the researcher, the planner, or the
|
|
321
|
+
pattern mapper against a premise the user has not yet reconciled. Point the user at re-running
|
|
322
|
+
`/gsd:plan-phase {X}` once the named artifacts are regenerated, or at disabling the check with
|
|
323
|
+
`gsd_run query config-set workflow.context_drift_action warn` if the flag was a false positive.
|
|
324
|
+
|
|
325
|
+
If `stale_artifacts` is empty, continue silently to §5 — nothing to report.
|
|
326
|
+
|
|
290
327
|
## 5. Handle Research
|
|
291
328
|
|
|
292
329
|
**Skip if:** `--gaps` flag or `--skip-research` flag or `--reviews` flag.
|
|
@@ -372,7 +409,7 @@ Agent(
|
|
|
372
409
|
)
|
|
373
410
|
```
|
|
374
411
|
|
|
375
|
-
> **ORCHESTRATOR RULE — ALL RUNTIMES**: 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.
|
|
412
|
+
> **ORCHESTRATOR RULE — ALL RUNTIMES**: 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. Never call `ScheduleWakeup` or any host wake/sleep-scheduling tool to literalize this wait (#4079) — the Agent() call returns on its own; a partial-args wake call surfaces a red validation error.
|
|
376
413
|
|
|
377
414
|
### Handle Researcher Return
|
|
378
415
|
|
|
@@ -547,8 +584,6 @@ map is refreshed first. (`drift_action: auto-remap` stays at `execute:wave:post`
|
|
|
547
584
|
ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null || true
|
|
548
585
|
```
|
|
549
586
|
|
|
550
|
-
**If exists AND `--reviews` flag:** Skip prompt — go straight to replanning (the purpose of `--reviews` is to replan with review feedback).
|
|
551
|
-
|
|
552
587
|
**If exists AND no `--reviews` flag:** Offer: 1) Add more plans, 2) View existing, 3) Replan from scratch.
|
|
553
588
|
|
|
554
589
|
## 7. Use Context Paths from INIT
|
|
@@ -584,6 +619,11 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR_FOR_SPEC}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
|
|
584
619
|
UI_SPEC_PATH="${UI_SPEC_FILE}"
|
|
585
620
|
```
|
|
586
621
|
|
|
622
|
+
**If plans exist AND the `--reviews` flag is set:** Before replanning from `--reviews`, scan
|
|
623
|
+
`REVIEWS_PATH` for open plan-revision conflicts inside the writer-owned delimiter pair. Go
|
|
624
|
+
straight to replanning with those records included, and flip the matching line to `- [x]` once
|
|
625
|
+
the chosen resolution is applied, using the SAME close gate as step 12 below.
|
|
626
|
+
|
|
587
627
|
## 7.5. Verify Nyquist Artifacts
|
|
588
628
|
|
|
589
629
|
Skip if `nyquist_validation_enabled` is false OR `research_enabled` is false.
|
|
@@ -635,7 +675,7 @@ Agent(
|
|
|
635
675
|
)
|
|
636
676
|
```
|
|
637
677
|
|
|
638
|
-
> **ORCHESTRATOR RULE — ALL RUNTIMES**: 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.
|
|
678
|
+
> **ORCHESTRATOR RULE — ALL RUNTIMES**: 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. Never call `ScheduleWakeup` or any host wake/sleep-scheduling tool to literalize this wait (#4079) — the Agent() call returns on its own; a partial-args wake call surfaces a red validation error.
|
|
639
679
|
|
|
640
680
|
**Handle return:**
|
|
641
681
|
- **`## PATTERN MAPPING COMPLETE`:** Update `PATTERNS_PATH` to the created file path, continue to step 8.
|
|
@@ -745,7 +785,7 @@ ${AGENT_SKILLS_PLANNER}
|
|
|
745
785
|
|
|
746
786
|
For each current actionable finding in REVIEWS.md, the planner MUST either:
|
|
747
787
|
- incorporate it into a PLAN.md task, `<action>`, `<acceptance_criteria>`, `<verify>`, `must_haves`, threat model, or artifact list; or
|
|
748
|
-
- explicitly document a deferral/rejection rationale in the relevant PLAN.md
|
|
788
|
+
- explicitly document a deferral/rejection rationale in the relevant PLAN.md, using the Review Dispositions Ledger in `gsd-core/references/planner-reviews.md`.
|
|
749
789
|
|
|
750
790
|
Historical findings already incorporated, explicitly deferred/rejected in PLAN.md, or marked fully resolved do not require new plan changes.
|
|
751
791
|
</review_incorporation_contract>
|
|
@@ -1165,9 +1205,9 @@ Track `stall_reentry_count` (starts at 0; incremented each time "Adjust approach
|
|
|
1165
1205
|
|
|
1166
1206
|
**If iteration_count < 3:**
|
|
1167
1207
|
|
|
1168
|
-
Parse issue count from checker return: count BLOCKER + WARNING entries in the YAML issues block (structured output from gsd-plan-checker). 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.
|
|
1208
|
+
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.
|
|
1169
1209
|
|
|
1170
|
-
Display: `Revision iteration {N}/3 -- {blocker_count} blockers, {warning_count} warnings`
|
|
1210
|
+
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`
|
|
1171
1211
|
|
|
1172
1212
|
**Stall detection:** If `issue_count >= prev_issue_count`:
|
|
1173
1213
|
Display: `Revision loop stalled — issue count not decreasing ({issue_count} issues remain after {N} iterations)`
|
|
@@ -1207,9 +1247,14 @@ ${AGENT_SKILLS_PLANNER}
|
|
|
1207
1247
|
</revision_context>
|
|
1208
1248
|
|
|
1209
1249
|
<instructions>
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1250
|
+
`required_property` + evidence + severity BIND. `fix_hint` is ONE non-binding example route: a
|
|
1251
|
+
smaller or different mechanism reaching the same property resolves it — say which. Re-check CONTEXT.md's locked decisions, capability guidance, and existing plan constraints
|
|
1252
|
+
BEFORE editing; if a hint would contradict one, or the
|
|
1253
|
+
property is unreachable without breaking one, return `## REVISION_CONFLICT` with the conflict and
|
|
1254
|
+
the alternatives rather than applying or working around it. Full contract:
|
|
1255
|
+
`gsd-core/references/planner-revision.md`.
|
|
1256
|
+
|
|
1257
|
+
Do NOT replan from scratch unless fundamental. Return what changed.
|
|
1213
1258
|
</instructions>
|
|
1214
1259
|
```
|
|
1215
1260
|
|
|
@@ -1225,10 +1270,83 @@ Agent(
|
|
|
1225
1270
|
|
|
1226
1271
|
**ORCHESTRATOR RULE — ALL RUNTIMES:** (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.
|
|
1227
1272
|
|
|
1228
|
-
|
|
1273
|
+
**If the planner returns `## REVISION_CONFLICT`:** follow the shared Conflict Return protocol in
|
|
1274
|
+
`gsd-core/references/revision-loop.md`, with this workflow's bindings:
|
|
1275
|
+
|
|
1276
|
+
```bash
|
|
1277
|
+
if ! CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence --raw 2>/dev/null); then
|
|
1278
|
+
echo "BLOCKED: cannot read workflow.plan_review_convergence." >&2
|
|
1279
|
+
exit 1
|
|
1280
|
+
fi
|
|
1281
|
+
REVIEWS_FILE="${REVIEWS_PATH}"
|
|
1282
|
+
if [ "${CONVERGENCE_ENABLED}" = "true" ] && [ -n "${REVIEWS_FILE}" ] && [ ! -f "${REVIEWS_FILE}" ]; then
|
|
1283
|
+
echo "BLOCKED: cannot persist plan-revision conflict -- REVIEWS_PATH not a regular file: ${REVIEWS_FILE}" >&2
|
|
1284
|
+
exit 1
|
|
1285
|
+
fi
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
- Counter not spent: `iteration_count`.
|
|
1289
|
+
- Record channel: `$REVIEWS_FILE`'s `## Plan-Revision Conflicts` section. plan-phase wrote the
|
|
1290
|
+
line, so plan-phase closes it.
|
|
1291
|
+
- After re-spawning, return to this step, not the checker.
|
|
1292
|
+
- Escalates via the iteration cap on repeated `required_property`, and on the THIRD conflict
|
|
1293
|
+
return of this loop whatever property it names.
|
|
1294
|
+
- Sanitize-then-insert is real shell; fields reach `awk` via `ENVIRON`, never `-v` (decodes
|
|
1295
|
+
literal `\n` as a real newline). Export the row's
|
|
1296
|
+
`CONFLICT_DIMENSION/_PLAN/_PROPERTY/_CONSTRAINT/_ALTERNATIVES`, then run:
|
|
1297
|
+
|
|
1298
|
+
```bash
|
|
1299
|
+
if [ "${CONVERGENCE_ENABLED}" = "true" ] && [ -n "${REVIEWS_FILE}" ]; then
|
|
1300
|
+
san() { printf '%s' "$1" | tr '\r\n\t' ' ' | sed -E 's/^[[:space:]]*[#|`-]+[[:space:]]*//'; }
|
|
1301
|
+
LINE="- [ ] REVISION_CONFLICT $(san "${CONFLICT_DIMENSION}")/$(san "${CONFLICT_PLAN}") — required_property: $(san "${CONFLICT_PROPERTY}") | conflicts with: $(san "${CONFLICT_CONSTRAINT}") | alternatives: $(san "${CONFLICT_ALTERNATIVES}")"
|
|
1302
|
+
END='<!-- gsd:plan-revision-conflicts:end -->'
|
|
1303
|
+
TMP=$(mktemp "${REVIEWS_FILE}.XXXXXX")
|
|
1304
|
+
if ! LINE="$LINE" END="$END" awk '
|
|
1305
|
+
{ cur = $0; sub(/\r$/, "", cur) }
|
|
1306
|
+
cur == ENVIRON["LINE"] { seen = 1 }
|
|
1307
|
+
cur == ENVIRON["END"] && !ins { if (!seen) print ENVIRON["LINE"]; ins = 1 }
|
|
1308
|
+
{ print }
|
|
1309
|
+
END { if (!ins) exit 2 }
|
|
1310
|
+
' "${REVIEWS_FILE}" > "${TMP}"; then
|
|
1311
|
+
rm -f "${TMP}"
|
|
1312
|
+
echo "BLOCKED: no end delimiter in '${REVIEWS_FILE}'." >&2
|
|
1313
|
+
exit 1
|
|
1314
|
+
fi
|
|
1315
|
+
mv "${TMP}" "${REVIEWS_FILE}"
|
|
1316
|
+
fi
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
**Otherwise (revised plans, not `## REVISION_CONFLICT`):** if this re-spawn followed a
|
|
1320
|
+
resolved conflict, close its record — nothing persists across fences, so export `REVIEWS_FILE`,
|
|
1321
|
+
the same `CONFLICT_DIMENSION`/`CONFLICT_PLAN` used to open it, and `CONFLICT_RESOLUTION` (a
|
|
1322
|
+
one-line summary). Then run:
|
|
1323
|
+
|
|
1324
|
+
```bash
|
|
1325
|
+
if [ "${CONVERGENCE_ENABLED}" = "true" ] && [ -n "${REVIEWS_FILE}" ]; then
|
|
1326
|
+
san() { printf '%s' "$1" | tr '\r\n\t' ' ' | sed -E 's/^[[:space:]]*[#|`-]+[[:space:]]*//'; }
|
|
1327
|
+
PREFIX="- [ ] REVISION_CONFLICT $(san "${CONFLICT_DIMENSION}")/$(san "${CONFLICT_PLAN}") — "
|
|
1328
|
+
RES=$(printf '%s' "${CONFLICT_RESOLUTION}" | tr '\r\n\t' ' ')
|
|
1329
|
+
TMP=$(mktemp "${REVIEWS_FILE}.XXXXXX")
|
|
1330
|
+
if ! PREFIX="$PREFIX" RES="$RES" awk '
|
|
1331
|
+
{ cur = $0; sub(/\r$/, "", cur) }
|
|
1332
|
+
!d && index(cur, ENVIRON["PREFIX"]) == 1 { print "- [x]" substr(cur, 6) " | resolved: " ENVIRON["RES"]; d = 1; next }
|
|
1333
|
+
{ print }
|
|
1334
|
+
END { if (!d) exit 2 }
|
|
1335
|
+
' "${REVIEWS_FILE}" > "${TMP}"; then
|
|
1336
|
+
rm -f "${TMP}"
|
|
1337
|
+
echo "BLOCKED: no open conflict '${CONFLICT_DIMENSION}/${CONFLICT_PLAN}' in '${REVIEWS_FILE}'." >&2
|
|
1338
|
+
exit 1
|
|
1339
|
+
fi
|
|
1340
|
+
mv "${TMP}" "${REVIEWS_FILE}"
|
|
1341
|
+
fi
|
|
1342
|
+
```
|
|
1343
|
+
|
|
1344
|
+
Spawn checker again (step 10), then increment `iteration_count`.
|
|
1229
1345
|
|
|
1230
1346
|
**If iteration_count >= 3:**
|
|
1231
1347
|
|
|
1348
|
+
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).
|
|
1349
|
+
|
|
1232
1350
|
Display: `Max iterations reached. {N} issues remain:` + issue list
|
|
1233
1351
|
|
|
1234
1352
|
Offer: 1) Force proceed, 2) Provide guidance and retry, 3) Abandon
|
|
@@ -119,7 +119,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
119
119
|
|
|
120
120
|
Parse JSON for: `phase_dir`, `phase_number`, `padded_phase`, `phase_name`, `has_plans`, `plan_count`, `commit_docs`, `text_mode`, `response_language`.
|
|
121
121
|
|
|
122
|
-
**If `response_language` is set:** All user-facing output should be in `{response_language}`.
|
|
122
|
+
**If `response_language` is set:** All user-facing output — narration between tool calls, status updates, progress notes, findings, questions, and report prose — should be in `{response_language}`.
|
|
123
123
|
|
|
124
124
|
Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from init JSON is `true`. When `TEXT_MODE` is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number.
|
|
125
125
|
|
|
@@ -341,13 +341,20 @@ Run this pass whenever the source-grounding pass ran — it is the second axis o
|
|
|
341
341
|
|
|
342
342
|
**Coverage, never silence.** If STATE.md or CONTEXT.md is absent, that axis is skipped and the skip is recorded in the same "Verification coverage" block. A clean pass must never mean "nothing was compared."
|
|
343
343
|
|
|
344
|
-
After agent returns, verify REVIEWS.md exists
|
|
344
|
+
After agent returns, verify REVIEWS.md exists. Assign the path directly and quote it — an unquoted
|
|
345
|
+
`${phase_dir}` inside `$(ls …)` word-splits and glob-expands, and a discarded stderr hides it (#3899):
|
|
345
346
|
```bash
|
|
346
|
-
|
|
347
|
+
if [ -z "${phase_dir}" ]; then
|
|
348
|
+
echo "ERROR: phase_dir is empty — cannot resolve the expected REVIEWS.md path." >&2
|
|
349
|
+
exit 1
|
|
350
|
+
fi
|
|
351
|
+
REVIEWS_FILE="${phase_dir}/${padded_phase}-REVIEWS.md"
|
|
352
|
+
if [ ! -f "${REVIEWS_FILE}" ] || [ ! -r "${REVIEWS_FILE}" ]; then
|
|
353
|
+
echo "ERROR: expected reviews file is not a readable file: '${REVIEWS_FILE}'. Confirm the phase directory resolved correctly before concluding the review agent produced nothing." >&2
|
|
354
|
+
exit 1
|
|
355
|
+
fi
|
|
347
356
|
```
|
|
348
357
|
|
|
349
|
-
If REVIEWS_FILE is empty: Error — review agent did not produce REVIEWS.md. Exit.
|
|
350
|
-
|
|
351
358
|
### 5b. Extract unresolved counts from CYCLE_SUMMARY Contract
|
|
352
359
|
|
|
353
360
|
**Do NOT grep REVIEWS.md for HIGH or actionable counts.** REVIEWS.md accumulates history across cycles — resolved findings from prior cycles remain in the file as audit trail, inflating a raw grep count and causing false stall detection.
|
|
@@ -390,7 +397,68 @@ if [ "${ACTIONABLE_COUNT}" -gt 0 ] && [ -z "${ACTIONABLE_LINES}" ]; then
|
|
|
390
397
|
fi
|
|
391
398
|
```
|
|
392
399
|
|
|
393
|
-
**
|
|
400
|
+
**Open plan-revision conflicts are part of the converged condition (#3771).** An entry under
|
|
401
|
+
`## Plan-Revision Conflicts` in REVIEWS.md is a checker `fix_hint` that contradicted a locked
|
|
402
|
+
decision, capability guidance, or an existing plan constraint, recorded by `/gsd:plan-phase`
|
|
403
|
+
together with the alternatives the planner considered. It is NOT counted by `CYCLE_SUMMARY`, so
|
|
404
|
+
it must be read from the file directly — evaluate this BEFORE the converged branch below, or a
|
|
405
|
+
run would write `planned-phase` and print the success banner over a conflict nobody resolved:
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
if [ ! -f "${REVIEWS_FILE}" ]; then
|
|
409
|
+
# Fail CLOSED. A missing/non-file REVIEWS.md is "I cannot tell", never "no conflicts".
|
|
410
|
+
echo "BLOCKED: cannot read REVIEWS.md ('${REVIEWS_FILE}') to check for open plan-revision conflicts. Refusing to declare convergence on an unverifiable gate." >&2
|
|
411
|
+
exit 1
|
|
412
|
+
fi
|
|
413
|
+
if OPEN_CONFLICTS=$(awk '
|
|
414
|
+
BEGIN { saw_title = 0; in_owned = 0; saw_heading = 0; done = 0; count = 0 }
|
|
415
|
+
{ sub(/\r$/, "") }
|
|
416
|
+
!saw_title && /^# Cross-AI Plan Review — Phase / { saw_title = 1; next }
|
|
417
|
+
saw_title && !in_owned && !done {
|
|
418
|
+
if ($0 == "") next
|
|
419
|
+
if ($0 == "<!-- gsd:plan-revision-conflicts:begin -->") { in_owned = 1; next }
|
|
420
|
+
exit 2
|
|
421
|
+
}
|
|
422
|
+
in_owned && $0 == "<!-- gsd:plan-revision-conflicts:begin -->" { exit 2 }
|
|
423
|
+
in_owned && !saw_heading && $0 == "" { next }
|
|
424
|
+
in_owned && !saw_heading && $0 == "## Plan-Revision Conflicts" { saw_heading = 1; next }
|
|
425
|
+
in_owned && !saw_heading { exit 2 }
|
|
426
|
+
in_owned && $0 == "<!-- gsd:plan-revision-conflicts:end -->" {
|
|
427
|
+
done = 1
|
|
428
|
+
in_owned = 0
|
|
429
|
+
print count
|
|
430
|
+
exit
|
|
431
|
+
}
|
|
432
|
+
in_owned && /^- \[ \] REVISION_CONFLICT .*required_property:/ { count++ }
|
|
433
|
+
END { if (!done) exit 2 }
|
|
434
|
+
' "${REVIEWS_FILE}"); then
|
|
435
|
+
:
|
|
436
|
+
else
|
|
437
|
+
awk_status=$?
|
|
438
|
+
echo "BLOCKED: could not parse the writer-owned plan-revision conflict block in '${REVIEWS_FILE}' (awk exit ${awk_status}). Refusing to declare convergence on an unverifiable gate." >&2
|
|
439
|
+
exit 1
|
|
440
|
+
fi
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
`/gsd:review` emits exactly one writer-owned slot immediately after the artifact title,
|
|
444
|
+
between `<!-- gsd:plan-revision-conflicts:begin -->` and
|
|
445
|
+
`<!-- gsd:plan-revision-conflicts:end -->`. Inside that slot, `/gsd:plan-phase` records each
|
|
446
|
+
conflict as a `- [ ] REVISION_CONFLICT` checklist line and flips it to
|
|
447
|
+
`- [x] REVISION_CONFLICT` when resolved. The reader counts only the first fixed slot at that
|
|
448
|
+
position and stops at its explicit end delimiter. Reviewer output is rendered after the slot, so
|
|
449
|
+
raw reviewer text containing either the heading or an exact conflict-shaped checklist line cannot
|
|
450
|
+
forge blocking state. There is deliberately no fallback to the prior global line-shape scan: that
|
|
451
|
+
shape never merged to `next`, and accepting both grammars would recreate the reviewer collision.
|
|
452
|
+
|
|
453
|
+
**Only `/gsd:plan-phase` mutates the contents of this slot.** The review agent preserves the
|
|
454
|
+
existing `## Plan-Revision Conflicts` block byte-for-byte between its delimiters; every other
|
|
455
|
+
agent with write access to REVIEWS.md must leave it alone. Appending, editing, reordering or
|
|
456
|
+
deleting a line there forges the state of a blocking gate. Readers read. If `OPEN_CONFLICTS` > 0, convergence has NOT been
|
|
457
|
+
achieved regardless of the counts: skip the converged branch and continue to 5c so the next cycle
|
|
458
|
+
arbitrates. Escalation at `MAX_CYCLES` is unchanged and still terminates the loop, so an
|
|
459
|
+
unresolvable conflict escalates rather than deadlocking.
|
|
460
|
+
|
|
461
|
+
**If HIGH_COUNT == 0 and ACTIONABLE_COUNT == 0 and OPEN_CONFLICTS == 0 (converged):**
|
|
394
462
|
|
|
395
463
|
```bash
|
|
396
464
|
gsd_run state planned-phase --phase "${PHASE}" --name "${phase_name}" --plans "${PLAN_COUNT}"
|
|
@@ -410,11 +478,11 @@ Display:
|
|
|
410
478
|
|
|
411
479
|
Exit — convergence achieved.
|
|
412
480
|
|
|
413
|
-
**If HIGH_COUNT > 0 or ACTIONABLE_COUNT > 0:** Continue to 5c.
|
|
481
|
+
**If HIGH_COUNT > 0 or ACTIONABLE_COUNT > 0 or OPEN_CONFLICTS > 0:** Continue to 5c.
|
|
414
482
|
|
|
415
483
|
### 5c. Stall Detection + Escalation Check
|
|
416
484
|
|
|
417
|
-
Display: `◆ Cycle {cycle}/{MAX_CYCLES} — {HIGH_COUNT} HIGH, {ACTIONABLE_COUNT} actionable non-HIGH review concerns found`
|
|
485
|
+
Display: `◆ Cycle {cycle}/{MAX_CYCLES} — {HIGH_COUNT} HIGH, {ACTIONABLE_COUNT} actionable non-HIGH review concerns, {OPEN_CONFLICTS} open plan-revision conflicts found`
|
|
418
486
|
|
|
419
487
|
**Stall detection:** If `UNRESOLVED_COUNT >= prev_unresolved_count`:
|
|
420
488
|
```text
|
|
@@ -424,6 +492,29 @@ Display: `◆ Cycle {cycle}/{MAX_CYCLES} — {HIGH_COUNT} HIGH, {ACTIONABLE_COUN
|
|
|
424
492
|
|
|
425
493
|
**Max cycles check:** If `cycle >= MAX_CYCLES`:
|
|
426
494
|
|
|
495
|
+
**If `OPEN_CONFLICTS` > 0 (#3771): "Proceed anyway" is never offered.** An open plan-revision
|
|
496
|
+
conflict is a blocker — this loop's whole purpose is to surface it rather than let a success
|
|
497
|
+
banner paper over it, so escalation cannot end in the same silent acceptance a HIGH/actionable
|
|
498
|
+
concern can. Only "Manual review" is available:
|
|
499
|
+
|
|
500
|
+
If `TEXT_MODE` is true, present as plain text:
|
|
501
|
+
```text
|
|
502
|
+
Plan convergence did not complete after {MAX_CYCLES} cycles.
|
|
503
|
+
{OPEN_CONFLICTS} open plan-revision conflict(s) remain — these are blockers and cannot be accepted:
|
|
504
|
+
|
|
505
|
+
{HIGH_LINES}
|
|
506
|
+
|
|
507
|
+
{ACTIONABLE_LINES}
|
|
508
|
+
|
|
509
|
+
Review the concerns in: {REVIEWS_FILE}
|
|
510
|
+
|
|
511
|
+
To replan manually: /gsd:plan-phase {PHASE} --reviews
|
|
512
|
+
To restart loop: /gsd:plan-review-convergence {PHASE} {REVIEWER_FLAGS}
|
|
513
|
+
```
|
|
514
|
+
Exit workflow.
|
|
515
|
+
|
|
516
|
+
**Otherwise (`OPEN_CONFLICTS` == 0):**
|
|
517
|
+
|
|
427
518
|
If `TEXT_MODE` is true, present as plain-text numbered list:
|
|
428
519
|
```text
|
|
429
520
|
Plan convergence did not complete after {MAX_CYCLES} cycles.
|
|
@@ -478,7 +569,7 @@ Display: `◆ Replanning inline with review feedback... (plan-phase runs here in
|
|
|
478
569
|
Skill(skill="gsd-plan-phase", args="{PHASE} --reviews --skip-research {GSD_WS}")
|
|
479
570
|
```
|
|
480
571
|
|
|
481
|
-
Run plan-phase **inline** (do NOT wrap it in Agent()). Same rationale as step 4: the convergence orchestrator runs at depth 0 with Agent available, so inline plan-phase can spawn gsd-planner and gsd-plan-checker at depth 1. Wrapping in Agent() pushes plan-phase to depth 1 where the Agent tool is absent — the replan loop can never produce a revised plan when HIGHs are found. This is the root cause of bug #936. Actionable MEDIUM/LOW findings must be incorporated into executable PLAN.md content or explicitly deferred/rejected in the relevant PLAN.md before convergence can complete. Wait until plan-phase completes (outputs '## PLANNING COMPLETE') and updated PLAN.md files are committed before continuing.
|
|
572
|
+
Run plan-phase **inline** (do NOT wrap it in Agent()). Same rationale as step 4: the convergence orchestrator runs at depth 0 with Agent available, so inline plan-phase can spawn gsd-planner and gsd-plan-checker at depth 1. Wrapping in Agent() pushes plan-phase to depth 1 where the Agent tool is absent — the replan loop can never produce a revised plan when HIGHs are found. This is the root cause of bug #936. Actionable MEDIUM/LOW findings must be incorporated into executable PLAN.md content or explicitly deferred/rejected in the relevant PLAN.md before convergence can complete. The same holds for any open `## Plan-Revision Conflicts` entry (#3771): the replan must resolve it by adopting one of its recorded alternatives, overriding the named constraint, or amending the constraint — and mark the entry resolved. Re-running the planner against an unchanged conflict cannot resolve it and only burns a cycle. Wait until plan-phase completes (outputs '## PLANNING COMPLETE') and updated PLAN.md files are committed before continuing.
|
|
482
573
|
|
|
483
574
|
After plan-phase completes → go back to **step 5a** (review again).
|
|
484
575
|
|
|
@@ -497,7 +588,8 @@ After plan-phase completes → go back to **step 5a** (review again).
|
|
|
497
588
|
- [ ] Abort with clear error if current_actionable is absent or malformed
|
|
498
589
|
- [ ] Warn if ACTIONABLE_COUNT > 0 but ## Current Actionable Non-HIGH Concerns section is absent from return message
|
|
499
590
|
- [ ] The review Agent fully completes gsd-review before returning (plan-phase runs inline — no Agent wrap)
|
|
500
|
-
- [ ] Loop exits on: no HIGH concerns
|
|
591
|
+
- [ ] Loop exits on: no HIGH concerns, no actionable non-HIGH concerns, and OPEN_CONFLICTS == 0 (converged) OR max cycles (escalation)
|
|
592
|
+
- [ ] OPEN_CONFLICTS read from REVIEWS.md and evaluated BEFORE the converged branch writes state or prints the banner
|
|
501
593
|
- [ ] Stall detection reported when total unresolved review concern count is not decreasing
|
|
502
594
|
- [ ] STATE.md updated on convergence completion
|
|
503
595
|
</success_criteria>
|
|
@@ -140,7 +140,7 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "
|
|
|
140
140
|
gsd_run query commit "docs: plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
143
|
+
**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.
|
|
144
144
|
</step>
|
|
145
145
|
|
|
146
146
|
<step name="confirm">
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@~/.claude/gsd-core/references/response-language-directive.md
|
|
2
|
+
|
|
1
3
|
<purpose>
|
|
2
4
|
Create a clean branch for pull requests by filtering .planning/ paths out of the
|
|
3
5
|
cherry-picked history. Two modes, selected by the `planning.pr_strict` config key:
|
|
@@ -261,7 +263,10 @@ if [ "$PR_STRICT" = "true" ]; then
|
|
|
261
263
|
FILTER_PATHS=".planning/"
|
|
262
264
|
FORBIDDEN_RE="^\.planning/"
|
|
263
265
|
else
|
|
264
|
-
|
|
266
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
267
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
268
|
+
# one iteration there.
|
|
269
|
+
FILTER_PATHS=$(for d in $(printf '%s' "$TRANSIENT_DIRS"); do printf '.planning/%s/ ' "$d"; done)
|
|
265
270
|
FORBIDDEN_RE="^\.planning/($(echo "$TRANSIENT_DIRS" | tr ' ' '|'))/"
|
|
266
271
|
fi
|
|
267
272
|
```
|
|
@@ -322,12 +327,15 @@ touching the same planning path makes `git cherry-pick` abort with *"untracked w
|
|
|
322
327
|
files would be overwritten by merge"*, and every remaining commit is silently dropped.
|
|
323
328
|
|
|
324
329
|
```bash
|
|
325
|
-
|
|
330
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
331
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
332
|
+
# one iteration there.
|
|
333
|
+
for HASH in $(printf '%s' "$INCLUDED_COMMITS"); do
|
|
326
334
|
# A modify/delete conflict on a filtered path is EXPECTED and is resolved below — the
|
|
327
335
|
# filtered path is absent from HEAD by construction. Do not treat it as a failure here.
|
|
328
336
|
git cherry-pick --no-commit "$HASH" || true
|
|
329
337
|
|
|
330
|
-
for P in $FILTER_PATHS; do
|
|
338
|
+
for P in $(printf '%s' "$FILTER_PATHS"); do
|
|
331
339
|
git rm -r -f -q --ignore-unmatch -- "$P" 2>/dev/null || true
|
|
332
340
|
git checkout HEAD -- "$P" 2>/dev/null || true
|
|
333
341
|
done
|
|
@@ -19,7 +19,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
|
|
|
19
19
|
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
22
|
+
**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.
|
|
23
23
|
|
|
24
24
|
## 1. Initialize
|
|
25
25
|
|