@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,193 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pinned baseline for scripts/lint-docs-guard-registration.cjs's
|
|
5
|
+
* `docs-guard-exempt` identity ratchet — mirrors
|
|
6
|
+
* scripts/lint-allow-test-rule-refs.cjs's `allow-test-rule` ratchet
|
|
7
|
+
* (scripts/lib/allowlist-ratchet.cjs, ADR-456's pattern).
|
|
8
|
+
*
|
|
9
|
+
* Every test file basename here is a KNOWN, already-reviewed
|
|
10
|
+
* `// docs-guard-exempt: <reason>` marker. Nothing caps how many files may
|
|
11
|
+
* carry the marker in the abstract, but ADDING a new one anywhere in
|
|
12
|
+
* tests/*.test.cjs fails `lint-docs-guard-registration` until this baseline
|
|
13
|
+
* is deliberately updated — so a new exemption always shows up as a
|
|
14
|
+
* reviewable diff here, instead of silently opting a file out of the
|
|
15
|
+
* docs-guard registration requirement with zero signal.
|
|
16
|
+
*
|
|
17
|
+
* A file listed here that no longer exists, or no longer carries a real
|
|
18
|
+
* `docs-guard-exempt:` marker in its first 20 lines, is reported STALE and
|
|
19
|
+
* must be pruned (ratchet-down, same as the sibling gate).
|
|
20
|
+
*
|
|
21
|
+
* Seeded 2026-08-23 (#3753 security follow-up FIX 2) from every real marker
|
|
22
|
+
* found via scripts/lint-docs-guard-registration.cjs's own `findExemption`
|
|
23
|
+
* scan of tests/*.test.cjs — derived, not retyped from memory.
|
|
24
|
+
*
|
|
25
|
+
* Extended 2026-08-23 (#3753 correctness follow-up): the reader-detection
|
|
26
|
+
* fixes (Defects A/B/C) surfaced 86 previously-undetected docs/ readers. 40
|
|
27
|
+
* were genuine docs-content guards (added to DOCS_GUARD_TESTS in
|
|
28
|
+
* scripts/docs-guard-registry.cjs); the 46 added here touch a docs/ path
|
|
29
|
+
* only incidentally (fixture data, external URL citations, comment-only
|
|
30
|
+
* mentions, metadata labels, or scan-exclusion lists) — see each file's own
|
|
31
|
+
* `docs-guard-exempt:` marker for its specific reason.
|
|
32
|
+
*/
|
|
33
|
+
const DOCS_GUARD_EXEMPT_BASELINE = [
|
|
34
|
+
'adr-parser.test.cjs',
|
|
35
|
+
'adr-parser.unit.test.cjs',
|
|
36
|
+
'agent-marker-documentation-guard.test.cjs',
|
|
37
|
+
'antigravity-upgrades.test.cjs',
|
|
38
|
+
'capability-cli.test.cjs',
|
|
39
|
+
'capability-validator-task-content-resolver.test.cjs',
|
|
40
|
+
'ci-docs-guard-registry.test.cjs',
|
|
41
|
+
'ci-test-scope.test.cjs',
|
|
42
|
+
'cline-install.test.cjs',
|
|
43
|
+
'code-review-depth.test.cjs',
|
|
44
|
+
'code-review-pipeline-regression.test.cjs',
|
|
45
|
+
'codebuddy-upgrades.test.cjs',
|
|
46
|
+
'commands.test.cjs',
|
|
47
|
+
'commit-docs-bypass.test.cjs',
|
|
48
|
+
'complexity-trigger.test.cjs',
|
|
49
|
+
'concurrency-safety.test.cjs',
|
|
50
|
+
'cursor-imperative-reference.test.cjs',
|
|
51
|
+
'declarative-reference-antigravity.test.cjs',
|
|
52
|
+
'declarative-reference-zcode.test.cjs',
|
|
53
|
+
'emitted-attribution.test.cjs',
|
|
54
|
+
'eslint-rules.test.cjs',
|
|
55
|
+
'estimate-calibrate.test.cjs',
|
|
56
|
+
'gen-context-index.test.cjs',
|
|
57
|
+
'gen-registry.test.cjs',
|
|
58
|
+
'gsd-agent-isolation-guard.test.cjs',
|
|
59
|
+
'hermes-dispatch-upgrade.test.cjs',
|
|
60
|
+
'install-minimal-hooks.test.cjs',
|
|
61
|
+
'install-runtime-artifacts.test.cjs',
|
|
62
|
+
'installer-migration-config-root-marker.test.cjs',
|
|
63
|
+
'installer-migration-pi-extension-ext.test.cjs',
|
|
64
|
+
'installer-migrations.test.cjs',
|
|
65
|
+
'kimi-upgrades.test.cjs',
|
|
66
|
+
'lint-allow-test-rule-refs.test.cjs',
|
|
67
|
+
'lint-docs-command-form.test.cjs',
|
|
68
|
+
'lint-docs-required.test.cjs',
|
|
69
|
+
'manifest-version-sync.test.cjs',
|
|
70
|
+
'milestone-archive.test.cjs',
|
|
71
|
+
'model-resolver.test.cjs',
|
|
72
|
+
'new-project-mvp-prompt.test.cjs',
|
|
73
|
+
'onboard-command.test.cjs',
|
|
74
|
+
'opencode-command-dir-plural.test.cjs',
|
|
75
|
+
'phase.test.cjs',
|
|
76
|
+
'pr-branch-planning-filter.test.cjs',
|
|
77
|
+
'precommit-alias-drift-hook.test.cjs',
|
|
78
|
+
'removed-but-needed-lint.test.cjs',
|
|
79
|
+
'repo-invariants.test.cjs',
|
|
80
|
+
'require-issue-link-policy.test.cjs',
|
|
81
|
+
'reviewer-manifest-body.test.cjs',
|
|
82
|
+
'run-tests-harness.test.cjs',
|
|
83
|
+
'runtime-name-policy.test.cjs',
|
|
84
|
+
'security-prompt-injection.security.test.cjs',
|
|
85
|
+
'shipped-reference-cites.test.cjs',
|
|
86
|
+
'state.test.cjs',
|
|
87
|
+
'worktree-safety.test.cjs',
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Security follow-up FIX 3: a per-file fingerprint of every distinct
|
|
92
|
+
* `docs/...` path TOKEN referenced by each baselined file (derived via
|
|
93
|
+
* scripts/lint-docs-guard-registration.cjs's `extractDocsPathReferences`,
|
|
94
|
+
* never retyped from memory). A baselined file whose live fingerprint
|
|
95
|
+
* DIFFERS from the recorded one here fails the lint — the exemption's
|
|
96
|
+
* premise ("this file doesn't really guard shipped docs content") may no
|
|
97
|
+
* longer hold and a human must re-confirm it before the entry is updated.
|
|
98
|
+
* Keeping this a plain, sorted, diffable path list (not a hash) is
|
|
99
|
+
* deliberate: a reviewer can see exactly WHAT changed from the PR diff
|
|
100
|
+
* alone.
|
|
101
|
+
*
|
|
102
|
+
* Seeded 2026-08-23 alongside DOCS_GUARD_EXEMPT_BASELINE above, from the
|
|
103
|
+
* exact same scan.
|
|
104
|
+
*/
|
|
105
|
+
const DOCS_GUARD_EXEMPT_DOCS_PATHS = {
|
|
106
|
+
'adr-parser.test.cjs': ['docs/adr/0001.md', 'docs/adr/0002.md', 'docs/adr/0010.md', 'docs/adr/NNNN.md'],
|
|
107
|
+
'adr-parser.unit.test.cjs': ['docs/adr/0001.md', 'docs/adr/0099.md', 'docs/adr/NNNN.md'],
|
|
108
|
+
'agent-marker-documentation-guard.test.cjs': ['docs/reference', 'docs/reference/workflow-fragments.md'],
|
|
109
|
+
'antigravity-upgrades.test.cjs': ['docs/cli', 'docs/cli/gcli-migration', 'docs/cli/permissions'],
|
|
110
|
+
'capability-cli.test.cjs': ['docs/reference/gsd-capability-command.md'],
|
|
111
|
+
// #3970: cites docs/adr/3646-per-task-content-resolution-seam.md in an
|
|
112
|
+
// explanatory comment describing ADR-3646's Decision 3; the file never
|
|
113
|
+
// reads that (or any) docs/ file.
|
|
114
|
+
'capability-validator-task-content-resolver.test.cjs': ['docs/adr/3646-per-task-content-resolution-seam.md'],
|
|
115
|
+
'ci-docs-guard-registry.test.cjs': [
|
|
116
|
+
'docs/AGENTS.md', 'docs/COMMANDS.md', 'docs/INVENTORY.md', 'docs/a.md', 'docs/adr',
|
|
117
|
+
'docs/adr/0001-example.md', 'docs/adrenaline.md', 'docs/bar.md', 'docs/foo.md', 'docs/how-to/foo.md',
|
|
118
|
+
'docs/how-to/some-unrelated-guide.md', 'docs/how-to/x.md', 'docs/some-unrelated-file.md',
|
|
119
|
+
'docs/totally-unrelated.md',
|
|
120
|
+
],
|
|
121
|
+
'ci-test-scope.test.cjs': [
|
|
122
|
+
'docs/a.md', 'docs/adr', 'docs/adr/22-plan-drift-guard.md', 'docs/how-to/configure-model-profiles.md',
|
|
123
|
+
'docs/installer-migrations.md', 'docs/ja-JP', 'docs/ja-JP/USAGE.md', 'docs/usage.md', 'docs/x.md',
|
|
124
|
+
],
|
|
125
|
+
'cline-install.test.cjs': ['docs/guide.md'],
|
|
126
|
+
'code-review-depth.test.cjs': ['docs/src/auth/x.ts'],
|
|
127
|
+
'code-review-pipeline-regression.test.cjs': ['docs/DEVELOPMENT.md'],
|
|
128
|
+
'codebuddy-upgrades.test.cjs': ['docs/cli/sub-agents'],
|
|
129
|
+
'commands.test.cjs': ['docs/x.md'],
|
|
130
|
+
'commit-docs-bypass.test.cjs': [
|
|
131
|
+
'docs/40-design.md', 'docs/CONFIGURATION.md', 'docs/readme.md', 'docs/tracked-var-mentioning',
|
|
132
|
+
],
|
|
133
|
+
'complexity-trigger.test.cjs': ['docs/readme.md'],
|
|
134
|
+
// #3884: cites docs/CLI-TOOLS.md:736 in an explanatory comment describing
|
|
135
|
+
// the real `frontmatter get <file> [--field key]` CLI shape; the file
|
|
136
|
+
// never reads that (or any) docs/ file.
|
|
137
|
+
'concurrency-safety.test.cjs': ['docs/CLI-TOOLS.md'],
|
|
138
|
+
'cursor-imperative-reference.test.cjs': ['docs/sdk/typescript'],
|
|
139
|
+
'declarative-reference-antigravity.test.cjs': ['docs/cli/features'],
|
|
140
|
+
'declarative-reference-zcode.test.cjs': ['docs/reference/host-integration-capability-matrix.md'],
|
|
141
|
+
'emitted-attribution.test.cjs': ['docs/README.md', 'docs/tests', 'docs/tests/helpers/install-shared.cjs'],
|
|
142
|
+
// #3914: cites docs/adr/3889-process-exit-contract.md ~:350-362 in an
|
|
143
|
+
// explanatory comment describing the intentional computed-property
|
|
144
|
+
// boundary move; the file never reads that (or any) docs/ file.
|
|
145
|
+
'eslint-rules.test.cjs': ['docs/adr/3889-process-exit-contract.md', 'docs/readme.md'],
|
|
146
|
+
'estimate-calibrate.test.cjs': [
|
|
147
|
+
'docs/adr', 'docs/adr/2629-phase-effort-estimation-calibration.md', 'docs/reference',
|
|
148
|
+
'docs/reference/planning-artifacts.md',
|
|
149
|
+
],
|
|
150
|
+
'gen-context-index.test.cjs': ['docs/CONTEXT-INDEX.json', 'docs/INVENTORY-MANIFEST.json'],
|
|
151
|
+
'gen-registry.test.cjs': ['docs/registries', 'docs/registries/reviewers.json'],
|
|
152
|
+
'gsd-agent-isolation-guard.test.cjs': ['docs/adr/1239-...md', 'docs/adr/1239-gsd-embeddable-orchestration-engine.md'],
|
|
153
|
+
'hermes-dispatch-upgrade.test.cjs': ['docs/guides/delegation-patterns.md'],
|
|
154
|
+
'install-minimal-hooks.test.cjs': ['docs/en/hooks', 'docs/en/users/features/hooks'],
|
|
155
|
+
'install-runtime-artifacts.test.cjs': ['docs/CONFIGURATION.md', 'docs/adr/58-...md', 'docs/adr/58-runtime-install-policy-module.md', 'docs/cli/slash-commands'],
|
|
156
|
+
'installer-migration-config-root-marker.test.cjs': ['docs/installer-migrations.md'],
|
|
157
|
+
'installer-migration-pi-extension-ext.test.cjs': ['docs/installer-migrations.md'],
|
|
158
|
+
'installer-migrations.test.cjs': ['docs/installer-migrations.md'],
|
|
159
|
+
'kimi-upgrades.test.cjs': ['docs/reference/host-integration-capability-matrix.md'],
|
|
160
|
+
'lint-allow-test-rule-refs.test.cjs': ['docs/readme.md'],
|
|
161
|
+
'lint-docs-command-form.test.cjs': ['docs/adr', 'docs/adr/999-example.md', 'docs/how-to/example.md'],
|
|
162
|
+
'lint-docs-required.test.cjs': [
|
|
163
|
+
'docs/COMMANDS.md', 'docs/USER-GUIDE.md', 'docs/adr', 'docs/adr/0001-foo.md', 'docs/adr/0099-new.md',
|
|
164
|
+
'docs/agents', 'docs/agents/triage-labels.md',
|
|
165
|
+
],
|
|
166
|
+
'manifest-version-sync.test.cjs': [],
|
|
167
|
+
// #3884: re-confirmed — the added docs/CLI-TOOLS.md:458 reference is the
|
|
168
|
+
// same class as the existing docs/TESTING-SUITES.md one (a placement-note
|
|
169
|
+
// / explanatory comment citing documented CLI behavior for context, never
|
|
170
|
+
// a read target); the exemption's premise still holds for both.
|
|
171
|
+
'milestone-archive.test.cjs': ['docs/CLI-TOOLS.md', 'docs/TESTING-SUITES.md'],
|
|
172
|
+
'model-resolver.test.cjs': ['docs/TESTING-SUITES.md'],
|
|
173
|
+
'new-project-mvp-prompt.test.cjs': ['docs/CONFIGURATION.md'],
|
|
174
|
+
'onboard-command.test.cjs': ['docs/adr/0001-runtime.md'],
|
|
175
|
+
'opencode-command-dir-plural.test.cjs': ['docs/commands'],
|
|
176
|
+
'phase.test.cjs': ['docs/adr/3524-...md', 'docs/adr/3524-cjs-sdk-hard-seam.md'],
|
|
177
|
+
'pr-branch-planning-filter.test.cjs': ['docs/readme.md'],
|
|
178
|
+
'precommit-alias-drift-hook.test.cjs': ['docs/adr/0174-...md', 'docs/adr/0174-retire-gsd-sdk-package-boundary.md'],
|
|
179
|
+
'removed-but-needed-lint.test.cjs': [
|
|
180
|
+
'docs/README.md', 'docs/getting-started.md', 'docs/gsd-new-workspace.md', 'docs/setup.md', 'docs/some-doc.md',
|
|
181
|
+
],
|
|
182
|
+
'repo-invariants.test.cjs': ['docs/FEATURES.md', 'docs/workflows/README'],
|
|
183
|
+
'require-issue-link-policy.test.cjs': ['docs/-prefixed', 'docs/CONFIGURATION.md', 'docs/a.md', 'docs/b.md', 'docs/guide.md'],
|
|
184
|
+
'reviewer-manifest-body.test.cjs': ['docs/how-to/ship-a-reviewer-lane.md'],
|
|
185
|
+
'run-tests-harness.test.cjs': ['docs/TESTING-SUITES.md'],
|
|
186
|
+
'runtime-name-policy.test.cjs': ['docs/customize/skills'],
|
|
187
|
+
'security-prompt-injection.security.test.cjs': ['docs/notes.md'],
|
|
188
|
+
'shipped-reference-cites.test.cjs': [],
|
|
189
|
+
'state.test.cjs': ['docs/CONFIGURATION.md', 'docs/reference/state-md.md'],
|
|
190
|
+
'worktree-safety.test.cjs': ['docs/SUMMARY.md'],
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
module.exports = { DOCS_GUARD_EXEMPT_BASELINE, DOCS_GUARD_EXEMPT_DOCS_PATHS };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "gsd-core/bin/lib/vendor/re2js.d.cts",
|
|
4
|
+
"reason": "Vendored third-party type declaration (#3477): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored .cjs it describes is globally ignored as verbatim upstream output. Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules."
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"path": "src/vendor/re2js.d.cts",
|
|
8
|
+
"reason": "Vendored third-party type declaration (#3477): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored .cjs it describes is globally ignored as verbatim upstream output. Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"path": "src/vendor/js-yaml.d.cts",
|
|
12
|
+
"reason": "Vendored third-party type declaration (ADR-3473 §8.1, #3881): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored js-yaml .cjs it describes is globally ignored as verbatim upstream output (gsd-core/bin/lib/vendor/**). Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules — same precedent as src/vendor/re2js.d.cts above."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "tests/fixtures/brand-typing/bad-calibrated-as-sample-basis.cts",
|
|
16
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "tests/fixtures/brand-typing/bad-double-calibration.cts",
|
|
20
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "tests/fixtures/brand-typing/bad-raw-against-budget.cts",
|
|
24
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "tests/fixtures/brand-typing/bad-rebrand-calibrated-as-raw.cts",
|
|
28
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "tests/fixtures/brand-typing/bad-unbranded-number-as-raw.cts",
|
|
32
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"path": "tests/fixtures/brand-typing/ok-correct-composition.cts",
|
|
36
|
+
"reason": "Positive-control counterpart to the bad-* must-not-compile fixtures (#3059); kept in the same exemption so the pair stays together."
|
|
37
|
+
}
|
|
38
|
+
]
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* lint-eslint-glob-coverage.cjs — ESLint `files:` glob coverage drift guard (#3059).
|
|
6
|
+
*
|
|
7
|
+
* ## What this enforces
|
|
8
|
+
*
|
|
9
|
+
* `eslint.config.mjs` is a flat config: a tracked source file is only linted
|
|
10
|
+
* if it matches at least one config object's `files:` glob (or a global,
|
|
11
|
+
* files-less block). A file matching NO glob resolves to zero reachable
|
|
12
|
+
* rules and `eslint .` silently exits 0 on it — the #3059 defect class (62
|
|
13
|
+
* tracked source files found with this shape). This guard walks every
|
|
14
|
+
* tracked `.cjs/.cts/.js/.mjs` source file, resolves its real ESLint config,
|
|
15
|
+
* and fails when a file resolves to zero rules and isn't a deliberately
|
|
16
|
+
* exempted, reasoned allowlist entry.
|
|
17
|
+
*
|
|
18
|
+
* This checks rule REACHABILITY (does at least one rule apply to this file
|
|
19
|
+
* at all, any severity), not rule SEVERITY (whether an applicable rule is
|
|
20
|
+
* `error` vs `warn` vs `off`) — severity coverage is a separate gate, #1885
|
|
21
|
+
* F17. A file with one `off` rule reachable still counts as "covered" here:
|
|
22
|
+
* it proves the file was deliberately targeted by a `files:` glob, which is
|
|
23
|
+
* the thing #3059 is about.
|
|
24
|
+
*
|
|
25
|
+
* ## Goodhart rationale
|
|
26
|
+
*
|
|
27
|
+
* A coverage metric is trivially gameable by padding the allowlist instead
|
|
28
|
+
* of fixing the glob, so every knob here is built to resist that:
|
|
29
|
+
* - Every allowlist entry MUST carry a non-empty `reason` — an unreasoned
|
|
30
|
+
* entry is indistinguishable from "quietly made the metric look better".
|
|
31
|
+
* - The allowlist only ratchets DOWN: an entry whose path now resolves to
|
|
32
|
+
* >=1 rule (`allowlist_stale`) is a failure, forcing prompt removal
|
|
33
|
+
* rather than letting stale exemptions accumulate as free cover for
|
|
34
|
+
* future accidental escapes at the same path.
|
|
35
|
+
* - A tracked-file-count floor (`tracked_count_below_floor`) exists so a
|
|
36
|
+
* broken or empty `git ls-files` (e.g. wrong cwd, detached worktree)
|
|
37
|
+
* can't report a vacuous "0 escapes out of 0 checked" clean run.
|
|
38
|
+
*
|
|
39
|
+
* ## Ignored vs. unmatched (the discrimination this script makes)
|
|
40
|
+
*
|
|
41
|
+
* ESLint's `ignores:` blocks are the one legitimate "this file is not meant
|
|
42
|
+
* to be linted" decision (e.g. the ADR-457 tsc-emitted `.cjs` artifacts
|
|
43
|
+
* under `gsd-core/bin/lib/`) and must NOT be reported as uncovered. But
|
|
44
|
+
* `ESLint#isPathIgnored` cannot be trusted uniformly across extensions:
|
|
45
|
+
* for ESLint's default-lintable extensions (`.js`/`.mjs`/`.cjs`), it
|
|
46
|
+
* reports `true` only when the path matches an explicit `ignores:` glob —
|
|
47
|
+
* verified empirically: an unmatched top-level `.cjs` probe file reports
|
|
48
|
+
* `isPathIgnored() === false` with an empty resolved rule set, not `true`.
|
|
49
|
+
* For `.cts` (and any other non-default extension), flat config requires an
|
|
50
|
+
* EXPLICIT `files:` glob match to be linted at all; a `.cts` file matching
|
|
51
|
+
* no `files:` glob ALSO reports `isPathIgnored() === true` — indistinguishable,
|
|
52
|
+
* via this API, from a genuine `ignores:` entry (verified with a scratch
|
|
53
|
+
* `.cts` fixture under `tests/fixtures/`). This repo's `ignores:` list never
|
|
54
|
+
* contains a `.cts` path (ADR-457 retires only the emitted `.cjs`; the
|
|
55
|
+
* `.cts` source is always meant to stay linted), so for `.cts` specifically
|
|
56
|
+
* an `isPathIgnored() === true` verdict can only mean "matches no `files:`
|
|
57
|
+
* glob" and is therefore treated as UNCOVERED, not ignored. See
|
|
58
|
+
* `resolveFileCoverage` below.
|
|
59
|
+
*
|
|
60
|
+
* ## Why `bin/install.js` is NOT in the allowlist
|
|
61
|
+
*
|
|
62
|
+
* The allowlist below is exclusively for files that resolve to ZERO rules —
|
|
63
|
+
* it is a registry of accepted escapes, not a general-purpose "reasons for
|
|
64
|
+
* how a file is configured" log. The `bin/install.js` / `bin/gsd-mcp-server.js`
|
|
65
|
+
* / `scripts/build-hooks.js` family is deliberately covered by a minimal,
|
|
66
|
+
* 2-rule block in `eslint.config.mjs` per ADR-1703 (targeting only the
|
|
67
|
+
* portability defect surface, not a full style sweep of ~12k lines of
|
|
68
|
+
* generated code) — see the comment at that block in `eslint.config.mjs`.
|
|
69
|
+
* Because 2 rules is non-empty, that family already passes this guard
|
|
70
|
+
* without needing an allowlist entry, and adding one anyway would itself be
|
|
71
|
+
* flagged `allowlist_stale` (see the ratchet above). The allowlist exemption
|
|
72
|
+
* surface deliberately cannot be used to re-state a decision that is already
|
|
73
|
+
* recorded in the config; #3059 is the guard, ADR-1703 is the decision.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
const fs = require('fs');
|
|
77
|
+
const path = require('path');
|
|
78
|
+
|
|
79
|
+
const ROOT = path.join(__dirname, '..');
|
|
80
|
+
const ALLOWLIST_PATH = path.join(__dirname, 'lint-eslint-glob-coverage.allowlist.json');
|
|
81
|
+
|
|
82
|
+
const SOURCE_EXT_RE = /\.(cjs|cts|js|mjs)$/;
|
|
83
|
+
|
|
84
|
+
// ESLint's flat-config default-lintable extensions: a file with one of these
|
|
85
|
+
// extensions that matches no `files:` glob still reports `isPathIgnored()
|
|
86
|
+
// === false` (with an empty resolved rule set) — so for these extensions,
|
|
87
|
+
// `isPathIgnored() === true` reliably means an explicit `ignores:` match.
|
|
88
|
+
const DEFAULT_LINTABLE_EXT_RE = /\.(js|mjs|cjs)$/;
|
|
89
|
+
|
|
90
|
+
const MIN_TRACKED_SOURCE_FILES = 500;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Runs `git ls-files` and returns the tracked source files (repo-relative,
|
|
94
|
+
* POSIX-normalized, filtered to SOURCE_EXT_RE). Never throws: a git failure
|
|
95
|
+
* (non-zero exit or timeout) produces a degraded `{ ok: false }` result so
|
|
96
|
+
* callers can turn it into a `git_failed` violation instead of crashing.
|
|
97
|
+
*
|
|
98
|
+
* @param {object} [opts]
|
|
99
|
+
* @param {Function} [opts.execFile] - injectable sync exec function with the
|
|
100
|
+
* `execFileSync(cmd, args, options)` signature; defaults to
|
|
101
|
+
* `child_process.execFileSync`.
|
|
102
|
+
*/
|
|
103
|
+
function listTrackedSourceFiles({ execFile } = {}) {
|
|
104
|
+
const run = execFile || require('child_process').execFileSync;
|
|
105
|
+
let stdout;
|
|
106
|
+
try {
|
|
107
|
+
// The test runner and CI execute inside a container where this repo is
|
|
108
|
+
// owned by a different UID than the running user; bare `git ls-files`
|
|
109
|
+
// then refuses with "detected dubious ownership" unless the path is in
|
|
110
|
+
// `safe.directory`, and this guard degrades to a `git_failed` violation
|
|
111
|
+
// — exactly where it must run to be a useful gate (#3059). `-c
|
|
112
|
+
// safe.directory=*` scopes the override to THIS invocation only (it
|
|
113
|
+
// never writes to any config file, global or local), and the wildcard
|
|
114
|
+
// is fine here because this command only ever enumerates tracked paths
|
|
115
|
+
// in the repo the guard is already executing inside.
|
|
116
|
+
stdout = run('git', ['-c', 'safe.directory=*', 'ls-files'], {
|
|
117
|
+
cwd: ROOT,
|
|
118
|
+
encoding: 'utf8',
|
|
119
|
+
// 30s — `git ls-files` on this tree returns ~1175 paths in <1s; 30s is
|
|
120
|
+
// the CLAUDE.md git ceiling, generous for a cold index.
|
|
121
|
+
timeout: 30000,
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return { ok: false, files: [], error: (err && err.message) || String(err) };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const files = String(stdout)
|
|
128
|
+
// CRLF-safe: `git ls-files` output may carry \r\n on a Windows checkout
|
|
129
|
+
// or a git config with core.autocrlf set (DEFECT.CRLF class).
|
|
130
|
+
.split(/\r?\n/)
|
|
131
|
+
.filter((line) => line.length > 0)
|
|
132
|
+
// Unconditional backslash normalization (never path.sep-gated): the
|
|
133
|
+
// guard's own process may run on any platform regardless of what
|
|
134
|
+
// produced the tracked-file listing.
|
|
135
|
+
.map((line) => line.replace(/\\/g, '/'))
|
|
136
|
+
.filter((line) => SOURCE_EXT_RE.test(line));
|
|
137
|
+
|
|
138
|
+
return { ok: true, files };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Loads and parses the allowlist JSON file. */
|
|
142
|
+
function loadAllowlist() {
|
|
143
|
+
const raw = fs.readFileSync(ALLOWLIST_PATH, 'utf8');
|
|
144
|
+
return JSON.parse(raw);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolves the ESLint coverage verdict for a single tracked file. See the
|
|
149
|
+
* "Ignored vs. unmatched" header section for the extension-dependent
|
|
150
|
+
* discrimination rationale.
|
|
151
|
+
*
|
|
152
|
+
* @param {import('eslint').ESLint} eslint
|
|
153
|
+
* @param {string} relPath - repo-relative POSIX path
|
|
154
|
+
* @returns {Promise<{ ignored: boolean, ruleCount: number }>}
|
|
155
|
+
*/
|
|
156
|
+
async function resolveFileCoverage(eslint, relPath) {
|
|
157
|
+
const absPath = path.join(ROOT, relPath);
|
|
158
|
+
const ignored = await eslint.isPathIgnored(absPath);
|
|
159
|
+
|
|
160
|
+
if (ignored) {
|
|
161
|
+
if (DEFAULT_LINTABLE_EXT_RE.test(relPath)) {
|
|
162
|
+
// .js/.mjs/.cjs: isPathIgnored() only reports true for an explicit
|
|
163
|
+
// `ignores:` glob match — a recorded decision.
|
|
164
|
+
return { ignored: true, ruleCount: 0 };
|
|
165
|
+
}
|
|
166
|
+
// .cts (or any non-default extension): isPathIgnored() can't
|
|
167
|
+
// distinguish "explicit ignores: match" from "no files: glob matched
|
|
168
|
+
// it at all" — and this repo's ignores: list never targets .cts, so
|
|
169
|
+
// treat it as the latter (uncovered), never as ignored.
|
|
170
|
+
return { ignored: false, ruleCount: 0 };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const config = await eslint.calculateConfigForFile(absPath);
|
|
174
|
+
const ruleCount = config && config.rules ? Object.keys(config.rules).length : 0;
|
|
175
|
+
return { ignored: false, ruleCount };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Builds the default real-ESLint-backed resolveConfig function. */
|
|
179
|
+
function createDefaultResolveConfig() {
|
|
180
|
+
const { ESLint } = require('eslint');
|
|
181
|
+
const eslint = new ESLint({ cwd: ROOT });
|
|
182
|
+
return (relPath) => resolveFileCoverage(eslint, relPath);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The pure coverage predicate. All I/O is injectable via `deps` so tests
|
|
187
|
+
* never need a temp repo, a real subprocess, or a real ESLint instance:
|
|
188
|
+
*
|
|
189
|
+
* @param {object} [deps]
|
|
190
|
+
* @param {string[] | { ok: boolean, files?: string[], error?: string }} [deps.trackedFiles]
|
|
191
|
+
* Either a plain array of tracked source paths (success shorthand), or a
|
|
192
|
+
* `listTrackedSourceFiles()`-shaped result object (so a git failure can be
|
|
193
|
+
* injected directly). Defaults to a real `listTrackedSourceFiles()` call.
|
|
194
|
+
* @param {(relPath: string) => Promise<{ignored:boolean,ruleCount:number}> | {ignored:boolean,ruleCount:number}} [deps.resolveConfig]
|
|
195
|
+
* Per-file coverage resolver. Defaults to a real ESLint instance.
|
|
196
|
+
* @param {Array<{path:string,reason?:string}>} [deps.allowlist] - defaults to
|
|
197
|
+
* the real `loadAllowlist()`.
|
|
198
|
+
* @param {number} [deps.minTrackedFiles] - defaults to MIN_TRACKED_SOURCE_FILES.
|
|
199
|
+
* @returns {Promise<{ ok: boolean, escapes: Array<{path:string}>, violations: Array<{kind:string,path:string|null,detail:string}>, checked: number }>}
|
|
200
|
+
*/
|
|
201
|
+
async function checkGlobCoverage(deps = {}) {
|
|
202
|
+
const minTrackedFiles =
|
|
203
|
+
typeof deps.minTrackedFiles === 'number' ? deps.minTrackedFiles : MIN_TRACKED_SOURCE_FILES;
|
|
204
|
+
|
|
205
|
+
const violations = [];
|
|
206
|
+
|
|
207
|
+
let trackedResult;
|
|
208
|
+
if (deps.trackedFiles === undefined) {
|
|
209
|
+
trackedResult = listTrackedSourceFiles();
|
|
210
|
+
} else if (Array.isArray(deps.trackedFiles)) {
|
|
211
|
+
trackedResult = { ok: true, files: deps.trackedFiles };
|
|
212
|
+
} else {
|
|
213
|
+
trackedResult = deps.trackedFiles;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (!trackedResult.ok) {
|
|
217
|
+
violations.push({
|
|
218
|
+
kind: 'git_failed',
|
|
219
|
+
path: null,
|
|
220
|
+
detail: trackedResult.error || 'listTrackedSourceFiles() failed',
|
|
221
|
+
});
|
|
222
|
+
return { ok: false, escapes: [], violations, checked: 0 };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const trackedFiles = trackedResult.files;
|
|
226
|
+
|
|
227
|
+
if (trackedFiles.length < minTrackedFiles) {
|
|
228
|
+
violations.push({
|
|
229
|
+
kind: 'tracked_count_below_floor',
|
|
230
|
+
path: null,
|
|
231
|
+
detail: `tracked source file count ${trackedFiles.length} is below the floor of ${minTrackedFiles} — a broken or empty git ls-files must never report a vacuous clean run`,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const trackedSet = new Set(trackedFiles);
|
|
236
|
+
const allowlist = deps.allowlist === undefined ? loadAllowlist() : deps.allowlist;
|
|
237
|
+
|
|
238
|
+
const seenAllowlistPaths = new Set();
|
|
239
|
+
const allowlistPathSet = new Set();
|
|
240
|
+
for (const entry of allowlist) {
|
|
241
|
+
const entryPath = entry && entry.path;
|
|
242
|
+
|
|
243
|
+
if (seenAllowlistPaths.has(entryPath)) {
|
|
244
|
+
violations.push({
|
|
245
|
+
kind: 'allowlist_duplicate',
|
|
246
|
+
path: entryPath,
|
|
247
|
+
detail: 'path appears more than once in the allowlist',
|
|
248
|
+
});
|
|
249
|
+
} else {
|
|
250
|
+
seenAllowlistPaths.add(entryPath);
|
|
251
|
+
}
|
|
252
|
+
allowlistPathSet.add(entryPath);
|
|
253
|
+
|
|
254
|
+
if (!Object.prototype.hasOwnProperty.call(entry, 'reason')) {
|
|
255
|
+
violations.push({
|
|
256
|
+
kind: 'allowlist_missing_reason',
|
|
257
|
+
path: entryPath,
|
|
258
|
+
detail: 'allowlist entry is missing a "reason" key',
|
|
259
|
+
});
|
|
260
|
+
} else if (typeof entry.reason !== 'string' || entry.reason.trim() === '') {
|
|
261
|
+
violations.push({
|
|
262
|
+
kind: 'allowlist_empty_reason',
|
|
263
|
+
path: entryPath,
|
|
264
|
+
detail: 'allowlist entry "reason" is empty or whitespace-only',
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (!trackedSet.has(entryPath)) {
|
|
269
|
+
violations.push({
|
|
270
|
+
kind: 'allowlist_missing_path',
|
|
271
|
+
path: entryPath,
|
|
272
|
+
detail: 'allowlisted path is not a tracked source file',
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const resolveConfig = deps.resolveConfig || createDefaultResolveConfig();
|
|
278
|
+
|
|
279
|
+
const escapes = [];
|
|
280
|
+
let checked = 0;
|
|
281
|
+
|
|
282
|
+
for (const file of trackedFiles) {
|
|
283
|
+
checked += 1;
|
|
284
|
+
const result = await resolveConfig(file);
|
|
285
|
+
const isAllowlisted = allowlistPathSet.has(file);
|
|
286
|
+
|
|
287
|
+
if (result.ignored) {
|
|
288
|
+
// A recorded ESLint `ignores:` decision — never an escape, regardless
|
|
289
|
+
// of allowlist membership.
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (result.ruleCount === 0) {
|
|
294
|
+
if (isAllowlisted) continue;
|
|
295
|
+
escapes.push({ path: file });
|
|
296
|
+
violations.push({
|
|
297
|
+
kind: 'uncovered',
|
|
298
|
+
path: file,
|
|
299
|
+
detail: 'resolves to 0 reachable ESLint rules and is not allowlisted',
|
|
300
|
+
});
|
|
301
|
+
} else if (isAllowlisted) {
|
|
302
|
+
violations.push({
|
|
303
|
+
kind: 'allowlist_stale',
|
|
304
|
+
path: file,
|
|
305
|
+
detail: 'allowlisted path now resolves to >=1 ESLint rule — prune the entry, the allowlist only ratchets down',
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return { ok: violations.length === 0, escapes, violations, checked };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (require.main === module) {
|
|
314
|
+
checkGlobCoverage()
|
|
315
|
+
.then((result) => {
|
|
316
|
+
if (result.violations.length > 0) {
|
|
317
|
+
console.error(
|
|
318
|
+
`lint-eslint-glob-coverage: ${result.violations.length} violation(s) across ${result.checked} tracked source file(s) (${result.escapes.length} uncovered escape(s))`
|
|
319
|
+
);
|
|
320
|
+
for (const v of result.violations) {
|
|
321
|
+
console.error(` [${v.kind}] ${v.path === null ? '(n/a)' : v.path}${v.detail ? ' — ' + v.detail : ''}`);
|
|
322
|
+
}
|
|
323
|
+
process.exitCode = 1;
|
|
324
|
+
} else {
|
|
325
|
+
console.log(`ok lint-eslint-glob-coverage: ${result.checked} tracked source file(s), 0 escapes`);
|
|
326
|
+
}
|
|
327
|
+
})
|
|
328
|
+
.catch((err) => {
|
|
329
|
+
console.error(err && err.stack ? err.stack : String(err));
|
|
330
|
+
process.exitCode = 1;
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
module.exports = {
|
|
335
|
+
checkGlobCoverage,
|
|
336
|
+
listTrackedSourceFiles,
|
|
337
|
+
loadAllowlist,
|
|
338
|
+
SOURCE_EXT_RE,
|
|
339
|
+
MIN_TRACKED_SOURCE_FILES,
|
|
340
|
+
};
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* lint-fix-has-regression-
|
|
5
|
+
* lint-fix-has-regression-tests.cjs — gate: every fix(#NNNN) commit must
|
|
6
6
|
* include at least one behavioral test file (tests/*.test.cjs) that is NOT
|
|
7
7
|
* an auto-generated fixture/baseline.
|
|
8
8
|
*
|
|
9
|
+
* Renamed (was `lint-fix-has-regression-test.cjs`, singular): the old
|
|
10
|
+
* basename matched Node's `*-test.EXT` test-collection pattern, so the
|
|
11
|
+
* remote push-gate runner collected and executed this SOURCE file as a
|
|
12
|
+
* test while GitHub CI (which globs only tests/**\/*.test.cjs) never saw
|
|
13
|
+
* it — see scripts/lint-source-test-name-collision.cjs.
|
|
14
|
+
*
|
|
9
15
|
* ## Why
|
|
10
16
|
*
|
|
11
17
|
* CONTRIBUTING.md:47: "Fix it. Write a test that would have caught the bug."
|
|
@@ -82,7 +88,7 @@ function getChangedTestFiles(baseRef) {
|
|
|
82
88
|
|
|
83
89
|
function main() {
|
|
84
90
|
if (process.env.GSD_SKIP_REGRESSION_TEST_GATE === '1') {
|
|
85
|
-
console.log('lint-fix-has-regression-
|
|
91
|
+
console.log('lint-fix-has-regression-tests: SKIPPED (GSD_SKIP_REGRESSION_TEST_GATE=1)');
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
94
|
|
|
@@ -92,12 +98,12 @@ function main() {
|
|
|
92
98
|
try {
|
|
93
99
|
fixCommits = getFixCommits(baseRef);
|
|
94
100
|
} catch {
|
|
95
|
-
console.log(`lint-fix-has-regression-
|
|
101
|
+
console.log(`lint-fix-has-regression-tests: no fix/feat commits found vs ${baseRef}, skipping`);
|
|
96
102
|
return;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
if (fixCommits.length === 0) {
|
|
100
|
-
console.log('lint-fix-has-regression-
|
|
106
|
+
console.log('lint-fix-has-regression-tests: no fix/feat commits, passing');
|
|
101
107
|
return;
|
|
102
108
|
}
|
|
103
109
|
|
|
@@ -113,7 +119,7 @@ function main() {
|
|
|
113
119
|
.map((c) => ` ${c.sha} ${c.subject}`)
|
|
114
120
|
.join('\n');
|
|
115
121
|
throw new ExitError(1,
|
|
116
|
-
`lint-fix-has-regression-
|
|
122
|
+
`lint-fix-has-regression-tests: ${fixCommits.length} fix/feat commit(s) but ZERO behavioral test files (*.test.cjs) in the diff.\n` +
|
|
117
123
|
`Auto-generated fixtures (tests/fixtures/, *-baseline.json) do NOT count.\n\n` +
|
|
118
124
|
`Fix commits:\n${commitList}\n\n` +
|
|
119
125
|
`CONTRIBUTING.md:47: "Write a test that would have caught the bug."\n` +
|
|
@@ -123,7 +129,7 @@ function main() {
|
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
console.log(
|
|
126
|
-
`lint-fix-has-regression-
|
|
132
|
+
`lint-fix-has-regression-tests: PASS — ${fixCommits.length} fix/feat commit(s), ` +
|
|
127
133
|
`${testFiles.length} behavioral test file(s): ${testFiles.join(', ')}`
|
|
128
134
|
);
|
|
129
135
|
}
|