@opengsd/gsd-core 1.15.0 → 1.16.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 +85 -5
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/install.js +126 -196
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +5 -0
- package/commands/gsd/capture.md +8 -4
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +5 -1
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +142 -56
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +183 -103
- package/gsd-core/bin/lib/capability-validator.cjs +16 -0
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +173 -170
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +413 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +162 -96
- package/gsd-core/bin/lib/install-engine.cjs +19 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +280 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state.cjs +214 -105
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1165 -314
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +84 -90
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase.md +78 -170
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +147 -16
- package/hooks/dist/gsd-statusline.js +15 -7
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +8 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +147 -16
- package/hooks/gsd-statusline.js +15 -7
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +10 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- 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-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +5 -1
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -17,11 +17,16 @@ exports.isCompletedInventory = isCompletedInventory;
|
|
|
17
17
|
exports.buildWorkstreamInventory = buildWorkstreamInventory;
|
|
18
18
|
const node_path_1 = __importDefault(require("node:path"));
|
|
19
19
|
const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
|
|
20
|
+
// #5060: `phase-status.cjs` is a load-time leaf (no top-level requires) — its
|
|
21
|
+
// `phaseStatusFromFacts`/`toWireStatus` are pure functions of facts, so
|
|
22
|
+
// importing them here does not violate this module's "No I/O. No async."
|
|
23
|
+
// contract.
|
|
24
|
+
const phase_status_cjs_1 = require("./phase-status.cjs");
|
|
20
25
|
// Internal helpers
|
|
21
26
|
function toPosixPath(p) {
|
|
22
27
|
return p.split('\\').join('/');
|
|
23
28
|
}
|
|
24
|
-
// #2562/#2645's
|
|
29
|
+
// #2562/#2645's former failing-verdict set (the verdicts that used to
|
|
25
30
|
// disqualify a phase from `complete` when combined with a local
|
|
26
31
|
// summary-count-meets-plan-count check) was removed by ADR-3180 §7.4
|
|
27
32
|
// (#3186): `complete` is now the single canonical owner's verdict
|
|
@@ -133,11 +138,14 @@ function buildWorkstreamInventory(inputs) {
|
|
|
133
138
|
// read `pending` instead of `complete`. `complete` defaults to `false`
|
|
134
139
|
// when absent so a caller that has not been updated to pass it never
|
|
135
140
|
// silently reads as complete.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
// #5060: routed through the Phase Status Module's owner ladder rather
|
|
142
|
+
// than a local re-derivation of the same complete/planCount branches.
|
|
143
|
+
const status = (0, phase_status_cjs_1.toWireStatus)((0, phase_status_cjs_1.phaseStatusFromFacts)({
|
|
144
|
+
planCount,
|
|
145
|
+
summaryCount,
|
|
146
|
+
complete: counts?.complete ?? false,
|
|
147
|
+
verificationStatus: counts?.verificationStatus ?? null,
|
|
148
|
+
}));
|
|
141
149
|
// #2562: only current-milestone phases feed the rollup when scoping is on,
|
|
142
150
|
// and only one directory per phase key (see rollupDirs above).
|
|
143
151
|
const countsTowardMilestone = (!scoped || counts?.inMilestone !== false) && rollupDirs.has(dir);
|
|
@@ -33,7 +33,7 @@ const { extractFrontmatter, stripFrontmatter } = frontmatterMod;
|
|
|
33
33
|
const markdown_table_cjs_1 = require("./markdown-table.cjs");
|
|
34
34
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- verification.cjs is an export= CommonJS module
|
|
35
35
|
const verificationMod = require("./verification.cjs");
|
|
36
|
-
const { isPhaseComplete } = verificationMod;
|
|
36
|
+
const { isPhaseComplete, isVerificationStatus, VERIFICATION_STATUS } = verificationMod;
|
|
37
37
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
|
|
38
38
|
const phaseIdMod = require("./phase-id.cjs");
|
|
39
39
|
const { phaseKeyFromDir, phaseKeyFromProse, parentPhaseKey } = phaseIdMod;
|
|
@@ -269,7 +269,10 @@ function readVerificationLedger(wsDir) {
|
|
|
269
269
|
}
|
|
270
270
|
const out = {};
|
|
271
271
|
for (const [key, value] of Object.entries(parsed)) {
|
|
272
|
-
|
|
272
|
+
// #5118: an entry outside the closed enum (a stored `unknown` from an
|
|
273
|
+
// older run) reads as absent — the phase then fails CLOSED to
|
|
274
|
+
// `unrecorded`, the same posture as a corrupt ledger.
|
|
275
|
+
if (isVerificationStatus(value))
|
|
273
276
|
out[key] = value;
|
|
274
277
|
}
|
|
275
278
|
return { state: 'ok', entries: out };
|
|
@@ -555,7 +558,7 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
555
558
|
// unverified-fallback diagnostic (#3057 B4) — the closest existing idiom,
|
|
556
559
|
// since `WorkstreamInventory`'s aggregate return shape carries no
|
|
557
560
|
// per-phase verification detail for this to attach to.
|
|
558
|
-
if (verificationResult.staleCheckIndeterminate) {
|
|
561
|
+
if ('staleCheckIndeterminate' in verificationResult && verificationResult.staleCheckIndeterminate) {
|
|
559
562
|
writeDiagnostic(`⚠ workstream-inventory: verification staleness check could not complete for phase directory '${dir}' in workstream '${name}' — routed as not-stale, but this was not actually verified. See #3057.\n`, { phaseDir: dir, reason: 'staleCheckIndeterminate' });
|
|
560
563
|
}
|
|
561
564
|
return {
|
|
@@ -566,14 +569,24 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
566
569
|
summaryCount: counts.summaryCount,
|
|
567
570
|
inMilestone: isDirInCurrentMilestone(dir),
|
|
568
571
|
liveVerificationStatus: verificationResult.status,
|
|
572
|
+
// #5118: the owner's out-of-set report error, carried to the check below.
|
|
573
|
+
statusError: completionResult.value.statusError,
|
|
569
574
|
// ADR-3180 §7.4 (#3186): the owner's verdict, read live off disk — never
|
|
570
575
|
// ledger-adjusted (see the phaseFilesCounts map below; the ledger only
|
|
571
576
|
// ever substitutes a 'missing' status with a remembered one, and under
|
|
572
|
-
// disk-strict
|
|
573
|
-
//
|
|
577
|
+
// disk-strict 'missing' is never complete, so there is nothing for the
|
|
578
|
+
// ledger to override here).
|
|
574
579
|
complete: completionResult.value.complete,
|
|
575
580
|
};
|
|
576
581
|
});
|
|
582
|
+
// #5118 (no write before the error): this inspection WRITES the ledger
|
|
583
|
+
// below, so a report whose `status` is outside the closed set fails it
|
|
584
|
+
// first — the owner's own error thrown as-is (like `init *`, `phase *` and
|
|
585
|
+
// `state *`), which the CLI entry seam projects once into its reason and
|
|
586
|
+
// message; nothing persisted.
|
|
587
|
+
const firstStatusError = rawPhaseEntries.find((entry) => entry.statusError)?.statusError;
|
|
588
|
+
if (firstStatusError)
|
|
589
|
+
throw firstStatusError;
|
|
577
590
|
// #2645: only the directory Bug #2445's de-dup rollup would actually pick
|
|
578
591
|
// for a phase key may read or write that key's ledger entry. Letting every
|
|
579
592
|
// same-keyed directory (including a stale leftover) write would let a
|
|
@@ -604,10 +617,11 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
604
617
|
const verificationLedger = ledgerRead.entries;
|
|
605
618
|
let ledgerDirty = false;
|
|
606
619
|
for (const winner of ledgerWinnerByKey.values()) {
|
|
607
|
-
|
|
620
|
+
const live = winner.liveVerificationStatus;
|
|
621
|
+
if (live === null || live === VERIFICATION_STATUS.MISSING)
|
|
608
622
|
continue;
|
|
609
|
-
if (verificationLedger[winner.phaseKey] !==
|
|
610
|
-
verificationLedger[winner.phaseKey] =
|
|
623
|
+
if (verificationLedger[winner.phaseKey] !== live) {
|
|
624
|
+
verificationLedger[winner.phaseKey] = live;
|
|
611
625
|
ledgerDirty = true;
|
|
612
626
|
}
|
|
613
627
|
}
|
|
@@ -620,20 +634,16 @@ function inspectWorkstream(cwd, name, options = {}) {
|
|
|
620
634
|
writeVerificationLedger(wsDir, verificationLedger);
|
|
621
635
|
const phaseFilesCounts = rawPhaseEntries.map(entry => {
|
|
622
636
|
const isLedgerWinner = ledgerWinnerByKey.get(entry.phaseKey) === entry;
|
|
637
|
+
// A live `missing` on the ledger winner reads the remembered verdict when
|
|
638
|
+
// there is one. #5118: the former `unrecorded` state ("adopted, never
|
|
639
|
+
// recorded") is deleted — its only reader, phaseStatusFromFacts, treats it
|
|
640
|
+
// exactly like `missing` (only `human_needed` changes the ladder, and under
|
|
641
|
+
// disk-strict neither is ever complete), so it was a dead distinction.
|
|
623
642
|
let verificationStatus = entry.liveVerificationStatus;
|
|
624
|
-
if (entry.liveVerificationStatus ===
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
verificationStatus = 'missing';
|
|
629
|
-
}
|
|
630
|
-
else {
|
|
631
|
-
// States 2/3 ('corrupt' or 'ok'): this workstream has adopted the
|
|
632
|
-
// ledger. A remembered entry wins; no entry fails CLOSED to the
|
|
633
|
-
// 'unrecorded' sentinel rather than falling open to 'missing'.
|
|
634
|
-
const remembered = verificationLedger[entry.phaseKey];
|
|
635
|
-
verificationStatus = remembered !== undefined ? remembered : 'unrecorded';
|
|
636
|
-
}
|
|
643
|
+
if (entry.liveVerificationStatus === VERIFICATION_STATUS.MISSING && isLedgerWinner) {
|
|
644
|
+
const remembered = verificationLedger[entry.phaseKey];
|
|
645
|
+
if (remembered !== undefined)
|
|
646
|
+
verificationStatus = remembered;
|
|
637
647
|
}
|
|
638
648
|
return {
|
|
639
649
|
directory: entry.directory,
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
* phase-id.cts's toDir/getPhaseDirFromPhaseId.
|
|
27
27
|
*/
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
|
|
29
|
+
exports.RESERVED_WORKSTREAM_NAMES = exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
|
|
30
|
+
exports.isReservedWorkstreamName = isReservedWorkstreamName;
|
|
31
|
+
exports.reservedWorkstreamNameMessage = reservedWorkstreamNameMessage;
|
|
30
32
|
exports.normalizeWorkstreamNameInput = normalizeWorkstreamNameInput;
|
|
31
33
|
exports.hasInvalidPathSegment = hasInvalidPathSegment;
|
|
32
34
|
exports.validateActiveWorkstreamName = validateActiveWorkstreamName;
|
|
@@ -36,6 +38,34 @@ exports.isValidActiveWorkstreamName = isValidActiveWorkstreamName;
|
|
|
36
38
|
exports.assertValidActiveWorkstreamName = assertValidActiveWorkstreamName;
|
|
37
39
|
exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = 'Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots';
|
|
38
40
|
const ACTIVE_WORKSTREAM_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
41
|
+
/**
|
|
42
|
+
* Names that pass the charset check but can never name a workstream (#4772).
|
|
43
|
+
* `none` reads as "no workstream" to every caller that types it, yet the path
|
|
44
|
+
* layer treated it as a literal directory, so `--ws none` silently resolved
|
|
45
|
+
* `.planning/workstreams/none/...` (and fell back to the root config). Single
|
|
46
|
+
* owner: resolveActiveWorkstream and workstream create/set all consume this list.
|
|
47
|
+
*/
|
|
48
|
+
exports.RESERVED_WORKSTREAM_NAMES = Object.freeze(['none']);
|
|
49
|
+
/** True when `name` (trimmed, case-insensitive) is a reserved workstream name. */
|
|
50
|
+
function isReservedWorkstreamName(name) {
|
|
51
|
+
const value = normalizeWorkstreamNameInput(name);
|
|
52
|
+
return value !== null && exports.RESERVED_WORKSTREAM_NAMES.includes(value.toLowerCase());
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The error text shared by every site that rejects a reserved name. `source`
|
|
56
|
+
* (where the name came from: 'cli' | 'env' | 'store') picks a remedy that can
|
|
57
|
+
* actually be carried out: the rejection happens in the gsd-tools bootstrap
|
|
58
|
+
* before any verb runs, so advising `workstream set --clear` would fail too.
|
|
59
|
+
*/
|
|
60
|
+
function reservedWorkstreamNameMessage(name, source = null) {
|
|
61
|
+
const value = normalizeWorkstreamNameInput(name) ?? '';
|
|
62
|
+
const remedy = source === 'env'
|
|
63
|
+
? 'unset GSD_WORKSTREAM for flat mode'
|
|
64
|
+
: source === 'store'
|
|
65
|
+
? 'delete the stale active-workstream pointer for flat mode'
|
|
66
|
+
: 'omit --ws for flat mode';
|
|
67
|
+
return `Workstream name '${value}' is reserved and cannot name a workstream; ${remedy}`;
|
|
68
|
+
}
|
|
39
69
|
function normalizeWorkstreamNameInput(name) {
|
|
40
70
|
const value = String(name ?? '').trim();
|
|
41
71
|
return value || null;
|
|
@@ -50,6 +50,9 @@ function migrateToWorkstreams(cwd, workstreamName) {
|
|
|
50
50
|
catch {
|
|
51
51
|
throw new Error('Invalid workstream name for migration');
|
|
52
52
|
}
|
|
53
|
+
if ((0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(workstreamName)) {
|
|
54
|
+
throw new Error((0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(workstreamName));
|
|
55
|
+
}
|
|
53
56
|
const baseDir = planningRoot(cwd);
|
|
54
57
|
const wsDir = node_path_1.default.join(baseDir, 'workstreams', workstreamName);
|
|
55
58
|
if (node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'workstreams'))) {
|
|
@@ -101,6 +104,9 @@ function cmdWorkstreamCreate(cwd, name, options, raw) {
|
|
|
101
104
|
if (!slug) {
|
|
102
105
|
error('Invalid workstream name — must contain at least one alphanumeric character');
|
|
103
106
|
}
|
|
107
|
+
if ((0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(slug)) {
|
|
108
|
+
error((0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(slug));
|
|
109
|
+
}
|
|
104
110
|
const baseDir = planningRoot(cwd);
|
|
105
111
|
if (!node_fs_1.default.existsSync(baseDir)) {
|
|
106
112
|
error(`.planning/ directory not found — run ${(0, runtime_slash_cjs_1.formatGsdSlash)('new-project', (0, runtime_slash_cjs_1.resolveRuntime)(cwd))} first`);
|
|
@@ -331,8 +337,11 @@ function cmdWorkstreamSet(cwd, name, raw) {
|
|
|
331
337
|
output({ active: null, cleared: true, previous: previous || null }, raw, undefined);
|
|
332
338
|
return;
|
|
333
339
|
}
|
|
334
|
-
if (!(0, workstream_name_policy_cjs_1.isValidActiveWorkstreamName)(name)) {
|
|
335
|
-
|
|
340
|
+
if (!(0, workstream_name_policy_cjs_1.isValidActiveWorkstreamName)(name) || (0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(name)) {
|
|
341
|
+
const message = (0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(name)
|
|
342
|
+
? (0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(name)
|
|
343
|
+
: 'Workstream name must be alphanumeric, hyphens, underscores, or dots';
|
|
344
|
+
output({ active: null, error: 'invalid_name', message }, raw, undefined);
|
|
336
345
|
return;
|
|
337
346
|
}
|
|
338
347
|
const wsDir = node_path_1.default.join(planningRoot(cwd), 'workstreams', name);
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"phase_id_convention": null,
|
|
15
15
|
"mode": "interactive",
|
|
16
16
|
"claude_md_path": "./.claude/CLAUDE.md",
|
|
17
|
+
"gates": {
|
|
18
|
+
"execute_next_plan": true,
|
|
19
|
+
"confirm_transition": true,
|
|
20
|
+
"confirm_milestone_scope": true
|
|
21
|
+
},
|
|
17
22
|
"git": {
|
|
18
23
|
"branching_strategy": "none",
|
|
19
24
|
"create_tag": true,
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
"_comment": "Canonical schema manifest for valid config key paths. This manifest is the single CJS source of truth for valid config keys; dynamicKeyPatterns source strings are recompiled to RegExp at runtime by config-schema.cjs. runtimeStateKeys mirrors RUNTIME_STATE_KEYS.",
|
|
3
3
|
"validKeys": [
|
|
4
4
|
"mode",
|
|
5
|
+
"gates.execute_next_plan",
|
|
6
|
+
"gates.confirm_transition",
|
|
7
|
+
"gates.confirm_milestone_scope",
|
|
5
8
|
"granularity",
|
|
6
9
|
"parallelization",
|
|
7
10
|
"commit_docs",
|
|
@@ -111,6 +114,7 @@
|
|
|
111
114
|
"resolve_model_ids",
|
|
112
115
|
"effort.default",
|
|
113
116
|
"fast_mode.enabled",
|
|
117
|
+
"audit.enabled",
|
|
114
118
|
"plan_review.source_grounding",
|
|
115
119
|
"plan_review.source_grounding_authority",
|
|
116
120
|
"model_policy.provider",
|
|
@@ -5,7 +5,8 @@ Smart discuss is the autonomous-optimized variant of `gsd-discuss-phase`. It pro
|
|
|
5
5
|
**Inputs:** `PHASE_NUM` from execute_phase. Run init to get phase paths:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
GSD_WS=$(echo " $ARGUMENTS" | sed -nE 's/.* --ws +([A-Za-z0-9][A-Za-z0-9._-]*).*/--ws \1/p' | head -n 1)
|
|
9
|
+
PHASE_STATE=$(gsd_run query init.phase-op ${GSD_WS:+--ws=${GSD_WS##* }} ${PHASE_NUM})
|
|
9
10
|
```
|
|
10
11
|
|
|
11
12
|
Parse from JSON: `phase_dir`, `phase_slug`, `padded_phase`, `phase_name`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UI Design Contract (Frontend Phases) — Autonomous Mode
|
|
2
2
|
|
|
3
|
-
Step 3a.5 of `/gsd:autonomous`: resolve whether the current phase needs a UI-SPEC.md generated before planning, and generate one via active `plan:pre` step hooks if so.
|
|
3
|
+
Step 3a.5 of `/gsd:autonomous`: resolve whether the current phase needs a UI-SPEC.md generated before planning, and generate one via active `plan:pre` step hooks if so. Non-blocking for every answer it gets — proceeds to step 3b (Plan) — except a gate that could not look (below), which is surfaced and stops.
|
|
4
4
|
|
|
5
5
|
**Inputs:** `PHASE_NUM`, `PHASE_DIR` from execute_phase.
|
|
6
6
|
|
|
@@ -16,10 +16,10 @@ Read the `activeHooks` array directly from `HOOKS_JSON` (in-context — do NOT i
|
|
|
16
16
|
(At least one active step hook ⇒ `workflow.ui_phase` is on.) Run the UI-SPEC gate:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
GATE=$(gsd_run check ui-plan-gate "${PHASE_NUM}" --raw)
|
|
19
|
+
GATE=$(gsd_run check ui-plan-gate "${PHASE_NUM}" --raw) && GATE_RC=0 || GATE_RC=$?
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
A non-zero `GATE_RC` is a command failure, including `69` (`UNAVAILABLE`: the gate could not read its evidence, so its `frontend: false` is not an answer): surface it and stop — never skip silently to 3b as if the phase had no frontend. Otherwise read `frontend` and `hasUiSpec` from `GATE` (in-context).
|
|
23
23
|
|
|
24
24
|
**If `frontend` is false:** Skip silently to 3b.
|
|
25
25
|
|
|
@@ -15,15 +15,10 @@ If any of these is false, the gate is inactive — execution proceeds normally.
|
|
|
15
15
|
For each task gated by TDD, the executor MUST verify (before running the implementation step):
|
|
16
16
|
|
|
17
17
|
1. **A failing-test commit exists.** Search git log on the current branch for a commit matching `test({phase}-{plan})` whose subject mentions the same plan as the current task. The commit must touch a test file (`*.test.*`, `*.spec.*`, `tests/**`).
|
|
18
|
-
2. **The test was actually red — INTENTIONALLY (#3770).**
|
|
19
|
-
```bash
|
|
20
|
-
gsd_run check tdd-red-evidence <record.json> --raw
|
|
21
|
-
```
|
|
22
|
-
- `RED_EVIDENCE_OK` (reason `target_test_failed`): the TARGET test named by the plan failed on a real assertion — the ONLY verdict that authorizes GREEN.
|
|
23
|
-
- `INVALID_RED` (reasons `unexpected_green`, `zero_tests_discovered`, `nonzero_exit_without_test_failure`, `fixture_or_load_failure`, `no_target_test_failure`, `invalid_record`, `unreadable_record`): the gate trips — halt, fix the RED phase (test identity, fixture, discovery), and re-verify before any implementation step. A `RED:` prefix or `(RED)` tag in the commit message is NOT sufficient evidence on its own.
|
|
18
|
+
2. **The test was actually red — INTENTIONALLY (#3770).** Read `gsd-core/references/tdd.md`, "Red-Green-Refactor Cycle", RED step 4, and follow its complete evidence contract before GREEN. That section owns format selection (TAP, including Node/Vitest; JUnit XML, including Surefire/Failsafe; swift-testing console; or Python `unittest` text), reporter reruns, report freshness, the classifier invocation, and semantic inspection. Require `RED_EVIDENCE_OK` for the actual run and verify the planned target assertion failed for the intended reason. An `INVALID_RED` verdict, unsupported format, or failed semantic assessment trips this gate; self-attestation cannot substitute for machine validation. A `RED:` prefix or `(RED)` tag in the commit message is not evidence.
|
|
24
19
|
3. **No implementation commit yet.** No `feat({phase}-{plan})` commit may exist for the same plan ID before the failing-test commit.
|
|
25
20
|
|
|
26
|
-
If any check fails, the gate trips.
|
|
21
|
+
If any check fails, the gate trips. A non-zero exit from `gsd_run check tdd-red-evidence` (`69` `UNAVAILABLE`: the record could not be read, #5170) is a command failure that has NOT authorized GREEN — the gate trips. For check 2, an `INVALID_RED` classifier verdict or a failed semantic assessment trips the gate (halt reason `invalid_red`) — the executor MUST halt and block the implementation step.
|
|
27
22
|
|
|
28
23
|
## What "behavior-adding task" means
|
|
29
24
|
|
|
@@ -52,7 +47,7 @@ The executor MUST:
|
|
|
52
47
|
Required next step:
|
|
53
48
|
1. Write a failing test for the behavior above.
|
|
54
49
|
2. Commit it as: test({phase}-{plan}): {short description}
|
|
55
|
-
3. Re-run /gsd
|
|
50
|
+
3. Re-run /gsd:execute-phase
|
|
56
51
|
```
|
|
57
52
|
|
|
58
53
|
3. Exit the current execution wave cleanly. Do NOT roll back any prior commits in the same wave.
|
|
@@ -65,7 +60,7 @@ The existing end-of-phase TDD review (in `workflows/execute-phase.md`'s `tdd_rev
|
|
|
65
60
|
Under TDD mode, escalate this to **blocking**:
|
|
66
61
|
- If any TDD plan is missing a RED or GREEN commit, the executor MUST refuse to mark the phase complete.
|
|
67
62
|
- The user is shown the same review table, but the verdict line reads:
|
|
68
|
-
> "Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under TDD. Resolve and re-run /gsd
|
|
63
|
+
> "Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under TDD. Resolve and re-run /gsd:execute-phase, or override with `/gsd:execute-phase {phase} --force-mvp-gate` to ship anyway."
|
|
69
64
|
|
|
70
65
|
The `--force-mvp-gate` flag is documented but not introduced by this plan — it is the escape hatch the spec mentions; if the user later builds it, the workflow already references the contract.
|
|
71
66
|
|
|
@@ -73,7 +68,7 @@ The `--force-mvp-gate` flag is documented but not introduced by this plan — it
|
|
|
73
68
|
|
|
74
69
|
- It does not enforce REFACTOR commits. REFACTOR remains optional (per `gsd-core/references/tdd.md`).
|
|
75
70
|
- It does not check test quality (the test could be trivially weak). That's the planner's job. It DOES check that the RED failure was intentional — the target test failing an assertion (#3770).
|
|
76
|
-
- It does not
|
|
71
|
+
- It does not start implementation by running tests. During RED, the executor runs the planned test and captures its result, rerunning the planned target with a supported reporter when the first report is unsupported (`tdd.md` RED step 4); before GREEN, this gate inspects that persisted evidence, git history, and test assertion. The implementation step starts only after the RED gate passes.
|
|
77
72
|
- It does not gate config-only or doc-only tasks (see "behavior-adding task" definition).
|
|
78
73
|
|
|
79
74
|
## Compatibility with existing TDD discipline
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
- `## Cross-Plan Wiring Gap` with plan/link/from/pattern rows
|
|
5
5
|
- Options: investigate+fix before continue, or continue with cascade risk
|
|
6
6
|
Skip key-links that reference files in the CURRENT (upcoming) wave.
|
|
7
|
+
Exit status (#5170): `0` all verified; `1` a link failed (read the JSON); `66` the plan declares no
|
|
8
|
+
key_links (nothing to check); `69` the plan is missing/unreadable (could not look — surface it, never
|
|
9
|
+
treat the plan as wired).
|
|
7
10
|
|
|
8
11
|
7c. **Between-wave manifest reset and worktree base refresh (waves 2+ only — #1369):**
|
|
9
12
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**If `response_language` is set:** User-facing orchestrator output (questions, narration, report-template prose) in `{response_language}`; technical terms, code, file paths, and subagent prompts stay in English. Pass `response_language: {value}` into every spawned subagent prompt so any user-facing output they produce stays in the configured language.
|
|
4
4
|
|
|
5
|
-
**The `gsd-verifier` subagent has no workflow file of its own (#2529):** the `verify_phase_goal`
|
|
5
|
+
**The `gsd-verifier` subagent has no workflow file of its own (#2529):** the shared verification step (`workflows/execute-phase/steps/verify-phase-goal.md`, included by execute-phase's `verify_phase_goal` and by verify-work, #5118) reaches it by dispatch, not by reading a workflow, so there is no file in which to place a directive — the dispatch prompt is the only place its coverage can live. That prompt MUST carry this line verbatim, immediately after `Create VERIFICATION.md.` (the shared step's prompt carries it inline, so both callers inject it):
|
|
6
6
|
|
|
7
7
|
`Use response_language {response_language} for all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code and paths.`
|
|
8
8
|
|
|
@@ -4,5 +4,5 @@ Use this bootstrap block when a workflow must call `gsd-tools` from the active w
|
|
|
4
4
|
Keep this resolver centralized; workflows should reference this file instead of copying the shell probe.
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() {
|
|
7
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { set -- "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}" "$HOME/.gemini/antigravity-ide" "$HOME/.gemini/antigravity-cli" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}" "${CLINE_CONFIG_DIR:-$HOME/.cline}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}" "${CODEX_HOME:-$HOME/.codex}" "${COPILOT_CONFIG_DIR:-${COPILOT_HOME:-$HOME/.copilot}}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}" "${HERMES_HOME:-$HOME/.hermes}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}" "${KIMI_CONFIG_DIR:-$HOME/.config/agents}" "$HOME/.agents" "${KIMI_CODE_HOME:-$HOME/.kimi-code}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}" "${TRAE_CONFIG_DIR:-$HOME/.trae}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}" "${ZCODE_CONFIG_DIR:-$HOME/.zcode}" "${GROK_AGENTS_HOME:-$HOME/.agents}"; for _h; do _gsd_at "$_h/gsd-core/bin/${_GSD_SHIM_NAME}" && return 0; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
8
8
|
```
|
|
@@ -108,7 +108,13 @@ Evaluate `check` (one of `query`, `predicate`, or `agentVerdict`). Then honor `b
|
|
|
108
108
|
- `blocking: false` → advisory only; surface the message but continue regardless of outcome.
|
|
109
109
|
|
|
110
110
|
Honor `onError` if the check itself errors: `skip` means treat as non-blocking and continue;
|
|
111
|
-
`halt` means surface the error and stop.
|
|
111
|
+
`halt` means surface the error and stop. "Errors" means a non-zero exit from `gsd_run check ...`,
|
|
112
|
+
and that includes `69` (`UNAVAILABLE`, #5170): a gate verb exits `69` when it **could not look** at
|
|
113
|
+
its evidence, still printing the gate's usual JSON (its own fields name what could not be read, such
|
|
114
|
+
as `status: "unresolvable"`, `readError`, or `unreadable`). That JSON is not a verdict — do not act
|
|
115
|
+
on its `block`; route it by `onError` as a step-1 command failure. Exit `0` always means a
|
|
116
|
+
delivered verdict, a blocking one included (`block: true`): a gate verb never exits non-zero to say
|
|
117
|
+
"blocked".
|
|
112
118
|
|
|
113
119
|
## Empty / absent `activeHooks`
|
|
114
120
|
|
|
@@ -34,7 +34,7 @@ STOP. Do not proceed to auto-advance or transition.
|
|
|
34
34
|
1. Parse `--auto` flag from $ARGUMENTS
|
|
35
35
|
2. Read consolidated auto-mode (`active` = chain flag OR user preference; chain flag already synced in init step):
|
|
36
36
|
```bash
|
|
37
|
-
AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null ||
|
|
37
|
+
AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null) || AUTO_MODE="false"
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
**If `--auto` flag present OR `AUTO_MODE` is true (AND verification passed with no gaps):**
|
|
@@ -432,7 +432,7 @@ Several config fields affect each other or trigger special behavior:
|
|
|
432
432
|
|
|
433
433
|
4. **`parallelization` polymorphism** -- Accepts both a simple boolean and an object with an `enabled` field. `loadConfig()` normalizes either form to a boolean. `{ "enabled": true }` is equivalent to `true`.
|
|
434
434
|
|
|
435
|
-
5. **Search API keys and flags** -- `brave_search`, `firecrawl`, and `exa_search` are auto-set to `true` during project creation if the corresponding API key is detected (environment variable or
|
|
435
|
+
5. **Search API keys and flags** -- `brave_search`, `firecrawl`, and `exa_search` are auto-set to `true` during project creation if the corresponding API key is detected (environment variable or `$GSD_HOME/.gsd/<name>_api_key` file; `GSD_HOME` defaults to the home directory). Setting them to `true` without the API key has no effect.
|
|
436
436
|
|
|
437
437
|
6. **`planning.*` and top-level equivalence** -- `planning.commit_docs` and `commit_docs` are equivalent; `planning.search_gitignored` and `search_gitignored` are equivalent. If both are set, the top-level value takes precedence.
|
|
438
438
|
|
|
@@ -55,7 +55,7 @@ When SPIDR triggers, the workflow:
|
|
|
55
55
|
2. Asks "Which SPIDR axis fits best?" with the five options above.
|
|
56
56
|
3. Walks through the chosen axis interactively (one focused question), produces a split proposal: "Phase N (this one): X. Phase N+1: Y. Phase N+2: Z."
|
|
57
57
|
4. Confirms the split with the user.
|
|
58
|
-
5. On accept: writes the FIRST phase's story to the current ROADMAP entry; defers creating new phases for the splits to a follow-up step (the workflow surfaces a list of `/gsd
|
|
58
|
+
5. On accept: writes the FIRST phase's story to the current ROADMAP entry; defers creating new phases for the splits to a follow-up step (the workflow surfaces a list of `/gsd:phase` invocations the user can run after `mvp-phase` completes — but does not run them automatically, to preserve user control over phase numbering).
|
|
59
59
|
6. On reject: proceeds with the original story unchanged.
|
|
60
60
|
|
|
61
61
|
## Anti-patterns to reject
|
|
@@ -78,7 +78,7 @@ Output: [Working, tested feature]
|
|
|
78
78
|
|
|
79
79
|
<output>
|
|
80
80
|
After completion, create SUMMARY.md with:
|
|
81
|
-
- RED: What test was written, why it failed
|
|
81
|
+
- RED: What test was written, why it failed, and the semantic assessment of its RED evidence
|
|
82
82
|
- GREEN: What implementation made it pass
|
|
83
83
|
- REFACTOR: What cleanup was done (if any)
|
|
84
84
|
- Commits: List of commits produced
|
|
@@ -95,7 +95,13 @@ After completion, create SUMMARY.md with:
|
|
|
95
95
|
1. Create test file following project conventions
|
|
96
96
|
2. Write test describing expected behavior (from `<behavior>` element)
|
|
97
97
|
3. Run test - it MUST fail **intentionally** (#3770): the TARGET test you named must be the test that fails, on an assertion for the planned behavior. A nonzero exit alone is NOT RED — syntax errors, zero-test discovery, fixture crashes, parser errors, and unrelated assertions are INVALID_RED and must not authorize GREEN.
|
|
98
|
-
4. Persist the RED evidence
|
|
98
|
+
4. Persist the RED evidence from the actual command: `{command, exitCode, output, targetTest, targetFile, expected, actual}`. Preserve the real exit status and unmodified report; record the planned expected result and observed actual result. Write the record inside the project directory; the classifier refuses a path outside it. It reads only these fields, so the further fields below stay in the record for review.
|
|
99
|
+
- Select evidence by **report format**, regardless of runner or package manager. The classifier has a shared TAP adapter for Node's built-in test runner and Vitest (`tap` / `tap-flat`), a JUnit XML adapter for Maven Surefire/Failsafe, a swift-testing console adapter for `swift test`, and a Python `unittest` text adapter. Other producers of these formats use the same adapters.
|
|
100
|
+
- TAP: capture the complete reporter output, including its test plan. Node summary comments are optional. The report must start with its TAP output: capture the reporter's own stdout (for npm scripts, `npm run --silent`), not package-manager banners. Use the target test's exact name; when names repeat, use its qualified name as emitted in the report (`tap-flat` emits only the full `file > suite > test` name). Suite/file summary failures are not target assertions. If the reporter is incompatible, rerun the planned target with a supported reporter through the project's test command, capture that real command and result, then submit the rerun's record to the classifier below. Preserve other console output separately rather than editing the report to make it parse.
|
|
101
|
+
- JUnit XML: capture the unchanged target report generated by the actual run. For Maven this is `target/surefire-reports/TEST-*.xml` or `target/failsafe-reports/TEST-*.xml`. Record the report path, run start, and modification time as `reportPath`, `runStartedAt`, and `reportModifiedAt`; require the report to be newer than the run start and verify the named target class or method executed in that run. Name the target as the method, the class (simple or package-qualified), or `<package.Class>#<method>`. Put one complete XML document in `output`, preserving console output alongside it. Missing, stale, or ambiguous reports require STOP and investigation.
|
|
102
|
+
- swift-testing and `unittest`: capture the complete console output without color (`NO_COLOR=1`), including the final summary. swift-testing needs one `Test` result line (passed, failed, skipped, or cancelled) for every test its `Test run with N tests` summary counts; it names a test by its quoted display name or, without one, by its function name (`addsNumbers()`), and either name identifies the target; repeated swift-testing names are ambiguous and block GREEN. `unittest` needs one `FAIL:`/`ERROR:` header for every failure or error its `FAILED (...)` line counts; repeated headers from one test's failing subTests count as one failing test, a method name that repeats across classes needs its `module.Class.method` id, and a `unittest.loader._FailedTest` entry is a load failure, never RED.
|
|
103
|
+
- Pass the unchanged record to `gsd_run check tdd-red-evidence <record.json> --raw` and require `RED_EVIDENCE_OK` before GREEN. Every `INVALID_RED` reason (`unexpected_green`, `zero_tests_discovered`, `nonzero_exit_without_test_failure`, `fixture_or_load_failure`, `no_target_test_failure`, `invalid_record`, `unreadable_record`) trips the gate. `invalid_record` includes unsupported or malformed reports; inspect `evidence.report_errors`. An unsupported format requires a supported reporter or a parser adapter before GREEN. Classifier rejection never authorizes a fallback to self-attestation.
|
|
104
|
+
- After machine validation, inspect whether the target actually executed and failed on the planned assertion for the intended reason. Zero tests, a missing, skipped, or cancelled target, setup, collection, import, syntax, or fixture faults, unrelated failures, unexpected green, and incomplete or ambiguous evidence block GREEN. Record this semantic assessment as `semanticAssessment` in the RED evidence and in the SUMMARY's RED entry; never fabricate reports, counters, or parser verdicts.
|
|
99
105
|
5. If test passes: feature exists or test is wrong. Investigate.
|
|
100
106
|
6. Commit: `test({phase}-{plan}): add failing test for [feature]`
|
|
101
107
|
|
|
@@ -279,14 +285,14 @@ When `workflow.tdd_mode` is enabled in config, the RED/GREEN/REFACTOR gate seque
|
|
|
279
285
|
|
|
280
286
|
| Gate | Required | Commit Pattern | Validation |
|
|
281
287
|
|------|----------|---------------|------------|
|
|
282
|
-
| RED | Yes | `test({phase}-{plan}): ...` |
|
|
288
|
+
| RED | Yes | `test({phase}-{plan}): ...` | Target test exists AND fails before implementation: a complete report in a supported format (RED step 4) from the current run must return `RED_EVIDENCE_OK`, followed by semantic inspection of the planned assertion (RED step 4) |
|
|
283
289
|
| GREEN | Yes | `feat({phase}-{plan}): ...` | Test passes after implementation |
|
|
284
290
|
| REFACTOR | No | `refactor({phase}-{plan}): ...` | Tests still pass after cleanup |
|
|
285
291
|
|
|
286
292
|
### Fail-Fast Rules
|
|
287
293
|
|
|
288
294
|
1. **Unexpected GREEN in RED phase:** If the test passes before any implementation code is written, STOP. The feature may already exist or the test is wrong. Investigate before proceeding.
|
|
289
|
-
2. **INVALID_RED in RED phase (#3770):** A nonzero exit is not RED by itself.
|
|
295
|
+
2. **INVALID_RED in RED phase (#3770):** A nonzero exit is not RED by itself. Follow the format-based evidence contract in RED step 4, including reporter reruns and report freshness. An `INVALID_RED` verdict or failed semantic assessment halts GREEN. Unsupported, incomplete, ambiguous, or contradictory evidence cannot authorize implementation.
|
|
290
296
|
3. **Missing RED commit:** If no `test(...)` commit precedes the `feat(...)` commit, the TDD discipline was violated. Flag in SUMMARY.md.
|
|
291
297
|
4. **REFACTOR breaks tests:** Undo the refactor immediately. Commit was premature — refactor in smaller steps.
|
|
292
298
|
|
|
@@ -34,12 +34,15 @@ no `<decisions>` block.
|
|
|
34
34
|
GATE_CFG=$(gsd_run query config-get workflow.context_coverage_gate 2>/dev/null || echo "true")
|
|
35
35
|
if [ "$GATE_CFG" != "false" ]; then
|
|
36
36
|
CONTEXT_PATH=$(ls "${PHASE_DIR}"/*-CONTEXT.md 2>/dev/null | head -1) # #2962: not a for-glob (zsh aborts)
|
|
37
|
-
DECISION_RESULT=$(gsd_run query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}")
|
|
37
|
+
DECISION_RESULT=$(gsd_run query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}") && DECISION_EXIT=0 || DECISION_EXIT=$?
|
|
38
38
|
fi
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
The handler returns JSON `{ skipped, blocking: false, total, honored,
|
|
42
|
-
not_honored: [...], message }`.
|
|
42
|
+
not_honored: [...], message }`. A non-zero `DECISION_EXIT` (`69` `UNAVAILABLE`: the gate
|
|
43
|
+
could not read CONTEXT.md or the phase artifacts, #5170) is **not** "no decisions": record
|
|
44
|
+
`Decision coverage: not evaluated (the gate could not read its evidence)` in VERIFICATION.md
|
|
45
|
+
and do not report counts.
|
|
43
46
|
|
|
44
47
|
**Reporting:** Append the handler's `message` (a `### Decision Coverage`
|
|
45
48
|
section) to VERIFICATION.md regardless of outcome — even when all
|
|
@@ -15,9 +15,9 @@ The user-flow form mirrors what a real user does: open, fill, click, see. No HTT
|
|
|
15
15
|
|
|
16
16
|
The framing fires when:
|
|
17
17
|
- The phase under verification has `**Mode:** mvp` in ROADMAP.md (parsed via `gsd_run query roadmap.get-phase --pick mode`).
|
|
18
|
-
- AND the phase has a user-story-formatted goal (set by `/gsd
|
|
18
|
+
- AND the phase has a user-story-formatted goal (set by `/gsd:mvp-phase` per Phase 2): "As a [user role], I want to [capability], so that [outcome]."
|
|
19
19
|
|
|
20
|
-
If the phase has `mode: mvp` but the goal is NOT in user-story format, the verifier surfaces this as a discrepancy and asks the user to run `/gsd
|
|
20
|
+
If the phase has `mode: mvp` but the goal is NOT in user-story format, the verifier surfaces this as a discrepancy and asks the user to run `/gsd:mvp-phase` to reformat the goal — same pattern as the planner agent under MVP_MODE (per `gsd-core/references/planner-mvp-mode.md`).
|
|
21
21
|
|
|
22
22
|
## Generated UAT script structure under MVP mode
|
|
23
23
|
|
|
@@ -77,13 +77,43 @@ and broader temp hygiene is left to OS temp cleanup or future maintenance work.
|
|
|
77
77
|
|
|
78
78
|
## Routing Propagation
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
Every workstream-scoped workflow parses the `--ws <name>` it was started with out of
|
|
81
|
+
`$ARGUMENTS` in each shell fence that needs it (fences are separate shells, so nothing is
|
|
82
|
+
carried over between them) and sets `GSD_WS`:
|
|
83
|
+
- `GSD_WS` is `--ws <name>` when the command was started with `--ws`, and empty otherwise
|
|
84
|
+
(flat mode, backward compatible). It is always re-assigned, so a stale value never leaks in.
|
|
85
|
+
- Every `gsd_run query agent-skills <agent>` and `gsd_run query init.*` call in those
|
|
86
|
+
workflows forwards it as the single token `${GSD_WS:+--ws=${GSD_WS##* }}`. The explicit
|
|
87
|
+
flag has the highest priority above, so the workstream a command was started for wins over
|
|
88
|
+
the session pointer and the shared marker. The single-token form is required because zsh
|
|
89
|
+
does not word-split an unquoted `$GSD_WS`.
|
|
90
|
+
- Workflows recognize the documented spelling `--ws <name>`; `--ws=<name>` is accepted by the
|
|
91
|
+
CLI itself but is not parsed out of `$ARGUMENTS` by workflows.
|
|
92
|
+
- Routing suggestions (`/gsd:plan-phase {X} ${GSD_WS}`) carry the same value to the next command.
|
|
93
|
+
- Project and workspace lifecycle workflows (`new-project`, `new-workspace`,
|
|
94
|
+
`list-workspaces`, `remove-workspace`, `update`) are root-scoped and do not forward it.
|
|
95
|
+
|
|
96
|
+
`tests/agent-skills.test.cjs` scans every fenced call in `gsd-core/workflows/` so a new call
|
|
97
|
+
that omits the flag fails CI.
|
|
83
98
|
|
|
84
99
|
This ensures workstream scope chains automatically through the workflow:
|
|
85
100
|
`new-milestone → discuss-phase → plan-phase → execute-phase → transition`
|
|
86
101
|
|
|
102
|
+
## Reserved names
|
|
103
|
+
|
|
104
|
+
`none` (case-insensitive) cannot name a workstream. `--ws none`, `--ws=none`, `GSD_WORKSTREAM=none`
|
|
105
|
+
and a pointer of `none` are all rejected with a "reserved" error, and `workstream create` and
|
|
106
|
+
`workstream set` refuse it unconditionally. The one exception on the read side is a
|
|
107
|
+
`.planning/workstreams/none/` directory that already exists: it stays addressable with `--ws none`
|
|
108
|
+
so projects that used the name before it was reserved keep working (the directory name must match
|
|
109
|
+
exactly; `NONE` is still rejected). Such a grandfathered directory is reachable through `--ws` and
|
|
110
|
+
`GSD_WORKSTREAM` only, because `workstream set none` refuses unconditionally. To force flat mode,
|
|
111
|
+
omit `--ws`, unset `GSD_WORKSTREAM`, or clear the pointer (`workstream set --clear`). The rejection
|
|
112
|
+
happens before any command runs, so a stale `GSD_WORKSTREAM=none` in the environment must be unset
|
|
113
|
+
first. The reserved list has a single owner
|
|
114
|
+
(`RESERVED_WORKSTREAM_NAMES` in `src/workstream-name-policy.cts`); near-misses such as `none1` or
|
|
115
|
+
`nonexistent` are ordinary names.
|
|
116
|
+
|
|
87
117
|
## Directory Structure
|
|
88
118
|
|
|
89
119
|
```
|
|
@@ -17,7 +17,7 @@ These files live directly at `.planning/` — not inside phase subdirectories.
|
|
|
17
17
|
| `STATE.md` | `state.md` | `/gsd:new-project`, `/gsd:health --repair` | Current session state, active phase, last activity |
|
|
18
18
|
| `REQUIREMENTS.md` | `requirements.md` | `/gsd:new-milestone` | Functional requirements with traceability |
|
|
19
19
|
| `MILESTONES.md` | `milestone.md` | `/gsd:complete-milestone` | Log of completed milestones with accomplishments |
|
|
20
|
-
| `BACKLOG.md` | *(inline)* | `/gsd
|
|
20
|
+
| `BACKLOG.md` | *(inline)* | `/gsd:capture --backlog` | Pending ideas and deferred work |
|
|
21
21
|
| `LEARNINGS.md` | *(inline)* | `/gsd:extract-learnings`, `/gsd:execute-phase` (gated: `features.global_learnings`) | Phase retrospective learnings for future plans |
|
|
22
22
|
| `THREADS.md` | *(inline)* | `/gsd:thread` | Persistent discussion threads |
|
|
23
23
|
| `config.json` | `config.json` | `/gsd:new-project`, `/gsd:health --repair` | Project-specific GSD configuration |
|
|
@@ -66,7 +66,7 @@ blocked: [N]
|
|
|
66
66
|
|
|
67
67
|
<!-- YAML format for plan-phase --gaps consumption -->
|
|
68
68
|
- truth: "[expected behavior from test]"
|
|
69
|
-
status: failed
|
|
69
|
+
status: failed | resolved
|
|
70
70
|
reason: "User reported: [verbatim response]"
|
|
71
71
|
severity: blocker | major | minor | cosmetic
|
|
72
72
|
test: [N]
|
|
@@ -74,6 +74,10 @@ blocked: [N]
|
|
|
74
74
|
artifacts: [] # Filled by diagnosis
|
|
75
75
|
missing: [] # Filled by diagnosis
|
|
76
76
|
debug_session: "" # Filled by diagnosis
|
|
77
|
+
resolved_by: "" # Written by verify-work's reconcile_gaps (#1921) when
|
|
78
|
+
# an executed gap-closure plan resolves this gap —
|
|
79
|
+
# never author this directly. Plan basename.
|
|
80
|
+
resolved_at: "" # Written alongside resolved_by (#1921).
|
|
77
81
|
```
|
|
78
82
|
|
|
79
83
|
---
|
|
@@ -107,6 +111,18 @@ blocked: [N]
|
|
|
107
111
|
- APPEND only when issue found (YAML format)
|
|
108
112
|
- After diagnosis: fill `root_cause`, `artifacts`, `missing`, `debug_session`
|
|
109
113
|
- This section feeds directly into /gsd:plan-phase --gaps
|
|
114
|
+
- `status: resolved` (#1921, #4983): when `/gsd:verify-work`'s `reconcile_gaps`
|
|
115
|
+
step finds an executed gap-closure plan (a `*-PLAN.md` naming this entry's
|
|
116
|
+
`gap_id` with a matching `*-SUMMARY.md`), it updates the entry IN PLACE —
|
|
117
|
+
`status: failed` → `status: resolved` — and adds `resolved_by` (the
|
|
118
|
+
resolving plan's basename) and `resolved_at` (the date). A resolved entry
|
|
119
|
+
is no longer surfaced as an open gap, and its matching `### N.` test's
|
|
120
|
+
`result: issue` no longer blocks `phase uat-passed` — but only when
|
|
121
|
+
`resolved_by` names a plan that actually exists in the phase directory with
|
|
122
|
+
a matching SUMMARY; a hand-written `status: resolved` with no valid
|
|
123
|
+
`resolved_by` still blocks (src/uat-predicate.cts's `isTestGapResolved`).
|
|
124
|
+
A later regression against the same test gets a fresh `gap_id`, never a
|
|
125
|
+
reopened resolved one.
|
|
110
126
|
|
|
111
127
|
</section_rules>
|
|
112
128
|
|