@opengsd/gsd-core 1.10.0 → 1.12.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/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +12 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +22 -14
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +5 -3
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +23 -2
- package/agents/gsd-plan-checker.md +50 -53
- package/agents/gsd-planner.md +50 -50
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +13 -4
- package/bin/install.js +1448 -1103
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/quick.md +9 -5
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +1035 -138
- package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
- package/gsd-core/bin/lib/api-coverage.cjs +33 -14
- package/gsd-core/bin/lib/artifacts.cjs +5 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +1026 -268
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +845 -130
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +700 -40
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +216 -42
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +1172 -108
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
- package/gsd-core/bin/lib/config-loader.cjs +187 -23
- package/gsd-core/bin/lib/config.cjs +102 -3
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +208 -33
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +899 -229
- package/gsd-core/bin/lib/gap-checker.cjs +95 -10
- package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
- package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +439 -168
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +811 -259
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
- package/gsd-core/bin/lib/install-profiles.cjs +212 -61
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +170 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +183 -22
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +842 -73
- package/gsd-core/bin/lib/model-catalog.cjs +232 -16
- package/gsd-core/bin/lib/model-resolver.cjs +193 -68
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
- package/gsd-core/bin/lib/phase-id.cjs +514 -40
- package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
- package/gsd-core/bin/lib/phase-locator.cjs +262 -34
- package/gsd-core/bin/lib/phase.cjs +1038 -214
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +98 -3
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
- package/gsd-core/bin/lib/probe-core.cjs +5 -2
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
- package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +442 -96
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
- package/gsd-core/bin/lib/smart-entry.cjs +133 -23
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +52 -19
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +338 -8
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +846 -176
- package/gsd-core/bin/lib/state.cjs +2589 -369
- package/gsd-core/bin/lib/surface.cjs +33 -11
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
- package/gsd-core/bin/lib/uat.cjs +1761 -167
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
- package/gsd-core/bin/lib/unusable-input.cjs +37 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +75 -0
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +272 -9
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +453 -918
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
- package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +44 -26
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +39 -21
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +4 -6
- package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +17 -11
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +5 -4
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +61 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +44 -13
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +5 -5
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -17
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +5 -4
- package/gsd-core/templates/state.md +11 -4
- package/gsd-core/templates/verification-report.md +9 -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 +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +13 -20
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +11 -27
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +64 -5
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
- package/gsd-core/workflows/code-review-fix.md +38 -11
- package/gsd-core/workflows/code-review.md +159 -52
- package/gsd-core/workflows/complete-milestone.md +151 -23
- package/gsd-core/workflows/debug.md +12 -8
- package/gsd-core/workflows/diagnose-issues.md +47 -15
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +27 -2
- package/gsd-core/workflows/eval-review.md +7 -14
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
- 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 +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +72 -100
- package/gsd-core/workflows/execute-plan.md +52 -15
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +76 -10
- package/gsd-core/workflows/import.md +18 -15
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +49 -16
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +8 -5
- package/gsd-core/workflows/new-milestone.md +22 -29
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +26 -40
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +14 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +162 -59
- package/gsd-core/workflows/plan-review-convergence.md +96 -11
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +61 -18
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
- package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
- package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +55 -44
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +219 -20
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +69 -7
- package/gsd-core/workflows/ship.md +116 -50
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +53 -13
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +64 -9
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +49 -14
- package/gsd-core/workflows/ui-phase.md +15 -21
- package/gsd-core/workflows/ui-review.md +8 -12
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +7 -11
- package/gsd-core/workflows/validate-phase.md +3 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +66 -25
- package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
- package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +37 -27
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +55 -32
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +231 -24
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +162 -46
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +9 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +158 -30
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +2 -3
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +83 -3
- package/hooks/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +37 -27
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +55 -32
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +231 -24
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +162 -46
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +9 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +28 -11
- package/pi/gsd.cjs +19 -5
- package/scripts/base64-scan.sh +74 -12
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/build-hooks.js +5 -0
- package/scripts/changeset/lint.cjs +60 -5
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +64 -14
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +11 -21
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +138 -25
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +308 -0
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +492 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +471 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +488 -0
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +950 -0
- package/scripts/lint-test-file-count.allowlist.json +137 -8
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +830 -0
- package/scripts/lint-vendored-deps.cjs +297 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +100 -14
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +24 -7
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +0 -1
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +9 -5
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -107
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -574
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -37,8 +37,8 @@ echo "$ARGUMENTS" | grep -qE '\-\-ws\s+\S+' && GSD_WS=$(echo "$ARGUMENTS" | grep
|
|
|
37
37
|
## 1.5. Config Gate (feature disabled by default)
|
|
38
38
|
|
|
39
39
|
```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}"; if [ -f "$
|
|
41
|
-
CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence 2>/dev/null || echo "false")
|
|
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; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
41
|
+
CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence --raw 2>/dev/null || echo "false")
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
**If `CONVERGENCE_ENABLED` is not `"true"`:** Display and exit:
|
|
@@ -134,9 +134,7 @@ PHASE_INFO=$(gsd_run roadmap get-phase "${PHASE}")
|
|
|
134
134
|
Display startup banner:
|
|
135
135
|
|
|
136
136
|
```text
|
|
137
|
-
|
|
138
|
-
GSD ► PLAN CONVERGENCE — Phase {phase_number}
|
|
139
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
137
|
+
### GSD ► PLAN CONVERGENCE — Phase {phase_number}
|
|
140
138
|
|
|
141
139
|
Reviewers: {REVIEWER_DISPLAY}
|
|
142
140
|
Max cycles: {MAX_CYCLES}
|
|
@@ -156,9 +154,12 @@ Skill(skill="gsd-plan-phase", args="{PHASE} {GSD_WS}")
|
|
|
156
154
|
|
|
157
155
|
Run plan-phase **inline** (do NOT wrap it in Agent()). The convergence orchestrator runs at depth 0 with Agent available, so inline plan-phase can spawn gsd-planner and gsd-plan-checker at depth 1 — the one level of nesting that works on Claude Code. Wrapping plan-phase in Agent() would push it to depth 1 where the Agent tool is absent, preventing it from spawning any sub-agents. Wait until plan-phase completes and PLAN.md files are committed before continuing.
|
|
158
156
|
|
|
159
|
-
After plan-phase completes, verify plans were created
|
|
157
|
+
After plan-phase completes, verify plans were created. This asks "did initial
|
|
158
|
+
planning write files to disk" — a planner-produced-nothing check, not
|
|
159
|
+
outstanding-work counting — so it takes the PHYSICAL set (`plan_count_all`,
|
|
160
|
+
`status: superseded` INCLUDED, #3218):
|
|
160
161
|
```bash
|
|
161
|
-
PLAN_COUNT=$(
|
|
162
|
+
PLAN_COUNT=$(gsd_run query find-phase "${PHASE}" | jq -r '.plan_count_all // 0')
|
|
162
163
|
```
|
|
163
164
|
|
|
164
165
|
If PLAN_COUNT == 0: Error — initial planning failed. Exit.
|
|
@@ -197,9 +198,50 @@ Your final response MUST include a machine-readable line of exactly this form:
|
|
|
197
198
|
Where <N> is the integer count of HIGH-severity concerns that REMAIN UNRESOLVED in this cycle's findings.
|
|
198
199
|
Where <M> is the integer count of actionable MEDIUM/LOW concerns that REMAIN UNRESOLVED because the latest PLAN.md files do not yet incorporate them or explicitly defer/reject them.
|
|
199
200
|
|
|
201
|
+
Consensus gate (applies to NEWLY RAISED HIGHs only; evaluate before the counting rules below):
|
|
202
|
+
This gate engages ONLY when 2 or more reviewers actually ran and produced a review section this
|
|
203
|
+
cycle. With exactly one reviewer, skip this entire gate — a single reviewer's HIGH always counts,
|
|
204
|
+
exactly as before.
|
|
205
|
+
|
|
206
|
+
Classify each newly raised HIGH by what the claim ASSERTS, not by whether it happens to contain a
|
|
207
|
+
file:line citation:
|
|
208
|
+
- EXISTENCE-CLASS — asserts that a named symbol, file, path, flag, commit, or ID exists,
|
|
209
|
+
is absent, or says something specific ("X does not exist", "the plan cites Y which is missing",
|
|
210
|
+
"file Z contains Q").
|
|
211
|
+
- JUDGMENT-CLASS — asserts a design or correctness property ("no idempotency on retried writes",
|
|
212
|
+
"race between A and B", "missing rate limit"). A judgment-class HIGH stays judgment-class even
|
|
213
|
+
when it cites a file for context.
|
|
214
|
+
|
|
215
|
+
A HIGH raised by 2+ reviewers is corroborated and always counts.
|
|
216
|
+
|
|
217
|
+
For a HIGH raised by exactly ONE reviewer:
|
|
218
|
+
- EXISTENCE-CLASS — counts only if the source-grounding pass independently confirms it against
|
|
219
|
+
real project source, or another reviewer raised the same or a materially overlapping concern
|
|
220
|
+
(i.e. it lands in REVIEWS.md's Consensus Summary "Agreed Concerns").
|
|
221
|
+
- JUDGMENT-CLASS — counts UNLESS that reviewer's own section OPENS with an evidence-quality
|
|
222
|
+
discount marker blockquote: `[reviewed-without-source-citations]` or
|
|
223
|
+
`[reviewed-without-repo-access]`, or the reviewer is a diff-only lane (CodeRabbit). The marker
|
|
224
|
+
must be the LEADING blockquote of that reviewer's section — a review that merely quotes a
|
|
225
|
+
marker while discussing it is NOT marked. Corroboration by another reviewer overrides the
|
|
226
|
+
marker and the HIGH counts.
|
|
227
|
+
|
|
228
|
+
Judgment-class findings are deliberately NOT subject to corroboration. Different reviewers catch
|
|
229
|
+
materially different classes of issue, so requiring two of them to independently raise the same
|
|
230
|
+
architectural concern would suppress exactly the findings a multi-reviewer setup exists to surface.
|
|
231
|
+
|
|
232
|
+
FAIL OPEN: if EVERY reviewer that ran this cycle carries a discount marker, this gate does not
|
|
233
|
+
apply at all — count as if it were absent. A gate must never manufacture convergence out of a
|
|
234
|
+
cycle in which nothing was verified.
|
|
235
|
+
|
|
236
|
+
A HIGH suppressed by this gate is still listed under "## Current HIGH Concerns", tagged
|
|
237
|
+
`(single-reviewer, unconfirmed)`. It is excluded from current_high only — never silently dropped,
|
|
238
|
+
and never removed from the report.
|
|
239
|
+
|
|
240
|
+
This gate governs current_high only. current_actionable is unaffected.
|
|
241
|
+
|
|
200
242
|
Counting rules:
|
|
201
243
|
INCLUDE in the count:
|
|
202
|
-
- Newly raised HIGHs in this cycle
|
|
244
|
+
- Newly raised HIGHs in this cycle (subject to the consensus gate above)
|
|
203
245
|
- PARTIALLY RESOLVED HIGHs: concern acknowledged and a mitigation is in progress, but not yet verified/completed
|
|
204
246
|
- Previously raised HIGHs that are still unresolved
|
|
205
247
|
|
|
@@ -254,6 +296,51 @@ Run this pass unless `plan_review.source_grounding` is `false`. It verifies ever
|
|
|
254
296
|
- Signature mismatches cannot be asserted under `grep`/`intel`; report the signature as UNCHECKABLE.
|
|
255
297
|
5. **Coverage block.** Append a "Verification coverage" section to `REVIEWS.md` listing every UNCHECKABLE/skipped symbol and why — a clean review must never silently mean "nothing was checked."
|
|
256
298
|
|
|
299
|
+
### Cross-artifact fact-drift pass (same gate: `plan_review.source_grounding`)
|
|
300
|
+
|
|
301
|
+
Run this pass whenever the source-grounding pass ran — it is the second axis of the same drift guard, gated by the same `plan_review.source_grounding` key and adding no config surface of its own. Where source-grounding asks *"does this symbol exist in the source?"*, this asks *"does the project state the same fact in two planning artifacts, and do the two disagree?"* Because each phase runs in a fresh context, an agent typically reads only one artifact and trusts it, so a stale duplicate silently steers it wrong.
|
|
302
|
+
|
|
303
|
+
**Key on knowledge, not on similar text.** DRY is about a single authoritative representation of a piece of *knowledge*. Two passages that merely read alike, or that restate one fact at different levels of detail, are NOT drift. Only a contradiction is.
|
|
304
|
+
|
|
305
|
+
1. **Phase status — decided by the seam, not by judgment.** Do not eyeball this axis:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
DRIFT=$(gsd_run drift-guard phase-status --phase "${PHASE}")
|
|
309
|
+
# $DRIFT is JSON: {"verdict":"consistent|lag|drifted|uncheckable","stateStatus":…,"roadmapStatus":…}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
- `drifted` — STATE.md and ROADMAP.md contradict each other. Report it; the authority is STATE.md.
|
|
313
|
+
- `lag` — one lifecycle step apart between non-terminal statuses. NOT a finding.
|
|
314
|
+
- `consistent` — nothing to report.
|
|
315
|
+
- `uncheckable` — a document was absent or carried a status outside both vocabularies. Record it in the coverage block; never read it as consistent.
|
|
316
|
+
|
|
317
|
+
Completeness is terminal: when exactly one side says the phase is complete, the verdict is `drifted` and never `lag`, however few steps apart the two words look.
|
|
318
|
+
|
|
319
|
+
2. **Pair up the remaining facts by judgment.** The authority column names the source of truth, so a finding can say which side to keep:
|
|
320
|
+
|
|
321
|
+
| Fact class | Artifact pair | Authority | Decided by |
|
|
322
|
+
|---|---|---|---|
|
|
323
|
+
| Success criteria / must-have truths | ROADMAP.md Success Criteria ↔ PLAN.md `must_haves.truths` | ROADMAP.md | judgment |
|
|
324
|
+
| Requirement IDs | ROADMAP.md `**Requirements:**` ↔ PLAN.md task requirement refs | ROADMAP.md | judgment |
|
|
325
|
+
| Phase status | STATE.md status ↔ ROADMAP.md phase state | STATE.md | step 1 (deterministic) |
|
|
326
|
+
| Glossary / domain term | CONTEXT.md `Decisions` ↔ PLAN.md usage of the term | CONTEXT.md | judgment |
|
|
327
|
+
|
|
328
|
+
3. **Judge each judgment pair.** FLAG only when ALL THREE hold:
|
|
329
|
+
|
|
330
|
+
1. both sides name the *same* fact — same requirement ID, same success criterion, or the same defined term; and
|
|
331
|
+
2. the two representations *contradict*, one asserting what the other denies, rather than differing in wording or in level of detail; and
|
|
332
|
+
3. the pair is one of the judgment pairs above.
|
|
333
|
+
|
|
334
|
+
4. **Record.** Emit each finding into `REVIEWS.md` beside the source-grounding coverage block, quoting both locations and naming the divergence and the authority, so the author can collapse the two copies to a single source of truth.
|
|
335
|
+
|
|
336
|
+
**Do NOT flag:** a wording-only difference that asserts the same thing; a fact that appears in one artifact only — single-source is the target state, not a finding; a PLAN that ADDS a truth beyond the roadmap Success Criteria, which is sanctioned (plans may add, never subtract); a `lag` verdict from step 1 — two non-terminal statuses a single lifecycle step apart, in either direction, since STATE.md is written at planning time independently of ROADMAP.md and can lead as readily as trail (a disagreement about *completion* is never lag, and step 1 already reports it as `drifted`); anything under CONTEXT.md's `Claude's Discretion` or `Deferred Ideas`, which are non-authoritative by design.
|
|
337
|
+
|
|
338
|
+
**Report once, not twice — these belong to `gsd-plan-checker`:** a PLAN that omits a roadmap Success Criterion is scope reduction (Dimension 7b); a requirement ID the ROADMAP never defines is requirement coverage (Dimension 1); two PLAN.md files in one phase disagreeing is cross-plan data contracts (Dimension 9).
|
|
339
|
+
|
|
340
|
+
**Severity: advisory, never a blocker.** This pass never sets `hardBlock`, and its findings contribute to neither `HIGH_COUNT` nor `ACTIONABLE_COUNT` — a project carrying pre-existing drift must still be able to converge, or an advisory check becomes an endless replan loop.
|
|
341
|
+
|
|
342
|
+
**Coverage, never silence.** If STATE.md or CONTEXT.md is absent, that axis is skipped and the skip is recorded in the same "Verification coverage" block. A clean pass must never mean "nothing was compared."
|
|
343
|
+
|
|
257
344
|
After agent returns, verify REVIEWS.md exists:
|
|
258
345
|
```bash
|
|
259
346
|
REVIEWS_FILE=$(ls ${phase_dir}/${padded_phase}-REVIEWS.md 2>/dev/null)
|
|
@@ -311,9 +398,7 @@ gsd_run state planned-phase --phase "${PHASE}" --name "${phase_name}" --plans "$
|
|
|
311
398
|
|
|
312
399
|
Display:
|
|
313
400
|
```text
|
|
314
|
-
|
|
315
|
-
GSD ► CONVERGENCE COMPLETE ✓
|
|
316
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
401
|
+
### GSD ► CONVERGENCE COMPLETE ✓
|
|
317
402
|
|
|
318
403
|
Phase {phase_number} converged in {cycle} cycle(s).
|
|
319
404
|
No HIGH concerns remaining.
|
|
@@ -135,8 +135,8 @@ Store relevant file paths as `$BREADCRUMBS`.
|
|
|
135
135
|
|
|
136
136
|
<step name="commit-seed">
|
|
137
137
|
```bash
|
|
138
|
-
_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}"; if [ -f "$
|
|
139
|
-
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
|
|
138
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
139
|
+
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
|
|
140
140
|
gsd_run query commit "docs: plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md
|
|
141
141
|
```
|
|
142
142
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
<purpose>
|
|
2
|
-
Create a clean branch for pull requests by filtering
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
Create a clean branch for pull requests by filtering .planning/ paths out of the
|
|
3
|
+
cherry-picked history. Two modes, selected by the `planning.pr_strict` config key:
|
|
4
|
+
|
|
5
|
+
- **default** (`planning.pr_strict: false`) — the PR branch contains code changes and
|
|
6
|
+
structural planning state. Reviewers don't see GSD transient artifacts (PLAN.md,
|
|
7
|
+
SUMMARY.md, CONTEXT.md, RESEARCH.md, etc.), but milestone archives, STATE.md,
|
|
8
|
+
ROADMAP.md, and PROJECT.md changes are preserved.
|
|
9
|
+
- **strict** (`planning.pr_strict: true`) — *every* .planning/ path is filtered out,
|
|
10
|
+
structural files included. This is what makes `planning.commit_docs: true` safe for a
|
|
11
|
+
project that versions its planning tree locally but publishes none of it: planning state
|
|
12
|
+
keeps real git history (so `/gsd:undo` and revert paths have something to restore) and
|
|
13
|
+
executor worktrees still find their PLAN.md, while the public PR carries nothing from
|
|
14
|
+
`.planning/`.
|
|
6
15
|
|
|
7
16
|
Uses git cherry-pick with path filtering to rebuild a clean history.
|
|
8
17
|
</purpose>
|
|
@@ -14,7 +23,7 @@ Parse `$ARGUMENTS` for target branch. If no argument is supplied, detect the
|
|
|
14
23
|
default branch via the single resolver (#1146).
|
|
15
24
|
|
|
16
25
|
```bash
|
|
17
|
-
_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}"; if [ -f "$
|
|
26
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
18
27
|
CURRENT_BRANCH=$(git branch --show-current)
|
|
19
28
|
TARGET=${1:-$(gsd_run query git.base-branch)}
|
|
20
29
|
```
|
|
@@ -22,6 +31,7 @@ TARGET=${1:-$(gsd_run query git.base-branch)}
|
|
|
22
31
|
Check preconditions:
|
|
23
32
|
- Must be on a feature branch (not main/master)
|
|
24
33
|
- Must have commits ahead of target
|
|
34
|
+
- Working tree must be clean
|
|
25
35
|
|
|
26
36
|
```bash
|
|
27
37
|
AHEAD=$(git rev-list --count "$TARGET".."$CURRENT_BRANCH" 2>/dev/null)
|
|
@@ -29,17 +39,36 @@ if [ "$AHEAD" = "0" ]; then
|
|
|
29
39
|
echo "No commits ahead of $TARGET — nothing to filter."
|
|
30
40
|
exit 0
|
|
31
41
|
fi
|
|
42
|
+
|
|
43
|
+
# The filter below removes files from the index AND the working tree before each
|
|
44
|
+
# commit lands, and this command switches branches underneath the user's own
|
|
45
|
+
# checkout. An uncommitted edit to a tracked file would be destroyed by that, and
|
|
46
|
+
# git cherry-pick refuses to run against a dirty tree anyway — so fail here, where
|
|
47
|
+
# the message is legible, rather than midway through the cherry-pick loop.
|
|
48
|
+
DIRTY=$(git status --porcelain --untracked-files=no)
|
|
49
|
+
if [ -n "$DIRTY" ]; then
|
|
50
|
+
echo "Working tree has uncommitted changes — commit or stash them first:" >&2
|
|
51
|
+
echo "$DIRTY" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Resolve the filter mode from config. A non-zero exit or an unset key means the default
|
|
57
|
+
mode; only the literal string `true` selects strict.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
PR_STRICT=$(gsd_run query config-get planning.pr_strict --raw 2>/dev/null)
|
|
61
|
+
if [ "$PR_STRICT" = "true" ]; then PR_MODE="strict"; else PR_MODE="default"; PR_STRICT="false"; fi
|
|
32
62
|
```
|
|
33
63
|
|
|
34
64
|
Display:
|
|
35
65
|
```
|
|
36
|
-
|
|
37
|
-
GSD ► PR BRANCH
|
|
38
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
66
|
+
### GSD ► PR BRANCH
|
|
39
67
|
|
|
40
68
|
Branch: {CURRENT_BRANCH}
|
|
41
69
|
Target: {TARGET}
|
|
42
70
|
Commits: {AHEAD} ahead
|
|
71
|
+
Mode: {PR_MODE} (planning.pr_strict={PR_STRICT})
|
|
43
72
|
```
|
|
44
73
|
</step>
|
|
45
74
|
|
|
@@ -207,47 +236,62 @@ Classify commits:
|
|
|
207
236
|
git log --oneline "$TARGET".."$CURRENT_BRANCH" --no-merges
|
|
208
237
|
```
|
|
209
238
|
|
|
210
|
-
**
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
239
|
+
**Canonical path declarations.** These two lines are the single source of truth for the
|
|
240
|
+
whole command. `create_pr_branch` derives *which paths it removes* from them, and `verify`
|
|
241
|
+
derives *which paths must not appear* from the same two lines — so the two steps cannot
|
|
242
|
+
disagree about what the filter promised. Declare them exactly once; do not restate either
|
|
243
|
+
list anywhere else in this file.
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# Transient planning subdirectories — reviewer noise (PLAN.md, SUMMARY.md, CONTEXT.md,
|
|
247
|
+
# RESEARCH.md, and friends). Filtered out in BOTH modes.
|
|
248
|
+
TRANSIENT_DIRS="phases quick research threads todos debug seeds codebase ui-reviews"
|
|
249
|
+
|
|
250
|
+
# Structural planning files — repository planning state. Preserved in default mode,
|
|
251
|
+
# filtered out in strict mode. Anchored on both alternatives so `.planning/STATEX.md`
|
|
252
|
+
# and `.planning/STATE.md.bak` are NOT treated as structural.
|
|
253
|
+
STRUCTURAL_RE="^\.planning/(STATE|ROADMAP|MILESTONES|PROJECT|REQUIREMENTS)\.md$|^\.planning/milestones/"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Derive the mode's two projections — `FILTER_PATHS` (what `create_pr_branch` removes from
|
|
257
|
+
each cherry-picked commit) and `FORBIDDEN_RE` (what `verify` asserts is absent):
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
if [ "$PR_STRICT" = "true" ]; then
|
|
261
|
+
FILTER_PATHS=".planning/"
|
|
262
|
+
FORBIDDEN_RE="^\.planning/"
|
|
263
|
+
else
|
|
264
|
+
FILTER_PATHS=$(for d in $TRANSIENT_DIRS; do printf '.planning/%s/ ' "$d"; done)
|
|
265
|
+
FORBIDDEN_RE="^\.planning/($(echo "$TRANSIENT_DIRS" | tr ' ' '|'))/"
|
|
266
|
+
fi
|
|
267
|
+
```
|
|
228
268
|
|
|
229
269
|
For each commit, check what it touches:
|
|
230
270
|
|
|
231
271
|
```bash
|
|
232
272
|
# For each commit hash
|
|
233
273
|
FILES=$(git diff-tree --no-commit-id --name-only -r $HASH)
|
|
234
|
-
NON_PLANNING=$(echo "$FILES" | grep -v "^\.planning/"
|
|
235
|
-
STRUCTURAL=$(echo "$FILES" | grep -
|
|
236
|
-
TRANSIENT_ONLY=$(echo "$FILES" | grep "^\.planning/" | grep -vE "^\.planning/(STATE|ROADMAP|MILESTONES|PROJECT|REQUIREMENTS)\.md|^\.planning/milestones/" | wc -l)
|
|
274
|
+
NON_PLANNING=$(echo "$FILES" | grep -c -v "^\.planning/" || true)
|
|
275
|
+
STRUCTURAL=$(echo "$FILES" | grep -Ec "$STRUCTURAL_RE" || true)
|
|
237
276
|
```
|
|
238
277
|
|
|
239
278
|
Classify:
|
|
240
|
-
- **Code commits**:
|
|
241
|
-
- **
|
|
242
|
-
|
|
243
|
-
- **
|
|
279
|
+
- **Code commits**: touch at least one non-`.planning/` file → INCLUDE (both modes)
|
|
280
|
+
- **Mixed commits**: touch code + any planning files → INCLUDE (both modes; the planning
|
|
281
|
+
paths are filtered out by `create_pr_branch`, not the commit)
|
|
282
|
+
- **Structural planning commits**: touch only structural `.planning/` files → INCLUDE in
|
|
283
|
+
**default** mode; **EXCLUDE** in strict mode, which has no structural carve-out
|
|
284
|
+
- **Transient planning commits**: touch only `.planning/` paths that are not structural →
|
|
285
|
+
EXCLUDE (both modes)
|
|
286
|
+
|
|
287
|
+
In strict mode this collapses to a single rule: `NON_PLANNING > 0` → INCLUDE, else EXCLUDE.
|
|
244
288
|
|
|
245
289
|
Display analysis:
|
|
246
290
|
```
|
|
247
|
-
Commits to include: {N} (code changes + structural planning)
|
|
248
|
-
Commits to exclude: {N} (
|
|
249
|
-
Mixed commits: {N} (code + planning — included)
|
|
250
|
-
Structural planning commits: {N} (
|
|
291
|
+
Commits to include: {N} (code changes{, + structural planning — default mode only})
|
|
292
|
+
Commits to exclude: {N} (planning-only)
|
|
293
|
+
Mixed commits: {N} (code + planning — included, planning paths filtered)
|
|
294
|
+
Structural planning commits: {N} ({included|excluded — strict mode})
|
|
251
295
|
```
|
|
252
296
|
</step>
|
|
253
297
|
|
|
@@ -259,18 +303,69 @@ PR_BRANCH="${CURRENT_BRANCH}-pr"
|
|
|
259
303
|
git checkout -b "$PR_BRANCH" "$TARGET"
|
|
260
304
|
```
|
|
261
305
|
|
|
262
|
-
Cherry-pick
|
|
306
|
+
Cherry-pick the included commits, in order, filtering `$FILTER_PATHS` out of each one.
|
|
307
|
+
|
|
308
|
+
The filter forces every filtered path back to **exactly what the PR branch's HEAD already
|
|
309
|
+
has**, in both the index and the working tree. That is stricter than simply un-staging, and
|
|
310
|
+
both halves matter:
|
|
311
|
+
|
|
312
|
+
- `git rm -r -f --ignore-unmatch` clears the index entry (including an unmerged one) and
|
|
313
|
+
removes the file the pick just wrote. It only ever touches paths that are in the index, so
|
|
314
|
+
a genuinely untracked planning file of the user's is never harmed.
|
|
315
|
+
- `git checkout HEAD --` then restores whatever the target branch legitimately tracks at
|
|
316
|
+
those paths. **Without this, un-staging a path the target branch already tracks records a
|
|
317
|
+
DELETION** — the generated PR would remove the base branch's planning files. In strict mode
|
|
318
|
+
that would be the base's entire `.planning/` tree.
|
|
319
|
+
|
|
320
|
+
Leaving the filtered file behind in the working tree is not an option either: a later commit
|
|
321
|
+
touching the same planning path makes `git cherry-pick` abort with *"untracked working tree
|
|
322
|
+
files would be overwritten by merge"*, and every remaining commit is silently dropped.
|
|
263
323
|
|
|
264
324
|
```bash
|
|
265
|
-
for HASH in $
|
|
266
|
-
|
|
267
|
-
#
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
for
|
|
271
|
-
git rm -r --
|
|
325
|
+
for HASH in $INCLUDED_COMMITS; do
|
|
326
|
+
# A modify/delete conflict on a filtered path is EXPECTED and is resolved below — the
|
|
327
|
+
# filtered path is absent from HEAD by construction. Do not treat it as a failure here.
|
|
328
|
+
git cherry-pick --no-commit "$HASH" || true
|
|
329
|
+
|
|
330
|
+
for P in $FILTER_PATHS; do
|
|
331
|
+
git rm -r -f -q --ignore-unmatch -- "$P" 2>/dev/null || true
|
|
332
|
+
git checkout HEAD -- "$P" 2>/dev/null || true
|
|
272
333
|
done
|
|
273
|
-
|
|
334
|
+
|
|
335
|
+
# Anything still unmerged is a REAL conflict, outside the filter. Halt — do not
|
|
336
|
+
# improvise a resolution and do not continue, which would drop the rest of the queue.
|
|
337
|
+
# Unwind first: this loop runs in the user's own checkout, so exiting mid-sequence
|
|
338
|
+
# would strand them on a half-built branch with cherry-pick state still live.
|
|
339
|
+
if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
|
|
340
|
+
echo "Conflict outside the .planning/ filter while picking $HASH:" >&2
|
|
341
|
+
git diff --name-only --diff-filter=U >&2
|
|
342
|
+
# Order matters. `--quit` drops the sequencer state but leaves the unmerged index
|
|
343
|
+
# in place, and an unmerged index makes `git checkout` refuse — so reset first.
|
|
344
|
+
# $PR_BRANCH is disposable and every commit on it was cherry-picked, and the
|
|
345
|
+
# clean-tree precondition guarantees the user had nothing uncommitted, so a hard
|
|
346
|
+
# reset here cannot destroy anything of theirs.
|
|
347
|
+
git cherry-pick --quit 2>/dev/null || true
|
|
348
|
+
git reset -q --hard HEAD
|
|
349
|
+
if git checkout -q "$CURRENT_BRANCH"; then
|
|
350
|
+
git branch -q -D "$PR_BRANCH" 2>/dev/null || true
|
|
351
|
+
echo "Restored $CURRENT_BRANCH and removed the partial $PR_BRANCH." >&2
|
|
352
|
+
else
|
|
353
|
+
# Never claim a restore that did not happen — say exactly where they are.
|
|
354
|
+
echo "Could not return to $CURRENT_BRANCH; you are still on $PR_BRANCH." >&2
|
|
355
|
+
echo "Run: git checkout $CURRENT_BRANCH && git branch -D $PR_BRANCH" >&2
|
|
356
|
+
fi
|
|
357
|
+
echo "Resolve the conflict against $TARGET, then re-run /gsd:pr-branch." >&2
|
|
358
|
+
exit 1
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# Nothing left after filtering (possible when a pick's only surviving content was
|
|
362
|
+
# planning state): clear the sequencer rather than failing on an empty commit.
|
|
363
|
+
if git diff --cached --quiet; then
|
|
364
|
+
git cherry-pick --quit 2>/dev/null || true
|
|
365
|
+
continue
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
git commit -q -C "$HASH"
|
|
274
369
|
done
|
|
275
370
|
```
|
|
276
371
|
|
|
@@ -281,20 +376,50 @@ git checkout "$CURRENT_BRANCH"
|
|
|
281
376
|
</step>
|
|
282
377
|
|
|
283
378
|
<step name="verify">
|
|
379
|
+
Assert against the **active mode's** contract — `$FORBIDDEN_RE`, the same declaration
|
|
380
|
+
`create_pr_branch` filtered on. Counting every `.planning/` path unconditionally would
|
|
381
|
+
contradict default mode, which is specified to preserve structural files: a correct run
|
|
382
|
+
would report itself as failed on every phase that touched STATE.md, which is every phase.
|
|
383
|
+
|
|
284
384
|
```bash
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
385
|
+
DIFF_PATHS=$(git diff --name-only "$TARGET".."$PR_BRANCH")
|
|
386
|
+
FORBIDDEN=$(echo "$DIFF_PATHS" | grep -Ec "$FORBIDDEN_RE" || true)
|
|
387
|
+
PLANNING_TOTAL=$(echo "$DIFF_PATHS" | grep -c "^\.planning/" || true)
|
|
388
|
+
ALLOWED=$((PLANNING_TOTAL - FORBIDDEN))
|
|
389
|
+
TOTAL_FILES=$(echo "$DIFF_PATHS" | grep -c . || true)
|
|
288
390
|
PR_COMMITS=$(git rev-list --count "$TARGET".."$PR_BRANCH")
|
|
391
|
+
|
|
392
|
+
# #3679: a DELETED planning path is never legitimate — this workflow only ever
|
|
393
|
+
# excludes content a cherry-picked commit ADDED; pre-existing target-tracked
|
|
394
|
+
# planning files must survive byte-identical. Name-only counting cannot see
|
|
395
|
+
# status (a deleted structural/allowed path verifies clean there), so gate on
|
|
396
|
+
# deletions explicitly, across every planning category.
|
|
397
|
+
PLANNING_DELETIONS=$(git diff --name-status --no-renames "$TARGET".."$PR_BRANCH" | grep "^D" | grep -c "\.planning/" || true)
|
|
398
|
+
|
|
399
|
+
# Default mode preserves anything under .planning/ that is neither transient nor
|
|
400
|
+
# structural — config.json, intel/, workstreams/. That is deliberate and unchanged, but it
|
|
401
|
+
# must not be silent: report it so the user can choose strict mode knowingly.
|
|
402
|
+
OTHER=$(echo "$DIFF_PATHS" | grep "^\.planning/" | grep -Ev "$FORBIDDEN_RE" | grep -Ev "$STRUCTURAL_RE" || true)
|
|
289
403
|
```
|
|
290
404
|
|
|
405
|
+
`$FORBIDDEN` is the pass/fail number — it must be `0`. A non-zero value means the filter
|
|
406
|
+
did not do what this mode promised; report it and do not tell the user to push.
|
|
407
|
+
|
|
408
|
+
`$PLANNING_DELETIONS` is a second hard gate (#3679) — it must also be `0`. A non-zero
|
|
409
|
+
value means the PR branch would DELETE planning files the target branch tracks
|
|
410
|
+
(`git diff --name-status --no-renames "$TARGET".."$PR_BRANCH" | grep "^D" | grep "\.planning/"` lists
|
|
411
|
+
them). That is data loss, not filtering — report it, do not tell the user to push, and
|
|
412
|
+
rebuild the branch.
|
|
413
|
+
|
|
291
414
|
Display results:
|
|
292
415
|
```
|
|
293
416
|
✅ PR branch created: {PR_BRANCH}
|
|
294
417
|
|
|
295
418
|
Original: {AHEAD} commits, {ORIGINAL_FILES} files
|
|
296
419
|
PR branch: {PR_COMMITS} commits, {TOTAL_FILES} files
|
|
297
|
-
|
|
420
|
+
Mode: {PR_MODE}
|
|
421
|
+
Planning paths in diff: {PLANNING_TOTAL} (allowed {ALLOWED}, forbidden {FORBIDDEN} — must be 0)
|
|
422
|
+
Planning deletions: {PLANNING_DELETIONS} (must be 0 — #3679)
|
|
298
423
|
|
|
299
424
|
Next steps:
|
|
300
425
|
git push origin {PR_BRANCH}
|
|
@@ -302,14 +427,25 @@ Next steps:
|
|
|
302
427
|
|
|
303
428
|
Or use /gsd:ship to create the PR automatically.
|
|
304
429
|
```
|
|
430
|
+
|
|
431
|
+
When `$OTHER` is non-empty (default mode only — strict forbids all of it), append:
|
|
432
|
+
```
|
|
433
|
+
ℹ️ These .planning/ paths are neither transient nor structural, so default mode keeps them:
|
|
434
|
+
{OTHER}
|
|
435
|
+
Set `planning.pr_strict: true` to keep every .planning/ path out of the PR branch.
|
|
436
|
+
```
|
|
305
437
|
</step>
|
|
306
438
|
|
|
307
439
|
</process>
|
|
308
440
|
|
|
309
441
|
<success_criteria>
|
|
442
|
+
- [ ] Working tree was clean before the PR branch was created
|
|
310
443
|
- [ ] PR branch created from target
|
|
311
444
|
- [ ] Planning-only commits excluded
|
|
312
|
-
- [ ]
|
|
445
|
+
- [ ] Zero paths matching the active mode's `$FORBIDDEN_RE` in the PR branch diff —
|
|
446
|
+
strict: no `.planning/` path at all; default: none from `$TRANSIENT_DIRS`
|
|
447
|
+
- [ ] No `.planning/` path the target branch already tracked was deleted
|
|
448
|
+
- [ ] Every included commit landed — none dropped by a failed cherry-pick
|
|
313
449
|
- [ ] Commit messages preserved from original
|
|
314
450
|
- [ ] User shown next steps
|
|
315
451
|
</success_criteria>
|