@opengsd/gsd-core 1.15.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +85 -5
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/install.js +126 -196
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +5 -0
- package/commands/gsd/capture.md +8 -4
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +5 -1
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +142 -56
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +183 -103
- package/gsd-core/bin/lib/capability-validator.cjs +16 -0
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +173 -170
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +413 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +162 -96
- package/gsd-core/bin/lib/install-engine.cjs +19 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +280 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state.cjs +214 -105
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1165 -314
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +84 -90
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase.md +78 -170
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +147 -16
- package/hooks/dist/gsd-statusline.js +15 -7
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +8 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +147 -16
- package/hooks/gsd-statusline.js +15 -7
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +10 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +5 -1
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -17,10 +17,22 @@
|
|
|
17
17
|
* `passed+gaps_found+human_needed` instead of `passed` and blocking a
|
|
18
18
|
* passed phase).
|
|
19
19
|
*
|
|
20
|
-
* The fix-forward is to scope the grep to
|
|
21
|
-
* take only the first match:
|
|
20
|
+
* The fix-forward for a scalar with no owning query is to scope the grep to
|
|
21
|
+
* the leading frontmatter block and take only the first match:
|
|
22
22
|
* sed -n '/^---$/,/^---$/p' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d ' '
|
|
23
23
|
*
|
|
24
|
+
* ## Rule `verification-status-raw-read` (#5118, ADR-5057 Phase 4)
|
|
25
|
+
*
|
|
26
|
+
* A VERIFICATION report's `status` HAS an owning query — its closed enum,
|
|
27
|
+
* staleness check and routing live in src/verification.cts. Reading that
|
|
28
|
+
* scalar with awk / sed / grep `^status:` (scoped to the frontmatter or not)
|
|
29
|
+
* bypasses all three (transition.md's awk read was W15 in the #5118 census),
|
|
30
|
+
* so it is red even when frontmatter-scoped. The fix-forward is the owner:
|
|
31
|
+
* gsd_run query verification.status "$PHASE_DIR" --pick status
|
|
32
|
+
* `findRawVerificationStatusReadsInBlock` flags a logical line (backslash
|
|
33
|
+
* continuations joined) that names a `*VERIFICATION*` path or variable and
|
|
34
|
+
* reads `^status` with awk, sed or grep.
|
|
35
|
+
*
|
|
24
36
|
* ## What this scans
|
|
25
37
|
*
|
|
26
38
|
* Every fenced ```bash / ```sh code block in `gsd-core/workflows/*.md`,
|
|
@@ -68,6 +80,17 @@ const FRONTMATTER_SCOPE_RE = /\^---[\s\S]{0,300}?---/;
|
|
|
68
80
|
|
|
69
81
|
const ALLOW_RE = /#\s*lint-allow:\s*frontmatter-scalar-broad-grep/;
|
|
70
82
|
|
|
83
|
+
const RULE_BROAD_GREP = 'frontmatter-scalar-broad-grep';
|
|
84
|
+
const RULE_VERIFICATION_RAW_READ = 'verification-status-raw-read';
|
|
85
|
+
|
|
86
|
+
// #5118: a VERIFICATION report path or variable (`*-VERIFICATION.md`,
|
|
87
|
+
// `$VERIFICATION_FILE`, `${VERIFICATION_PATH}`), a raw `^status` pattern, and
|
|
88
|
+
// the text tool doing the read. Case-INsensitive (#5118 review): a lower-case
|
|
89
|
+
// `$verification_file` / `*-verification.md` read is the same bypass.
|
|
90
|
+
const VERIFICATION_PATH_RE = /verification/i;
|
|
91
|
+
const RAW_STATUS_PATTERN_RE = /\^status\b/;
|
|
92
|
+
const RAW_READ_TOOL_RE = /(^|[\s|;&(`$])(awk|gawk|sed|grep|egrep)\s/;
|
|
93
|
+
|
|
71
94
|
// `| head -1` / `| head -n 1` immediately after the grep is functionally
|
|
72
95
|
// equivalent to `-m1` for this check: frontmatter always precedes the body
|
|
73
96
|
// in these generated reports, so the first grep match is always the
|
|
@@ -163,12 +186,63 @@ function findBroadGrepsInBlock(lines) {
|
|
|
163
186
|
}
|
|
164
187
|
|
|
165
188
|
if (pipedToTokenTool || comparedLater) {
|
|
166
|
-
findings.push({ lineIndex: i, key, snippet: line.trim() });
|
|
189
|
+
findings.push({ lineIndex: i, key, snippet: line.trim(), rule: RULE_BROAD_GREP });
|
|
167
190
|
}
|
|
168
191
|
}
|
|
169
192
|
return findings;
|
|
170
193
|
}
|
|
171
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Join backslash-continued physical lines into logical lines, remembering the
|
|
197
|
+
* index of each logical line's FIRST physical line.
|
|
198
|
+
* @param {string[]} lines
|
|
199
|
+
* @returns {{ lineIndex: number, text: string }[]}
|
|
200
|
+
*/
|
|
201
|
+
function logicalLines(lines) {
|
|
202
|
+
const out = [];
|
|
203
|
+
let current = null;
|
|
204
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
205
|
+
const line = lines[i];
|
|
206
|
+
const continued = /\\\s*$/.test(line);
|
|
207
|
+
const piece = continued ? line.replace(/\\\s*$/, ' ') : line;
|
|
208
|
+
if (current === null) current = { lineIndex: i, text: piece };
|
|
209
|
+
else current.text += piece;
|
|
210
|
+
if (!continued) {
|
|
211
|
+
out.push(current);
|
|
212
|
+
current = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (current !== null) out.push(current);
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Pure (#5118): find every raw read of a VERIFICATION report's `status` in a
|
|
221
|
+
* single fenced bash/sh block — awk / sed / grep over a `*VERIFICATION*`
|
|
222
|
+
* path with a `^status` pattern, whether or not it is frontmatter-scoped.
|
|
223
|
+
* The owner query (`gsd_run query verification.status …`) carries no
|
|
224
|
+
* `^status` pattern and is never flagged. Returns
|
|
225
|
+
* `{ lineIndex, key, snippet, rule }[]` (lineIndex = the logical line's first
|
|
226
|
+
* physical line).
|
|
227
|
+
* @param {string[]} lines
|
|
228
|
+
* @returns {{ lineIndex: number, key: string, snippet: string, rule: string }[]}
|
|
229
|
+
*/
|
|
230
|
+
function findRawVerificationStatusReadsInBlock(lines) {
|
|
231
|
+
const findings = [];
|
|
232
|
+
for (const { lineIndex, text } of logicalLines(lines)) {
|
|
233
|
+
if (!VERIFICATION_PATH_RE.test(text)) continue;
|
|
234
|
+
if (!RAW_STATUS_PATTERN_RE.test(text)) continue;
|
|
235
|
+
if (!RAW_READ_TOOL_RE.test(text)) continue;
|
|
236
|
+
findings.push({
|
|
237
|
+
lineIndex,
|
|
238
|
+
key: 'status',
|
|
239
|
+
snippet: text.replace(/\s+/g, ' ').trim(),
|
|
240
|
+
rule: RULE_VERIFICATION_RAW_READ,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return findings;
|
|
244
|
+
}
|
|
245
|
+
|
|
172
246
|
function walkMarkdown(dir) {
|
|
173
247
|
const out = [];
|
|
174
248
|
let entries;
|
|
@@ -198,12 +272,18 @@ function scan(roots = DEFAULT_ROOTS) {
|
|
|
198
272
|
for (const file of walkMarkdown(abs)) {
|
|
199
273
|
const blocks = extractBashBlocks(fs.readFileSync(file, 'utf8'));
|
|
200
274
|
for (const block of blocks) {
|
|
201
|
-
|
|
275
|
+
const rawReads = findRawVerificationStatusReadsInBlock(block.lines);
|
|
276
|
+
const rawReadLines = new Set(rawReads.map((f) => f.lineIndex));
|
|
277
|
+
// A raw VERIFICATION `status` read is reported once, under its own
|
|
278
|
+
// rule, not a second time as a broad grep.
|
|
279
|
+
const broad = findBroadGrepsInBlock(block.lines).filter((f) => !rawReadLines.has(f.lineIndex));
|
|
280
|
+
for (const finding of [...rawReads, ...broad]) {
|
|
202
281
|
offenders.push({
|
|
203
282
|
file: path.relative(ROOT, file),
|
|
204
283
|
line: block.startLine + finding.lineIndex,
|
|
205
284
|
key: finding.key,
|
|
206
285
|
snippet: finding.snippet,
|
|
286
|
+
rule: finding.rule,
|
|
207
287
|
});
|
|
208
288
|
}
|
|
209
289
|
}
|
|
@@ -217,21 +297,47 @@ function main() {
|
|
|
217
297
|
const roots = rootsEnv ? rootsEnv.split(path.delimiter).filter(Boolean) : DEFAULT_ROOTS;
|
|
218
298
|
const offenders = scan(roots);
|
|
219
299
|
if (offenders.length > 0) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
'
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
300
|
+
const detailFor = (rule) => offenders
|
|
301
|
+
.filter((o) => o.rule === rule)
|
|
302
|
+
.map((o) => ` ${o.file}:${o.line} ${o.snippet}`)
|
|
303
|
+
.join('\n');
|
|
304
|
+
const sections = [];
|
|
305
|
+
const rawReads = detailFor(RULE_VERIFICATION_RAW_READ);
|
|
306
|
+
if (rawReads) {
|
|
307
|
+
sections.push(
|
|
308
|
+
`[${RULE_VERIFICATION_RAW_READ}] a VERIFICATION report's \`status\` read with awk/sed/grep\n`
|
|
309
|
+
+ '(DEFECT.FRONTMATTER-SCALAR-BROAD-GREP, #5118). It bypasses the closed VerificationStatus\n'
|
|
310
|
+
+ 'enum, the staleness check and the routing table. Read it through its owner:\n'
|
|
311
|
+
+ ' gsd_run query verification.status "$PHASE_DIR" --pick status\n'
|
|
312
|
+
+ rawReads,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
const broad = detailFor(RULE_BROAD_GREP);
|
|
316
|
+
if (broad) {
|
|
317
|
+
sections.push(
|
|
318
|
+
`[${RULE_BROAD_GREP}] \`grep "^key:"\` over the whole file, compared to an exact token,\n`
|
|
319
|
+
+ 'with no frontmatter scoping and no -m1 (DEFECT.FRONTMATTER-SCALAR-BROAD-GREP).\n'
|
|
320
|
+
+ 'A body line beginning `key:` is enough to break this. Scope a scalar that has no owning\n'
|
|
321
|
+
+ 'query to the frontmatter block (a VERIFICATION `status` always goes through its owner):\n'
|
|
322
|
+
+ ' sed -n \'/^---$/,/^---$/p\' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d \' \'\n'
|
|
323
|
+
+ 'or add `# lint-allow: frontmatter-scalar-broad-grep — <reason>` if this is a genuine\n'
|
|
324
|
+
+ 'whole-body scan:\n'
|
|
325
|
+
+ broad,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
throw new ExitError(1, `lint-frontmatter-scalar-broad-grep:\n${sections.join('\n')}`);
|
|
231
329
|
}
|
|
232
330
|
console.log(`ok lint-frontmatter-scalar-broad-grep: no un-scoped frontmatter-scalar greps in ${roots.length} root(s)`);
|
|
233
331
|
}
|
|
234
332
|
|
|
235
|
-
module.exports = {
|
|
333
|
+
module.exports = {
|
|
334
|
+
findBroadGrepsInBlock,
|
|
335
|
+
findRawVerificationStatusReadsInBlock,
|
|
336
|
+
extractBashBlocks,
|
|
337
|
+
scan,
|
|
338
|
+
DEFAULT_ROOTS,
|
|
339
|
+
RULE_BROAD_GREP,
|
|
340
|
+
RULE_VERIFICATION_RAW_READ,
|
|
341
|
+
};
|
|
236
342
|
|
|
237
343
|
if (require.main === module) runMain(main);
|
|
@@ -84,13 +84,16 @@
|
|
|
84
84
|
* shape as `collectDiskPhases` and the `audit.cts` scanners; it must see
|
|
85
85
|
* every phase directory regardless of milestone window to catch a
|
|
86
86
|
* naming/duplicate defect wherever it lives.
|
|
87
|
-
* - `src/
|
|
88
|
-
* `phase` argument to its directory (falling back to an
|
|
89
|
-
* match) — a single-phase LOOKUP, not a current-milestone
|
|
90
|
-
* Originally `cmdVerifySchemaDrift`'s own inline block;
|
|
91
|
-
* into this shared helper (also used by the
|
|
92
|
-
* without changing what question it asks, so the exemption moved
|
|
93
|
-
* the call site rather than multiplying.
|
|
87
|
+
* - `src/gate-phase-context.cts` `resolvePhaseDirByToken`: resolves ONE
|
|
88
|
+
* caller-supplied `phase` argument to its directory (falling back to an
|
|
89
|
+
* exact-name match) — a single-phase LOOKUP, not a current-milestone
|
|
90
|
+
* enumeration. Originally `cmdVerifySchemaDrift`'s own inline block;
|
|
91
|
+
* #3348 lifted it into this shared helper (also used by the context-drift
|
|
92
|
+
* check) without changing what question it asks, so the exemption moved
|
|
93
|
+
* with the call site rather than multiplying. #5219 (ADR-5057 §4) moved
|
|
94
|
+
* both checks into gate modules and the helper beside `resolvePhaseDir`
|
|
95
|
+
* in the gate phase-context module (it is not `resolvePhaseDir`: it
|
|
96
|
+
* lists ONE given phases directory and nothing else).
|
|
94
97
|
* - `src/init.cts` `detectHasPriorPhases`: answers "has this project EVER
|
|
95
98
|
* completed a phase", explicitly excluding the current one. A history
|
|
96
99
|
* probe across all milestones, not a current-milestone enumeration.
|
|
@@ -309,7 +312,8 @@ const OWNER_FILES = new Set([
|
|
|
309
312
|
// `lint-milestone-window-drift.cjs`'s FUNCTION_SCOPED_EXEMPTIONS mechanism.
|
|
310
313
|
// See the header comment for the full written reason behind each entry.
|
|
311
314
|
const FUNCTION_SCOPED_EXEMPTIONS = new Map([
|
|
312
|
-
[path.join('src', 'verify.cts'), new Set(['cmdValidateHealth'
|
|
315
|
+
[path.join('src', 'verify.cts'), new Set(['cmdValidateHealth'])],
|
|
316
|
+
[path.join('src', 'gate-phase-context.cts'), new Set(['resolvePhaseDirByToken'])],
|
|
313
317
|
[path.join('src', 'init.cts'), new Set(['detectHasPriorPhases', 'detectUiPhaseActive'])],
|
|
314
318
|
[path.join('src', 'milestone.cts'), new Set(['archivePhaseDirectories', 'cmdMilestoneComplete', 'cmdPhasesClear'])],
|
|
315
319
|
// #3849: collectSiblingWorktreePhaseNums reads a SIBLING worktree's phases dir —
|
|
@@ -283,6 +283,34 @@ function findPhaseHeadingScanLiteralDrift(text) {
|
|
|
283
283
|
return out;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Scan the authored source tree (`src/**\/*.cts`, the same `SCAN_DIRS` root
|
|
288
|
+
* and `phase-id.cts` owner exemption that `scanRepo` applies to this
|
|
289
|
+
* detector — the heading-scan literal is a `src/**\/*.cts` defect, not a
|
|
290
|
+
* markdown one, unlike its sibling wrappers below) for unsanctioned
|
|
291
|
+
* hand-rolled heading-scan literals. Returns [{ file, line, found }] with
|
|
292
|
+
* repo-relative paths.
|
|
293
|
+
*/
|
|
294
|
+
function scanMarkdownPhaseHeadingScanLiteral(root) {
|
|
295
|
+
const violations = [];
|
|
296
|
+
for (const dir of SCAN_DIRS) {
|
|
297
|
+
for (const file of walk(path.join(root, dir), [])) {
|
|
298
|
+
const rel = path.relative(root, file);
|
|
299
|
+
if (EXEMPT.has(rel)) continue;
|
|
300
|
+
let text;
|
|
301
|
+
try {
|
|
302
|
+
text = fs.readFileSync(file, 'utf8');
|
|
303
|
+
} catch {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
for (const d of findPhaseHeadingScanLiteralDrift(text)) {
|
|
307
|
+
violations.push({ file: rel, kind: 'phase-heading-scan-literal', ...d });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return violations;
|
|
312
|
+
}
|
|
313
|
+
|
|
286
314
|
// #4634: ban base-10-forced shell arithmetic (`$((10#...))`) on a variable
|
|
287
315
|
// that still carries a possibly-decimal/multi-segment phase id — this
|
|
288
316
|
// construct is exactly the pattern that breaks on a value like `08.5`. The
|
|
@@ -857,6 +885,7 @@ module.exports = {
|
|
|
857
885
|
findNameValidityDrift,
|
|
858
886
|
findBranchSlugFallbackDrift,
|
|
859
887
|
findPhaseHeadingScanLiteralDrift,
|
|
888
|
+
scanMarkdownPhaseHeadingScanLiteral,
|
|
860
889
|
findShellPhaseArithDrift,
|
|
861
890
|
findSingleSegmentPhaseRegexDrift,
|
|
862
891
|
findLetterlessPhaseMirrorDrift,
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PlanningDoc positive-control lint (ADR-4910 §7, "Every parser ships a
|
|
6
|
+
* positive control per accepted grammar", epic #4906 Phase 6 / #5007).
|
|
7
|
+
*
|
|
8
|
+
* `NodeKind` (`src/planning-document.cts`, compiled to
|
|
9
|
+
* `gsd-core/bin/lib/planning-document.cjs`) is the single-source union naming
|
|
10
|
+
* every grammar `parsePlanningDoc` accepts: `frontmatter` / `section` /
|
|
11
|
+
* `boldField` / `table` / `checklist`. This lint asserts one positive-control
|
|
12
|
+
* fixture per declared grammar, under `tests/fixtures/planning-document/`,
|
|
13
|
+
* each of which must round-trip through the real `parsePlanningDoc` and
|
|
14
|
+
* actually produce a node of that kind — not merely "the parser didn't
|
|
15
|
+
* throw". Per CONTRIBUTING.md's fixture-provenance rule (#2371), every
|
|
16
|
+
* fixture here is authored independently, never copied from
|
|
17
|
+
* `src/planning-document.cts`'s own docstring examples or from
|
|
18
|
+
* `tests/planning-document.test.cjs`'s existing fixtures.
|
|
19
|
+
*
|
|
20
|
+
* The `accepted` set (`NodeKind`) is a TypeScript-only type, erased by
|
|
21
|
+
* compilation — it carries no runtime value in the built `.cjs` seam. So this
|
|
22
|
+
* lint reads it directly out of `src/planning-document.cts`'s own source
|
|
23
|
+
* text (the `export type NodeKind = ...;` declaration), the same way
|
|
24
|
+
* `scripts/lint-phase-id-drift.cjs` reads source text for its own literal
|
|
25
|
+
* checks — NOT by importing a type, which is impossible from a `.cjs`
|
|
26
|
+
* script. This is what makes the guarantee live: a NEW grammar kind added to
|
|
27
|
+
* `NodeKind` with no registry entry fails this lint immediately, before any
|
|
28
|
+
* fixture is even written, closing the "parser without one fails the build"
|
|
29
|
+
* requirement in ADR-4910 §7.
|
|
30
|
+
*
|
|
31
|
+
* Modeled on `scripts/lint-table-schema-drift.cjs`'s registry/exit-code/
|
|
32
|
+
* error-message structure — a hardcoded `{grammar -> fixture file}` map,
|
|
33
|
+
* exit 0 clean / exit 1 with a per-entry reason on drift, wired into
|
|
34
|
+
* `lint:ci` — but the ASSERTION is stricter than that script's verbatim-
|
|
35
|
+
* substring check: proof the grammar is genuinely *accepted* (the fixture
|
|
36
|
+
* parses without error and yields a node of that kind), per ADR-4910 §7's
|
|
37
|
+
* own text, not just "a string appears somewhere".
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const fs = require('node:fs');
|
|
41
|
+
const path = require('node:path');
|
|
42
|
+
|
|
43
|
+
const PLANNING_DOCUMENT_SRC = path.join('src', 'planning-document.cts');
|
|
44
|
+
const PLANNING_DOCUMENT_LIB = path.join('gsd-core', 'bin', 'lib', 'planning-document.cjs');
|
|
45
|
+
const FIXTURE_DIR = path.join('tests', 'fixtures', 'planning-document');
|
|
46
|
+
|
|
47
|
+
// grammar kind (must match a `NodeKind` union member verbatim) -> the ONE
|
|
48
|
+
// canonical positive-control fixture file (relative to FIXTURE_DIR) that
|
|
49
|
+
// proves that grammar is accepted (ADR-4910 §7).
|
|
50
|
+
const POSITIVE_CONTROL_REGISTRY = {
|
|
51
|
+
frontmatter: 'frontmatter.md',
|
|
52
|
+
section: 'section.md',
|
|
53
|
+
boldField: 'boldfield.md',
|
|
54
|
+
table: 'table.md',
|
|
55
|
+
checklist: 'checklist.md',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Any real entry from `PLANNING_ARTIFACTS` satisfies `parsePlanningDoc`'s
|
|
59
|
+
// artifact-kind gate equally — the specific name does not affect which
|
|
60
|
+
// grammars a fixture's BODY is recognised as containing.
|
|
61
|
+
const FIXTURE_ARTIFACT_NAME = 'ROADMAP.md';
|
|
62
|
+
|
|
63
|
+
// Test-only env var name. `resolveRegistry` below JSON-parses this (when set)
|
|
64
|
+
// and shallow-merges it over `POSITIVE_CONTROL_REGISTRY`, so a test can spawn
|
|
65
|
+
// THIS SAME, otherwise-unmodified, script file as a real child process
|
|
66
|
+
// against a deliberately broken registry entry (a missing entry, or one
|
|
67
|
+
// pointed at a nonexistent fixture) — proving the lint genuinely fails the
|
|
68
|
+
// build, per ADR-4910 §7's "a parser without one fails the build" guarantee
|
|
69
|
+
// — without ever touching the real registry or fixture files.
|
|
70
|
+
//
|
|
71
|
+
// This env var alone is NEVER sufficient to activate the override — a bare
|
|
72
|
+
// `process.env` lookup would mean a stray, accidentally-inherited copy of
|
|
73
|
+
// this variable (a leftover shell `export`, a misconfigured CI environment,
|
|
74
|
+
// a compromised dependency's postinstall script) could silently swap the
|
|
75
|
+
// registry in a REAL `npm run lint:ci` / `npm run lint:planning-document-
|
|
76
|
+
// positive-control` invocation, with nothing in the code enforcing otherwise
|
|
77
|
+
// (flagged by both the security review and the code-review Standards axis
|
|
78
|
+
// on #5007 Phase 6: the old comment asserted "no real invocation ever sets
|
|
79
|
+
// this" as a convention, not a fact the code made true).
|
|
80
|
+
//
|
|
81
|
+
// What now makes it true, by construction: `scanRepo` only reads this env
|
|
82
|
+
// var via `resolveRegistry` when its caller ALSO passes `allowOverride ===
|
|
83
|
+
// true`, which `main()` only does when the `--test-registry-override` CLI
|
|
84
|
+
// flag is present in argv (see `parseArgs`). The test file spawns this
|
|
85
|
+
// script as a real child process (`tests/helpers/process-seam.cjs`'s
|
|
86
|
+
// `runNode`, over `spawnSync`) — a process boundary that can only carry data
|
|
87
|
+
// in via `env`/`argv`, so the override cannot be passed as an in-process
|
|
88
|
+
// function parameter here the way it can be for the pure functions below.
|
|
89
|
+
// Requiring BOTH the env var and the CLI flag closes the gap: neither
|
|
90
|
+
// `lint:ci` nor `lint:planning-document-positive-control` (see package.json)
|
|
91
|
+
// ever passes `--test-registry-override` in their fixed argv, and unlike an
|
|
92
|
+
// env var, a CLI flag is never accidentally "leaked" into a fixed npm-script
|
|
93
|
+
// invocation. See tests/lint-planning-document-positive-control.test.cjs.
|
|
94
|
+
const TEST_REGISTRY_OVERRIDE_ENV_VAR = 'LINT_PLANNING_DOCUMENT_POSITIVE_CONTROL_TEST_REGISTRY_OVERRIDE';
|
|
95
|
+
|
|
96
|
+
/** CLI flag gate for the test-only override (see `TEST_REGISTRY_OVERRIDE_ENV_VAR`
|
|
97
|
+
* above). Must be passed explicitly in argv — never inferred from env — for
|
|
98
|
+
* `resolveRegistry`'s env-var override to be honored at all. */
|
|
99
|
+
const TEST_REGISTRY_OVERRIDE_CLI_FLAG = '--test-registry-override';
|
|
100
|
+
|
|
101
|
+
/** Resolve the registry to scan against: the real hardcoded registry, unless
|
|
102
|
+
* BOTH `allowOverride` is `true` (only ever set by the
|
|
103
|
+
* `--test-registry-override` CLI flag, see `TEST_REGISTRY_OVERRIDE_CLI_FLAG`)
|
|
104
|
+
* AND the test-only override env var is set and parses as JSON, in which
|
|
105
|
+
* case its keys are shallow-merged on top (see
|
|
106
|
+
* `TEST_REGISTRY_OVERRIDE_ENV_VAR`). Without `allowOverride === true`, the
|
|
107
|
+
* env var is never even read. */
|
|
108
|
+
function resolveRegistry(env, allowOverride) {
|
|
109
|
+
if (!allowOverride) return POSITIVE_CONTROL_REGISTRY;
|
|
110
|
+
const override = env[TEST_REGISTRY_OVERRIDE_ENV_VAR];
|
|
111
|
+
if (!override) return POSITIVE_CONTROL_REGISTRY;
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(override);
|
|
114
|
+
return { ...POSITIVE_CONTROL_REGISTRY, ...parsed };
|
|
115
|
+
} catch {
|
|
116
|
+
return POSITIVE_CONTROL_REGISTRY;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract the live `NodeKind` union members from `planning-document.cts`'s
|
|
122
|
+
* own source text — the "accepted grammars" set (ADR-4910 §4a) — read
|
|
123
|
+
* directly from source (never from the compiled seam, which erases the TS
|
|
124
|
+
* type) so a newly added grammar kind is detected even before any registry
|
|
125
|
+
* entry or fixture exists for it.
|
|
126
|
+
*
|
|
127
|
+
* Pure: takes a `readFile(relPath) -> string|null` accessor so tests can
|
|
128
|
+
* inject a scratch source file without touching the real repo tree.
|
|
129
|
+
*/
|
|
130
|
+
function readLiveGrammarKinds(readFile) {
|
|
131
|
+
const text = readFile(PLANNING_DOCUMENT_SRC);
|
|
132
|
+
if (text == null) {
|
|
133
|
+
return { ok: false, reason: `cannot read ${PLANNING_DOCUMENT_SRC}` };
|
|
134
|
+
}
|
|
135
|
+
const m = /export type NodeKind\s*=\s*([^;]+);/.exec(text);
|
|
136
|
+
if (!m) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
reason: `could not find 'export type NodeKind = ...;' in ${PLANNING_DOCUMENT_SRC} — has the type been renamed or removed?`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const kinds = [...m[1].matchAll(/'([^']+)'/g)].map((mm) => mm[1]);
|
|
143
|
+
if (kinds.length === 0) {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
reason: `the 'NodeKind' union in ${PLANNING_DOCUMENT_SRC} matched but contained no string-literal members`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { ok: true, value: kinds };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Pure: given the live grammar-kind list, the hardcoded registry, a
|
|
154
|
+
* `readFixture(fileName) -> string|null` accessor, the real `parsePlanningDoc`
|
|
155
|
+
* function, and the artifact name to parse fixtures as, find every gap.
|
|
156
|
+
* Returns `[{ kind, fixture?, reason }]`; empty when clean.
|
|
157
|
+
*
|
|
158
|
+
* Checks, per live grammar kind:
|
|
159
|
+
* 1. a registry entry exists at all (the §7 "parser without one fails the
|
|
160
|
+
* build" guarantee — this fires even with an EMPTY registry);
|
|
161
|
+
* 2. the registered fixture file exists and is readable;
|
|
162
|
+
* 3. the fixture parses successfully via the real parser;
|
|
163
|
+
* 4. the parsed document actually contains a node of that kind (proof the
|
|
164
|
+
* grammar was recognised, not just "didn't throw").
|
|
165
|
+
* Also flags a registry entry naming a grammar the parser no longer
|
|
166
|
+
* declares (a stale entry), so the registry cannot silently drift wider
|
|
167
|
+
* than the parser either.
|
|
168
|
+
*/
|
|
169
|
+
function findPositiveControlGaps(liveKinds, registry, readFixture, parsePlanningDocFn, artifactName) {
|
|
170
|
+
const violations = [];
|
|
171
|
+
|
|
172
|
+
for (const kind of liveKinds) {
|
|
173
|
+
const fixtureName = registry[kind];
|
|
174
|
+
if (!fixtureName) {
|
|
175
|
+
violations.push({
|
|
176
|
+
kind,
|
|
177
|
+
reason:
|
|
178
|
+
`parser declares grammar '${kind}' (NodeKind) but POSITIVE_CONTROL_REGISTRY has no entry for it — ` +
|
|
179
|
+
'add one and a matching fixture under tests/fixtures/planning-document/',
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const content = readFixture(fixtureName);
|
|
185
|
+
if (content == null) {
|
|
186
|
+
violations.push({
|
|
187
|
+
kind,
|
|
188
|
+
fixture: fixtureName,
|
|
189
|
+
reason: `fixture file not found or unreadable: ${path.join(FIXTURE_DIR, fixtureName)}`,
|
|
190
|
+
});
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const result = parsePlanningDocFn(content, artifactName);
|
|
195
|
+
if (!result.ok) {
|
|
196
|
+
violations.push({
|
|
197
|
+
kind,
|
|
198
|
+
fixture: fixtureName,
|
|
199
|
+
reason: `fixture failed to parse via parsePlanningDoc: ${result.reason}`,
|
|
200
|
+
});
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const hasKind = result.value.nodes.some((n) => n.kind === kind);
|
|
205
|
+
if (!hasKind) {
|
|
206
|
+
violations.push({
|
|
207
|
+
kind,
|
|
208
|
+
fixture: fixtureName,
|
|
209
|
+
reason: `fixture parsed successfully but produced no '${kind}' node — it does not actually exercise this grammar`,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (const kind of Object.keys(registry)) {
|
|
215
|
+
if (!liveKinds.includes(kind)) {
|
|
216
|
+
violations.push({
|
|
217
|
+
kind,
|
|
218
|
+
fixture: registry[kind],
|
|
219
|
+
reason: `registry entry names grammar '${kind}', which is not in the parser's live NodeKind union — stale entry, remove it`,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return violations;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Load the built seam and the real source/fixture tree rooted at `root`, and
|
|
229
|
+
* run `findPositiveControlGaps` against them. Returns the same shape as
|
|
230
|
+
* `findPositiveControlGaps`. If the seam hasn't been built yet, or the
|
|
231
|
+
* `NodeKind` union can't be located, reports a single actionable violation
|
|
232
|
+
* rather than throwing.
|
|
233
|
+
*
|
|
234
|
+
* `allowOverride` (default `false`) must be explicitly `true` for the
|
|
235
|
+
* test-only env-var registry override to be honored at all — see
|
|
236
|
+
* `resolveRegistry` and `TEST_REGISTRY_OVERRIDE_ENV_VAR`'s header comment.
|
|
237
|
+
*/
|
|
238
|
+
function scanRepo(root, env, allowOverride = false) {
|
|
239
|
+
const readFile = (relPath) => {
|
|
240
|
+
try {
|
|
241
|
+
return fs.readFileSync(path.join(root, relPath), 'utf8');
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const readFixture = (fileName) => readFile(path.join(FIXTURE_DIR, fileName));
|
|
247
|
+
|
|
248
|
+
const live = readLiveGrammarKinds(readFile);
|
|
249
|
+
if (!live.ok) {
|
|
250
|
+
return [{ kind: null, reason: live.reason }];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const libPath = path.join(root, PLANNING_DOCUMENT_LIB);
|
|
254
|
+
let seam;
|
|
255
|
+
try {
|
|
256
|
+
seam = require(libPath);
|
|
257
|
+
} catch (e) {
|
|
258
|
+
return [
|
|
259
|
+
{
|
|
260
|
+
kind: null,
|
|
261
|
+
reason: `cannot load the planning-document seam at ${path.relative(root, libPath)} — run 'npm run build:lib' first (${e.message})`,
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const registry = resolveRegistry(env || process.env, allowOverride);
|
|
267
|
+
return findPositiveControlGaps(live.value, registry, readFixture, seam.parsePlanningDoc, FIXTURE_ARTIFACT_NAME);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Parse a bare `--root <path>` CLI override (defaults to the real repo root)
|
|
271
|
+
* and the `--test-registry-override` flag that gates `resolveRegistry`'s
|
|
272
|
+
* env-var override (see `TEST_REGISTRY_OVERRIDE_CLI_FLAG`'s header comment).
|
|
273
|
+
* No real invocation (`npm run lint:ci`, `npm run lint:planning-document-
|
|
274
|
+
* positive-control`) ever passes this flag. */
|
|
275
|
+
function parseArgs(argv) {
|
|
276
|
+
let root = path.join(__dirname, '..');
|
|
277
|
+
let allowTestRegistryOverride = false;
|
|
278
|
+
for (let i = 0; i < argv.length; i++) {
|
|
279
|
+
if (argv[i] === '--root' && argv[i + 1]) {
|
|
280
|
+
root = path.resolve(argv[i + 1]);
|
|
281
|
+
i += 1;
|
|
282
|
+
} else if (argv[i] === TEST_REGISTRY_OVERRIDE_CLI_FLAG) {
|
|
283
|
+
allowTestRegistryOverride = true;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return { root, allowTestRegistryOverride };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function main() {
|
|
290
|
+
const { root, allowTestRegistryOverride } = parseArgs(process.argv.slice(2));
|
|
291
|
+
const violations = scanRepo(root, process.env, allowTestRegistryOverride);
|
|
292
|
+
if (violations.length === 0) {
|
|
293
|
+
process.stdout.write(
|
|
294
|
+
'ok planning-document-positive-control: every declared PlanningDoc grammar has a passing positive-control fixture\n',
|
|
295
|
+
);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
process.stderr.write(
|
|
299
|
+
'planning-document-positive-control: PlanningDoc grammar(s) missing or failing a positive-control fixture (ADR-4910 §7).\n',
|
|
300
|
+
);
|
|
301
|
+
process.stderr.write(
|
|
302
|
+
'Add/fix a fixture under tests/fixtures/planning-document/ and register it in POSITIVE_CONTROL_REGISTRY in\n' +
|
|
303
|
+
'scripts/lint-planning-document-positive-control.cjs — each fixture must round-trip through parsePlanningDoc\n' +
|
|
304
|
+
'and yield a node of the declared kind.\n',
|
|
305
|
+
);
|
|
306
|
+
for (const v of violations) {
|
|
307
|
+
const id = v.kind ?? '?';
|
|
308
|
+
const loc = v.fixture ? ` (${path.join(FIXTURE_DIR, v.fixture)})` : '';
|
|
309
|
+
process.stderr.write(` ${id}${loc}: ${v.reason}\n`);
|
|
310
|
+
}
|
|
311
|
+
process.exitCode = 1;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (require.main === module) main();
|
|
315
|
+
|
|
316
|
+
module.exports = {
|
|
317
|
+
findPositiveControlGaps,
|
|
318
|
+
readLiveGrammarKinds,
|
|
319
|
+
resolveRegistry,
|
|
320
|
+
scanRepo,
|
|
321
|
+
parseArgs,
|
|
322
|
+
POSITIVE_CONTROL_REGISTRY,
|
|
323
|
+
FIXTURE_ARTIFACT_NAME,
|
|
324
|
+
PLANNING_DOCUMENT_SRC,
|
|
325
|
+
PLANNING_DOCUMENT_LIB,
|
|
326
|
+
FIXTURE_DIR,
|
|
327
|
+
TEST_REGISTRY_OVERRIDE_ENV_VAR,
|
|
328
|
+
TEST_REGISTRY_OVERRIDE_CLI_FLAG,
|
|
329
|
+
};
|
|
@@ -78,7 +78,10 @@ const EXACT_INLINE_DIRECTIVE_WORKFLOWS = new Set([
|
|
|
78
78
|
'discuss-phase/modes/text.md',
|
|
79
79
|
'discuss-phase/templates/context.md',
|
|
80
80
|
'discuss-phase/templates/discussion-log.md',
|
|
81
|
+
'execute-phase/steps/code-review-disposition.md',
|
|
81
82
|
'execute-phase/steps/codebase-drift-gate.md',
|
|
83
|
+
'execute-phase/steps/gap-closure-artifacts.md',
|
|
84
|
+
'execute-phase/steps/regression-gate.md',
|
|
82
85
|
'execute-phase/steps/regression-gate-run.md',
|
|
83
86
|
'execute-phase/steps/worktree-recovery-policy.md',
|
|
84
87
|
'help/modes/brief.md',
|
|
@@ -29,6 +29,8 @@ const { runMain } = require('./lib/cli-exit.cjs');
|
|
|
29
29
|
|
|
30
30
|
const PROFILES_MODULE = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'install-profiles.cjs');
|
|
31
31
|
const { PROFILES, loadSkillsManifest, resolveProfile } = require(PROFILES_MODULE);
|
|
32
|
+
// The one frontmatter fence owner, from the same build:lib output as install-profiles.
|
|
33
|
+
const { locateFrontmatterFence } = require('../gsd-core/bin/lib/frontmatter-fence.cjs');
|
|
32
34
|
|
|
33
35
|
// ---------------------------------------------------------------------------
|
|
34
36
|
// Argument parsing
|
|
@@ -58,9 +60,11 @@ function extractBodyReferences(body) {
|
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
function extractBody(content) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
// The block is the one the one fence owner finds (found while implementing #5105);
|
|
64
|
+
// the body starts past the closing fence line and its line ending.
|
|
65
|
+
const fence = locateFrontmatterFence(content);
|
|
66
|
+
if (!fence || !fence.closed) return content;
|
|
67
|
+
return content.slice(fence.closingFenceEnd).replace(/^\r?\n/, '');
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
// ---------------------------------------------------------------------------
|
|
@@ -142,6 +142,7 @@
|
|
|
142
142
|
"files": [
|
|
143
143
|
"verify-archive-dirs-live-path.test.cjs",
|
|
144
144
|
"verify-health.test.cjs",
|
|
145
|
+
"verify-lifecycle-writes-e2e.test.cjs",
|
|
145
146
|
"verify-mvp-uat.test.cjs",
|
|
146
147
|
"verify-npm-publish.test.cjs",
|
|
147
148
|
"verify-test-quality.test.cjs",
|
|
@@ -150,7 +151,7 @@
|
|
|
150
151
|
"verify.test.cjs"
|
|
151
152
|
],
|
|
152
153
|
"issue": "#3813 — the live-path #1883 suite drives buildPlanningSnapshot in-process with an fs fault; the verify module suites are CLI-driving and cannot host an fs monkeypatch",
|
|
153
|
-
"justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane). #4546 adds verify-work-deferred-promotion (deferred-follow-up promotion writer contract + parity)."
|
|
154
|
+
"justification": "verify-command-grounding added by #2401/#3678; allowlist follow-up landed with #3606 (base was red on this lane). #4546 adds verify-work-deferred-promotion (deferred-follow-up promotion writer contract + parity). #5105 adds verify-lifecycle-writes-e2e.test.cjs (Phase 3 of #5056: end-to-end fixture proving the fixed post-fingerprint verbs leave an unchanged re-run fresh, plus its own pre-fix CONTROL — a distinct end-to-end concern from the existing per-verb unit suites)."
|
|
154
155
|
},
|
|
155
156
|
"install": {
|
|
156
157
|
"files": [
|
|
@@ -293,6 +294,15 @@
|
|
|
293
294
|
],
|
|
294
295
|
"issue": "4657",
|
|
295
296
|
"justification": "The ui-consideration-probe cluster gains its workflow-prose contract file (tests/ui-consideration-probe-ui-phase-contract.test.cjs, #4657), mirroring the edge probe's split (edge-probe.test.cjs / edge-probe-docs-fixtures.test.cjs / edge-probe-spec-phase-contract.test.cjs). The contract file reads shipped gsd-core/workflows/ui-phase.md under the source-text-is-the-product exception, which the unit file deliberately does not carry (it asserts typed returns only)."
|
|
297
|
+
},
|
|
298
|
+
"verification": {
|
|
299
|
+
"files": [
|
|
300
|
+
"verification-append-audit.test.cjs",
|
|
301
|
+
"verification-overrides.test.cjs",
|
|
302
|
+
"verification-status.test.cjs"
|
|
303
|
+
],
|
|
304
|
+
"issue": "5105",
|
|
305
|
+
"justification": "#5105 (Phase 3 of #5056) adds verification-append-audit.test.cjs for the new `verification.append-audit` verb (deny-by-default audit-block append/no-op, #4887) — a distinct concern from verification-status.test.cjs's status/fingerprint suite and verification-overrides.test.cjs's override handling."
|
|
296
306
|
}
|
|
297
307
|
}
|
|
298
308
|
}
|