@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,461 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* lint-health-diagnostic-rule-table.cjs — gate: enforces ADR-3180 §8.2's 1:1
|
|
6
|
+
* rule-code invariant and §8.5's fixture-proof invariant for
|
|
7
|
+
* `src/health-diagnostic.cts`'s RULES table (Phase 11, #3309).
|
|
8
|
+
*
|
|
9
|
+
* ## What this enforces
|
|
10
|
+
*
|
|
11
|
+
* 1. (§8.2 rule 1 — 1:1 code invariant) Every `rule.code` in RULES (exported
|
|
12
|
+
* from the compiled `gsd-core/bin/lib/health-diagnostic.cjs`) is unique,
|
|
13
|
+
* and every rule's `severity` is one of `SEVERITY`'s values. The severity
|
|
14
|
+
* check exists only to confirm the compiled artifact was not hand-edited
|
|
15
|
+
* to bypass the `Rule.severity` required field TypeScript already
|
|
16
|
+
* enforces at compile time — "severity is a property of the RULE, never
|
|
17
|
+
* the emit call."
|
|
18
|
+
* 2. (§8.5 — fixture-proof invariant) Every code in RULES has a paired test:
|
|
19
|
+
* the code string (e.g. `'W001'`) appears as a literal AND within a
|
|
20
|
+
* `describe(`/`test(` block whose title also names that exact code, in
|
|
21
|
+
* one of the health-diagnostic test files
|
|
22
|
+
* (`tests/health-diagnostic-rules/*.test.cjs`,
|
|
23
|
+
* `tests/health-diagnostic.test.cjs`). A mere comment/string mention
|
|
24
|
+
* outside a titled block does not count as coverage.
|
|
25
|
+
*
|
|
26
|
+
* EXCEPTION — `PERMANENTLY_INERT_CODES` (below): a rule whose `check`
|
|
27
|
+
* always returns `[]` BY DESIGN (the real check lives outside the rule
|
|
28
|
+
* table entirely, because it needs ambient I/O `Rule.check` cannot
|
|
29
|
+
* perform — §8.1 rule 1) can never satisfy a real fixture-proof, no
|
|
30
|
+
* matter how many tests reference its code. Before this exception
|
|
31
|
+
* existed, W024 "passed" this guard only because an unrelated test title
|
|
32
|
+
* (the RULES-array shape assertion, "exports exactly 5 rules: W024, ...")
|
|
33
|
+
* happened to contain the string "W024" — accidental coverage, not proof
|
|
34
|
+
* the rule can fire. `PERMANENTLY_INERT_CODES` makes that exemption
|
|
35
|
+
* explicit and auditable instead of relying on a coincidental title
|
|
36
|
+
* match, and the PASS output now reports exempted codes SEPARATELY from
|
|
37
|
+
* genuinely fixture-covered ones rather than folding them together.
|
|
38
|
+
* 3. (Phase 12, #3310 — S0NN pass) `cmdStateValidate` (src/state.cts) emits
|
|
39
|
+
* 7 coded diagnostics (S001-S007) built inline via a local
|
|
40
|
+
* `stateDiagnostic()` helper — NOT `Rule`-table entries, so they are not
|
|
41
|
+
* read from the compiled module the way RULES/CONSISTENCY_RULES are.
|
|
42
|
+
* This third pass hardcodes that code list (`STATE_VALIDATE_CODES`,
|
|
43
|
+
* below) and applies the SAME §8.5 fixture-proof check against
|
|
44
|
+
* `tests/state.test.cjs`, reported in its own PASS/FAIL section —
|
|
45
|
+
* mirroring the C0NN pass's structure, just with a hardcoded list
|
|
46
|
+
* instead of a `Rule[]` array as the code source.
|
|
47
|
+
*
|
|
48
|
+
* Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
|
|
49
|
+
* ("The lint guard (§8.2 1:1 invariant + §8.5 fixture proof)").
|
|
50
|
+
*
|
|
51
|
+
* ## Deviation from the design doc's original plan
|
|
52
|
+
*
|
|
53
|
+
* The design doc assumed fixtures would live as separate files at
|
|
54
|
+
* `tests/fixtures/health-diagnostic/<code>.*`. That did not happen during
|
|
55
|
+
* implementation — all 8 rule-group test files
|
|
56
|
+
* (`tests/health-diagnostic-rules/*.test.cjs`) build fixtures INLINE via
|
|
57
|
+
* real temp directories (`createTempDir()` from `tests/helpers.cjs`) and a
|
|
58
|
+
* real, non-mocked `buildPlanningSnapshot(tmpCwd)` call (see
|
|
59
|
+
* `tests/health-diagnostic-rules/root-existence.test.cjs`). This guard
|
|
60
|
+
* therefore verifies the fixture-proof invariant STATICALLY against the
|
|
61
|
+
* test files' own text — mirroring `scripts/lint-fix-has-regression-tests.cjs`'s
|
|
62
|
+
* house style — rather than dynamically re-running fixture-building code
|
|
63
|
+
* this guard does not own.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
const fs = require('node:fs');
|
|
67
|
+
const path = require('node:path');
|
|
68
|
+
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
|
|
69
|
+
|
|
70
|
+
const REPO_ROOT = path.join(__dirname, '..');
|
|
71
|
+
const COMPILED_MODULE_REL = 'gsd-core/bin/lib/health-diagnostic.cjs';
|
|
72
|
+
const COMPILED_MODULE_PATH = path.join(REPO_ROOT, COMPILED_MODULE_REL);
|
|
73
|
+
const TEST_GROUP_DIR = path.join(REPO_ROOT, 'tests', 'health-diagnostic-rules');
|
|
74
|
+
const SKELETON_TEST_FILE = path.join(REPO_ROOT, 'tests', 'health-diagnostic.test.cjs');
|
|
75
|
+
|
|
76
|
+
// Phase 12 (#3310, ADR-3180 §8.4) — the C0NN namespace's own fixture-proof
|
|
77
|
+
// test file. §8.5 extends to `CONSISTENCY_RULES`'s NEW codes only (C001-C004
|
|
78
|
+
// — W006/W007 are already fixture-proofed above, against the SAME `Rule`
|
|
79
|
+
// objects; re-checking them here would be redundant, not additional
|
|
80
|
+
// coverage).
|
|
81
|
+
const CONSISTENCY_TEST_FILE = path.join(REPO_ROOT, 'tests', 'health-diagnostic-rules', 'consistency.test.cjs');
|
|
82
|
+
const CONSISTENCY_CODE_PREFIX_RE = /^C\d{3}$/;
|
|
83
|
+
|
|
84
|
+
// Phase 12 (#3310, ADR-3180 §8.5 extension) — the S0NN namespace's own
|
|
85
|
+
// fixture-proof pass. These codes are NOT collected in any exported `Rule[]`
|
|
86
|
+
// array: `cmdStateValidate` (src/state.cts) builds `Diagnostic[]` directly via
|
|
87
|
+
// a local `stateDiagnostic()` helper, not via the rule-table evaluator (out of
|
|
88
|
+
// scope for the RULES/CONSISTENCY_RULES-keyed passes above).
|
|
89
|
+
//
|
|
90
|
+
// #3696: the list is DISCOVERED from the source, not hardcoded. It used to be a
|
|
91
|
+
// literal `['S001', ..., 'S007']`, which is precisely the shape ADR-3180
|
|
92
|
+
// Decision 4(a) forbids — "guards discover call sites by whole-repo scan, never
|
|
93
|
+
// by an allowlist of known files" — because such a guard can only ever be as
|
|
94
|
+
// complete as the author's recall. Adding S008/S009 to `cmdStateValidate` left
|
|
95
|
+
// this pass reporting a confident, green "7 code(s), all fixture-covered" while
|
|
96
|
+
// two new codes had no fixture requirement at all: a zero it did not earn. The
|
|
97
|
+
// scan below cannot report a code it has not read out of the source.
|
|
98
|
+
const STATE_VALIDATE_TEST_FILE = path.join(REPO_ROOT, 'tests', 'state.test.cjs');
|
|
99
|
+
const STATE_VALIDATE_SOURCE_FILE = path.join(REPO_ROOT, 'src', 'state.cts');
|
|
100
|
+
// `g` is required by String.prototype.matchAll, which (unlike .exec) does not
|
|
101
|
+
// carry lastIndex across calls — so this constant is safe to share.
|
|
102
|
+
// #3696 review: `\s*` before `(` too. Requiring no space silently dropped a
|
|
103
|
+
// `stateDiagnostic ('S010', …)` call site from the discovered set, and since the
|
|
104
|
+
// fail-closed check below only fires on a FULLY empty result, a partial miss
|
|
105
|
+
// escaped the fixture-proof check entirely — the same "only as complete as the
|
|
106
|
+
// author's recall" failure this rewrite exists to prevent.
|
|
107
|
+
const STATE_DIAGNOSTIC_CALL_RE = /\bstateDiagnostic\s*\(\s*(['"`])(S\d{3})\1/g;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Every S0NN code `cmdStateValidate` can emit, read off its
|
|
111
|
+
* `stateDiagnostic(...)` call sites in `sourceText`.
|
|
112
|
+
*
|
|
113
|
+
* Takes the source TEXT rather than reading the path itself, so the discovery
|
|
114
|
+
* rule is exercisable against controlled fixtures — including the fail-closed
|
|
115
|
+
* path below, which is the branch that matters and which a path-reading
|
|
116
|
+
* function could only be tested on by mutating the real `src/state.cts`.
|
|
117
|
+
*
|
|
118
|
+
* Fails closed. An empty result means the helper was renamed or its call shape
|
|
119
|
+
* changed, and a guard that answers "0 codes, all covered" to that is worse than
|
|
120
|
+
* no guard — so it raises instead. Line/regex-based (not full AST) per this
|
|
121
|
+
* repo's existing lint-guard house style, same as TITLED_BLOCK_RE below.
|
|
122
|
+
*/
|
|
123
|
+
function discoverStateValidateCodes(sourceText, sourceLabel = formatRepoRelative(STATE_VALIDATE_SOURCE_FILE)) {
|
|
124
|
+
const codes = [...sourceText.matchAll(STATE_DIAGNOSTIC_CALL_RE)].map((m) => m[2]);
|
|
125
|
+
const unique = [...new Set(codes)].sort();
|
|
126
|
+
if (unique.length === 0) {
|
|
127
|
+
throw new ExitError(
|
|
128
|
+
1,
|
|
129
|
+
`lint-health-diagnostic-rule-table: found no stateDiagnostic() call sites in ${sourceLabel}.\n`
|
|
130
|
+
+ ' This pass discovers the S0NN code set from those call sites (#3696), so an empty\n'
|
|
131
|
+
+ ' result means the helper was renamed or its call shape changed — not that there are\n'
|
|
132
|
+
+ ' no codes. Update STATE_DIAGNOSTIC_CALL_RE to match the new shape.\n',
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return unique;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function readStateValidateSource() {
|
|
139
|
+
if (!fs.existsSync(STATE_VALIDATE_SOURCE_FILE)) {
|
|
140
|
+
throw new ExitError(
|
|
141
|
+
1,
|
|
142
|
+
`lint-health-diagnostic-rule-table: cannot discover S0NN codes — ${formatRepoRelative(STATE_VALIDATE_SOURCE_FILE)} not found.\n`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return fs.readFileSync(STATE_VALIDATE_SOURCE_FILE, 'utf8');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const STATE_VALIDATE_CODES = discoverStateValidateCodes(readStateValidateSource());
|
|
149
|
+
|
|
150
|
+
// Matches `describe(`/`test(`/`it(` calls whose first argument is a string
|
|
151
|
+
// literal, capturing that literal as the block's title. Line/regex-based
|
|
152
|
+
// (not full AST) per this repo's existing lint-guard house style
|
|
153
|
+
// (scripts/lint-planning-snapshot-bypass-drift.cjs's scanCode precedent).
|
|
154
|
+
const TITLED_BLOCK_RE = /\b(describe|test|it)\(\s*(['"`])((?:\\.|(?!\2)[^\\])*)\2/g;
|
|
155
|
+
|
|
156
|
+
// Rule codes whose `check` is a documented PERMANENT no-op (always returns
|
|
157
|
+
// `[]`) because the real check requires ambient I/O forbidden inside a
|
|
158
|
+
// `Rule.check(snapshot)` (§8.1 rule 1) — the real check runs elsewhere,
|
|
159
|
+
// outside the rule table. These can never be proven via a real
|
|
160
|
+
// diagnostic-firing fixture, so they are exempted from the §8.5 fixture-proof
|
|
161
|
+
// invariant explicitly here rather than via an accidental test-title match.
|
|
162
|
+
// Adding an entry is a deliberate, reviewed decision — see each reason.
|
|
163
|
+
const PERMANENTLY_INERT_CODES = new Map([
|
|
164
|
+
[
|
|
165
|
+
'W024',
|
|
166
|
+
'readStateHeadFreshness requires a git-log shell-out, forbidden ambient I/O for Rule.check ' +
|
|
167
|
+
'(§8.1 rule 1) — the real check runs in cmdValidateHealth itself, outside the rule table ' +
|
|
168
|
+
'(src/verify.cts). This rule-table entry is a permanent no-op by design, not a fixture gap.',
|
|
169
|
+
],
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Load the compiled health-diagnostic module. Throws a clear ExitError
|
|
174
|
+
* (not a raw MODULE_NOT_FOUND) if `npm run build:lib` has not run.
|
|
175
|
+
*/
|
|
176
|
+
function loadCompiledModule(compiledPath = COMPILED_MODULE_PATH) {
|
|
177
|
+
if (!fs.existsSync(compiledPath)) {
|
|
178
|
+
throw new ExitError(
|
|
179
|
+
2,
|
|
180
|
+
`lint-health-diagnostic-rule-table: compiled artifact not found at ${COMPILED_MODULE_REL}.\n` +
|
|
181
|
+
'Run `npm run build:lib` first.',
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return require(compiledPath);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* §8.2 rule 1 — 1:1 code invariant: every rule.code is unique, and every
|
|
189
|
+
* rule's severity is a member of SEVERITY's values.
|
|
190
|
+
*
|
|
191
|
+
* @param {Array<{code: string, severity: string}>} rules
|
|
192
|
+
* @param {Record<string, string>} severity SEVERITY export (code -> value)
|
|
193
|
+
* @returns {{duplicates: Array<{code: string, count: number}>, badSeverities: Array<{code: string, severity: unknown}>}}
|
|
194
|
+
*/
|
|
195
|
+
function checkOneToOneInvariant(rules, severity) {
|
|
196
|
+
const severityValues = new Set(Object.values(severity));
|
|
197
|
+
const counts = new Map();
|
|
198
|
+
const badSeverities = [];
|
|
199
|
+
|
|
200
|
+
for (const rule of rules) {
|
|
201
|
+
counts.set(rule.code, (counts.get(rule.code) || 0) + 1);
|
|
202
|
+
if (!severityValues.has(rule.severity)) {
|
|
203
|
+
badSeverities.push({ code: rule.code, severity: rule.severity });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const duplicates = [...counts.entries()]
|
|
208
|
+
.filter(([, count]) => count > 1)
|
|
209
|
+
.map(([code, count]) => ({ code, count }));
|
|
210
|
+
|
|
211
|
+
return { duplicates, badSeverities };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Extracts every `describe(`/`test(`/`it(` block title found in `text`.
|
|
216
|
+
*
|
|
217
|
+
* @param {string} text
|
|
218
|
+
* @returns {string[]}
|
|
219
|
+
*/
|
|
220
|
+
function extractTitledBlocks(text) {
|
|
221
|
+
const titles = [];
|
|
222
|
+
TITLED_BLOCK_RE.lastIndex = 0;
|
|
223
|
+
let match;
|
|
224
|
+
while ((match = TITLED_BLOCK_RE.exec(text)) !== null) {
|
|
225
|
+
titles.push(match[3]);
|
|
226
|
+
}
|
|
227
|
+
return titles;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* True iff `code` appears verbatim, as a whole token, inside at least one of
|
|
232
|
+
* `titles`. Whole-token match guards against a shorter code accidentally
|
|
233
|
+
* substring-matching inside an unrelated longer token.
|
|
234
|
+
*
|
|
235
|
+
* @param {string} code
|
|
236
|
+
* @param {string[]} titles
|
|
237
|
+
*/
|
|
238
|
+
function codeAppearsInTitle(code, titles) {
|
|
239
|
+
const codeRe = new RegExp(`(?:^|[^A-Za-z0-9])${code}(?:$|[^A-Za-z0-9])`);
|
|
240
|
+
return titles.some((title) => codeRe.test(`|${title}|`));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Locates every health-diagnostic test file this guard scans for §8.5
|
|
245
|
+
* fixture-proof coverage.
|
|
246
|
+
*
|
|
247
|
+
* @param {string} repoRoot
|
|
248
|
+
* @returns {string[]} absolute paths, sorted
|
|
249
|
+
*/
|
|
250
|
+
function findHealthDiagnosticTestFiles(repoRoot = REPO_ROOT) {
|
|
251
|
+
const groupDir = path.join(repoRoot, 'tests', 'health-diagnostic-rules');
|
|
252
|
+
const files = [];
|
|
253
|
+
if (fs.existsSync(groupDir)) {
|
|
254
|
+
for (const entry of fs.readdirSync(groupDir)) {
|
|
255
|
+
if (entry.endsWith('.test.cjs')) {
|
|
256
|
+
files.push(path.join(groupDir, entry));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const skeletonTestFile = path.join(repoRoot, 'tests', 'health-diagnostic.test.cjs');
|
|
261
|
+
if (fs.existsSync(skeletonTestFile)) {
|
|
262
|
+
files.push(skeletonTestFile);
|
|
263
|
+
}
|
|
264
|
+
return files.sort();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* §8.5 — fixture-proof invariant: for every code in `rules`, confirm at
|
|
269
|
+
* least one test file in `testFiles` has a `describe(`/`test(`/`it(` block
|
|
270
|
+
* whose title names that exact code — UNLESS the code is listed in
|
|
271
|
+
* `PERMANENTLY_INERT_CODES`, in which case it is reported separately as
|
|
272
|
+
* `exempted` (visibly, not folded into "covered") and never fails the guard
|
|
273
|
+
* regardless of test coverage.
|
|
274
|
+
*
|
|
275
|
+
* @param {Array<{code: string}>} rules
|
|
276
|
+
* @param {string[]} testFiles absolute paths to *.test.cjs files to scan
|
|
277
|
+
* @param {Map<string, string>} inertCodes PERMANENTLY_INERT_CODES (injectable for tests)
|
|
278
|
+
* @returns {{uncovered: string[], exempted: string[], testFilesScanned: string[]}}
|
|
279
|
+
*/
|
|
280
|
+
function checkFixtureProofInvariant(rules, testFiles, inertCodes = PERMANENTLY_INERT_CODES) {
|
|
281
|
+
const allTitles = [];
|
|
282
|
+
for (const file of testFiles) {
|
|
283
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
284
|
+
allTitles.push(...extractTitledBlocks(text));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const uncovered = [];
|
|
288
|
+
const exempted = [];
|
|
289
|
+
for (const rule of rules) {
|
|
290
|
+
if (inertCodes.has(rule.code)) {
|
|
291
|
+
exempted.push(rule.code);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (!codeAppearsInTitle(rule.code, allTitles)) {
|
|
295
|
+
uncovered.push(rule.code);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return { uncovered, exempted, testFilesScanned: testFiles };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function formatRepoRelative(absPath) {
|
|
303
|
+
return path.relative(REPO_ROOT, absPath).split(path.sep).join('/');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function main() {
|
|
307
|
+
const { RULES, CONSISTENCY_RULES, SEVERITY } = loadCompiledModule();
|
|
308
|
+
|
|
309
|
+
const { duplicates, badSeverities } = checkOneToOneInvariant(RULES, SEVERITY);
|
|
310
|
+
|
|
311
|
+
const testFiles = findHealthDiagnosticTestFiles(REPO_ROOT);
|
|
312
|
+
const { uncovered, exempted } = checkFixtureProofInvariant(RULES, testFiles);
|
|
313
|
+
|
|
314
|
+
// ─── C0NN check pass (Phase 12, #3310) — separate from the W/E/I pass
|
|
315
|
+
// above, own reporting section, does NOT re-check W006/W007's fixture
|
|
316
|
+
// proof (already covered above against the same `Rule` objects).
|
|
317
|
+
const consistencyNewRules = CONSISTENCY_RULES.filter((r) => CONSISTENCY_CODE_PREFIX_RE.test(r.code));
|
|
318
|
+
const { duplicates: consistencyDuplicates, badSeverities: consistencyBadSeverities } = checkOneToOneInvariant(
|
|
319
|
+
consistencyNewRules,
|
|
320
|
+
SEVERITY,
|
|
321
|
+
);
|
|
322
|
+
const consistencyTestFiles = fs.existsSync(CONSISTENCY_TEST_FILE) ? [CONSISTENCY_TEST_FILE] : [];
|
|
323
|
+
const { uncovered: consistencyUncovered } = checkFixtureProofInvariant(
|
|
324
|
+
consistencyNewRules,
|
|
325
|
+
consistencyTestFiles,
|
|
326
|
+
new Map(),
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
// ─── S0NN check pass (Phase 12, #3310) — separate from the W/E/I and C0NN
|
|
330
|
+
// passes above, own reporting section. Hardcoded code list (see the
|
|
331
|
+
// STATE_VALIDATE_CODES comment above) rather than read from a Rule[] array.
|
|
332
|
+
const stateValidateTestFiles = fs.existsSync(STATE_VALIDATE_TEST_FILE) ? [STATE_VALIDATE_TEST_FILE] : [];
|
|
333
|
+
const { uncovered: stateValidateUncovered } = checkFixtureProofInvariant(
|
|
334
|
+
STATE_VALIDATE_CODES.map((code) => ({ code })),
|
|
335
|
+
stateValidateTestFiles,
|
|
336
|
+
new Map(),
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const problems = [];
|
|
340
|
+
|
|
341
|
+
if (duplicates.length > 0) {
|
|
342
|
+
const list = duplicates.map((d) => ` ${d.code} (${d.count} occurrences)`).join('\n');
|
|
343
|
+
problems.push(
|
|
344
|
+
`§8.2 rule 1 violated: ${duplicates.length} duplicated rule code(s) in RULES ` +
|
|
345
|
+
`(${COMPILED_MODULE_REL}):\n${list}\n` +
|
|
346
|
+
' remedy: codes are append-only and 1:1 with a single Rule — rename or remove the duplicate.',
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (badSeverities.length > 0) {
|
|
351
|
+
const list = badSeverities
|
|
352
|
+
.map((b) => ` ${b.code}: severity=${JSON.stringify(b.severity)}`)
|
|
353
|
+
.join('\n');
|
|
354
|
+
problems.push(
|
|
355
|
+
`§8.2 rule 3 violated: ${badSeverities.length} rule(s) with a severity not in SEVERITY's values:\n${list}\n` +
|
|
356
|
+
' remedy: severity is a property of the RULE — set it to SEVERITY.ERROR/WARNING/INFO.',
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (uncovered.length > 0) {
|
|
361
|
+
const scannedList = testFiles.map(formatRepoRelative).join('\n ');
|
|
362
|
+
problems.push(
|
|
363
|
+
`§8.5 violated: ${uncovered.length} rule code(s) with no describe()/test() block naming them ` +
|
|
364
|
+
`(a comment or bare string mention does not count):\n ${uncovered.join(', ')}\n\n` +
|
|
365
|
+
` Searched these test files:\n ${scannedList}\n\n` +
|
|
366
|
+
' remedy: add or extend a describe()/test() title in the matching ' +
|
|
367
|
+
'tests/health-diagnostic-rules/<group>.test.cjs file so the block title ' +
|
|
368
|
+
`names the code verbatim (e.g. describe('${uncovered[0]} — ...', () => { ... })), ` +
|
|
369
|
+
'and drive the rule to fire against a real fixture built via createTempDir() + buildPlanningSnapshot() ' +
|
|
370
|
+
'(see tests/health-diagnostic-rules/root-existence.test.cjs).',
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (consistencyDuplicates.length > 0) {
|
|
375
|
+
const list = consistencyDuplicates.map((d) => ` ${d.code} (${d.count} occurrences)`).join('\n');
|
|
376
|
+
problems.push(
|
|
377
|
+
`§8.2 rule 1 violated (C0NN namespace): ${consistencyDuplicates.length} duplicated rule code(s) in ` +
|
|
378
|
+
`CONSISTENCY_RULES (${COMPILED_MODULE_REL}):\n${list}\n` +
|
|
379
|
+
' remedy: codes are append-only and 1:1 with a single Rule — rename or remove the duplicate.',
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (consistencyBadSeverities.length > 0) {
|
|
384
|
+
const list = consistencyBadSeverities
|
|
385
|
+
.map((b) => ` ${b.code}: severity=${JSON.stringify(b.severity)}`)
|
|
386
|
+
.join('\n');
|
|
387
|
+
problems.push(
|
|
388
|
+
`§8.2 rule 3 violated (C0NN namespace): ${consistencyBadSeverities.length} rule(s) with a severity not ` +
|
|
389
|
+
`in SEVERITY's values:\n${list}\n` +
|
|
390
|
+
' remedy: severity is a property of the RULE — set it to SEVERITY.ERROR/WARNING/INFO.',
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (consistencyUncovered.length > 0) {
|
|
395
|
+
problems.push(
|
|
396
|
+
`§8.5 violated (C0NN namespace): ${consistencyUncovered.length} rule code(s) with no describe()/test() ` +
|
|
397
|
+
`block naming them (a comment or bare string mention does not count):\n ${consistencyUncovered.join(', ')}\n\n` +
|
|
398
|
+
` Searched: ${formatRepoRelative(CONSISTENCY_TEST_FILE)}` +
|
|
399
|
+
(consistencyTestFiles.length === 0 ? ' (file not found)' : '') +
|
|
400
|
+
'\n\n remedy: add or extend a describe()/test() title in tests/health-diagnostic-rules/consistency.test.cjs ' +
|
|
401
|
+
`so the block title names the code verbatim (e.g. describe('${consistencyUncovered[0]} — ...', () => { ... })), ` +
|
|
402
|
+
'and drive the rule to fire against a real fixture built via createTempDir() + buildPlanningSnapshot().',
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (stateValidateUncovered.length > 0) {
|
|
407
|
+
problems.push(
|
|
408
|
+
`§8.5 violated (S0NN namespace): ${stateValidateUncovered.length} code(s) with no describe()/test() ` +
|
|
409
|
+
`block naming them (a comment or bare string mention does not count):\n ${stateValidateUncovered.join(', ')}\n\n` +
|
|
410
|
+
` Searched: ${formatRepoRelative(STATE_VALIDATE_TEST_FILE)}` +
|
|
411
|
+
(stateValidateTestFiles.length === 0 ? ' (file not found)' : '') +
|
|
412
|
+
'\n\n remedy: add or extend a describe()/test() title in tests/state.test.cjs ' +
|
|
413
|
+
`so the block title names the code verbatim (e.g. test('${stateValidateUncovered[0]}: ...', () => { ... })), ` +
|
|
414
|
+
'mirroring the existing `#3310 state validate — S0NN coded diagnostics` describe block.',
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (problems.length > 0) {
|
|
419
|
+
throw new ExitError(1, `${problems.join('\n\n')}\n`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const coveredCount = RULES.length - exempted.length;
|
|
423
|
+
const exemptedDetail = exempted
|
|
424
|
+
.map((code) => `${code} (${PERMANENTLY_INERT_CODES.get(code)})`)
|
|
425
|
+
.join('; ');
|
|
426
|
+
|
|
427
|
+
console.log(
|
|
428
|
+
`lint-health-diagnostic-rule-table: PASS — ${RULES.length} rule code(s): ${coveredCount} covered by a ` +
|
|
429
|
+
`real fixture, ${exempted.length} exempted across ${testFiles.length} test file(s).` +
|
|
430
|
+
(exempted.length > 0 ? `\n Exempted: ${exemptedDetail}` : ''),
|
|
431
|
+
);
|
|
432
|
+
console.log(
|
|
433
|
+
`lint-health-diagnostic-rule-table: PASS (C0NN namespace) — ${consistencyNewRules.length} new rule code(s) ` +
|
|
434
|
+
`(${consistencyNewRules.map((r) => r.code).join(', ')}), all fixture-covered in ` +
|
|
435
|
+
`${formatRepoRelative(CONSISTENCY_TEST_FILE)}.`,
|
|
436
|
+
);
|
|
437
|
+
console.log(
|
|
438
|
+
`lint-health-diagnostic-rule-table: PASS (S0NN namespace) — ${STATE_VALIDATE_CODES.length} code(s) ` +
|
|
439
|
+
`(${STATE_VALIDATE_CODES.join(', ')}), all fixture-covered in ` +
|
|
440
|
+
`${formatRepoRelative(STATE_VALIDATE_TEST_FILE)}.`,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
runMain(main);
|
|
445
|
+
|
|
446
|
+
module.exports = {
|
|
447
|
+
loadCompiledModule,
|
|
448
|
+
checkOneToOneInvariant,
|
|
449
|
+
extractTitledBlocks,
|
|
450
|
+
codeAppearsInTitle,
|
|
451
|
+
findHealthDiagnosticTestFiles,
|
|
452
|
+
checkFixtureProofInvariant,
|
|
453
|
+
PERMANENTLY_INERT_CODES,
|
|
454
|
+
COMPILED_MODULE_PATH,
|
|
455
|
+
TEST_GROUP_DIR,
|
|
456
|
+
SKELETON_TEST_FILE,
|
|
457
|
+
CONSISTENCY_TEST_FILE,
|
|
458
|
+
STATE_VALIDATE_TEST_FILE,
|
|
459
|
+
STATE_VALIDATE_CODES,
|
|
460
|
+
discoverStateValidateCodes,
|
|
461
|
+
};
|