@opengsd/gsd-core 1.13.0 → 1.15.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/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- 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 +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- 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 +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- 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 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +39 -209
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +45 -187
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- 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 +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- 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 +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -33,11 +33,13 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D
|
|
|
33
33
|
|
|
34
34
|
<process>
|
|
35
35
|
|
|
36
|
+
**Compact Content Gate.** Read and follow `gsd-core/references/compact-content-gate.md` now — it states the `workflow.compact_content` check and the resolution rule this spine defers to. When it directs a Read, read `gsd-core/workflows/verify-work/detail/elaboration.md` in full before continuing past this point; its content elaborates on the resume/reconcile steps and the full gap-closure sub-flow below.
|
|
37
|
+
|
|
36
38
|
<step name="initialize" priority="first">
|
|
37
39
|
If $ARGUMENTS contains a phase number, load context:
|
|
38
40
|
|
|
39
41
|
```bash
|
|
40
|
-
_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; };
|
|
42
|
+
_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() { _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}"; }; 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
|
|
41
43
|
GSD_WS=""
|
|
42
44
|
echo "$ARGUMENTS" | grep -qE -- '--ws[[:space:]]+[A-Za-z0-9._-]+' && GSD_WS=$(echo "$ARGUMENTS" | grep -oE -- '--ws[[:space:]]+[A-Za-z0-9._-]+')
|
|
43
45
|
PHASE_ARG=$(echo "$ARGUMENTS" | sed -E 's/--ws[[:space:]]+[A-Za-z0-9._-]+//g' | xargs)
|
|
@@ -181,18 +183,31 @@ instrument — the executor's own narration is never the last word. For each `*-
|
|
|
181
183
|
BASE=$(grep -oE '^plan_head_before: [0-9a-f]{7,40}' "$SUMMARY_FILE" | awk '{print $2}')
|
|
182
184
|
CLAIMED=$(grep -oE '^commits: [0-9]+' "$SUMMARY_FILE" | grep -oE '[0-9]+' || echo absent)
|
|
183
185
|
ACTUAL=$(git rev-list --count "${BASE}"..HEAD)
|
|
186
|
+
AFTER=$(grep -oE '^plan_head_after: [0-9a-f]{7,40}' "$SUMMARY_FILE" | awk '{print $2}')
|
|
184
187
|
```
|
|
185
188
|
- A `commits: absent` or `plan_head_before: absent` SUMMARY (pre-#3968 legacy) is reported as
|
|
186
189
|
a WARNING with the measured git state, not a mismatch.
|
|
187
|
-
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
- **Bounded reconciliation (#4670).** A SUMMARY carrying `plan_head_after:` (the executor's
|
|
191
|
+
HEAD at its measurement moment — after the last task commit, before the SUMMARY commit) is
|
|
192
|
+
reconciled against the plan's OWN window:
|
|
193
|
+
```bash
|
|
194
|
+
if git merge-base --is-ancestor "$AFTER" HEAD 2>/dev/null \
|
|
195
|
+
&& [ "$(git rev-list --count "${BASE}..${AFTER}")" = "$CLAIMED" ]; then
|
|
196
|
+
: # consistent
|
|
197
|
+
fi
|
|
198
|
+
```
|
|
199
|
+
Consistent → done. Anything else is a **BLOCKER** — `commit_claim_mismatch` with both
|
|
200
|
+
numbers and the SUMMARY path: commits claimed but never made (#3968), task commits lost
|
|
201
|
+
after the fact, or the plan's recorded window rewritten afterwards (a rebase/amend/cherry-pick
|
|
202
|
+
of those commits makes `$AFTER` a non-ancestor — recount that plan's commits manually
|
|
203
|
+
before treating it as a genuine mismatch). The unbounded `${BASE}..HEAD` count is NOT
|
|
204
|
+
evidence either way: it grows with every later plan's commits and execute-phase's own
|
|
205
|
+
phase-completion commit, so an honest plan would read as a mismatch (#4670).
|
|
206
|
+
- **Legacy fallback (#4670).** A SUMMARY with a base but no `plan_head_after:` (pre-#4670)
|
|
207
|
+
cannot be bounded to its own window — report the measured `${BASE}..HEAD` count as a
|
|
208
|
+
**WARNING** with the SUMMARY's task-commit list for manual counting. The old
|
|
209
|
+
`ACTUAL == CLAIMED` / `ACTUAL == CLAIMED + 1` tolerance was a guess that later plans'
|
|
210
|
+
commits defeat; it must never produce a BLOCKER on the unsound window.
|
|
196
211
|
</step>
|
|
197
212
|
|
|
198
213
|
<step name="extract_tests">
|
|
@@ -375,7 +390,7 @@ Display the returned checkpoint EXACTLY as-is:
|
|
|
375
390
|
- Do NOT add commentary before or after the block.
|
|
376
391
|
- If you notice protocol/meta markers such as `to=all:`, role-routing text, XML system tags, hidden instruction markers, ad copy, or any unrelated suffix, discard the draft and output `{CHECKPOINT}` only.
|
|
377
392
|
|
|
378
|
-
**Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex,
|
|
393
|
+
**Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Antigravity, etc.) where `AskUserQuestion` is not available.
|
|
379
394
|
Wait for user response (plain text, no AskUserQuestion).
|
|
380
395
|
</step>
|
|
381
396
|
|
|
@@ -489,50 +504,20 @@ If no more tests → Go to `complete_session`
|
|
|
489
504
|
</step>
|
|
490
505
|
|
|
491
506
|
<step name="reconcile_gaps">
|
|
492
|
-
**Reconcile diagnosed gaps against completed gap-closure plans (#1921):**
|
|
493
|
-
|
|
494
|
-
When verify-work resumes after `/gsd:execute-phase --gaps-only`, the UAT `## Gaps` entries still read `status: failed` even though their fix plans have executed. Without reconciliation verify-work re-diagnoses them as fresh blockers and spawns new gap plans — losing the verification state. This step closes the loop.
|
|
495
|
-
|
|
496
|
-
Read the UAT `## Gaps` section and the phase dir `*-PLAN.md` frontmatter. For each gap with `status: failed`:
|
|
497
|
-
1. Find a `*-PLAN.md` whose frontmatter `gap_ids` includes the gap's `gap_id` (`G-{phase}-{N}`).
|
|
498
|
-
2. If such a plan exists AND has a matching `*-SUMMARY.md` in the phase dir (the plan was executed by `--gaps-only`), the gap is **resolved** — update its YAML in place:
|
|
499
|
-
```yaml
|
|
500
|
-
- gap_id: G-{phase}-{N}
|
|
501
|
-
status: resolved # was: failed
|
|
502
|
-
resolved_by: {plan basename}
|
|
503
|
-
resolved_at: {today}
|
|
504
|
-
```
|
|
505
|
-
3. If no plan references the `gap_id`, or the plan has no SUMMARY, leave the gap `status: failed` (still open).
|
|
507
|
+
**Reconcile diagnosed gaps against completed gap-closure plans (#1921):** when verify-work resumes after `/gsd:execute-phase --gaps-only`, UAT `## Gaps` entries still read `status: failed` even though their fix plans already executed — without reconciliation they'd be re-diagnosed as fresh blockers. For each `status: failed` gap with a `*-PLAN.md` whose `gap_ids` names it AND a matching `*-SUMMARY.md`, mark it `resolved` (with `resolved_by`/`resolved_at`) in place; otherwise leave it `failed`. Resolved gaps are never re-diagnosed or re-planned; a later regression gets a fresh `gap_id`, not a reopened old one.
|
|
506
508
|
|
|
507
|
-
|
|
508
|
-
```
|
|
509
|
-
Reconciled gap-closure state: {resolved_count} gap(s) resolved by executed plans, {open_count} still open.
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
Resolved gaps are NOT re-diagnosed and do NOT spawn new gap plans. If the user later reports the same behavior as still broken, treat it as a new issue (a regression) with a fresh `gap_id`.
|
|
509
|
+
Exact YAML shape and the announcement line: `gsd-core/workflows/verify-work/detail/elaboration.md` § 1.
|
|
513
510
|
</step>
|
|
514
511
|
|
|
515
512
|
<step name="resume_from_file">
|
|
516
|
-
**Resume testing from UAT file:**
|
|
517
|
-
|
|
518
|
-
**First run `reconcile_gaps`** (above) so gaps already fixed by `/gsd:execute-phase --gaps-only` are marked `resolved` before testing resumes (#1921).
|
|
519
|
-
|
|
520
|
-
Read the full UAT file.
|
|
513
|
+
**Resume testing from UAT file:** first run `reconcile_gaps` (above), then read the full UAT file.
|
|
521
514
|
|
|
522
515
|
Find first test with `result: [pending]`.
|
|
523
516
|
If no `[pending]` test found → go to `complete_session`.
|
|
524
517
|
|
|
525
|
-
|
|
526
|
-
```
|
|
527
|
-
Resuming: Phase {phase} UAT
|
|
528
|
-
Progress: {passed + issues + skipped}/{total}
|
|
529
|
-
Issues found so far: {issues count}
|
|
530
|
-
|
|
531
|
-
Continuing from Test {N}...
|
|
532
|
-
```
|
|
518
|
+
Otherwise announce progress and continue from that test at `present_test`.
|
|
533
519
|
|
|
534
|
-
|
|
535
|
-
Proceed to `present_test`.
|
|
520
|
+
Exact resume-announcement wording: `gsd-core/workflows/verify-work/detail/elaboration.md` § 2.
|
|
536
521
|
</step>
|
|
537
522
|
|
|
538
523
|
<step name="complete_session">
|
|
@@ -570,6 +555,42 @@ Commit the UAT file:
|
|
|
570
555
|
gsd_run query commit "test({phase_num}): complete UAT - {passed} passed, {issues} issues" --files ".planning/phases/XX-name/{phase_num}-UAT.md"
|
|
571
556
|
```
|
|
572
557
|
|
|
558
|
+
**If the UAT file has a non-empty `## Deferred Follow-Ups` section,** those items are currently visible only inside this phase's `*-UAT.md` — offer to promote them to the roadmap backlog so they stay visible at the project level (#4546; reuses the exact entry mechanism `next.md`'s `prior_phase_completeness` step uses for plans-without-summaries):
|
|
559
|
+
|
|
560
|
+
```
|
|
561
|
+
Deferred follow-ups recorded: {N}
|
|
562
|
+
|
|
563
|
+
They currently live only in {phase_num}-UAT.md. Promote them to the ROADMAP.md backlog?
|
|
564
|
+
|
|
565
|
+
[P] Promote to ROADMAP.md 999.x backlog
|
|
566
|
+
[K] Keep them in the UAT file only
|
|
567
|
+
|
|
568
|
+
Choice [K]:
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
(TEXT_MODE: present this as a plain-text numbered list per the text-mode convention and wait for the typed choice.)
|
|
572
|
+
|
|
573
|
+
**If the user chooses [P]:**
|
|
574
|
+
1. Compute the next backlog number: `{backlog_number}` = the smallest positive integer not already used by an existing `### Phase 999.{n}` heading in `.planning/ROADMAP.md` — scan the headings rather than counting them, since numbering may be non-contiguous. If `.planning/ROADMAP.md` does not exist, create it containing only a `## Backlog` section and use `1`.
|
|
575
|
+
2. Append to that `## Backlog` section one backlog entry per deferred follow-up (each with its own `999.{backlog_number}` heading, incrementing per entry), with `test`/`idea`/`deferred_at` verbatim from the section's YAML and `{idea}` flattened to a single line (newlines → spaces — a multi-line response would corrupt the single-line entry; this mirrors `next.md`'s use of a slug for the same reason):
|
|
576
|
+
|
|
577
|
+
```markdown
|
|
578
|
+
### Phase 999.{backlog_number}: Follow-up — Phase {phase_num} deferred UAT follow-up: Test {test} (BACKLOG)
|
|
579
|
+
|
|
580
|
+
**Goal:** Resolve the UAT checkpoint deferred during Phase {phase_num} verification
|
|
581
|
+
**Source phase:** {phase_num}
|
|
582
|
+
**Deferred at:** {date} during /gsd:verify-work {phase} session completion
|
|
583
|
+
**Follow-ups:**
|
|
584
|
+
- [ ] Test {test}: {idea} (deferred {deferred_at})
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
3. Commit the deferral record:
|
|
588
|
+
```bash
|
|
589
|
+
gsd_run query commit "docs: defer Phase {phase_num} UAT follow-ups to backlog" --files .planning/ROADMAP.md
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**If the user chooses [K]:** continue to the summary unchanged — the deferred items remain in the UAT file's `## Deferred Follow-Ups` section.
|
|
593
|
+
|
|
573
594
|
Present summary:
|
|
574
595
|
```
|
|
575
596
|
## UAT Complete: Phase {phase}
|
|
@@ -631,7 +652,7 @@ If an active secure-phase step hook exists AND `SECURITY_FILE` exists: check fro
|
|
|
631
652
|
|
|
632
653
|
If no active secure-phase step hook exists OR (`SECURITY_FILE` exists AND `threats_open` is `0`):
|
|
633
654
|
|
|
634
|
-
If execution verification is waiting only on human UAT and this session recorded zero issues, canonicalize the report before the shared completion predicate:
|
|
655
|
+
If execution verification is waiting only on human UAT and this session recorded zero issues, canonicalize the report before the shared completion predicate. (#4663) Zero issues is NOT pass evidence on its own — blocked rows are not issues by this workflow's own rule, so a session that observed nothing (0 passed / 0 issues / N blocked) must NOT flip the report. The flip runs the SAME UAT-row predicate the phase-close uses, in its `--uat-only` form: it skips the verification-status blockers (the report still reads `human_needed` at this point — the full predicate could never pass here), and `passed` means at least one UAT check passed with no row pending/blocked/failed or skipped without a reason. The flagged transition-gate call below stays the final say on canonical verification:
|
|
635
656
|
|
|
636
657
|
```bash
|
|
637
658
|
PHASE_DIR=$(printf '%s' "$INIT" | jq -r '.phase_dir // empty')
|
|
@@ -640,19 +661,35 @@ VERIFICATION_STATUS=$(gsd_run query verification.status "$PHASE_DIR" 2>/dev/null
|
|
|
640
661
|
VERIFICATION_STATUS_VALUE=$(printf '%s' "$VERIFICATION_STATUS" | jq -r '.status // empty' 2>/dev/null || echo "")
|
|
641
662
|
PHASE_VERIFICATION_STATUS="$VERIFICATION_STATUS_VALUE"
|
|
642
663
|
if [ "$VERIFICATION_STATUS_VALUE" = "human_needed" ]; then
|
|
643
|
-
gsd_run
|
|
664
|
+
UAT_PRECHECK=$(gsd_run phase uat-passed "{phase}" --uat-only 2>/dev/null)
|
|
665
|
+
UAT_PRECHECK_PASSED=$(printf '%s' "$UAT_PRECHECK" | jq -r '.passed // false' 2>/dev/null || echo "false")
|
|
666
|
+
if [ "$UAT_PRECHECK_PASSED" = "true" ]; then
|
|
667
|
+
gsd_run query frontmatter.set "$VERIFICATION_FILE" --field status --value passed
|
|
668
|
+
else
|
|
669
|
+
UAT_BLOCKERS=$(printf '%s' "$UAT_PRECHECK" | jq -r '.blockers | length' 2>/dev/null)
|
|
670
|
+
[ -n "$UAT_BLOCKERS" ] || UAT_BLOCKERS="?"
|
|
671
|
+
echo "NOT canonicalizing: ${UAT_BLOCKERS} UAT row(s) blocked or not passing; verification stays human_needed. Resolve or pass them, then re-run /gsd:verify-work {phase}." >&2
|
|
672
|
+
fi
|
|
644
673
|
fi
|
|
645
674
|
```
|
|
646
675
|
|
|
647
|
-
If `PHASE_VERIFICATION_STATUS` is `stale`,
|
|
676
|
+
If `PHASE_VERIFICATION_STATUS` is `stale`, the covered source files changed after the verifier
|
|
677
|
+
last ran — re-run the VERIFIER, not this workflow (`/gsd:verify-work` never rewrites
|
|
678
|
+
VERIFICATION.md; its only write is the human_needed canonicalization, #4663). Spawn the
|
|
679
|
+
verifier for this phase exactly as execute-phase's `verify_phase_goal` step does (subagent
|
|
680
|
+
`gsd-verifier`; phase directory, goal, requirement IDs, and all SUMMARYs in
|
|
681
|
+
`<required_reading>`), then re-read `verification.status` and continue at the fresh/passed
|
|
682
|
+
case below. (#4682)
|
|
648
683
|
|
|
649
684
|
```
|
|
650
|
-
|
|
685
|
+
Verification is stale: covered source files changed after the verifier last ran.
|
|
651
686
|
|
|
652
687
|
Blocking completion:
|
|
653
688
|
verification is stale
|
|
654
689
|
|
|
655
|
-
-
|
|
690
|
+
- Re-run the verifier for phase {phase} (dispatch `gsd-verifier` as in execute-phase's
|
|
691
|
+
verify_phase_goal step) to regenerate VERIFICATION.md with a fresh digest, then re-run
|
|
692
|
+
`/gsd:verify-work {phase}`
|
|
656
693
|
```
|
|
657
694
|
|
|
658
695
|
Otherwise, check the shared UAT-plus-verification completion predicate before transition:
|
|
@@ -726,138 +763,29 @@ SECURITY: File paths in output are constructed from validated path components on
|
|
|
726
763
|
</step>
|
|
727
764
|
|
|
728
765
|
<step name="diagnose_issues">
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
```
|
|
732
|
-
---
|
|
733
|
-
|
|
734
|
-
{N} issues found. Diagnosing root causes...
|
|
735
|
-
|
|
736
|
-
Spawning parallel debug agents to investigate each issue.
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
- Load diagnose-issues workflow
|
|
740
|
-
- Follow @~/.claude/gsd-core/workflows/diagnose-issues.md
|
|
741
|
-
- Spawn parallel debug agents for each issue
|
|
742
|
-
- Collect root causes
|
|
743
|
-
- Update UAT.md with root causes
|
|
744
|
-
- Proceed to `plan_gap_closure`
|
|
745
|
-
|
|
746
|
-
Diagnosis runs automatically - no user prompt. Parallel agents investigate simultaneously, so overhead is minimal and fixes are more accurate.
|
|
766
|
+
When UAT testing found issues, this sub-flow (diagnose_issues -> plan_gap_closure -> verify_gap_plans -> revision_loop) runs before present_ready; a session with zero issues never reaches it. Spawn parallel debug agents (one per issue, via diagnose-issues.md) to find root causes with no user prompt, then update UAT.md and proceed to plan_gap_closure.
|
|
747
767
|
</step>
|
|
748
768
|
|
|
749
769
|
<step name="plan_gap_closure">
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
Display:
|
|
753
|
-
```
|
|
754
|
-
### GSD ► PLANNING FIXES
|
|
755
|
-
|
|
756
|
-
◆ Spawning planner for gap closure... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
Spawn gsd-planner in --gaps mode:
|
|
760
|
-
|
|
761
|
-
<!-- #2517 model-omit-on-inherit -->
|
|
762
|
-
|
|
763
|
-
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`planner_model`, `checker_model`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
|
764
|
-
|
|
765
|
-
````
|
|
766
|
-
Agent(
|
|
767
|
-
prompt="""
|
|
768
|
-
<planning_context>
|
|
769
|
-
|
|
770
|
-
**Phase:** {phase_number}
|
|
771
|
-
**Mode:** gap_closure
|
|
772
|
-
|
|
773
|
-
<required_reading>
|
|
774
|
-
- {phase_dir}/{phase_num}-UAT.md (UAT with diagnoses)
|
|
775
|
-
- {state_path} (Project State)
|
|
776
|
-
- {roadmap_path} (Roadmap)
|
|
777
|
-
</required_reading>
|
|
778
|
-
|
|
779
|
-
${AGENT_SKILLS_PLANNER}
|
|
780
|
-
|
|
781
|
-
</planning_context>
|
|
782
|
-
|
|
783
|
-
<downstream_consumer>
|
|
784
|
-
Output consumed by /gsd:execute-phase
|
|
785
|
-
Plans must be executable prompts.
|
|
786
|
-
|
|
787
|
-
<!-- #2508 runtime-aware-dispatch -->
|
|
788
|
-
|
|
789
|
-
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
|
790
|
-
|
|
791
|
-
**Gap linkage (#1921):** each created `*-PLAN.md` MUST list the UAT gap ids it addresses in its frontmatter:
|
|
792
|
-
```yaml
|
|
793
|
-
---
|
|
794
|
-
gap_closure: true
|
|
795
|
-
gap_ids: [G-{phase}-{N}, ...] # the ## Gaps gap_id values this plan fixes
|
|
796
|
-
---
|
|
797
|
-
```
|
|
798
|
-
This lets `/gsd:verify-work` reconcile resolved gaps on resume (a gap whose plan has a matching `*-SUMMARY.md` is marked `status: resolved`, not re-diagnosed as a fresh blocker).
|
|
799
|
-
</downstream_consumer>
|
|
800
|
-
""",
|
|
801
|
-
subagent_type="gsd-planner",
|
|
802
|
-
model="{planner_model}",
|
|
803
|
-
description="Plan gap fixes for Phase {phase}"
|
|
804
|
-
)
|
|
805
|
-
````
|
|
770
|
+
Spawn gsd-planner in --gaps mode against the UAT (with diagnoses), `{state_path}` (Project State), and `{roadmap_path}` (Roadmap). Each created PLAN.md MUST carry `gap_closure: true` and `gap_ids: [...]` in its frontmatter (#1921) so a later verify-work resume can reconcile it.
|
|
806
771
|
|
|
772
|
+
<!-- gsd:protected -->
|
|
807
773
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
808
774
|
|
|
809
|
-
|
|
810
|
-
- **PLANNING COMPLETE:** Proceed to `verify_gap_plans`
|
|
811
|
-
- **PLANNING INCONCLUSIVE:** Report and offer manual intervention
|
|
775
|
+
PLANNING COMPLETE proceeds to verify_gap_plans; PLANNING INCONCLUSIVE reports and offers manual intervention.
|
|
812
776
|
</step>
|
|
813
777
|
|
|
814
778
|
<step name="verify_gap_plans">
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
Display:
|
|
818
|
-
```
|
|
819
|
-
### GSD ► VERIFYING FIX PLANS
|
|
820
|
-
|
|
821
|
-
◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
822
|
-
```
|
|
823
|
-
|
|
824
|
-
Initialize: `iteration_count = 1`
|
|
825
|
-
|
|
826
|
-
Spawn gsd-plan-checker:
|
|
827
|
-
|
|
828
|
-
```
|
|
829
|
-
Agent(
|
|
830
|
-
prompt="""
|
|
831
|
-
<verification_context>
|
|
832
|
-
|
|
833
|
-
**Phase:** {phase_number}
|
|
834
|
-
**Phase Goal:** Close diagnosed gaps from UAT
|
|
835
|
-
|
|
836
|
-
<required_reading>
|
|
837
|
-
- {phase_dir}/*-PLAN.md (Plans to verify)
|
|
838
|
-
</required_reading>
|
|
839
|
-
|
|
840
|
-
${AGENT_SKILLS_CHECKER}
|
|
841
|
-
|
|
842
|
-
</verification_context>
|
|
843
|
-
|
|
844
|
-
<expected_output>
|
|
845
|
-
Return one of:
|
|
846
|
-
- ## VERIFICATION PASSED — all checks pass
|
|
847
|
-
- ## ISSUES FOUND — structured issue list
|
|
848
|
-
</expected_output>
|
|
849
|
-
""",
|
|
850
|
-
subagent_type="gsd-plan-checker",
|
|
851
|
-
model="{checker_model}",
|
|
852
|
-
description="Verify Phase {phase} fix plans"
|
|
853
|
-
)
|
|
854
|
-
```
|
|
779
|
+
Spawn gsd-plan-checker against the fix plans (iteration_count starts at 1), model="{checker_model}" (omit on inherit/empty, #2517).
|
|
855
780
|
|
|
781
|
+
<!-- gsd:protected -->
|
|
856
782
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
857
783
|
|
|
858
784
|
On return:
|
|
859
785
|
- **VERIFICATION PASSED:** Proceed to `present_ready`
|
|
860
786
|
- **ISSUES FOUND:** Count BLOCKER + WARNING entries in the YAML issues block; an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed). If zero — every entry is explicitly INFO — display `ℹ advisory — {dimension}: {description}` per entry and proceed to `present_ready`; INFO is advisory and never enters the loop (#3724). Otherwise proceed to `revision_loop`
|
|
787
|
+
|
|
788
|
+
Exact Agent() prompt fields: `gsd-core/workflows/verify-work/detail/elaboration.md` § 2.
|
|
861
789
|
</step>
|
|
862
790
|
|
|
863
791
|
<step name="revision_loop">
|
|
@@ -869,26 +797,6 @@ Display: `Sending back to planner for revision... (iteration {N}/3)`
|
|
|
869
797
|
|
|
870
798
|
Spawn gsd-planner with revision context:
|
|
871
799
|
|
|
872
|
-
```
|
|
873
|
-
Agent(
|
|
874
|
-
prompt="""
|
|
875
|
-
<revision_context>
|
|
876
|
-
|
|
877
|
-
**Phase:** {phase_number}
|
|
878
|
-
**Mode:** revision
|
|
879
|
-
|
|
880
|
-
<required_reading>
|
|
881
|
-
- {phase_dir}/*-PLAN.md (Existing plans)
|
|
882
|
-
</required_reading>
|
|
883
|
-
|
|
884
|
-
${AGENT_SKILLS_PLANNER}
|
|
885
|
-
|
|
886
|
-
**Checker issues:**
|
|
887
|
-
{structured_issues_from_checker}
|
|
888
|
-
|
|
889
|
-
</revision_context>
|
|
890
|
-
|
|
891
|
-
<instructions>
|
|
892
800
|
Read existing PLAN.md files. Make targeted updates to address checker issues.
|
|
893
801
|
|
|
894
802
|
`required_property` + evidence + severity BIND. `fix_hint` is ONE non-binding example route: a
|
|
@@ -900,14 +808,8 @@ the alternatives rather than applying or working around it. Full contract:
|
|
|
900
808
|
`gsd-core/references/planner-revision.md`, which you load in revision mode.
|
|
901
809
|
|
|
902
810
|
Do NOT replan from scratch unless issues are fundamental.
|
|
903
|
-
</instructions>
|
|
904
|
-
""",
|
|
905
|
-
subagent_type="gsd-planner",
|
|
906
|
-
model="{planner_model}",
|
|
907
|
-
description="Revise Phase {phase} plans"
|
|
908
|
-
)
|
|
909
|
-
```
|
|
910
811
|
|
|
812
|
+
<!-- gsd:protected -->
|
|
911
813
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
912
814
|
|
|
913
815
|
**If the planner returns `## REVISION_CONFLICT`:** do NOT increment `iteration_count` and do NOT
|
|
@@ -938,9 +840,12 @@ Offer options:
|
|
|
938
840
|
2. Provide guidance (user gives direction, retry)
|
|
939
841
|
3. Abandon (exit, user runs /gsd:plan-phase manually)
|
|
940
842
|
|
|
941
|
-
|
|
843
|
+
Then wait for the user to pick one.
|
|
844
|
+
|
|
845
|
+
Exact Agent() prompt fields (revision_context, required_reading): `gsd-core/workflows/verify-work/detail/elaboration.md` § 3.
|
|
942
846
|
</step>
|
|
943
847
|
|
|
848
|
+
|
|
944
849
|
<step name="present_ready">
|
|
945
850
|
**Present completion and next steps:**
|
|
946
851
|
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
const fs = require('fs');
|
|
64
64
|
const path = require('path');
|
|
65
65
|
const os = require('os');
|
|
66
|
-
const { readSentinel, VALID_ISOLATION, extractDispatchIdentifiers, sentinelAppliesToDispatch } = require('./lib/isolation-sentinel.js');
|
|
67
|
-
const { REASON_CODE } = require('./lib/isolation-deny-reason.js');
|
|
66
|
+
const { readSentinel, VALID_ISOLATION, extractDispatchIdentifiers, sentinelAppliesToDispatch, buildSentinelDiscard } = require('./lib/isolation-sentinel.js');
|
|
67
|
+
const { REASON_CODE, describeSentinelDiscard } = require('./lib/isolation-deny-reason.js');
|
|
68
68
|
const { HOOK_ON_CRASH, allow, deny, crash } = require('./lib/hook-exit.js');
|
|
69
69
|
|
|
70
70
|
// Required at module top, alongside the other ./lib requires — NOT behind
|
|
@@ -337,6 +337,30 @@ function resolveRegistryIsolation(cwd, configPath) {
|
|
|
337
337
|
if (!useWorktrees) isolation = 'none';
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
+
// #4734: a harness worktree can never be created in a directory that is not
|
|
341
|
+
// a git repository (or a repository with no commits) — git's definitive
|
|
342
|
+
// exit-128 answer on `rev-parse HEAD`. Demanding the isolation flag there
|
|
343
|
+
// blocked every flag-less dispatch the moment the sentinel went stale, on a
|
|
344
|
+
// root where no worktree can exist. Degrade to 'none' exactly like the
|
|
345
|
+
// use_worktrees opt-out above; the classification is owned by
|
|
346
|
+
// `classifyGitHead` (worktree-base-ref.cjs) — the same single owner the
|
|
347
|
+
// base-check's degrade decision uses — and ambiguous or failed resolutions
|
|
348
|
+
// keep the conservative (enforce) default, matching that check's own
|
|
349
|
+
// fail-closed treatment of the same classes.
|
|
350
|
+
if (isolation === 'harness-worktree') {
|
|
351
|
+
try {
|
|
352
|
+
ensureRuntimeBuild();
|
|
353
|
+
const { classifyGitHead } = require('../gsd-core/bin/lib/worktree-base-ref.cjs');
|
|
354
|
+
if (classifyGitHead({ cwd }).status === 'definitive-absence') {
|
|
355
|
+
isolation = 'none';
|
|
356
|
+
}
|
|
357
|
+
} catch {
|
|
358
|
+
// Unbuilt or unreadable runtime library — keep the conservative
|
|
359
|
+
// (enforce) default rather than silently disabling the guard, same
|
|
360
|
+
// posture as the ladder fallback above.
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
340
364
|
return { isolation, harnessFlag };
|
|
341
365
|
}
|
|
342
366
|
|
|
@@ -385,16 +409,20 @@ function resolveIsolationState(cwd, { clock = Date, dispatchIds = null } = {}) {
|
|
|
385
409
|
projectExists = false;
|
|
386
410
|
}
|
|
387
411
|
if (!projectExists) {
|
|
388
|
-
return { gsdProject: false, isolation: null, harnessFlag: null, error: null };
|
|
412
|
+
return { gsdProject: false, isolation: null, harnessFlag: null, error: null, sentinelDiscarded: null };
|
|
389
413
|
}
|
|
390
414
|
|
|
391
415
|
const sentinel = readSentinel(cwd, { clock });
|
|
392
|
-
|
|
416
|
+
// Hoisted so the "sentinel was present/fresh but did not apply" case below
|
|
417
|
+
// (#4594 row 15 — Postel's-Law finding) can distinguish itself from
|
|
418
|
+
// "absent"/"stale" without re-deriving applicability.
|
|
419
|
+
const applies = sentinelAppliesToDispatch(sentinel, dispatchIds);
|
|
420
|
+
if (sentinel.present && !sentinel.stale && applies) {
|
|
393
421
|
if (sentinel.isolation !== 'harness-worktree') {
|
|
394
|
-
return { gsdProject: true, isolation: sentinel.isolation, harnessFlag: null, error: null };
|
|
422
|
+
return { gsdProject: true, isolation: sentinel.isolation, harnessFlag: null, error: null, sentinelDiscarded: null };
|
|
395
423
|
}
|
|
396
424
|
if (sentinel.harnessFlag) {
|
|
397
|
-
return { gsdProject: true, isolation: 'harness-worktree', harnessFlag: sentinel.harnessFlag, error: null };
|
|
425
|
+
return { gsdProject: true, isolation: 'harness-worktree', harnessFlag: sentinel.harnessFlag, error: null, sentinelDiscarded: null };
|
|
398
426
|
}
|
|
399
427
|
// #3045 BLOCKER 2 fix: the sentinel already PROVED this dispatch requires
|
|
400
428
|
// isolation (it resolved harness-worktree) but carries no usable flag —
|
|
@@ -423,6 +451,7 @@ function resolveIsolationState(cwd, { clock = Date, dispatchIds = null } = {}) {
|
|
|
423
451
|
'dispatch-isolation sentinel resolved "harness-worktree" but recorded no harness_flag — ' +
|
|
424
452
|
'cannot verify what parameter the dispatch must carry.'
|
|
425
453
|
),
|
|
454
|
+
sentinelDiscarded: null,
|
|
426
455
|
};
|
|
427
456
|
}
|
|
428
457
|
|
|
@@ -430,11 +459,19 @@ function resolveIsolationState(cwd, { clock = Date, dispatchIds = null } = {}) {
|
|
|
430
459
|
// conservative fallback (#3045 finding — must still cover fail-closed case
|
|
431
460
|
// (a): a project that opted out of worktrees entirely via
|
|
432
461
|
// workflow.use_worktrees).
|
|
462
|
+
//
|
|
463
|
+
// #4594 row 15: a PRESENT, FRESH sentinel that simply does not apply to
|
|
464
|
+
// THIS dispatch (identifiers disagree) is a distinct case from "absent" or
|
|
465
|
+
// "stale" — record what was discarded so evaluateDispatch can name it in a
|
|
466
|
+
// block reason instead of silently falling through to a registry-resolution
|
|
467
|
+
// message that never mentions the sentinel existed.
|
|
468
|
+
const sentinelDiscarded = buildSentinelDiscard(sentinel, dispatchIds);
|
|
469
|
+
|
|
433
470
|
try {
|
|
434
471
|
const { isolation, harnessFlag } = resolveRegistryIsolation(cwd, configPath);
|
|
435
|
-
return { gsdProject: true, isolation, harnessFlag, error: null };
|
|
472
|
+
return { gsdProject: true, isolation, harnessFlag, error: null, sentinelDiscarded };
|
|
436
473
|
} catch (err) {
|
|
437
|
-
return { gsdProject: true, isolation: null, harnessFlag: null, error: err };
|
|
474
|
+
return { gsdProject: true, isolation: null, harnessFlag: null, error: err, sentinelDiscarded };
|
|
438
475
|
}
|
|
439
476
|
}
|
|
440
477
|
|
|
@@ -464,10 +501,16 @@ function evaluateDispatch(data, { clock = Date } = {}) {
|
|
|
464
501
|
}
|
|
465
502
|
|
|
466
503
|
const cwd = data.cwd || process.cwd();
|
|
467
|
-
// #3045 SECURITY F2: best-effort plan/phase extraction from this
|
|
468
|
-
// dispatch's own
|
|
469
|
-
//
|
|
470
|
-
|
|
504
|
+
// #3045 SECURITY F2 / #4594: best-effort plan/phase extraction from this
|
|
505
|
+
// dispatch's own text, so a fresh sentinel that disagrees with THIS
|
|
506
|
+
// dispatch is treated as inapplicable rather than trusted. PROMPT FIRST:
|
|
507
|
+
// `description` is short, model-authored free text that only carries usable
|
|
508
|
+
// identity when the model happens to reproduce the dispatch template
|
|
509
|
+
// verbatim, while the canonical `[gsd:dispatch phase="…" plan="…"]` marker
|
|
510
|
+
// (or, failing that, the prose fallback) lives in the prompt body itself —
|
|
511
|
+
// `description` is kept only as a fallback for a marker/prose match that
|
|
512
|
+
// exists solely in it.
|
|
513
|
+
const dispatchIds = extractDispatchIdentifiers(toolInput.prompt, toolInput.description);
|
|
471
514
|
const state = resolveIsolationState(cwd, { clock, dispatchIds });
|
|
472
515
|
|
|
473
516
|
if (!state.gsdProject) return { action: 'allow' };
|
|
@@ -493,7 +536,8 @@ function evaluateDispatch(data, { clock = Date } = {}) {
|
|
|
493
536
|
`required — a guard that cannot verify must not answer "safe" (#3050). Retry once the ` +
|
|
494
537
|
`project configuration is readable.`;
|
|
495
538
|
const reasonCode = isBuildFailure ? REASON_CODE.RUNTIME_BUILD_FAILED : REASON_CODE.CONFIG_UNREADABLE;
|
|
496
|
-
|
|
539
|
+
const fullReason = state.sentinelDiscarded ? reason + describeSentinelDiscard(state.sentinelDiscarded) : reason;
|
|
540
|
+
return { action: 'block', reason: fullReason, reasonCode, sentinelDiscarded: state.sentinelDiscarded };
|
|
497
541
|
}
|
|
498
542
|
|
|
499
543
|
if (state.isolation !== 'harness-worktree') return { action: 'allow' };
|
|
@@ -503,13 +547,14 @@ function evaluateDispatch(data, { clock = Date } = {}) {
|
|
|
503
547
|
|
|
504
548
|
if (toolInput[parsed.param] === parsed.value) return { action: 'allow' };
|
|
505
549
|
|
|
506
|
-
|
|
550
|
+
let reason =
|
|
507
551
|
`Agent isolation guard: this project's dispatch isolation resolves to "harness-worktree", ` +
|
|
508
552
|
`but the Agent() dispatch for subagent_type="${subagentType}" is missing ` +
|
|
509
553
|
`${parsed.param}="${parsed.value}". Add ${parsed.param}="${parsed.value}" to the Agent() ` +
|
|
510
554
|
`call so the executor runs in an isolated worktree instead of the primary checkout ` +
|
|
511
555
|
`(gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md).`;
|
|
512
|
-
|
|
556
|
+
if (state.sentinelDiscarded) reason += describeSentinelDiscard(state.sentinelDiscarded);
|
|
557
|
+
return { action: 'block', reason, reasonCode: REASON_CODE.HARNESS_FLAG_MISSING, sentinelDiscarded: state.sentinelDiscarded };
|
|
513
558
|
}
|
|
514
559
|
|
|
515
560
|
/* istanbul ignore next -- stdin adapter, exercised via spawnSync in tests */
|
|
@@ -524,7 +569,12 @@ function main() {
|
|
|
524
569
|
const data = JSON.parse(input);
|
|
525
570
|
const decision = evaluateDispatch(data);
|
|
526
571
|
if (decision.action === 'block') {
|
|
527
|
-
const out = {
|
|
572
|
+
const out = {
|
|
573
|
+
decision: 'block',
|
|
574
|
+
reason: decision.reason,
|
|
575
|
+
reason_code: decision.reasonCode,
|
|
576
|
+
sentinel_discarded: decision.sentinelDiscarded ?? null,
|
|
577
|
+
};
|
|
528
578
|
// Kimi feeds stderr (not stdout) back to the model on exit 2.
|
|
529
579
|
deny(out, decision.reason);
|
|
530
580
|
}
|