mandrel 1.94.0 → 2.1.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/.agents/README.md +116 -99
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +45 -51
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +498 -1287
- package/.agents/docs/agentrc-reference.json +185 -80
- package/.agents/docs/configuration.md +132 -190
- package/.agents/docs/execution-reference.md +51 -25
- package/.agents/docs/quality-gates.md +25 -33
- package/.agents/docs/workflows.md +8 -8
- package/.agents/instructions.md +113 -139
- package/.agents/rules/ci-remediation.md +11 -15
- package/.agents/rules/git-conventions-reference.md +48 -58
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +83 -254
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +22 -66
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +7 -10
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +328 -28
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
- package/.agents/scripts/lib/checks/index.js +3 -2
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +39 -9
- package/.agents/scripts/lib/close-validation/gates.js +15 -15
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +52 -35
- package/.agents/scripts/lib/config/explain.js +61 -48
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +29 -80
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +12 -15
- package/.agents/scripts/lib/config/runners.js +20 -66
- package/.agents/scripts/lib/config/temp-paths.js +30 -63
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
- package/.agents/scripts/lib/config-settings-schema.js +100 -60
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +242 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -190
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
- package/.agents/scripts/lib/git-utils.js +32 -20
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +10 -38
- package/.agents/scripts/lib/label-taxonomy.js +10 -55
- package/.agents/scripts/lib/observability/active-story-env.js +44 -165
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +5 -5
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
- package/.agents/scripts/lib/orchestration/code-review.js +78 -436
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
- package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -281
- package/.agents/scripts/lib/preflight-runner.js +4 -4
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +17 -19
- package/.agents/scripts/lib/story-body/story-body.js +130 -75
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
- package/.agents/scripts/lib/validation-evidence.js +32 -60
- package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +102 -80
- package/.agents/scripts/plan-persist.js +230 -279
- package/.agents/scripts/plan-run-epilogue.js +142 -0
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +13 -39
- package/.agents/scripts/providers/github/mappers.js +5 -12
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -156
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +25 -21
- package/.agents/scripts/single-story-close.js +178 -26
- package/.agents/scripts/single-story-confirm-merge.js +313 -24
- package/.agents/scripts/single-story-init.js +35 -30
- package/.agents/scripts/stories-wave-tick.js +85 -10
- package/.agents/scripts/story-plan.js +28 -49
- package/.agents/scripts/update-ticket-state.js +14 -65
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
- package/.agents/skills/core/scope-triage/SKILL.md +31 -172
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +3 -53
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +6 -7
- package/.agents/workflows/audit-clean-code.md +7 -7
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +9 -10
- package/.agents/workflows/audit-lighthouse.md +11 -3
- package/.agents/workflows/audit-navigability.md +13 -2
- package/.agents/workflows/audit-performance.md +5 -6
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +11 -12
- package/.agents/workflows/audit-security.md +4 -5
- package/.agents/workflows/audit-seo.md +13 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +10 -3
- package/.agents/workflows/deliver.md +177 -176
- package/.agents/workflows/git-cleanup.md +5 -6
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +75 -196
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
- package/.agents/workflows/helpers/deliver-story.md +606 -0
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +3 -3
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +277 -145
- package/.agents/workflows/qa-assist.md +27 -33
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -6
- package/README.md +9 -8
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +70 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +12 -8
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -66
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -464
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- package/.agents/workflows/helpers/single-story-deliver.md +0 -557
|
@@ -6,16 +6,19 @@
|
|
|
6
6
|
* without importing upward from a top-level CLI file.
|
|
7
7
|
*
|
|
8
8
|
* Pure (modulo `gitSpawn`) — exposed helpers are:
|
|
9
|
-
* - matchesFilePattern
|
|
10
|
-
* - matchesAnyFilePattern
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
9
|
+
* - matchesFilePattern — single file × single glob (picomatch, `dot`)
|
|
10
|
+
* - matchesAnyFilePattern — file list × pattern list, short-circuiting
|
|
11
|
+
* - selectSensitivePathClasses — change set × the manifest's `sensitivePaths`
|
|
12
|
+
* block; the review-depth derivation's matcher
|
|
13
|
+
* - selectAudits — main entry; reads audit-rules.json, runs `git
|
|
14
|
+
* diff --name-only`, applies keyword + glob
|
|
15
|
+
* rules.
|
|
13
16
|
*
|
|
14
17
|
* All rule-matching lives here; the former `select-audits.js` CLI wrapper
|
|
15
18
|
* was retired in #4482 (consumers call `selectAudits` via the barrel).
|
|
16
19
|
*/
|
|
17
20
|
|
|
18
|
-
import { readFileSync } from 'node:fs';
|
|
21
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
19
22
|
import fs from 'node:fs/promises';
|
|
20
23
|
import path from 'node:path';
|
|
21
24
|
import picomatch from 'picomatch';
|
|
@@ -109,10 +112,10 @@ export const LENS_TIERS = Object.freeze(['local', 'cumulative', 'global']);
|
|
|
109
112
|
* @throws {Error} When the manifest cannot be read or parsed.
|
|
110
113
|
*/
|
|
111
114
|
function readAuditRulesSync() {
|
|
112
|
-
const
|
|
115
|
+
const config = resolveConfig();
|
|
113
116
|
const rulesPath = path.join(
|
|
114
117
|
PROJECT_ROOT,
|
|
115
|
-
getPaths(
|
|
118
|
+
getPaths(config).schemasRoot,
|
|
116
119
|
'audit-rules.json',
|
|
117
120
|
);
|
|
118
121
|
try {
|
|
@@ -160,7 +163,7 @@ export function resolveLensTier(lens) {
|
|
|
160
163
|
* every path) matches every change set here, so its concern is verified at
|
|
161
164
|
* BOTH innermost tiers — the
|
|
162
165
|
* write-time checklist threading and this Story-scope lens pass — and excluded
|
|
163
|
-
* from Epic
|
|
166
|
+
* from the retired Epic-close roster (local lenses stay Story-scope only).
|
|
164
167
|
* A local lens with an empty `filePatterns` list matches nothing here, so a
|
|
165
168
|
* diff matching no local lens's patterns yields an empty roster and adds no
|
|
166
169
|
* lens work.
|
|
@@ -197,6 +200,50 @@ export function selectLocalLenses({
|
|
|
197
200
|
return selected;
|
|
198
201
|
}
|
|
199
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Select the sensitive-path classes a change set touches, from the
|
|
205
|
+
* `sensitivePaths` block of [`audit-rules.json`](../../../schemas/audit-rules.json).
|
|
206
|
+
*
|
|
207
|
+
* This is the matcher behind the close-time review-depth derivation
|
|
208
|
+
* (`review-depth.js#deriveChangeLevel`, Story #4542): a change set intersecting
|
|
209
|
+
* any registered class's globs is *observably* sensitive — auth, a migration, a
|
|
210
|
+
* billing path — and earns a deep pass however narrow the diff is. The classes
|
|
211
|
+
* and their globs live in the manifest next to the lens `triggers.filePatterns`
|
|
212
|
+
* precisely so an operator can extend them without a code change, and matching
|
|
213
|
+
* runs through the same {@link matchesAnyFilePattern} picomatch machinery rather
|
|
214
|
+
* than a second matcher with its own glob semantics.
|
|
215
|
+
*
|
|
216
|
+
* An empty change set, an absent `sensitivePaths` block, or a class whose globs
|
|
217
|
+
* match nothing all contribute no class — the caller then resolves depth from
|
|
218
|
+
* diff width alone.
|
|
219
|
+
*
|
|
220
|
+
* Pure over its injected seam: `injectedRules` skips the manifest disk read.
|
|
221
|
+
* Selection order follows the manifest's declaration order, which is
|
|
222
|
+
* deterministic.
|
|
223
|
+
*
|
|
224
|
+
* @param {{
|
|
225
|
+
* changedFiles?: string[],
|
|
226
|
+
* injectedRules?: { sensitivePaths?: Record<string, { filePatterns?: string[] }> },
|
|
227
|
+
* }} [params]
|
|
228
|
+
* @returns {string[]} The matched class names, in manifest order.
|
|
229
|
+
*/
|
|
230
|
+
export function selectSensitivePathClasses({
|
|
231
|
+
changedFiles,
|
|
232
|
+
injectedRules,
|
|
233
|
+
} = {}) {
|
|
234
|
+
const files = Array.isArray(changedFiles) ? changedFiles : [];
|
|
235
|
+
if (files.length === 0) return [];
|
|
236
|
+
|
|
237
|
+
const rules = injectedRules ?? readAuditRulesSync();
|
|
238
|
+
const matched = [];
|
|
239
|
+
for (const [name, entry] of Object.entries(rules.sensitivePaths ?? {})) {
|
|
240
|
+
if (matchesAnyFilePattern(entry?.filePatterns ?? [], files)) {
|
|
241
|
+
matched.push(name);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return matched;
|
|
245
|
+
}
|
|
246
|
+
|
|
200
247
|
/**
|
|
201
248
|
* Resolve the consumer's navigability route globs from the resolved config.
|
|
202
249
|
* Reads `delivery.quality.navigability.routeGlobs` — the route-tree SSOT the
|
|
@@ -221,9 +268,9 @@ export function resolveNavigabilityRouteGlobs(config) {
|
|
|
221
268
|
* `false` (the unconfigured no-op), so the existing change-set-scoped lens
|
|
222
269
|
* selection is unchanged.
|
|
223
270
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
271
|
+
* A pure predicate over a change set — the same input {@link selectAudits} and
|
|
272
|
+
* {@link selectLocalLenses} already match against. The caller unions its result
|
|
273
|
+
* into the lens roster it is assembling; no new routing machinery is added.
|
|
227
274
|
*
|
|
228
275
|
* @param {{ changedFiles?: string[], config?: object|null }} params
|
|
229
276
|
* @returns {boolean}
|
|
@@ -234,6 +281,206 @@ export function routesNavigabilityLens({ changedFiles, config } = {}) {
|
|
|
234
281
|
return matchesAnyFilePattern(globs, changedFiles ?? []);
|
|
235
282
|
}
|
|
236
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Package names (or scope/name segments of them) that declare a **web
|
|
286
|
+
* rendering surface**. Matched against the consumer's root `package.json`
|
|
287
|
+
* `dependencies` + `devDependencies` keys, segment-wise, so `@angular/core`
|
|
288
|
+
* matches via `angular` and `@remix-run/react` via `react`.
|
|
289
|
+
*/
|
|
290
|
+
const WEB_FRAMEWORK_PACKAGES = Object.freeze([
|
|
291
|
+
'react',
|
|
292
|
+
'next',
|
|
293
|
+
'vue',
|
|
294
|
+
'svelte',
|
|
295
|
+
'sveltekit',
|
|
296
|
+
'astro',
|
|
297
|
+
'nuxt',
|
|
298
|
+
'remix',
|
|
299
|
+
'remix-run',
|
|
300
|
+
'gatsby',
|
|
301
|
+
'angular',
|
|
302
|
+
]);
|
|
303
|
+
|
|
304
|
+
/** File extensions whose presence in the source tree implies a web surface. */
|
|
305
|
+
const WEB_ASSET_EXTENSIONS = Object.freeze(['.html', '.css', '.jsx', '.tsx']);
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Directories the web-surface file scan never descends into. `node_modules` is
|
|
309
|
+
* the load-bearing one (a dependency's bundled `.css` says nothing about the
|
|
310
|
+
* consumer's own surface); the test directories are excluded because a fixture
|
|
311
|
+
* `.html` is a test artifact, not a shipped page.
|
|
312
|
+
*/
|
|
313
|
+
const WEB_SCAN_SKIP_DIRS = Object.freeze([
|
|
314
|
+
'node_modules',
|
|
315
|
+
'.git',
|
|
316
|
+
'.worktrees',
|
|
317
|
+
'dist',
|
|
318
|
+
'build',
|
|
319
|
+
'out',
|
|
320
|
+
'coverage',
|
|
321
|
+
'temp',
|
|
322
|
+
'tmp',
|
|
323
|
+
'tests',
|
|
324
|
+
'test',
|
|
325
|
+
'__tests__',
|
|
326
|
+
'__mocks__',
|
|
327
|
+
'spec',
|
|
328
|
+
'e2e',
|
|
329
|
+
'fixtures',
|
|
330
|
+
]);
|
|
331
|
+
|
|
332
|
+
/** Scan bounds — the probe is a cheap heuristic, not an exhaustive crawl. */
|
|
333
|
+
const WEB_SCAN_MAX_DEPTH = 6;
|
|
334
|
+
const WEB_SCAN_MAX_ENTRIES = 4000;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Process-lifetime memo for the filesystem half of the web-surface probe,
|
|
338
|
+
* keyed by project root. The config half ({@link resolveNavigabilityRouteGlobs})
|
|
339
|
+
* is a free object read and is deliberately NOT memoized, so a caller passing a
|
|
340
|
+
* different config never reads a stale answer.
|
|
341
|
+
*
|
|
342
|
+
* @type {Map<string, boolean>}
|
|
343
|
+
*/
|
|
344
|
+
const _webSurfaceFsCache = new Map();
|
|
345
|
+
|
|
346
|
+
/** Test-only: drop the memo so a fixture root can be re-probed after edits. */
|
|
347
|
+
export function _resetWebSurfaceCache() {
|
|
348
|
+
_webSurfaceFsCache.clear();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* True when the root `package.json` declares a web-framework dependency.
|
|
353
|
+
* Returns `null` — *indeterminate* — when the manifest exists but cannot be
|
|
354
|
+
* read or parsed; the caller fails open on that (see {@link hasWebSurface}).
|
|
355
|
+
* A genuinely absent manifest (`ENOENT`) is determinate: there is no
|
|
356
|
+
* declaration, so there is no signal, and the file scan gets its turn.
|
|
357
|
+
*
|
|
358
|
+
* @param {string} root
|
|
359
|
+
* @returns {boolean|null}
|
|
360
|
+
*/
|
|
361
|
+
function declaresWebFramework(root) {
|
|
362
|
+
let raw;
|
|
363
|
+
try {
|
|
364
|
+
raw = readFileSync(path.join(root, 'package.json'), 'utf8');
|
|
365
|
+
} catch (err) {
|
|
366
|
+
if (err?.code === 'ENOENT') return false;
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
let pkg;
|
|
370
|
+
try {
|
|
371
|
+
pkg = JSON.parse(raw);
|
|
372
|
+
} catch {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
const names = [
|
|
376
|
+
...Object.keys(pkg?.dependencies ?? {}),
|
|
377
|
+
...Object.keys(pkg?.devDependencies ?? {}),
|
|
378
|
+
];
|
|
379
|
+
return names.some((name) =>
|
|
380
|
+
name
|
|
381
|
+
.replace(/^@/, '')
|
|
382
|
+
.split('/')
|
|
383
|
+
.some((segment) => WEB_FRAMEWORK_PACKAGES.includes(segment)),
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* True when a bounded scan of the source tree finds a web asset file
|
|
389
|
+
* (`.html` / `.css` / `.jsx` / `.tsx`) outside the skipped directories.
|
|
390
|
+
* Returns `null` — *indeterminate* — when the root itself is unreadable, or
|
|
391
|
+
* when the scan exhausted its entry budget without finding one: a truncated
|
|
392
|
+
* scan genuinely did not finish looking, and reporting "no web surface" from
|
|
393
|
+
* a half-walked tree would silently drop lens coverage.
|
|
394
|
+
*
|
|
395
|
+
* Uses `readdirSync(withFileTypes)` rather than `git ls-files` — a filesystem
|
|
396
|
+
* check suffices, and shelling out to git would make the probe cost a process
|
|
397
|
+
* spawn on every selection.
|
|
398
|
+
*
|
|
399
|
+
* @param {string} root
|
|
400
|
+
* @returns {boolean|null}
|
|
401
|
+
*/
|
|
402
|
+
function scanForWebAssets(root) {
|
|
403
|
+
let budget = WEB_SCAN_MAX_ENTRIES;
|
|
404
|
+
const queue = [{ dir: root, depth: 0 }];
|
|
405
|
+
let rootRead = false;
|
|
406
|
+
|
|
407
|
+
while (queue.length > 0) {
|
|
408
|
+
const { dir, depth } = queue.shift();
|
|
409
|
+
let entries;
|
|
410
|
+
try {
|
|
411
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
412
|
+
} catch {
|
|
413
|
+
// A single unreadable subdirectory is skipped: a permissions oddity is
|
|
414
|
+
// far likelier than an entire web surface hiding behind it. An
|
|
415
|
+
// unreadable ROOT is a different story — see below.
|
|
416
|
+
if (dir === root) return null;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (dir === root) rootRead = true;
|
|
420
|
+
|
|
421
|
+
for (const entry of entries) {
|
|
422
|
+
if (budget-- <= 0) return null; // truncated ⇒ indeterminate
|
|
423
|
+
if (entry.isDirectory()) {
|
|
424
|
+
if (WEB_SCAN_SKIP_DIRS.includes(entry.name)) continue;
|
|
425
|
+
if (depth + 1 <= WEB_SCAN_MAX_DEPTH) {
|
|
426
|
+
queue.push({ dir: path.join(dir, entry.name), depth: depth + 1 });
|
|
427
|
+
}
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (WEB_ASSET_EXTENSIONS.includes(path.extname(entry.name))) return true;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return rootRead ? false : null;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Decide whether the project has a **web surface** — the applicability
|
|
438
|
+
* predicate behind the `target: "web"` gate in `audit-rules.json` (#4579).
|
|
439
|
+
*
|
|
440
|
+
* Mandrel is materialized into other projects, so this cannot be a property of
|
|
441
|
+
* *this* repository: a consumer with a real web surface MUST still get the web
|
|
442
|
+
* lenses. It is therefore derived from observables in the consumer's own
|
|
443
|
+
* checkout, and deliberately NOT from a new `.agentrc` key — a new key would
|
|
444
|
+
* have to be threaded through the runtime AJV (`lib/config-settings-schema*.js`)
|
|
445
|
+
* *and* the published mirror, and would make consumers hand-configure something
|
|
446
|
+
* already derivable.
|
|
447
|
+
*
|
|
448
|
+
* A project is web-capable when ANY of these hold:
|
|
449
|
+
* 1. `delivery.quality.navigability.routeGlobs` is configured — the existing
|
|
450
|
+
* web signal the navigability lens already routes off.
|
|
451
|
+
* 2. The root `package.json` declares a web framework (react / next / vue /
|
|
452
|
+
* svelte / astro / nuxt / remix / gatsby / angular).
|
|
453
|
+
* 3. A bounded source scan finds a `.html` / `.css` / `.jsx` / `.tsx` file
|
|
454
|
+
* outside test directories.
|
|
455
|
+
*
|
|
456
|
+
* **Fail direction: OPEN.** When a signal is indeterminate — an unparseable
|
|
457
|
+
* `package.json`, an unreadable root, a scan that hit its entry budget — the
|
|
458
|
+
* project is treated as web-capable. A false positive costs one wasted lens
|
|
459
|
+
* run; a false negative silently drops audit coverage on a project that has a
|
|
460
|
+
* real web surface, and nothing downstream would ever report the omission.
|
|
461
|
+
* Wasted spend is recoverable; dropped coverage is not.
|
|
462
|
+
*
|
|
463
|
+
* @param {{ config?: object|null, projectRoot?: string }} [params]
|
|
464
|
+
* @returns {boolean}
|
|
465
|
+
*/
|
|
466
|
+
export function hasWebSurface({ config, projectRoot = PROJECT_ROOT } = {}) {
|
|
467
|
+
if (resolveNavigabilityRouteGlobs(config).length > 0) return true;
|
|
468
|
+
|
|
469
|
+
if (_webSurfaceFsCache.has(projectRoot)) {
|
|
470
|
+
return _webSurfaceFsCache.get(projectRoot);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const declared = declaresWebFramework(projectRoot);
|
|
474
|
+
// `null` is indeterminate, not false — fail open.
|
|
475
|
+
const result =
|
|
476
|
+
declared === null || declared === true
|
|
477
|
+
? true
|
|
478
|
+
: scanForWebAssets(projectRoot) !== false;
|
|
479
|
+
|
|
480
|
+
_webSurfaceFsCache.set(projectRoot, result);
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
|
|
237
484
|
/**
|
|
238
485
|
* Test a single filename against a single glob pattern using the project's
|
|
239
486
|
* configured matcher semantics (`picomatch` with `dot: true`). Exported so
|
|
@@ -261,6 +508,16 @@ export function matchesAnyFilePattern(patterns, files) {
|
|
|
261
508
|
* @param {number} params.ticketId
|
|
262
509
|
* @param {string} params.gate
|
|
263
510
|
* @param {import('../ITicketingProvider.js').ITicketingProvider} params.provider
|
|
511
|
+
* @param {string[]} [params.changedFiles]
|
|
512
|
+
* The change set to select over, when the caller already knows it. Supplying
|
|
513
|
+
* it skips the internal `git diff` entirely and `baseBranch` / `headRef` are
|
|
514
|
+
* then unused. Callers whose change set is NOT the working tree's
|
|
515
|
+
* `baseBranch...headRef` MUST pass this: the plan-run epilogue runs from the
|
|
516
|
+
* main checkout *after* its Stories have merged, where any `main...HEAD`
|
|
517
|
+
* range is empty by construction and selection would silently degrade to
|
|
518
|
+
* keyword-only matching (Story #4571). An empty array is honoured as
|
|
519
|
+
* "the set is known, and it is empty" — distinct from omitting the option,
|
|
520
|
+
* which means "derive it from git".
|
|
264
521
|
* @param {string} [params.baseBranch]
|
|
265
522
|
* @param {string} [params.headRef]
|
|
266
523
|
* Git ref whose diff-against-`baseBranch` defines the change set. Defaults
|
|
@@ -284,6 +541,9 @@ export function matchesAnyFilePattern(patterns, files) {
|
|
|
284
541
|
* Test-only seam to drive the `--gate-mode` / `MANDREL_GATE_MODE=1`
|
|
285
542
|
* detection; production callers leave unset and `isGateMode` reads
|
|
286
543
|
* `process.argv` / `process.env`.
|
|
544
|
+
* @param {typeof hasWebSurface} [params.hasWebSurfaceFn]
|
|
545
|
+
* Test-only seam overriding the web-surface probe behind the
|
|
546
|
+
* `target: "web"` applicability gate. Production callers leave unset.
|
|
287
547
|
*
|
|
288
548
|
* Returns either the success envelope (`{ selectedAudits, ticketId, gate, context }`)
|
|
289
549
|
* OR the degraded envelope (`{ ok: false, degraded: true, reason, detail }`)
|
|
@@ -294,18 +554,20 @@ export async function selectAudits({
|
|
|
294
554
|
ticketId,
|
|
295
555
|
gate,
|
|
296
556
|
provider,
|
|
557
|
+
changedFiles: injectedChangedFiles,
|
|
297
558
|
baseBranch = 'main',
|
|
298
559
|
headRef = 'HEAD',
|
|
299
560
|
injectedGitSpawn,
|
|
300
561
|
gitTimeoutMsOverride,
|
|
301
562
|
gateModeOpts,
|
|
563
|
+
hasWebSurfaceFn = hasWebSurface,
|
|
302
564
|
}) {
|
|
303
|
-
const
|
|
565
|
+
const config = resolveConfig();
|
|
304
566
|
const timeoutMs = gitTimeoutMsOverride ?? DEFAULT_GIT_TIMEOUT_MS;
|
|
305
567
|
|
|
306
568
|
const rulesPath = path.join(
|
|
307
569
|
PROJECT_ROOT,
|
|
308
|
-
getPaths(
|
|
570
|
+
getPaths(config).schemasRoot,
|
|
309
571
|
'audit-rules.json',
|
|
310
572
|
);
|
|
311
573
|
let rulesData;
|
|
@@ -323,6 +585,14 @@ export async function selectAudits({
|
|
|
323
585
|
|
|
324
586
|
const runGit = injectedGitSpawn ?? (async (...args) => gitSpawn(...args));
|
|
325
587
|
|
|
588
|
+
// A caller that already knows the change set supplies it, and no git ref is
|
|
589
|
+
// consulted at all — `baseBranch` / `headRef` describe a diff that is not
|
|
590
|
+
// being taken. The plan-run epilogue is the motivating caller (Story #4571):
|
|
591
|
+
// it resolves the run's landed diff from the Stories' squash-merges, and any
|
|
592
|
+
// `main...HEAD` range it could name from the main checkout post-land is
|
|
593
|
+
// empty by construction.
|
|
594
|
+
const hasInjectedChangedFiles = Array.isArray(injectedChangedFiles);
|
|
595
|
+
|
|
326
596
|
// Resolve `headRef` to a commit before diffing. A non-default `headRef`
|
|
327
597
|
// (Epic-mode callers pass `refs/heads/epic/<id>`) that the repo can't
|
|
328
598
|
// resolve means the requested Epic's branch is not present in this
|
|
@@ -331,7 +601,7 @@ export async function selectAudits({
|
|
|
331
601
|
// degraded signal instead of leaking the wrong scope. `HEAD` is always
|
|
332
602
|
// resolvable in a valid repo, so the default-path callers skip the probe
|
|
333
603
|
// cost on the common case.
|
|
334
|
-
if (headRef !== 'HEAD') {
|
|
604
|
+
if (!hasInjectedChangedFiles && headRef !== 'HEAD') {
|
|
335
605
|
let resolved;
|
|
336
606
|
try {
|
|
337
607
|
resolved = await withTimeout(
|
|
@@ -358,18 +628,22 @@ export async function selectAudits({
|
|
|
358
628
|
}
|
|
359
629
|
}
|
|
360
630
|
|
|
361
|
-
let changedFiles =
|
|
631
|
+
let changedFiles = hasInjectedChangedFiles
|
|
632
|
+
? injectedChangedFiles.map((f) => String(f).trim()).filter(Boolean)
|
|
633
|
+
: [];
|
|
362
634
|
try {
|
|
363
|
-
const diff =
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
635
|
+
const diff = hasInjectedChangedFiles
|
|
636
|
+
? null
|
|
637
|
+
: await withTimeout(
|
|
638
|
+
runGit(
|
|
639
|
+
process.cwd(),
|
|
640
|
+
'diff',
|
|
641
|
+
'--name-only',
|
|
642
|
+
`${baseBranch}...${headRef}`,
|
|
643
|
+
),
|
|
644
|
+
timeoutMs,
|
|
645
|
+
{ label: 'select-audits git diff' },
|
|
646
|
+
);
|
|
373
647
|
if (diff?.status === 0) {
|
|
374
648
|
changedFiles = diff.stdout
|
|
375
649
|
.split('\n')
|
|
@@ -393,16 +667,40 @@ export async function selectAudits({
|
|
|
393
667
|
|
|
394
668
|
const selectedAudits = [];
|
|
395
669
|
|
|
670
|
+
// Resolved at most once per call, and only if a `target: "web"` lens
|
|
671
|
+
// actually clears its gate — a Node-only project must not pay a filesystem
|
|
672
|
+
// scan on a roster with no web lens in it.
|
|
673
|
+
let webSurfaceMemo = null;
|
|
674
|
+
const projectIsWebCapable = () => {
|
|
675
|
+
if (webSurfaceMemo === null) {
|
|
676
|
+
webSurfaceMemo = hasWebSurfaceFn({ config });
|
|
677
|
+
}
|
|
678
|
+
return webSurfaceMemo;
|
|
679
|
+
};
|
|
680
|
+
|
|
396
681
|
for (const [auditName, ruleOpts] of Object.entries(rulesData.audits || {})) {
|
|
397
682
|
const triggers = ruleOpts.triggers || {};
|
|
398
683
|
|
|
399
684
|
const gateMatch = triggers.gates?.includes(gate);
|
|
400
685
|
if (!gateMatch) continue;
|
|
401
686
|
|
|
687
|
+
// Target-applicability gate (#4579). A lens declaring `target: "web"`
|
|
688
|
+
// has nothing to read on a project with no web surface, yet still
|
|
689
|
+
// whole-word-matches ordinary prose — `audit-seo` fires on the `meta`
|
|
690
|
+
// inside every Story body's `<!-- meta: {...} -->` machine comment. The
|
|
691
|
+
// roster's own instruction is that the host MUST walk every listed lens,
|
|
692
|
+
// so an inapplicable entry is not just wasted spend: it teaches operators
|
|
693
|
+
// to ignore the MUST. An absent `target` means "always applicable", so no
|
|
694
|
+
// existing lens changes behaviour.
|
|
695
|
+
if (ruleOpts.target === 'web' && !projectIsWebCapable()) continue;
|
|
696
|
+
|
|
402
697
|
const keywords = triggers.keywords || [];
|
|
403
698
|
let keywordMatch = false;
|
|
404
699
|
for (const kw of keywords) {
|
|
405
|
-
|
|
700
|
+
// Whole-word match: a bare substring test selects lenses on accidental
|
|
701
|
+
// fragments ("ui" inside "requires", "auth" inside "author" — #4579).
|
|
702
|
+
const escaped = kw.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
703
|
+
if (new RegExp(`\\b${escaped}\\b`).test(contentToSearch)) {
|
|
406
704
|
keywordMatch = true;
|
|
407
705
|
break;
|
|
408
706
|
}
|
|
@@ -430,8 +728,10 @@ export async function selectAudits({
|
|
|
430
728
|
changedFilesCount: changedFiles.length,
|
|
431
729
|
// The ref the change set was actually diffed against. Epic-mode callers
|
|
432
730
|
// assert this matches the requested Epic branch (Story #3362) so a
|
|
433
|
-
// mis-pinned diff never reaches the audit-lens selector silently.
|
|
434
|
-
|
|
731
|
+
// mis-pinned diff never reaches the audit-lens selector silently. `null`
|
|
732
|
+
// on the injected path: no ref was diffed, and naming one would invite
|
|
733
|
+
// exactly that assertion to pass against a diff nobody took.
|
|
734
|
+
resolvedRef: hasInjectedChangedFiles ? null : headRef,
|
|
435
735
|
ticketTitle: ticket.title,
|
|
436
736
|
},
|
|
437
737
|
};
|
package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js}
RENAMED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* lib/audit-to-stories/seed-
|
|
2
|
+
* lib/audit-to-stories/seed-from-findings.js
|
|
3
3
|
*
|
|
4
|
-
* Build the
|
|
5
|
-
*
|
|
4
|
+
* Build the `/plan --seed`-shaped one-pager markdown that the audit-to-
|
|
5
|
+
* stories Single-plan grouping path emits for `/plan` to consume.
|
|
6
6
|
*
|
|
7
|
-
* The seed renders the canonical one-pager sections so the
|
|
8
|
-
*
|
|
7
|
+
* The seed renders the canonical one-pager sections so the authoring
|
|
8
|
+
* pass can sharpen it without having to invent context:
|
|
9
9
|
* - Problem Statement (aggregated severity profile)
|
|
10
10
|
* - Recommended Direction (rollup of recommendations by dimension)
|
|
11
11
|
* - Key Assumptions (carries the source-report links forward)
|
|
12
12
|
* - MVP Scope (the proposed Stories, one bullet per group)
|
|
13
|
-
* - Key Files (explicit file paths so
|
|
14
|
-
*
|
|
13
|
+
* - Key Files (explicit file paths so `/plan` authoring has concrete
|
|
14
|
+
* anchors)
|
|
15
15
|
* - Not Doing (out-of-scope items by convention)
|
|
16
16
|
*
|
|
17
17
|
* Pure: returns a string. The caller decides where to persist it.
|
|
@@ -112,14 +112,14 @@ function formatKeyAssumptions(sourceReports) {
|
|
|
112
112
|
* @param {string[]} params.sourceReports — list of source report paths.
|
|
113
113
|
* @returns {string}
|
|
114
114
|
*/
|
|
115
|
-
export function
|
|
115
|
+
export function buildPlanSeedMarkdown({ groups, findings, sourceReports }) {
|
|
116
116
|
if (
|
|
117
117
|
!Array.isArray(groups) ||
|
|
118
118
|
!Array.isArray(findings) ||
|
|
119
119
|
!Array.isArray(sourceReports)
|
|
120
120
|
) {
|
|
121
121
|
throw new Error(
|
|
122
|
-
'
|
|
122
|
+
'buildPlanSeedMarkdown: groups, findings, sourceReports must all be arrays',
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
125
|
const problem = formatProblemStatement(findings);
|