@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
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Health Diagnostic Rules — STATE.md consistency group (Phase 11, #3309,
|
|
4
|
+
* ADR-3180 §8.2/§8.3/§8.5).
|
|
5
|
+
*
|
|
6
|
+
* Five rules, each a near-mechanical extraction of an already-working
|
|
7
|
+
* `addIssue` call site in `cmdValidateHealth` (Gall's Law, design doc "Rule
|
|
8
|
+
* table organization" / "Laws applied"):
|
|
9
|
+
*
|
|
10
|
+
* - W024 (`verify.cts:1709-1729`) — STATE.md `state_head` commit-age
|
|
11
|
+
* freshness vs. git HEAD. GENUINE GAP, deliberately NOT migrated — see the
|
|
12
|
+
* `RULE_W024` comment below for exactly why.
|
|
13
|
+
* - W002 (`verify.cts:1731-1774`) — STATE.md references a phase token not
|
|
14
|
+
* declared anywhere (disk or ROADMAP).
|
|
15
|
+
* - W011 (`verify.cts:2104-2134`) — STATE's current-phase status disagrees
|
|
16
|
+
* with ROADMAP's `[x]` checkbox for that same phase.
|
|
17
|
+
* - W021 (`verify.cts:2270-2299`, the FIRST `addIssue('warning', 'W021', ...)`
|
|
18
|
+
* call site) — under the `'milestone-prefixed'` `phase_id_convention`, a
|
|
19
|
+
* phase's integer prefix implies a different milestone than the ROADMAP
|
|
20
|
+
* section it is actually listed under.
|
|
21
|
+
* - W026 (`verify.cts:2356-2399`, the SECOND `addIssue('warning', 'W021', ...)`
|
|
22
|
+
* call site — split off per the design doc's "New codes for the two split
|
|
23
|
+
* subjects" section, since one code covering two unrelated subjects is a
|
|
24
|
+
* genuine conflation) — STATE says the milestone is complete/archived, but
|
|
25
|
+
* ROADMAP (scoped to that same milestone) still lists a phase with no
|
|
26
|
+
* matching disk directory.
|
|
27
|
+
*
|
|
28
|
+
* - W002's original message interpolates `${slash('health')}`
|
|
29
|
+
* (`verify.cts:1770`) and W011's interpolates `${slash('progress')}`
|
|
30
|
+
* (`verify.cts:2126`) — both per-project runtime-resolved values
|
|
31
|
+
* (`formatGsdSlash`, `src/runtime-slash.cts`) this rule's
|
|
32
|
+
* `(snapshot) => Diagnostic[]` signature has no access to. Hardcodes the
|
|
33
|
+
* canonical `/gsd-health`/`/gsd-progress` hyphen form instead, mirroring
|
|
34
|
+
* the sibling "config.json validation" group's W016 rule
|
|
35
|
+
* (`src/health-diagnostic-rules/config-validation.cts`), which hardcodes
|
|
36
|
+
* `/gsd-ai-integration-phase` the same way for the identical reason.
|
|
37
|
+
*
|
|
38
|
+
* Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
|
|
39
|
+
*/
|
|
40
|
+
// Runtime values (SEVERITY/REMEDY_ACTION/REMEDY_RISK) are needed here, not
|
|
41
|
+
// just types, so this is a normal (non type-only) `import ... = require(...)`
|
|
42
|
+
// — unlike `health-diagnostic.cts`'s own type-only import of
|
|
43
|
+
// `planning-snapshot.cjs`, which never touches that module's runtime values.
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- export= CommonJS module
|
|
45
|
+
const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
|
|
46
|
+
const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
48
|
+
const phaseIdMod = require("../phase-id.cjs");
|
|
49
|
+
const { getMilestoneFromPhaseId, matchPhaseDirs, normalizePhaseName, extractPhaseToken, PHASE_NUMBER_TOKEN_SOURCE } = phaseIdMod;
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- the single owner of the persisted status vocabulary
|
|
51
|
+
const stateDocumentMod = require("../state-document.cjs");
|
|
52
|
+
const { normalizeStateStatus } = stateDocumentMod;
|
|
53
|
+
// ─── W024 — STATE.md commit-age freshness (DELIBERATELY INERT) ─────────────
|
|
54
|
+
/**
|
|
55
|
+
* W024's real check (`verify.cts:1709-1729`) calls
|
|
56
|
+
* `readStateHeadFreshness(cwd, fm['state_head'])`, which shells out to `git
|
|
57
|
+
* log` to count commits between the frontmatter's `state_head` and the
|
|
58
|
+
* current HEAD. That is ambient I/O (git history), not `.planning/` content —
|
|
59
|
+
* confirmed against `src/planning-snapshot.cts`'s full 15-field
|
|
60
|
+
* `PlanningSnapshot` interface: no field wraps `readStateHeadFreshness` or
|
|
61
|
+
* exposes a commits-behind count.
|
|
62
|
+
*
|
|
63
|
+
* §8.1 rule 1 requires a rule's signature to be `(snapshot) => Diagnostic[]`
|
|
64
|
+
* with no ambient I/O inside `check` — so this rule does NOT call
|
|
65
|
+
* `readStateHeadFreshness` itself (that would violate the constraint the
|
|
66
|
+
* skeleton's own `Rule.check` type exists to enforce). Adding a 16th
|
|
67
|
+
* `PlanningSnapshot` field (e.g. `stateHeadFreshness: {value:
|
|
68
|
+
* {commitsBehind, stateHead}, scope}`) is the fix, but is out of this
|
|
69
|
+
* group's scope (`src/planning-snapshot.cts` is a shared file this task was
|
|
70
|
+
* not dispatched to extend).
|
|
71
|
+
*
|
|
72
|
+
* Registered here, `check` always returning `[]`, so the code table stays
|
|
73
|
+
* complete per §8.2's 1:1 invariant (every code the old `verify.cts` emitted
|
|
74
|
+
* has exactly one `Rule` entry) rather than silently dropping W024 from the
|
|
75
|
+
* table. This is a documented, deliberate deferral pending the 16th snapshot
|
|
76
|
+
* field — flagged prominently rather than quietly ported as a no-op.
|
|
77
|
+
*/
|
|
78
|
+
const RULE_W024 = {
|
|
79
|
+
code: 'W024',
|
|
80
|
+
severity: SEVERITY.WARNING,
|
|
81
|
+
description: 'STATE.md was written many commits ago — treat its contents as approximate',
|
|
82
|
+
repairable: false,
|
|
83
|
+
check: (_snapshot) => [],
|
|
84
|
+
};
|
|
85
|
+
// ─── W002 — STATE.md references an undeclared phase token ──────────────────
|
|
86
|
+
/**
|
|
87
|
+
* The "valid phase" set the original code builds from
|
|
88
|
+
* `collectDiskPhases(planBase)` (disk dir tokens) + ROADMAP heading tokens +
|
|
89
|
+
* `forEachArchivedPhaseToken` (archived milestone-phase-dir tokens,
|
|
90
|
+
* `verify.cts:1748`). This rebuilds the disk+ROADMAP two-thirds from parsed
|
|
91
|
+
* snapshot fields only: `phaseDirs.value` (disk dir names, tokenized the same
|
|
92
|
+
* way `collectDiskPhaseEntries` does — via `extractPhaseToken`) and
|
|
93
|
+
* `roadmapDeclaredPhases.value.map(p => p.phaseId)` (ROADMAP-declared phase
|
|
94
|
+
* ids). Archived-phase-token coverage is NOT included — no
|
|
95
|
+
* `PlanningSnapshot` field exposes archived milestone-phase-dir tokens
|
|
96
|
+
* (confirmed against the 15-field interface). Omitting it makes this valid
|
|
97
|
+
* set a SUBSET of the original's, which can only make MORE STATE.md phase
|
|
98
|
+
* tokens look "invalid" (never fewer) — a conservative, safe direction; a
|
|
99
|
+
* project with archived phases still referenced from STATE.md is the
|
|
100
|
+
* fixture shape that would expose a false positive, and none of this
|
|
101
|
+
* group's fixtures exercise archives, so this gap is disclosed rather than
|
|
102
|
+
* silently absorbed.
|
|
103
|
+
*
|
|
104
|
+
* UPDATE (#3652): archived-phase-token coverage IS now included, via the
|
|
105
|
+
* additive `snapshot.archivedPhaseTokens` field
|
|
106
|
+
* (`src/planning-snapshot.cts`, added for this fix) — the disclosed gap
|
|
107
|
+
* above is closed; the paragraph is kept for the "conservative direction"
|
|
108
|
+
* reasoning, which still explains why every OTHER omission in this
|
|
109
|
+
* function is safe.
|
|
110
|
+
*/
|
|
111
|
+
function buildValidPhaseSet(snapshot) {
|
|
112
|
+
const valid = new Set();
|
|
113
|
+
for (const dir of snapshot.phaseDirs.value) {
|
|
114
|
+
const token = extractPhaseToken(dir);
|
|
115
|
+
if (token)
|
|
116
|
+
valid.add(token);
|
|
117
|
+
}
|
|
118
|
+
for (const entry of snapshot.roadmapDeclaredPhases.value) {
|
|
119
|
+
valid.add(entry.phaseId);
|
|
120
|
+
}
|
|
121
|
+
for (const token of snapshot.archivedPhaseTokens.value) {
|
|
122
|
+
valid.add(token);
|
|
123
|
+
}
|
|
124
|
+
return valid;
|
|
125
|
+
}
|
|
126
|
+
/** Mirrors `verify.cts:1749-1758`'s zero-padding normalization exactly. */
|
|
127
|
+
function normalizePhaseTokenSet(valid) {
|
|
128
|
+
const normalized = new Set();
|
|
129
|
+
for (const p of valid) {
|
|
130
|
+
normalized.add(p);
|
|
131
|
+
const dotIdx = p.indexOf('.');
|
|
132
|
+
const head = dotIdx === -1 ? p : p.slice(0, dotIdx);
|
|
133
|
+
const tail = dotIdx === -1 ? '' : p.slice(dotIdx);
|
|
134
|
+
if (/^\d+$/.test(head)) {
|
|
135
|
+
normalized.add(head.padStart(2, '0') + tail);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return normalized;
|
|
139
|
+
}
|
|
140
|
+
const RULE_W002 = {
|
|
141
|
+
code: 'W002',
|
|
142
|
+
severity: SEVERITY.WARNING,
|
|
143
|
+
description: 'STATE.md references invalid phase',
|
|
144
|
+
repairable: false,
|
|
145
|
+
check: (snapshot) => {
|
|
146
|
+
const validPhases = buildValidPhaseSet(snapshot);
|
|
147
|
+
// Mirrors `verify.cts:1765`'s `if (normalizedValid.size > 0)` guard
|
|
148
|
+
// exactly — a project with zero declared phases emits nothing, never a
|
|
149
|
+
// false positive on every STATE.md phase mention.
|
|
150
|
+
if (validPhases.size === 0)
|
|
151
|
+
return [];
|
|
152
|
+
const normalizedValid = normalizePhaseTokenSet(validPhases);
|
|
153
|
+
const sortedValid = [...validPhases].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
154
|
+
const diagnostics = [];
|
|
155
|
+
for (const ref of snapshot.statePhaseTokens.value) {
|
|
156
|
+
const dotIdx = ref.indexOf('.');
|
|
157
|
+
const head = dotIdx === -1 ? ref : ref.slice(0, dotIdx);
|
|
158
|
+
const tail = dotIdx === -1 ? '' : ref.slice(dotIdx);
|
|
159
|
+
const padded = /^\d+$/.test(head) ? head.padStart(2, '0') + tail : ref;
|
|
160
|
+
if (normalizedValid.has(ref) || normalizedValid.has(padded))
|
|
161
|
+
continue;
|
|
162
|
+
diagnostics.push({
|
|
163
|
+
code: 'W002',
|
|
164
|
+
severity: SEVERITY.WARNING,
|
|
165
|
+
message: `STATE.md references phase ${ref}, but only phases ${sortedValid.join(', ')} are declared`,
|
|
166
|
+
remedy: adviseRemedy('Review STATE.md manually before changing it; /gsd-health --repair will not overwrite an existing STATE.md for phase mismatches'),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return diagnostics;
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
// ─── W011 — STATE current-phase status vs. ROADMAP checkbox disagree ───────
|
|
173
|
+
/**
|
|
174
|
+
* `currentPhaseLabel.value` is a prose string (e.g. `"3 of 8 (User Auth)"`),
|
|
175
|
+
* not a clean phase id — the leading integer (optionally letter-suffixed /
|
|
176
|
+
* dotted, the same `PHASE_NUMBER_TOKEN_SOURCE` grammar) is the "current
|
|
177
|
+
* phase" proxy the original `verify.cts:2109-2113` derives via its own
|
|
178
|
+
* `**Current Phase:**`/`Current Phase:` regex + `.replace(/^0+/, '')`. That
|
|
179
|
+
* literal field name does not exist in the current `state.md` template
|
|
180
|
+
* (which uses `Phase: [X] of [Y] ([Phase name])` under `## Current
|
|
181
|
+
* Position`) — `currentPhaseLabel` is the parsed owner of that exact field,
|
|
182
|
+
* so extracting its leading number is the equivalent-intent read against
|
|
183
|
+
* the template STATE.md actually ships. #3280: the label's ladder
|
|
184
|
+
* (`buildStateFields`, `src/planning-snapshot.cts`) now leads with the
|
|
185
|
+
* frontmatter `current_phase` scalar — the key `gsd-tools state update` /
|
|
186
|
+
* `state begin-phase` persist — so a bare `"2"` is the expected value on
|
|
187
|
+
* the machine-readable format, and this leading-number extraction handles
|
|
188
|
+
* it identically.
|
|
189
|
+
*/
|
|
190
|
+
function currentPhaseIdFromLabel(label) {
|
|
191
|
+
if (!label)
|
|
192
|
+
return null;
|
|
193
|
+
const m = label.match(new RegExp(`^0*(${PHASE_NUMBER_TOKEN_SOURCE})`));
|
|
194
|
+
return m ? m[1] : null;
|
|
195
|
+
}
|
|
196
|
+
const RULE_W011 = {
|
|
197
|
+
code: 'W011',
|
|
198
|
+
severity: SEVERITY.WARNING,
|
|
199
|
+
description: 'STATE.md current-phase status disagrees with ROADMAP.md checkbox',
|
|
200
|
+
repairable: false,
|
|
201
|
+
check: (snapshot) => {
|
|
202
|
+
const phaseId = currentPhaseIdFromLabel(snapshot.currentPhaseLabel.value);
|
|
203
|
+
if (phaseId === null)
|
|
204
|
+
return [];
|
|
205
|
+
const checked = snapshot.roadmapPhaseCheckboxes.value[phaseId];
|
|
206
|
+
if (checked !== true)
|
|
207
|
+
return [];
|
|
208
|
+
// #3280: the state writer persists `status` through `normalizeStateStatus`
|
|
209
|
+
// (`state.cts`'s syncStateFrontmatter), whose completion token is
|
|
210
|
+
// `completed` — an exact `'complete' || 'done'` comparison rejects the
|
|
211
|
+
// exact vocabulary the product writes and turns every legitimately
|
|
212
|
+
// completed frontmatter STATE.md into a false positive. Route the
|
|
213
|
+
// comparison through the same seam that owns the vocabulary
|
|
214
|
+
// (`state-document.cjs`'s `normalizeStateStatus`) rather than growing a
|
|
215
|
+
// second bespoke token list here.
|
|
216
|
+
const statusVal = (snapshot.stateStatus.value ?? '').trim();
|
|
217
|
+
if (normalizeStateStatus(statusVal, null) === 'completed')
|
|
218
|
+
return [];
|
|
219
|
+
return [
|
|
220
|
+
{
|
|
221
|
+
code: 'W011',
|
|
222
|
+
severity: SEVERITY.WARNING,
|
|
223
|
+
message: `STATE.md says current phase is ${phaseId} (status: ${statusVal.toLowerCase() || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`,
|
|
224
|
+
remedy: adviseRemedy('Run /gsd-progress to re-derive current position, or manually update STATE.md'),
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
// ─── W021 — phase_id_convention integer-prefix/milestone mismatch ──────────
|
|
230
|
+
const RULE_W021 = {
|
|
231
|
+
code: 'W021',
|
|
232
|
+
severity: SEVERITY.WARNING,
|
|
233
|
+
description: "Phase's integer prefix implies a different milestone than its ROADMAP section (phase_id_convention: milestone-prefixed)",
|
|
234
|
+
repairable: false,
|
|
235
|
+
check: (snapshot) => {
|
|
236
|
+
const convention = snapshot.config.value?.['phase_id_convention'];
|
|
237
|
+
if (convention !== 'milestone-prefixed')
|
|
238
|
+
return [];
|
|
239
|
+
const diagnostics = [];
|
|
240
|
+
for (const entry of snapshot.roadmapDeclaredPhases.value) {
|
|
241
|
+
// `entry.milestone === null` means the builder never found this phase
|
|
242
|
+
// heading inside any versioned (`v\d+\.\d+`) section — the original
|
|
243
|
+
// `checkMilestonePrefixMismatches` only ever iterates phases found
|
|
244
|
+
// WITHIN a section, so a phase outside any section is equivalently
|
|
245
|
+
// never checked here.
|
|
246
|
+
if (entry.milestone === null)
|
|
247
|
+
continue;
|
|
248
|
+
const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
|
|
249
|
+
if (expectedMilestone === null || expectedMilestone === entry.milestone)
|
|
250
|
+
continue;
|
|
251
|
+
diagnostics.push({
|
|
252
|
+
code: 'W021',
|
|
253
|
+
severity: SEVERITY.WARNING,
|
|
254
|
+
message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
|
|
255
|
+
remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return diagnostics;
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
// ─── W026 — STATE says milestone complete but ROADMAP lists unstarted phase ─
|
|
262
|
+
const RULE_W026 = {
|
|
263
|
+
code: 'W026',
|
|
264
|
+
severity: SEVERITY.WARNING,
|
|
265
|
+
description: 'STATE says milestone complete but ROADMAP lists an unstarted phase for that milestone',
|
|
266
|
+
repairable: false,
|
|
267
|
+
check: (snapshot) => {
|
|
268
|
+
const statusVal = (snapshot.stateStatus.value ?? '').trim().toLowerCase();
|
|
269
|
+
if (!/milestone complete|archived/.test(statusVal))
|
|
270
|
+
return [];
|
|
271
|
+
// `currentMilestoneRoadmapPhaseIds` is already scoped to the current
|
|
272
|
+
// milestone (`extractCurrentMilestone(roadmapRaw, cwd)`, the same
|
|
273
|
+
// `<details>`/`<summary>`-tolerant owner `verify.cts:2364` used) — no
|
|
274
|
+
// separate `currentMilestone` resolution/filter needed here (see the
|
|
275
|
+
// field's own doc comment on `PlanningSnapshot` for why
|
|
276
|
+
// `roadmapDeclaredPhases`'s `milestone` attribution is the wrong fit).
|
|
277
|
+
const unstarted = [];
|
|
278
|
+
for (const phaseId of snapshot.currentMilestoneRoadmapPhaseIds.value) {
|
|
279
|
+
const normalized = normalizePhaseName(phaseId);
|
|
280
|
+
// `allPhaseDirNames` — every directory under `phases/`, UNWINDOWED by
|
|
281
|
+
// ROADMAP-declaration membership — mirrors the original's own
|
|
282
|
+
// unwindowed `phaseDirNames2` (`verify.cts:2372-2382`, a direct
|
|
283
|
+
// `readdirSync` of the phases dir), not the current-milestone-windowed
|
|
284
|
+
// `phaseDirs`.
|
|
285
|
+
const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized).matches.length > 0;
|
|
286
|
+
if (!hasDirectory)
|
|
287
|
+
unstarted.push(phaseId);
|
|
288
|
+
}
|
|
289
|
+
if (unstarted.length === 0)
|
|
290
|
+
return [];
|
|
291
|
+
return [
|
|
292
|
+
{
|
|
293
|
+
code: 'W026',
|
|
294
|
+
severity: SEVERITY.WARNING,
|
|
295
|
+
message: `STATE says milestone complete but ROADMAP lists ${unstarted.length} unstarted phase(s) (e.g. Phase ${unstarted[0]})`,
|
|
296
|
+
remedy: adviseRemedy('Run validate consistency or re-run complete-milestone after verifying all phases are done'),
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
302
|
+
const RULES = [RULE_W024, RULE_W002, RULE_W011, RULE_W021, RULE_W026];
|
|
303
|
+
module.exports = { RULES };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Health Diagnostic — Worktree health rules (Phase 11, #3309, ADR-3180
|
|
4
|
+
* §8.2/§8.3/§8.5).
|
|
5
|
+
*
|
|
6
|
+
* Group: "Worktree health" (design doc, "Rule table organization" table) —
|
|
7
|
+
* W020 (×3 internal conditions, one subject: "the worktree health scan
|
|
8
|
+
* itself is degraded", design doc "Rejected alternatives" §3), W017 (orphan
|
|
9
|
+
* worktree), W027 (NEW — the split-off "stale worktree" subject, design
|
|
10
|
+
* doc's "New codes for the two split subjects" section).
|
|
11
|
+
*
|
|
12
|
+
* Ported behavior-preserving from `cmdValidateHealth`
|
|
13
|
+
* (`src/verify.cts:2193-2268`), the exact call sites for W020/W017/W027 (the
|
|
14
|
+
* pre-migration source still names the split-off stale-worktree site
|
|
15
|
+
* 'W017' — this batch is what actually applies the W027 split).
|
|
16
|
+
*
|
|
17
|
+
* W020's original THREE conditions were git_timed_out / git_list_failed / a
|
|
18
|
+
* per-finding 'unverified' kind, each with its own message. The first two
|
|
19
|
+
* are scan-level failures reported by `inspectWorktreeHealth`'s own `reason`
|
|
20
|
+
* field ('git_timed_out' vs 'git_list_failed' vs 'not_a_git_repo') —
|
|
21
|
+
* `planning-snapshot.cts`'s `buildWorktreeHealthField` now carries `reason`
|
|
22
|
+
* straight through on `PlanningSnapshot.worktreeHealth`, so `checkW020`
|
|
23
|
+
* below reproduces the original's exact branch-per-reason messages instead
|
|
24
|
+
* of collapsing them (a prior version of this file collapsed both into one
|
|
25
|
+
* message AND, worse, warned on 'not_a_git_repo' too — a regression, since
|
|
26
|
+
* the original silently skips a non-git cwd; see `verify.cts:2202-2217`).
|
|
27
|
+
*
|
|
28
|
+
* W027 restores the pre-migration active-worktree exclusion
|
|
29
|
+
* (`verify.cts:2233-2242`) via `PlanningSnapshot.cwd` — see `checkW027`'s own
|
|
30
|
+
* comment below for the mechanism.
|
|
31
|
+
*
|
|
32
|
+
* Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
|
|
33
|
+
*
|
|
34
|
+
* ADR-457 build-at-publish: source in
|
|
35
|
+
* src/health-diagnostic-rules/worktree-health.cts, compiled to
|
|
36
|
+
* gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs (gitignored).
|
|
37
|
+
*/
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
39
|
+
const shellCmdProjection = require("../shell-command-projection.cjs");
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
|
+
const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
|
|
42
|
+
const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
44
|
+
const planningScopeMod = require("../planning-scope.cjs");
|
|
45
|
+
const { SCOPE } = planningScopeMod;
|
|
46
|
+
// ─── W020 — worktree health scan itself is degraded (verify.cts:2193-2264) ─
|
|
47
|
+
//
|
|
48
|
+
// ONE rule, THREE internal conditions, all the same subject ("the worktree
|
|
49
|
+
// health scan itself is degraded" — design doc "Rejected alternatives" §3):
|
|
50
|
+
// (a) `git worktree list` timed out (verify.cts:2202-2209), (b) `git
|
|
51
|
+
// worktree list` failed outright (verify.cts:2210-2217), (c) a specific
|
|
52
|
+
// 'unverified' finding (existsSync ok, statSync threw,
|
|
53
|
+
// verify.cts:2256-2263). A fourth `!ok` reason, 'not_a_git_repo', and a
|
|
54
|
+
// thrown exception ('exception') are DELIBERATELY silent — the original's
|
|
55
|
+
// `if` ladder never matches 'not_a_git_repo', and the outer try/catch around
|
|
56
|
+
// the whole block is commented "git worktree not available or not a git
|
|
57
|
+
// repo — skip silently".
|
|
58
|
+
function checkW020(snapshot) {
|
|
59
|
+
const diagnostics = [];
|
|
60
|
+
const { scope, reason } = snapshot.worktreeHealth;
|
|
61
|
+
const degraded = scope === SCOPE.UNREADABLE;
|
|
62
|
+
// (a) — git worktree list timed out (verify.cts:2202-2209).
|
|
63
|
+
if (degraded && reason === 'git_timed_out') {
|
|
64
|
+
diagnostics.push({
|
|
65
|
+
code: 'W020',
|
|
66
|
+
severity: SEVERITY.WARNING,
|
|
67
|
+
message: 'Worktree health check degraded: git worktree list timed out after 10s — orphan/stale worktrees could not be inspected',
|
|
68
|
+
remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check for .git/index.lock or a hung git process'),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// (b) — git worktree list failed outright (verify.cts:2210-2217).
|
|
72
|
+
if (degraded && reason === 'git_list_failed') {
|
|
73
|
+
diagnostics.push({
|
|
74
|
+
code: 'W020',
|
|
75
|
+
severity: SEVERITY.WARNING,
|
|
76
|
+
message: 'Worktree health check degraded: git worktree list failed — orphan/stale worktrees could not be inspected',
|
|
77
|
+
remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check git repository state and permissions'),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// (c) — per-finding 'unverified' (existsSync ok, statSync threw).
|
|
81
|
+
for (const finding of snapshot.worktreeHealth.value) {
|
|
82
|
+
if (finding.kind !== 'unverified')
|
|
83
|
+
continue;
|
|
84
|
+
diagnostics.push({
|
|
85
|
+
code: 'W020',
|
|
86
|
+
severity: SEVERITY.WARNING,
|
|
87
|
+
message: `Worktree health check degraded: could not stat ${finding.path} — presence/staleness could not be verified`,
|
|
88
|
+
remedy: adviseRemedy('Check filesystem permissions on the worktree path, or investigate why statSync failed for it'),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return diagnostics;
|
|
92
|
+
}
|
|
93
|
+
// ─── W017 — orphan git worktree (verify.cts:2222-2229) ─────────────────────
|
|
94
|
+
//
|
|
95
|
+
// `finding.kind === 'orphan'` — path no longer exists on disk. One
|
|
96
|
+
// Diagnostic per orphan finding. Remedy mirrors the exact original literal
|
|
97
|
+
// fix, `verify.cts:2227`: `'Run: git worktree prune'`.
|
|
98
|
+
function checkW017(snapshot) {
|
|
99
|
+
const diagnostics = [];
|
|
100
|
+
for (const finding of snapshot.worktreeHealth.value) {
|
|
101
|
+
if (finding.kind !== 'orphan')
|
|
102
|
+
continue;
|
|
103
|
+
diagnostics.push({
|
|
104
|
+
code: 'W017',
|
|
105
|
+
severity: SEVERITY.WARNING,
|
|
106
|
+
message: `Orphan git worktree: ${finding.path} (path no longer exists on disk)`,
|
|
107
|
+
remedy: adviseRemedy('git worktree prune'),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return diagnostics;
|
|
111
|
+
}
|
|
112
|
+
// ─── W027 — stale git worktree (verify.cts:2232-2249, the split-off half of
|
|
113
|
+
// the pre-migration 'W017' site) ─────────────────────────────────────────
|
|
114
|
+
//
|
|
115
|
+
// `finding.kind === 'stale'` — age-based. Excludes the active session's own
|
|
116
|
+
// worktree, restored via `snapshot.cwd` (see module doc, gap 2 — RESOLVED):
|
|
117
|
+
// a 'stale' finding is skipped when `snapshot.cwd` equals the finding's path
|
|
118
|
+
// or is nested under it, the exact comparison `verify.cts:2238-2241` made
|
|
119
|
+
// against `process.cwd()`. Per this batch's brief: the interpolated command
|
|
120
|
+
// (with the real path) lives in `message`; `remedy.args.command` stays a
|
|
121
|
+
// static `<path>` template, mirroring the split the brief specifies.
|
|
122
|
+
// ─── #3663 — path-comparison provenance helper ─────────────────────────────
|
|
123
|
+
//
|
|
124
|
+
// snapshot.cwd is raw process-cwd-derived — path.resolve() normalizes
|
|
125
|
+
// separators and relative segments but NOT casing, and a process launched via
|
|
126
|
+
// a differently-cased path echoes that spelling back. finding.path is
|
|
127
|
+
// `git worktree list`-derived, which self-normalizes to the canonical
|
|
128
|
+
// on-disk casing (forward slashes). Comparing those two spellings strictly
|
|
129
|
+
// misclassifies the ACTIVE worktree as stale on win32 — so the comparison
|
|
130
|
+
// folds case ONLY on win32 (case-insensitive filesystem, via the Shell
|
|
131
|
+
// Command Projection seam's toComparablePathKey — the platform-conditional
|
|
132
|
+
// fold policy lives there, not per call site) and stays case-sensitive on
|
|
133
|
+
// POSIX, where differently-cased paths are genuinely different directories.
|
|
134
|
+
// No realpath resolution — that would change symlink matching behavior.
|
|
135
|
+
function isActiveWorktreePath(activeCwd, worktreePath, platform = process.platform) {
|
|
136
|
+
const active = shellCmdProjection.toComparablePathKey(activeCwd, platform);
|
|
137
|
+
const worktree = shellCmdProjection.toComparablePathKey(worktreePath, platform);
|
|
138
|
+
return active === worktree || active.startsWith(worktree + '/');
|
|
139
|
+
}
|
|
140
|
+
function checkW027(snapshot) {
|
|
141
|
+
const diagnostics = [];
|
|
142
|
+
const activeCwd = snapshot.cwd;
|
|
143
|
+
for (const finding of snapshot.worktreeHealth.value) {
|
|
144
|
+
if (finding.kind !== 'stale')
|
|
145
|
+
continue;
|
|
146
|
+
if (isActiveWorktreePath(activeCwd, finding.path))
|
|
147
|
+
continue;
|
|
148
|
+
diagnostics.push({
|
|
149
|
+
code: 'W027',
|
|
150
|
+
severity: SEVERITY.WARNING,
|
|
151
|
+
// #3280: staleness is a pure mtime heuristic and carries no information
|
|
152
|
+
// about whether the tree is clean — git's own refusal of a non-forced
|
|
153
|
+
// removal on a dirty tree is the safety net, so the remediation must
|
|
154
|
+
// direct the operator (or an agent executing this literally) to check
|
|
155
|
+
// for uncommitted work FIRST and keep `--force` an explicit discard
|
|
156
|
+
// opt-in, never the default instruction.
|
|
157
|
+
message: `Stale git worktree: ${finding.path} (last modified ${finding.ageMinutes} minutes ago). Inspect uncommitted work first: git -C ${finding.path} status --porcelain; if clean run: git worktree remove ${finding.path}; only add --force to discard changes`,
|
|
158
|
+
remedy: adviseRemedy('git -C <path> status --porcelain; if clean: git worktree remove <path>; add --force only to discard changes'),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return diagnostics;
|
|
162
|
+
}
|
|
163
|
+
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
164
|
+
const RULES = [
|
|
165
|
+
{
|
|
166
|
+
code: 'W020',
|
|
167
|
+
severity: SEVERITY.WARNING,
|
|
168
|
+
description: 'Worktree health scan degraded — git worktree list timed out, failed, or a finding could not be verified',
|
|
169
|
+
repairable: false,
|
|
170
|
+
check: checkW020,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
code: 'W017',
|
|
174
|
+
severity: SEVERITY.WARNING,
|
|
175
|
+
description: 'Orphan git worktree (path no longer exists on disk)',
|
|
176
|
+
repairable: false,
|
|
177
|
+
check: checkW017,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
code: 'W027',
|
|
181
|
+
severity: SEVERITY.WARNING,
|
|
182
|
+
description: 'Stale git worktree (not modified in a long time)',
|
|
183
|
+
repairable: false,
|
|
184
|
+
check: checkW027,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
module.exports = { RULES, isActiveWorktreePath };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Health Diagnostic Types — shared, dependency-free rule-table types (Phase
|
|
4
|
+
* 11, #3309, ADR-3180 §8.2/§8.3/§8.5).
|
|
5
|
+
*
|
|
6
|
+
* Split out from `src/health-diagnostic.cts` to break a CJS circular
|
|
7
|
+
* dependency between the evaluator and its own rule-group files
|
|
8
|
+
* (`src/health-diagnostic-rules/*.cts`): those files need the frozen
|
|
9
|
+
* `SEVERITY`/`REMEDY_ACTION`/`REMEDY_RISK` enums and the `Diagnostic`/
|
|
10
|
+
* `Remedy`/`Rule` shapes, but the evaluator (`health-diagnostic.cts`) also
|
|
11
|
+
* needs to `require()` every rule-group file to populate its `RULES` array —
|
|
12
|
+
* a rule-group file requiring `health-diagnostic.cjs` back, mid-load, reads
|
|
13
|
+
* `module.exports` before it is assigned, so the destructured enums come
|
|
14
|
+
* back `undefined`. This leaf has NO runtime dependency on anything in that
|
|
15
|
+
* cycle, so both sides can depend on it directly.
|
|
16
|
+
*
|
|
17
|
+
* Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
|
|
18
|
+
* Test matrix: .gsd/phase/refactor-3309-health-diagnostic-rule-table/50-test-matrix.md
|
|
19
|
+
*
|
|
20
|
+
* ADR-457 build-at-publish: source in src/health-diagnostic-types.cts,
|
|
21
|
+
* compiled to gsd-core/bin/lib/health-diagnostic-types.cjs (gitignored).
|
|
22
|
+
*/
|
|
23
|
+
// ─── Severity ───────────────────────────────────────────────────────────────
|
|
24
|
+
const SEVERITY = Object.freeze({
|
|
25
|
+
ERROR: 'error',
|
|
26
|
+
WARNING: 'warning',
|
|
27
|
+
INFO: 'info',
|
|
28
|
+
});
|
|
29
|
+
// ─── Remedy action / risk ───────────────────────────────────────────────────
|
|
30
|
+
// Harvested from health.md's published table + the corrected 6-action
|
|
31
|
+
// implementation (`src/verify.cts:2405-2553`) — not 5; `addAiIntegrationPhaseKey`
|
|
32
|
+
// (verify.cts:1860/2481-2502) was live in code, missing from docs (design
|
|
33
|
+
// doc, "Ground truth vs. issue #3309's claims" section).
|
|
34
|
+
const REMEDY_ACTION = Object.freeze({
|
|
35
|
+
CREATE_CONFIG: 'createConfig',
|
|
36
|
+
RESET_CONFIG: 'resetConfig',
|
|
37
|
+
REGENERATE_STATE: 'regenerateState',
|
|
38
|
+
ADD_NYQUIST_KEY: 'addNyquistKey',
|
|
39
|
+
ADD_AI_INTEGRATION_PHASE_KEY: 'addAiIntegrationPhaseKey',
|
|
40
|
+
BACKFILL_MILESTONES: 'backfillMilestones',
|
|
41
|
+
// §8.3 rule 5 — every non-repairable finding's `fix` string becomes an
|
|
42
|
+
// ADVISE payload; ADVISE never acts, only describes.
|
|
43
|
+
ADVISE: 'advise',
|
|
44
|
+
});
|
|
45
|
+
const REMEDY_RISK = Object.freeze({
|
|
46
|
+
NONE: 'none',
|
|
47
|
+
DESTRUCTIVE: 'destructive',
|
|
48
|
+
});
|
|
49
|
+
// ─── adviseRemedy — shared ADVISE-remedy builder ───────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Every rule-group file needs the same `{action: ADVISE, risk: NONE, args:
|
|
52
|
+
* {command}}` shape for a non-repairable finding's `fix` string (§8.3 rule
|
|
53
|
+
* 5). Was defined identically in `config-validation.cts` and
|
|
54
|
+
* `agent-install.cts`, and repeated inline elsewhere — moved to this shared,
|
|
55
|
+
* dependency-free leaf so every rule-group file imports one implementation
|
|
56
|
+
* instead of duplicating it.
|
|
57
|
+
*/
|
|
58
|
+
function adviseRemedy(command) {
|
|
59
|
+
return { action: REMEDY_ACTION.ADVISE, risk: REMEDY_RISK.NONE, args: { command } };
|
|
60
|
+
}
|
|
61
|
+
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
62
|
+
const healthDiagnosticTypes = {
|
|
63
|
+
SEVERITY,
|
|
64
|
+
REMEDY_ACTION,
|
|
65
|
+
REMEDY_RISK,
|
|
66
|
+
adviseRemedy,
|
|
67
|
+
};
|
|
68
|
+
module.exports = healthDiagnosticTypes;
|