@opengsd/gsd-core 1.11.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 +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -9
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +15 -55
- package/agents/gsd-planner.md +6 -4
- 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-verifier.md +1 -1
- package/bin/install.js +609 -134
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/quick.md +8 -4
- package/gsd-core/bin/gsd-tools.cjs +567 -51
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +336 -95
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-validator.cjs +205 -18
- package/gsd-core/bin/lib/check-command-router.cjs +145 -5
- 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 +410 -4
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +543 -44
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +118 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +84 -7
- 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/frontmatter.cjs +840 -305
- package/gsd-core/bin/lib/gap-checker.cjs +27 -3
- package/gsd-core/bin/lib/git-base-branch.cjs +174 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +6 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +120 -41
- package/gsd-core/bin/lib/install-engine.cjs +68 -3
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -1
- package/gsd-core/bin/lib/install-profiles.cjs +78 -4
- 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 +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +160 -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-table.cjs +52 -4
- package/gsd-core/bin/lib/milestone.cjs +90 -5
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +70 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +405 -84
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- 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-snapshot.cjs +18 -14
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -0
- package/gsd-core/bin/lib/probe-core.cjs +4 -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 +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +9 -9
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +79 -16
- package/gsd-core/bin/lib/roadmap.cjs +74 -19
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +96 -8
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +287 -55
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +71 -8
- package/gsd-core/bin/lib/smart-entry.cjs +12 -22
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +186 -0
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +517 -101
- package/gsd-core/bin/lib/state.cjs +946 -163
- package/gsd-core/bin/lib/surface.cjs +10 -2
- 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/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +1376 -125
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification.cjs +14 -1
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +95 -40
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +177 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- 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 +3 -2
- 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 +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +1 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- 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 +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- 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-human-verify-mode.md +15 -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 +37 -8
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/runtime-aware-dispatch.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 +2 -2
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- 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/phase-prompt.md +3 -0
- package/gsd-core/templates/state.md +7 -0
- 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 +4 -9
- 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 +10 -26
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +121 -40
- package/gsd-core/workflows/complete-milestone.md +15 -10
- package/gsd-core/workflows/debug.md +5 -3
- package/gsd-core/workflows/diagnose-issues.md +12 -6
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +3 -7
- 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 +2 -2
- 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 +1 -1
- package/gsd-core/workflows/eval-review.md +4 -9
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +113 -11
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +22 -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 +38 -54
- package/gsd-core/workflows/execute-plan.md +17 -12
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +2 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +3 -6
- package/gsd-core/workflows/import.md +14 -11
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +44 -11
- 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 +2 -2
- package/gsd-core/workflows/new-milestone.md +9 -21
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +12 -26
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -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 +121 -42
- package/gsd-core/workflows/plan-review-convergence.md +46 -9
- 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 +27 -12
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -3
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +20 -29
- 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 +193 -15
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +2 -2
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +3 -5
- package/gsd-core/workflows/ship.md +12 -6
- 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 +23 -1
- 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 +1 -1
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +5 -5
- package/gsd-core/workflows/ui-phase.md +10 -16
- package/gsd-core/workflows/ui-review.md +6 -10
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +6 -10
- package/gsd-core/workflows/validate-phase.md +2 -2
- 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 +57 -18
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- 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 +3 -1
- 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 +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- 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 +16 -7
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +17 -8
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +215 -26
- 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 +34 -16
- 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-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- 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 +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- 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 +16 -7
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +17 -8
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +215 -26
- 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 +34 -16
- 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-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +12 -7
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +5 -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 +45 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- 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-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +134 -1
- 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/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- 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 +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +21 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-removed-but-needed.cjs +184 -16
- 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-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +122 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/prompt-injection-scan.sh +75 -14
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -21,6 +21,9 @@ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs")
|
|
|
21
21
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
22
22
|
const text_lines_cjs_1 = require("./text-lines.cjs");
|
|
23
23
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
|
+
const coreUtils = require("./core-utils.cjs");
|
|
25
|
+
const { normalizeLineEndings } = coreUtils;
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
27
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
25
28
|
const { planningDir, quickDirFrom } = planningWorkspace;
|
|
26
29
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -31,7 +34,7 @@ const phaseIdMod = require("./phase-id.cjs");
|
|
|
31
34
|
const { PHASE_NUMBER_TOKEN_SOURCE, scopeToPhase } = phaseIdMod;
|
|
32
35
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
36
|
const phaseLocator = require("./phase-locator.cjs");
|
|
34
|
-
const {
|
|
37
|
+
const { getAllArchivedPhaseDirs } = phaseLocator;
|
|
35
38
|
const security_cjs_1 = require("./security.cjs");
|
|
36
39
|
const shell_command_projection_cjs_2 = require("./shell-command-projection.cjs");
|
|
37
40
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -279,9 +282,17 @@ function scanDebugSessions(planDir) {
|
|
|
279
282
|
catch {
|
|
280
283
|
continue;
|
|
281
284
|
}
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
286
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
287
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
288
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
289
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
290
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
291
|
+
// direction) rather than a real parse gap.
|
|
292
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
293
|
+
if (rawContent === null)
|
|
284
294
|
continue;
|
|
295
|
+
const content = normalizeLineEndings(rawContent);
|
|
285
296
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
286
297
|
const status = (fm.status || 'unknown').toLowerCase();
|
|
287
298
|
if (status === 'resolved' || status === 'complete')
|
|
@@ -393,11 +404,15 @@ function scanQuickTasks(planDir) {
|
|
|
393
404
|
catch {
|
|
394
405
|
continue;
|
|
395
406
|
}
|
|
396
|
-
|
|
397
|
-
|
|
407
|
+
// #3078-CR MEDIUM 2: same normalize-at-read-boundary fix as the other
|
|
408
|
+
// scans in this module — see the comment above `scanDebugSessions`'s
|
|
409
|
+
// read.
|
|
410
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeSum);
|
|
411
|
+
if (rawContent === null) {
|
|
398
412
|
status = 'unreadable';
|
|
399
413
|
}
|
|
400
414
|
else {
|
|
415
|
+
const content = normalizeLineEndings(rawContent);
|
|
401
416
|
fm = extractFrontmatter(content, safeSum);
|
|
402
417
|
status = (fm.status || 'unknown').toLowerCase();
|
|
403
418
|
}
|
|
@@ -465,9 +480,17 @@ function scanThreads(planDir) {
|
|
|
465
480
|
catch {
|
|
466
481
|
continue;
|
|
467
482
|
}
|
|
468
|
-
|
|
469
|
-
|
|
483
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
484
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
485
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
486
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
487
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
488
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
489
|
+
// direction) rather than a real parse gap.
|
|
490
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
491
|
+
if (rawContent === null)
|
|
470
492
|
continue;
|
|
493
|
+
const content = normalizeLineEndings(rawContent);
|
|
471
494
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
472
495
|
const status = deriveThreadStatus(fm, content);
|
|
473
496
|
if (!openStatuses.has(status))
|
|
@@ -532,9 +555,17 @@ function scanTodos(planDir) {
|
|
|
532
555
|
catch {
|
|
533
556
|
continue;
|
|
534
557
|
}
|
|
535
|
-
|
|
536
|
-
|
|
558
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
559
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
560
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
561
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
562
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
563
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
564
|
+
// direction) rather than a real parse gap.
|
|
565
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
566
|
+
if (rawContent === null)
|
|
537
567
|
continue;
|
|
568
|
+
const content = normalizeLineEndings(rawContent);
|
|
538
569
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
539
570
|
// Todos carry no natural status field — presence in pending/ IS "open" by
|
|
540
571
|
// definition (a resolved todo is moved out, not status-flagged). So the
|
|
@@ -596,9 +627,17 @@ function scanSeeds(planDir) {
|
|
|
596
627
|
catch {
|
|
597
628
|
continue;
|
|
598
629
|
}
|
|
599
|
-
|
|
600
|
-
|
|
630
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
631
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
632
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
633
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
634
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
635
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
636
|
+
// direction) rather than a real parse gap.
|
|
637
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
638
|
+
if (rawContent === null)
|
|
601
639
|
continue;
|
|
640
|
+
const content = normalizeLineEndings(rawContent);
|
|
602
641
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
603
642
|
const status = (fm.status || 'dormant').toLowerCase();
|
|
604
643
|
if (!unimplementedStatuses.has(status))
|
|
@@ -703,8 +742,11 @@ function listAuditPhaseTargets(planDir, cwd) {
|
|
|
703
742
|
activeUnreadable = true;
|
|
704
743
|
}
|
|
705
744
|
}
|
|
745
|
+
// #3804: the audit is cross-workstream by design — the shared
|
|
746
|
+
// getAllArchivedPhaseDirs helper (root + every workstream, distinct
|
|
747
|
+
// '<ws>/<version>' labels) owns that walk.
|
|
706
748
|
try {
|
|
707
|
-
for (const archived of
|
|
749
|
+
for (const archived of getAllArchivedPhaseDirs(cwd)) {
|
|
708
750
|
targets.push({ dir: archived.name, fullPath: archived.fullPath, milestone: archived.milestone });
|
|
709
751
|
}
|
|
710
752
|
}
|
|
@@ -748,9 +790,17 @@ function scanUatGaps(planDir, cwd) {
|
|
|
748
790
|
catch {
|
|
749
791
|
continue;
|
|
750
792
|
}
|
|
751
|
-
|
|
752
|
-
|
|
793
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
794
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
795
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
796
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
797
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
798
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
799
|
+
// direction) rather than a real parse gap.
|
|
800
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
801
|
+
if (rawContent === null)
|
|
753
802
|
continue;
|
|
803
|
+
const content = normalizeLineEndings(rawContent);
|
|
754
804
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
755
805
|
const status = (fm.status || 'unknown').toLowerCase();
|
|
756
806
|
const result = (fm.result || '').toLowerCase();
|
|
@@ -813,9 +863,17 @@ function scanVerificationGaps(planDir, cwd) {
|
|
|
813
863
|
catch {
|
|
814
864
|
continue;
|
|
815
865
|
}
|
|
816
|
-
|
|
817
|
-
|
|
866
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
867
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
868
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
869
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
870
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
871
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
872
|
+
// direction) rather than a real parse gap.
|
|
873
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
874
|
+
if (rawContent === null)
|
|
818
875
|
continue;
|
|
876
|
+
const content = normalizeLineEndings(rawContent);
|
|
819
877
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
820
878
|
const status = (fm.status || 'unknown').toLowerCase();
|
|
821
879
|
if (status !== 'gaps_found' && status !== 'human_needed')
|
|
@@ -867,9 +925,17 @@ function scanContextQuestions(planDir, cwd) {
|
|
|
867
925
|
catch {
|
|
868
926
|
continue;
|
|
869
927
|
}
|
|
870
|
-
|
|
871
|
-
|
|
928
|
+
// #3078-CR MEDIUM 2 (security review follow-up): normalize a lone-CR
|
|
929
|
+
// document at this read boundary, same seam as `src/uat.cts`'s
|
|
930
|
+
// `readNormalizedDocument` — `platformReadSync` performs no line-ending
|
|
931
|
+
// normalization itself, and extractFrontmatter/status-derivation below
|
|
932
|
+
// degrade a lone-CR file's frontmatter to `unknown`, which every scan
|
|
933
|
+
// in this module treats as "not open" (fail-open, the permissive
|
|
934
|
+
// direction) rather than a real parse gap.
|
|
935
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
936
|
+
if (rawContent === null)
|
|
872
937
|
continue;
|
|
938
|
+
const content = normalizeLineEndings(rawContent);
|
|
873
939
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
874
940
|
const questions = deriveOpenQuestions(content, fm);
|
|
875
941
|
if (questions.length === 0)
|
|
@@ -947,9 +1013,15 @@ function scanDeferredItems(planDir, cwd) {
|
|
|
947
1013
|
catch {
|
|
948
1014
|
continue;
|
|
949
1015
|
}
|
|
950
|
-
|
|
951
|
-
|
|
1016
|
+
// #3078-CR MEDIUM 2: normalize at this read boundary too —
|
|
1017
|
+
// `parseDeferredItemsWithStatus` performs no normalization of its own
|
|
1018
|
+
// (unlike `src/uat.cts`'s callers, which route through
|
|
1019
|
+
// `readNormalizedDocument`), so a lone-CR `deferred-items.md` was read as
|
|
1020
|
+
// one unbroken line and every entry in it silently vanished.
|
|
1021
|
+
const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
|
|
1022
|
+
if (rawContent === null)
|
|
952
1023
|
continue;
|
|
1024
|
+
const content = normalizeLineEndings(rawContent);
|
|
953
1025
|
for (const item of uat.parseDeferredItemsWithStatus(content)) {
|
|
954
1026
|
const rawStatus = (item.status || '').toLowerCase();
|
|
955
1027
|
if (rawStatus === 'resolved')
|
|
@@ -1051,8 +1123,18 @@ function auditOpenArtifacts(cwd) {
|
|
|
1051
1123
|
return { items: [{ scan_error: true, phase: '', file: '', text: '' }], acknowledged: 0 };
|
|
1052
1124
|
}
|
|
1053
1125
|
})();
|
|
1054
|
-
// Count real items (not scan_error sentinels)
|
|
1055
|
-
|
|
1126
|
+
// Count real items (not scan_error sentinels). #3817: a `_remainder_count`
|
|
1127
|
+
// marker is not a phantom — it RECORDS real items the detail list truncated
|
|
1128
|
+
// away for display, so its value counts toward the total. Truncation limits
|
|
1129
|
+
// display, never counting; only scan_error (a read failure, not an item)
|
|
1130
|
+
// contributes zero.
|
|
1131
|
+
const countReal = (arr) => arr.reduce((sum, i) => {
|
|
1132
|
+
if (i.scan_error)
|
|
1133
|
+
return sum;
|
|
1134
|
+
if (typeof i._remainder_count === 'number')
|
|
1135
|
+
return sum + i._remainder_count;
|
|
1136
|
+
return sum + 1;
|
|
1137
|
+
}, 0);
|
|
1056
1138
|
const counts = {
|
|
1057
1139
|
debug_sessions: countReal(debugSessions.items),
|
|
1058
1140
|
quick_tasks: countReal(quickTasks.items),
|
|
@@ -1110,10 +1192,7 @@ function auditOpenArtifacts(cwd) {
|
|
|
1110
1192
|
function formatAuditReport(auditResult) {
|
|
1111
1193
|
const { counts, items, has_open_items, acknowledged } = auditResult;
|
|
1112
1194
|
const lines = [];
|
|
1113
|
-
|
|
1114
|
-
lines.push(hr);
|
|
1115
|
-
lines.push(' Milestone Close: Open Artifact Audit');
|
|
1116
|
-
lines.push(hr);
|
|
1195
|
+
lines.push('### Milestone Close: Open Artifact Audit');
|
|
1117
1196
|
// WARNING 3 (#3458 follow-up review): the acknowledged tally previously
|
|
1118
1197
|
// existed only in `--json` output — the human report could not tell
|
|
1119
1198
|
// "clean because fixed" apart from "clean because silenced", which is the
|
|
@@ -1121,13 +1200,13 @@ function formatAuditReport(auditResult) {
|
|
|
1121
1200
|
if (!has_open_items) {
|
|
1122
1201
|
lines.push('');
|
|
1123
1202
|
if (acknowledged.total > 0) {
|
|
1124
|
-
lines.push(`
|
|
1203
|
+
lines.push(`All artifact types clear (${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} still suppressed).`);
|
|
1125
1204
|
}
|
|
1126
1205
|
else {
|
|
1127
|
-
lines.push('
|
|
1206
|
+
lines.push('All artifact types clear. Safe to proceed.');
|
|
1128
1207
|
}
|
|
1129
1208
|
lines.push('');
|
|
1130
|
-
lines.push(
|
|
1209
|
+
lines.push('---');
|
|
1131
1210
|
return lines.join('\n');
|
|
1132
1211
|
}
|
|
1133
1212
|
// WARNING 3: per-category "N previously acknowledged" suffix, so the
|
|
@@ -1228,12 +1307,12 @@ function formatAuditReport(auditResult) {
|
|
|
1228
1307
|
}
|
|
1229
1308
|
}
|
|
1230
1309
|
lines.push('');
|
|
1231
|
-
lines.push(
|
|
1232
|
-
lines.push(
|
|
1310
|
+
lines.push('---');
|
|
1311
|
+
lines.push('');
|
|
1312
|
+
lines.push(`**${counts.total} item${counts.total !== 1 ? 's' : ''} require decisions before close.**`);
|
|
1233
1313
|
if (acknowledged.total > 0) {
|
|
1234
|
-
lines.push(
|
|
1314
|
+
lines.push(`${acknowledged.total} previously acknowledged item${acknowledged.total !== 1 ? 's' : ''} also suppressed above the ${counts.total} open item${counts.total !== 1 ? 's' : ''}.`);
|
|
1235
1315
|
}
|
|
1236
|
-
lines.push(hr);
|
|
1237
1316
|
return lines.join('\n');
|
|
1238
1317
|
}
|
|
1239
1318
|
// ─── resolvePhaseTargetDir ─────────────────────────────────────────────────────
|
|
@@ -1294,18 +1373,42 @@ function resolvePhaseTargetDir(planDir, cwd, phase, archivedMilestone) {
|
|
|
1294
1373
|
* any read or write is attempted.
|
|
1295
1374
|
*/
|
|
1296
1375
|
function cmdAuditAcknowledge(cwd, args, raw) {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1376
|
+
// args already has the family + subcommand tokens stripped by the caller
|
|
1377
|
+
// (audit-command-router.cts:147 passes `hubArgs.slice(2)`), so validation
|
|
1378
|
+
// begins at index 0 — there is no positional this handler owns itself.
|
|
1379
|
+
const { category, milestone, at: atFlag, phase, file, 'archived-milestone': archivedMilestone, slug, 'seed-id': seedId, dir: quickDir, filename, text, } = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, {
|
|
1380
|
+
valueFlags: [
|
|
1381
|
+
'category', 'milestone', 'at',
|
|
1382
|
+
'phase', 'file', 'archived-milestone',
|
|
1383
|
+
'slug', 'seed-id', 'dir', 'filename', 'text',
|
|
1384
|
+
],
|
|
1385
|
+
positionals: 0,
|
|
1386
|
+
}, ioError);
|
|
1302
1387
|
if (!category)
|
|
1303
1388
|
ioError('--category is required');
|
|
1304
1389
|
if (!milestone)
|
|
1305
1390
|
ioError('--milestone is required');
|
|
1391
|
+
// All declared flags above are value flags, so each resolves to `string |
|
|
1392
|
+
// null` at runtime; the cast narrows away the `boolean` arm of
|
|
1393
|
+
// ParsedNamedArgs's value type that this call site never produces.
|
|
1306
1394
|
const at = atFlag || new Date().toISOString().slice(0, 10);
|
|
1307
1395
|
const planDir = planningDir(cwd);
|
|
1308
1396
|
const markerBase = { milestone: milestone, at };
|
|
1397
|
+
// #3078-CR MEDIUM 2: every `fs.readFileSync` in this function (below, and
|
|
1398
|
+
// in the flat-category branch further down) is DELIBERATELY left raw,
|
|
1399
|
+
// unlike `auditOpenArtifacts`'s scan reads (which now route through
|
|
1400
|
+
// `normalizeLineEndings`). This function splices frontmatter into the
|
|
1401
|
+
// EXISTING content and writes the result back via `platformWriteSync` /
|
|
1402
|
+
// `uat.acknowledgeDeferredItem` — both `spliceFrontmatter` and
|
|
1403
|
+
// `acknowledgeDeferredItem` locate and rewrite a specific byte span
|
|
1404
|
+
// (frontmatter block / matched deferred-item text) in the file exactly as
|
|
1405
|
+
// it exists on disk. Normalizing first would rewrite the file's line
|
|
1406
|
+
// endings as a side effect of an unrelated acknowledge operation, and a
|
|
1407
|
+
// splice computed against normalized text can land at the wrong offset
|
|
1408
|
+
// when written back over the RAW (un-normalized) original. The snapshot
|
|
1409
|
+
// VALUE computed below IS normalized (on a separate in-memory copy, never
|
|
1410
|
+
// the spliced one) so it agrees with the scanner's frame — see the comment
|
|
1411
|
+
// at `normalizedContent` further down.
|
|
1309
1412
|
// ── The four phase-scoped categories: --phase --file [--archived-milestone] ──
|
|
1310
1413
|
const PHASE_SCOPED = new Set(['uat_gaps', 'verification_gaps', 'context_questions', 'deferred_items']);
|
|
1311
1414
|
if (PHASE_SCOPED.has(category)) {
|
|
@@ -1335,7 +1438,10 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1335
1438
|
if (result.status === 'already_resolved')
|
|
1336
1439
|
ioError(`deferred item is already "status: resolved" — acknowledging a resolved item is a no-op`);
|
|
1337
1440
|
if (result.status === 'unsupported_heading_shape') {
|
|
1338
|
-
|
|
1441
|
+
// #3781: heading-shaped entries are supported; the remaining refusal
|
|
1442
|
+
// cause is a GFM table row embedded in the entry's span (non-contiguous
|
|
1443
|
+
// — a write cannot be anchored safely).
|
|
1444
|
+
ioError('this deferred item\'s span embeds a GFM table row, so the CLI writer cannot anchor a safe write to it — edit the file directly');
|
|
1339
1445
|
}
|
|
1340
1446
|
if (result.status === 'match_verification_failed') {
|
|
1341
1447
|
ioError(`internal error: matched span for --text "${text}" did not re-verify before write — refused rather than risk writing the wrong entry`);
|
|
@@ -1346,6 +1452,15 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1346
1452
|
}
|
|
1347
1453
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
1348
1454
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
1455
|
+
// Mixed-frame fix (security review, 4th instance on this branch): the
|
|
1456
|
+
// splice above and below stays keyed to RAW `content` (raw byte offsets
|
|
1457
|
+
// must not shift), but `scanUatGaps`/`scanContextQuestions` now derive
|
|
1458
|
+
// their comparison values from `normalizeLineEndings`d content. Deriving
|
|
1459
|
+
// the snapshot here from raw `content` would make a lone-CR file's
|
|
1460
|
+
// stored value permanently disagree with what the scanner recomputes —
|
|
1461
|
+
// `audit acknowledge` would be a silent no-op for lone-CR artifacts. Feed
|
|
1462
|
+
// the derive functions a normalized COPY; never splice from it.
|
|
1463
|
+
const normalizedContent = normalizeLineEndings(content);
|
|
1349
1464
|
let snapshotKey;
|
|
1350
1465
|
let currentValue;
|
|
1351
1466
|
if (category === 'uat_gaps') {
|
|
@@ -1353,7 +1468,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1353
1468
|
// pending scenarios added under the same status — snapshot the
|
|
1354
1469
|
// composite `deriveUatGapSnapshotValue` instead (see its doc comment).
|
|
1355
1470
|
snapshotKey = 'gap_snapshot';
|
|
1356
|
-
currentValue = deriveUatGapSnapshotValue((fm.status || 'unknown').toLowerCase(),
|
|
1471
|
+
currentValue = deriveUatGapSnapshotValue((fm.status || 'unknown').toLowerCase(), normalizedContent);
|
|
1357
1472
|
}
|
|
1358
1473
|
else if (category === 'verification_gaps') {
|
|
1359
1474
|
snapshotKey = 'status';
|
|
@@ -1364,7 +1479,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1364
1479
|
// question set, not just its count (see `deriveOpenQuestionsDigest`'s
|
|
1365
1480
|
// doc comment).
|
|
1366
1481
|
snapshotKey = 'questions_digest';
|
|
1367
|
-
currentValue = deriveOpenQuestionsDigest(deriveOpenQuestions(
|
|
1482
|
+
currentValue = deriveOpenQuestionsDigest(deriveOpenQuestions(normalizedContent, fm));
|
|
1368
1483
|
}
|
|
1369
1484
|
fm.audit_acknowledged = { ...markerBase, [snapshotKey]: currentValue };
|
|
1370
1485
|
const newContent = spliceFrontmatter(content, fm);
|
|
@@ -1465,6 +1580,13 @@ module.exports = {
|
|
|
1465
1580
|
formatAuditReport,
|
|
1466
1581
|
listAuditPhaseTargets,
|
|
1467
1582
|
cmdAuditAcknowledge,
|
|
1583
|
+
// #3805: exported so uat.cts's cmdAuditUat routes the SAME artifacts'
|
|
1584
|
+
// suppression through the ONE predicate instead of hand-rolling a tenth
|
|
1585
|
+
// copy outside this file's visibility (the exact defect class the
|
|
1586
|
+
// predicate's own header warns about). The snapshot derivations ride
|
|
1587
|
+
// along so the snapshotKeys cannot drift between the two consumers.
|
|
1588
|
+
isAuditItemAcknowledged,
|
|
1589
|
+
deriveUatGapSnapshotValue,
|
|
1468
1590
|
// #2142: exported so src/milestone.cts's archiveQuickTaskDirectories README
|
|
1469
1591
|
// index generator shares this ONE discovery rule rather than re-deriving it.
|
|
1470
1592
|
resolveQuickTaskSummaryFile,
|