@opengsd/gsd-core 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +85 -5
- package/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-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +3 -3
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -12
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +15 -9
- package/agents/gsd-planner.md +15 -11
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +166 -37
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +37 -14
- package/bin/install.js +764 -287
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +7 -2
- package/commands/gsd/capture.md +9 -5
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +12 -4
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +11 -7
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +7 -2
- package/commands/gsd/quick-batch.md +21 -9
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +7 -4
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +477 -78
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +144 -42
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +197 -222
- package/gsd-core/bin/lib/capability-validator.cjs +16 -1
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +343 -207
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +76 -19
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +426 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +364 -132
- package/gsd-core/bin/lib/install-engine.cjs +30 -33
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +37 -6
- package/gsd-core/bin/lib/model-resolver.cjs +171 -62
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- 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 +110 -8
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +489 -88
- package/gsd-core/bin/lib/plan-document.cjs +142 -20
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +692 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
- package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
- package/gsd-core/bin/lib/roadmap.cjs +405 -88
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
- package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +256 -105
- package/gsd-core/bin/lib/surface.cjs +19 -2
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
- package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
- package/gsd-core/bin/lib/uat.cjs +432 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1378 -274
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +357 -531
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/checkpoints.md +5 -3
- 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-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- 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 +7 -1
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/offer-next.md +1 -1
- 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 +12 -3
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +37 -8
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/references/worktree-path-safety.md +321 -0
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +4 -3
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +13 -4
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +43 -23
- package/gsd-core/workflows/check-todos.md +7 -6
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +112 -25
- package/gsd-core/workflows/code-review.md +146 -135
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +13 -8
- package/gsd-core/workflows/debug.md +32 -7
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +14 -5
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +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/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +96 -178
- package/gsd-core/workflows/execute-plan.md +18 -23
- package/gsd-core/workflows/explore.md +4 -4
- package/gsd-core/workflows/extract-learnings.md +4 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +3 -2
- package/gsd-core/workflows/help/modes/full.compact.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +4 -3
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +6 -4
- package/gsd-core/workflows/map-codebase.md +5 -4
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +11 -11
- 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 +7 -7
- 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 +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +50 -24
- 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 +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +62 -39
- package/gsd-core/workflows/reapply-patches.md +9 -3
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +33 -17
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +13 -13
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +4 -4
- package/gsd-core/workflows/ship.md +14 -13
- 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 +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +48 -11
- package/gsd-core/workflows/ui-review.md +21 -6
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +7 -7
- package/gsd-core/workflows/validate-phase.md +12 -13
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +129 -55
- package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +161 -4
- package/hooks/dist/gsd-statusline.js +85 -20
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +32 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +161 -4
- package/hooks/gsd-statusline.js +85 -20
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +22 -4
- package/scripts/build-hooks.js +15 -6
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +15 -8
- package/scripts/docs-guard-registry.cjs +34 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +79 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
- package/scripts/lib/ndjson-reporter.cjs +31 -5
- package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +319 -5
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +38 -9
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +7 -2
- package/skills/gsd-capture/SKILL.md +9 -5
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +12 -4
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +7 -2
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +21 -9
- package/skills/gsd-review/SKILL.md +7 -4
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
|
@@ -37,6 +37,22 @@
|
|
|
37
37
|
* over markdown, not `.cts` source, so its sanction is an HTML comment on the
|
|
38
38
|
* nearest preceding non-blank line: `<!-- phase-id-owner: <reason> -->`.
|
|
39
39
|
*
|
|
40
|
+
* - phase-heading-scan literal drift (#4906 Phase 5 / #4984): `findPhaseHeadingScanLiteralDrift`
|
|
41
|
+
* detects a hand-rolled `#{2,4}\s*Phase\s+` heading-SCAN literal, which bypasses
|
|
42
|
+
* `buildPhaseHeadingScanRegex` / `phaseHeadingPrefixSrcFor` (both in
|
|
43
|
+
* `src/phase-id.cts`) and so silently fails to recognize bracket-convention
|
|
44
|
+
* headings. Sanctioned the same way as the token/bracket/name-validity rules
|
|
45
|
+
* (`// phase-id-owner:` on the nearest preceding non-blank line), with a
|
|
46
|
+
* line-level escape for a line that already names either owner function.
|
|
47
|
+
* Wired into `scanRepo` (ADR-4910 §8): every pre-existing site this phase
|
|
48
|
+
* could not migrate (src/phase.cts x11, src/roadmap-parser.cts x3,
|
|
49
|
+
* src/planning-snapshot.cts x1) is grandfathered with a dedicated
|
|
50
|
+
* `// phase-id-owner:` sanction comment rather than a separate allowlist —
|
|
51
|
+
* the guard is ACTIVE from this phase forward: a fresh unsanctioned copy
|
|
52
|
+
* fails CI immediately, and each grandfathered comment is deleted as its
|
|
53
|
+
* site migrates in a later phase (ADR-4910 §8's census/grandfather/delete
|
|
54
|
+
* sequence, never renewed).
|
|
55
|
+
*
|
|
40
56
|
* - branch-slug fallback drift: a `.replace('{slug}', ... || 'phase')` call
|
|
41
57
|
* silently substitutes the literal string `'phase'` when a phase's slug
|
|
42
58
|
* can't be derived, producing a non-identifying branch name like
|
|
@@ -234,6 +250,67 @@ function findBranchSlugFallbackDrift(text) {
|
|
|
234
250
|
return out;
|
|
235
251
|
}
|
|
236
252
|
|
|
253
|
+
// #4906 Phase 5 (#4984): a hand-rolled heading-SCAN literal `#{2,4}\s*Phase\s+`
|
|
254
|
+
// (in either regex-literal `\s` or template `\\s` escaping, mirroring
|
|
255
|
+
// TOKEN_DRIFT_RE's tolerance) bypasses `buildPhaseHeadingScanRegex` /
|
|
256
|
+
// `phaseHeadingPrefixSrcFor` (both in `src/phase-id.cts`) entirely, so it
|
|
257
|
+
// silently fails to recognize bracket-convention headings (`[GSD.03] Phase
|
|
258
|
+
// 03:`) — the exact defect this phase fixed at five call sites in init.cts
|
|
259
|
+
// and milestone.cts. A line naming either owner function counts as "built
|
|
260
|
+
// from the owner" and is not flagged, mirroring the token rule's
|
|
261
|
+
// `line.includes(CANON_REF)` escape.
|
|
262
|
+
const PHASE_HEADING_SCAN_LITERAL_DRIFT_RE = /#\{2,4\}\\{1,2}s\*Phase\\{1,2}s\+/;
|
|
263
|
+
const PHASE_HEADING_SCAN_LITERAL_CANON_REFS = ['buildPhaseHeadingScanRegex', 'phaseHeadingPrefixSrcFor'];
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Pure: find every unsanctioned hand-rolled `#{2,4}\s*Phase\s+` heading-scan
|
|
267
|
+
* literal in `text`. Sanctioned when the line already names either owner
|
|
268
|
+
* function (`buildPhaseHeadingScanRegex(` / `phaseHeadingPrefixSrcFor(`), or
|
|
269
|
+
* by a `// phase-id-owner:` comment on the nearest preceding non-blank line
|
|
270
|
+
* (same mechanism as every other rule in this file). Returns [{ line, found }].
|
|
271
|
+
*/
|
|
272
|
+
function findPhaseHeadingScanLiteralDrift(text) {
|
|
273
|
+
const out = [];
|
|
274
|
+
const lines = text.split('\n');
|
|
275
|
+
for (let i = 0; i < lines.length; i++) {
|
|
276
|
+
const line = lines[i];
|
|
277
|
+
const m = PHASE_HEADING_SCAN_LITERAL_DRIFT_RE.exec(line);
|
|
278
|
+
if (!m) continue;
|
|
279
|
+
if (PHASE_HEADING_SCAN_LITERAL_CANON_REFS.some((ref) => line.includes(ref))) continue;
|
|
280
|
+
if (isSanctionedByPrecedingComment(lines, i, OWNER_RE)) continue;
|
|
281
|
+
out.push({ line: i + 1, found: m[0] });
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Scan the authored source tree (`src/**\/*.cts`, the same `SCAN_DIRS` root
|
|
288
|
+
* and `phase-id.cts` owner exemption that `scanRepo` applies to this
|
|
289
|
+
* detector — the heading-scan literal is a `src/**\/*.cts` defect, not a
|
|
290
|
+
* markdown one, unlike its sibling wrappers below) for unsanctioned
|
|
291
|
+
* hand-rolled heading-scan literals. Returns [{ file, line, found }] with
|
|
292
|
+
* repo-relative paths.
|
|
293
|
+
*/
|
|
294
|
+
function scanMarkdownPhaseHeadingScanLiteral(root) {
|
|
295
|
+
const violations = [];
|
|
296
|
+
for (const dir of SCAN_DIRS) {
|
|
297
|
+
for (const file of walk(path.join(root, dir), [])) {
|
|
298
|
+
const rel = path.relative(root, file);
|
|
299
|
+
if (EXEMPT.has(rel)) continue;
|
|
300
|
+
let text;
|
|
301
|
+
try {
|
|
302
|
+
text = fs.readFileSync(file, 'utf8');
|
|
303
|
+
} catch {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
for (const d of findPhaseHeadingScanLiteralDrift(text)) {
|
|
307
|
+
violations.push({ file: rel, kind: 'phase-heading-scan-literal', ...d });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return violations;
|
|
312
|
+
}
|
|
313
|
+
|
|
237
314
|
// #4634: ban base-10-forced shell arithmetic (`$((10#...))`) on a variable
|
|
238
315
|
// that still carries a possibly-decimal/multi-segment phase id — this
|
|
239
316
|
// construct is exactly the pattern that breaks on a value like `08.5`. The
|
|
@@ -246,11 +323,14 @@ function findBranchSlugFallbackDrift(text) {
|
|
|
246
323
|
// 1. Prose mentioning the literal pattern in a full-line `#`-comment
|
|
247
324
|
// (filtered by the caller, not this regex — see below).
|
|
248
325
|
// 2. `$((10#$PHASE_INT))` / `$((10#$SPOT_PHASE_INT))` — arithmetic on the
|
|
249
|
-
// NOW-safe variable the #4619 fix produces via
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
326
|
+
// NOW-safe variable the #4619 fix produces via a leading-digit-run split
|
|
327
|
+
// (`PHASE_INT=${PHASE_NUMBER%%[!0-9]*}` since #4748; `%%.*` before it);
|
|
328
|
+
// a digit-run value can never contain a dot OR a letter, so base-10
|
|
329
|
+
// arithmetic on it can never hit the #4619 / #4748 error classes. Any
|
|
330
|
+
// name ending in `_INT` (case-insensitive) is that established "already
|
|
331
|
+
// reduced to a safe integer" convention. That convention is a NAME, not
|
|
332
|
+
// a proof — `findDotOnlyIntegerSplitDrift` below polices that the split
|
|
333
|
+
// producing it actually stops at the first non-digit.
|
|
254
334
|
// 3. `$((10#{plan_padded}))` / `$((10#${PLAN_ID}))` — plan ids are plain
|
|
255
335
|
// integers and were never in scope; this rule only polices variables
|
|
256
336
|
// that carry a *phase* id.
|
|
@@ -389,6 +469,204 @@ function scanMarkdownSingleSegmentPhaseRegex(root) {
|
|
|
389
469
|
return violations;
|
|
390
470
|
}
|
|
391
471
|
|
|
472
|
+
// #4660 (epic #4634): the six shell/markdown mirrors #4568 widened on the
|
|
473
|
+
// segment-count axis stayed digit-only on the LETTER axis — the canonical
|
|
474
|
+
// grammar (`src/phase-id.cts`) is `\d+[A-Z]?(?:\.\d+)*`, with an optional
|
|
475
|
+
// single uppercase letter after the leading digits (`12A`, `3A`, `23A.1.2`,
|
|
476
|
+
// documented in docs/CONFIGURATION.md and relied on by `renameIntegerPhases`).
|
|
477
|
+
// A digit-only mirror `[0-9]+(\.[0-9]+)*` hard-rejects (validating sites) or
|
|
478
|
+
// silently truncates (extracting sites) a letter-suffixed id. This rule is the
|
|
479
|
+
// ratchet for that axis, the twin of the single-segment rule above: it flags
|
|
480
|
+
// the unbounded-segment shape whose digit run is NOT followed by the letter
|
|
481
|
+
// class. `[A-Z]` is the canonical spelling; the case-flexible `[A-Za-z]`
|
|
482
|
+
// directory-scanning variant is a deliberately separate axis and is tolerated
|
|
483
|
+
// here so this rule cannot force it to narrow.
|
|
484
|
+
const LETTERLESS_PHASE_MIRROR_DRIFT_RE =
|
|
485
|
+
/(?:\\{1,2}d|\[0-9\])\+(?!\[A-Z(?:a-z)?\]\?)\(\\{1,2}\.(?:\\{1,2}d|\[0-9\])\+\)\*/;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Pure: find every unsanctioned digit-only (letter-less) unbounded-segment
|
|
489
|
+
* phase regex in `text`, restricted to lines that plausibly carry a
|
|
490
|
+
* phase-number variable — the same `PHASE_CARRYING_LINE_RE` filter and the
|
|
491
|
+
* same `<!-- phase-id-owner: ... -->` sanction as the single-segment rule.
|
|
492
|
+
* Returns [{ line, found }].
|
|
493
|
+
*/
|
|
494
|
+
function findLetterlessPhaseMirrorDrift(text) {
|
|
495
|
+
const out = [];
|
|
496
|
+
const lines = text.split('\n');
|
|
497
|
+
for (let i = 0; i < lines.length; i++) {
|
|
498
|
+
const line = lines[i];
|
|
499
|
+
const m = LETTERLESS_PHASE_MIRROR_DRIFT_RE.exec(line);
|
|
500
|
+
if (!m) continue;
|
|
501
|
+
if (!PHASE_CARRYING_LINE_RE.test(line)) continue;
|
|
502
|
+
if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
|
|
503
|
+
out.push({ line: i + 1, found: m[0] });
|
|
504
|
+
}
|
|
505
|
+
return out;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Scan the same three markdown roots as the single-segment rule for
|
|
510
|
+
* unsanctioned letter-less phase-regex mirrors. Returns [{ file, line, found }]
|
|
511
|
+
* with repo-relative paths.
|
|
512
|
+
*/
|
|
513
|
+
function scanMarkdownLetterlessPhaseMirror(root) {
|
|
514
|
+
const violations = [];
|
|
515
|
+
for (const dir of SINGLE_SEGMENT_SCAN_DIRS) {
|
|
516
|
+
for (const file of walkMd(path.join(root, dir), [])) {
|
|
517
|
+
const rel = path.relative(root, file);
|
|
518
|
+
let text;
|
|
519
|
+
try {
|
|
520
|
+
text = fs.readFileSync(file, 'utf8');
|
|
521
|
+
} catch {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
for (const d of findLetterlessPhaseMirrorDrift(text)) {
|
|
525
|
+
violations.push({ file: rel, kind: 'letterless-phase-mirror', ...d });
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return violations;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// #4748 (epic #4634): three shell shapes OUTSIDE the grammar-mirror family the
|
|
533
|
+
// rules above police — consumers of a phase id rather than regexes for one —
|
|
534
|
+
// each of which the letter axis broke while every rule above reported clean:
|
|
535
|
+
//
|
|
536
|
+
// a. `PHASE_INT=${PHASE_NUMBER%%.*}` — the post-#4619 dot-only split. The
|
|
537
|
+
// `_INT` name it produces satisfies the shell-arithmetic rule's escape,
|
|
538
|
+
// but on `03A` the "integer" is `03A` and `$((10#03A))` aborts. The safe
|
|
539
|
+
// split stops at the first NON-digit: `${PHASE_NUMBER%%[!0-9]*}`.
|
|
540
|
+
// b. `[0-9]+\.?[0-9]*` (and `\d+\.?\d*`) — a digit-then-optional-dot
|
|
541
|
+
// extraction that is neither the bounded `(\.[0-9]+)?` shape the
|
|
542
|
+
// single-segment rule bans nor the unbounded `(\.[0-9]+)*` shape the
|
|
543
|
+
// letterless rule inspects, so both were blind to it. It captures `12`
|
|
544
|
+
// from `12A` and `23.1` from `23.1.2`, silently.
|
|
545
|
+
// c. `printf "%02d" "$PHASE_NUMBER"` — re-padding the whole id in shell.
|
|
546
|
+
// Rejects a letter id (prints `03`, exit 1) and misreads an already
|
|
547
|
+
// padded `08` as octal (prints `00`). Padding belongs to the canonical
|
|
548
|
+
// normalizer (`padded_phase` from init, or `normalizePhaseName`); the one
|
|
549
|
+
// legitimate shell pad is of an `_INT` value via `$((10#…))`.
|
|
550
|
+
//
|
|
551
|
+
// Same sanction as the other markdown rules: `<!-- phase-id-owner: … -->` on
|
|
552
|
+
// the nearest preceding non-blank line. Same documented limit: a per-line
|
|
553
|
+
// textual scan for the common accidental shape, not an obfuscated one.
|
|
554
|
+
|
|
555
|
+
// a. `<name>_INT=${<phase-carrying>%%.*}` — the `_INT` destination is the
|
|
556
|
+
// discriminator, deliberately: it is the name the shell-arithmetic rule
|
|
557
|
+
// trusts as "already a safe integer", so a dot-only split INTO it is the
|
|
558
|
+
// exact promise this rule exists to check. A dot-only split into any other
|
|
559
|
+
// name is a different, legitimate operation — `PARENT_PHASE="${PHASE_NUMBER%%.*}"`
|
|
560
|
+
// (gap-closure-artifacts.md) wants everything before the first dot, letter
|
|
561
|
+
// included, and is correct. Widening to any destination was tried and flagged
|
|
562
|
+
// that site. The optional quote after `=` is the one spelling that site uses.
|
|
563
|
+
const DOT_ONLY_INT_SPLIT_DRIFT_RE = /[A-Za-z0-9_]*_INT="?\$\{([A-Za-z0-9_]+)%%\\?\.\*\}/i;
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Pure: find every unsanctioned dot-only integer split of a phase-carrying
|
|
567
|
+
* variable in `text`. Skips full-line `#` comments (prose). Returns [{ line, found }].
|
|
568
|
+
*/
|
|
569
|
+
function findDotOnlyIntegerSplitDrift(text) {
|
|
570
|
+
const out = [];
|
|
571
|
+
const lines = text.split('\n');
|
|
572
|
+
for (let i = 0; i < lines.length; i++) {
|
|
573
|
+
const line = lines[i];
|
|
574
|
+
if (/^\s*#/.test(line)) continue;
|
|
575
|
+
const m = DOT_ONLY_INT_SPLIT_DRIFT_RE.exec(line);
|
|
576
|
+
if (!m) continue;
|
|
577
|
+
if (!/phase/i.test(m[1])) continue;
|
|
578
|
+
if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
|
|
579
|
+
out.push({ line: i + 1, found: m[0] });
|
|
580
|
+
}
|
|
581
|
+
return out;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// b. The digit-then-optional-dot shape, in both `[0-9]` and `\d` spellings.
|
|
585
|
+
// Anchored on the trailing `*` of the second digit class so a bare `[0-9]+`
|
|
586
|
+
// probe or a `[0-9]+\.[0-9]+` (mandatory-dot) shape is not matched.
|
|
587
|
+
const LOOSE_DOTTED_PHASE_DRIFT_RE = /(?:\\{1,2}d|\[0-9\])\+\\{1,2}\.\?(?:\\{1,2}d|\[0-9\])\*/;
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Pure: find every unsanctioned `[0-9]+\.?[0-9]*`-shaped phase extraction in
|
|
591
|
+
* `text`, restricted to phase-carrying lines like its two sibling regex rules.
|
|
592
|
+
* Returns [{ line, found }].
|
|
593
|
+
*/
|
|
594
|
+
function findLooseDottedPhaseRegexDrift(text) {
|
|
595
|
+
const out = [];
|
|
596
|
+
const lines = text.split('\n');
|
|
597
|
+
for (let i = 0; i < lines.length; i++) {
|
|
598
|
+
const line = lines[i];
|
|
599
|
+
const m = LOOSE_DOTTED_PHASE_DRIFT_RE.exec(line);
|
|
600
|
+
if (!m) continue;
|
|
601
|
+
if (!PHASE_CARRYING_LINE_RE.test(line)) continue;
|
|
602
|
+
if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
|
|
603
|
+
out.push({ line: i + 1, found: m[0] });
|
|
604
|
+
}
|
|
605
|
+
return out;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// c. `printf "%Nd" …` / `printf '%0Nd' …` — any integer conversion, either
|
|
609
|
+
// quote, with or without the zero flag — whose argument list names a
|
|
610
|
+
// phase-carrying variable that is NOT an `_INT` (the `$((10#$PHASE_INT))`
|
|
611
|
+
// pad is the sanctioned shape). `%d` cannot parse a letter id under any
|
|
612
|
+
// width, so the flag is not the discriminator. Captures the first such name
|
|
613
|
+
// so the report says what was padded.
|
|
614
|
+
const SHELL_PHASE_PRINTF_PAD_RE = /printf\s+(?:"%0?\d*d[^"]*"|'%0?\d*d[^']*')\s+(.*)$/;
|
|
615
|
+
const SHELL_VAR_NAME_RE = /\$\{?([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Pure: find every unsanctioned `printf "%02d"` re-pad of a phase-carrying,
|
|
619
|
+
* non-`_INT` shell variable in `text`. Skips full-line `#` comments.
|
|
620
|
+
* Returns [{ line, found }].
|
|
621
|
+
*/
|
|
622
|
+
function findShellPhasePrintfPadDrift(text) {
|
|
623
|
+
const out = [];
|
|
624
|
+
const lines = text.split('\n');
|
|
625
|
+
for (let i = 0; i < lines.length; i++) {
|
|
626
|
+
const line = lines[i];
|
|
627
|
+
if (/^\s*#/.test(line)) continue;
|
|
628
|
+
const m = SHELL_PHASE_PRINTF_PAD_RE.exec(line);
|
|
629
|
+
if (!m) continue;
|
|
630
|
+
const offender = [...m[1].matchAll(SHELL_VAR_NAME_RE)]
|
|
631
|
+
.map((v) => v[1])
|
|
632
|
+
.find((name) => /phase/i.test(name) && !/_int$/i.test(name));
|
|
633
|
+
if (!offender) continue;
|
|
634
|
+
if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
|
|
635
|
+
out.push({ line: i + 1, found: `printf "%0…d" …$${offender}` });
|
|
636
|
+
}
|
|
637
|
+
return out;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Scan the shell roots (`gsd-core/workflows/**\/*.md`, `gsd-core/references/**\/*.md`)
|
|
642
|
+
* for the two shell-idiom rules (a, c) and the three regex roots (those plus
|
|
643
|
+
* `agents/**\/*.md`) for the extraction-shape rule (b). Returns
|
|
644
|
+
* [{ file, kind, line, found }] with repo-relative paths.
|
|
645
|
+
*/
|
|
646
|
+
function scanMarkdownLetterAxisConsumers(root) {
|
|
647
|
+
const violations = [];
|
|
648
|
+
const collect = (dirs, finder, kind) => {
|
|
649
|
+
for (const dir of dirs) {
|
|
650
|
+
for (const file of walkMd(path.join(root, dir), [])) {
|
|
651
|
+
const rel = path.relative(root, file);
|
|
652
|
+
let text;
|
|
653
|
+
try {
|
|
654
|
+
text = fs.readFileSync(file, 'utf8');
|
|
655
|
+
} catch {
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
for (const d of finder(text)) {
|
|
659
|
+
violations.push({ file: rel, kind, ...d });
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
collect(MD_SCAN_DIRS, findDotOnlyIntegerSplitDrift, 'dot-only-int-split');
|
|
665
|
+
collect(SINGLE_SEGMENT_SCAN_DIRS, findLooseDottedPhaseRegexDrift, 'loose-dotted-phase-regex');
|
|
666
|
+
collect(MD_SCAN_DIRS, findShellPhasePrintfPadDrift, 'shell-phase-printf-pad');
|
|
667
|
+
return violations;
|
|
668
|
+
}
|
|
669
|
+
|
|
392
670
|
// Authored TypeScript source only (the generated bin/lib/*.cjs mirror it).
|
|
393
671
|
const SCAN_DIRS = ['src'];
|
|
394
672
|
const SCAN_EXT = new Set(['.cts', '.ts', '.mts']);
|
|
@@ -523,6 +801,16 @@ function scanRepo(root) {
|
|
|
523
801
|
for (const d of findBranchSlugFallbackDrift(text)) {
|
|
524
802
|
violations.push({ file: rel, kind: 'branch-slug-fallback', ...d });
|
|
525
803
|
}
|
|
804
|
+
// #4906 Phase 5 (#4984): heading-scan literal drift, owner file exempt
|
|
805
|
+
// via the shared `EXEMPT` check above. Pre-existing sites this phase
|
|
806
|
+
// could not reach (src/phase.cts, src/roadmap-parser.cts,
|
|
807
|
+
// src/planning-snapshot.cts) are grandfathered with a `// phase-id-owner:`
|
|
808
|
+
// sanction each, per ADR-4910 §8's census/grandfather/delete Phase 6 plan
|
|
809
|
+
// — the allowlist is those sanction comments, not a separate list here,
|
|
810
|
+
// and it is deleted entry-by-entry as each site migrates.
|
|
811
|
+
for (const d of findPhaseHeadingScanLiteralDrift(text)) {
|
|
812
|
+
violations.push({ file: rel, kind: 'phase-heading-scan-literal', ...d });
|
|
813
|
+
}
|
|
526
814
|
}
|
|
527
815
|
}
|
|
528
816
|
return violations;
|
|
@@ -541,6 +829,8 @@ function scanAll(root) {
|
|
|
541
829
|
...scanRepo(root),
|
|
542
830
|
...scanMarkdownShellArith(root),
|
|
543
831
|
...scanMarkdownSingleSegmentPhaseRegex(root),
|
|
832
|
+
...scanMarkdownLetterlessPhaseMirror(root),
|
|
833
|
+
...scanMarkdownLetterAxisConsumers(root),
|
|
544
834
|
];
|
|
545
835
|
}
|
|
546
836
|
|
|
@@ -567,8 +857,19 @@ function main() {
|
|
|
567
857
|
process.stderr.write('near-variant) is banned outright in gsd-core/workflows/**/*.md,\n');
|
|
568
858
|
process.stderr.write('gsd-core/references/**/*.md, and agents/**/*.md — widen it to `*` (unbounded\n');
|
|
569
859
|
process.stderr.write('segments) or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
|
|
860
|
+
process.stderr.write('A digit-only unbounded-segment phase regex `[0-9]+(\\.[0-9]+)*` on the same roots\n');
|
|
861
|
+
process.stderr.write('is missing the canonical letter axis (#4660) — widen to `[0-9]+[A-Z]?(\\.[0-9]+)*`\n');
|
|
862
|
+
process.stderr.write('or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
|
|
863
|
+
process.stderr.write('Three letter-hostile consumers of a phase id are banned on the same roots (#4748):\n');
|
|
864
|
+
process.stderr.write('a dot-only integer split `X_INT=${PHASE%%.*}` (split at the first non-digit,\n');
|
|
865
|
+
process.stderr.write('`${PHASE%%[!0-9]*}`); a `[0-9]+\\.?[0-9]*` extraction (use `[0-9]+[A-Z]?(\\.[0-9]+)*`);\n');
|
|
866
|
+
process.stderr.write('and a `printf "%02d"` re-pad of a phase variable (bind init\'s `padded_phase`, or pad\n');
|
|
867
|
+
process.stderr.write('only an `_INT` via `$((10#…))`) — or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
|
|
570
868
|
process.stderr.write('A `.replace(\'{slug}\', ... || \'phase\')` fallback is banned outright (#4126) —\n');
|
|
571
869
|
process.stderr.write('use `renderPhaseBranchName(` or sanction with\n');
|
|
870
|
+
process.stderr.write('`// phase-id-owner: <reason>` on the line directly above.\n');
|
|
871
|
+
process.stderr.write('A hand-rolled `#{2,4}\\s*Phase\\s+` heading-scan literal is banned (#4906 Phase 5) —\n');
|
|
872
|
+
process.stderr.write('use `buildPhaseHeadingScanRegex(` / `phaseHeadingPrefixSrcFor(` or sanction with\n');
|
|
572
873
|
process.stderr.write('`// phase-id-owner: <reason>` on the line directly above:\n');
|
|
573
874
|
for (const d of violations) {
|
|
574
875
|
process.stderr.write(` [${d.kind}] ${d.file}:${d.line} ${d.found}\n`);
|
|
@@ -583,10 +884,18 @@ module.exports = {
|
|
|
583
884
|
findBracketGrammarDrift,
|
|
584
885
|
findNameValidityDrift,
|
|
585
886
|
findBranchSlugFallbackDrift,
|
|
887
|
+
findPhaseHeadingScanLiteralDrift,
|
|
888
|
+
scanMarkdownPhaseHeadingScanLiteral,
|
|
586
889
|
findShellPhaseArithDrift,
|
|
587
890
|
findSingleSegmentPhaseRegexDrift,
|
|
891
|
+
findLetterlessPhaseMirrorDrift,
|
|
892
|
+
findDotOnlyIntegerSplitDrift,
|
|
893
|
+
findLooseDottedPhaseRegexDrift,
|
|
894
|
+
findShellPhasePrintfPadDrift,
|
|
588
895
|
scanMarkdownShellArith,
|
|
589
896
|
scanMarkdownSingleSegmentPhaseRegex,
|
|
897
|
+
scanMarkdownLetterlessPhaseMirror,
|
|
898
|
+
scanMarkdownLetterAxisConsumers,
|
|
590
899
|
scanRepo,
|
|
591
900
|
scanAll,
|
|
592
901
|
countSelectorBaselines,
|
|
@@ -595,6 +904,11 @@ module.exports = {
|
|
|
595
904
|
BRACKET_CODE_DRIFT_RE,
|
|
596
905
|
NAME_VALIDITY_DRIFT_RE,
|
|
597
906
|
BRANCH_SLUG_FALLBACK_DRIFT_RE,
|
|
907
|
+
PHASE_HEADING_SCAN_LITERAL_DRIFT_RE,
|
|
598
908
|
SHELL_PHASE_ARITH_DRIFT_RE,
|
|
599
909
|
SINGLE_SEGMENT_PHASE_DRIFT_RE,
|
|
910
|
+
LETTERLESS_PHASE_MIRROR_DRIFT_RE,
|
|
911
|
+
DOT_ONLY_INT_SPLIT_DRIFT_RE,
|
|
912
|
+
LOOSE_DOTTED_PHASE_DRIFT_RE,
|
|
913
|
+
SHELL_PHASE_PRINTF_PAD_RE,
|
|
600
914
|
};
|