mandrel 1.93.0 → 2.0.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 +59 -73
- package/.agents/agents/acceptance-critic.md +129 -0
- package/.agents/agents/story-worker.md +161 -0
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +108 -136
- package/.agents/docs/execution-reference.md +44 -22
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +107 -108
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +224 -0
- package/.agents/rules/git-conventions.md +42 -223
- package/.agents/rules/security-baseline.md +5 -0
- package/.agents/rules/testing-standards.md +106 -13
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +71 -201
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/acceptance-eval.js +62 -18
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-context-budget.js +62 -5
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/diagnose-friction.js +0 -6
- 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 +5 -5
- 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 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +160 -22
- package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +103 -0
- package/.agents/scripts/lib/config/explain.js +57 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +3 -8
- package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +39 -4
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +112 -3
- package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- 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/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- 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 +14 -14
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- 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/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/provider-factory.js +1 -1
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- 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 +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/post-structured-comment.js +38 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/sync-claude-agents.js +165 -0
- package/.agents/scripts/update-ticket-state.js +37 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
- package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +8 -418
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -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 +3 -3
- package/.agents/workflows/deliver.md +122 -131
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +3 -2
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +46 -0
- package/lib/cli/registry.js +95 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +5 -3
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer-mobile.md +0 -120
- package/.agents/personas/engineer-web.md +0 -111
- package/.agents/personas/engineer.md +0 -119
- package/.agents/personas/product.md +0 -94
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/refactorer.md +0 -113
- package/.agents/personas/security-engineer.md +0 -112
- package/.agents/personas/sre.md +0 -86
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/personas/ux-designer.md +0 -95
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- 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 -590
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-decompose.js +0 -54
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-plan-spec.js +0 -64
- 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/orchestration/context-hydration-engine.js +0 -660
- 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/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 -388
- 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/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/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-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
- 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 -278
- 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/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/post-merge-pipeline.js +0 -205
- 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-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
- 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 -301
- 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/plan-critics.js +0 -199
- package/.agents/scripts/retro-run.js +0 -218
- 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 -335
- package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
- package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
- package/.agents/skills/core/code-simplification/SKILL.md +0 -389
- package/.agents/skills/core/context-engineering/SKILL.md +0 -309
- package/.agents/skills/core/context-engineering/examples.md +0 -58
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
- 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 -413
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
- package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
- package/.agents/skills/core/idea-refinement/examples.md +0 -437
- package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
- package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
- package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
- package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
- package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
- package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
- package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
- package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
- package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
- package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
- package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
- package/.agents/workflows/helpers/deliver-epic.md +0 -955
- package/.agents/workflows/helpers/deliver-stories.md +0 -440
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
- 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 -351
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* phases/plan-epic.js — Tech Spec / Acceptance Table persistence phase.
|
|
3
|
-
*
|
|
4
|
-
* Story #4324: the `context::tech-spec` / `context::acceptance-spec` ticket
|
|
5
|
-
* classes are retired. The Epic body is the single planning document: this
|
|
6
|
-
* phase upserts the authored Tech Spec (opening with `## Delivery Slicing`)
|
|
7
|
-
* and the Acceptance Spec's AC-ID table (`## Acceptance Table`) as
|
|
8
|
-
* marker-delimited managed sections of the Epic body — see
|
|
9
|
-
* `lib/epic-body-sections.js`. Each write is **section-scoped**: only the
|
|
10
|
-
* managed region is replaced; the rest of the body is byte-preserved.
|
|
11
|
-
*
|
|
12
|
-
* Idempotent against partial state: when the Epic body already carries all
|
|
13
|
-
* requested sections, the phase short-circuits with `already-planned`.
|
|
14
|
-
* Pass `force: true` to re-plan: the managed sections are overwritten in
|
|
15
|
-
* place and a one-line regeneration audit comment lands on the Epic.
|
|
16
|
-
*
|
|
17
|
-
* The retired machine-managed `## Planning Artifacts` checklist (which
|
|
18
|
-
* linked the old context tickets) is stripped on every persist so a
|
|
19
|
-
* re-planned historical Epic stops advertising stale ticket links; the
|
|
20
|
-
* legacy tickets themselves are ignored (forward-only cutover — no
|
|
21
|
-
* backfill, no fetch).
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
hasEpicSection,
|
|
26
|
-
stripEpicSection,
|
|
27
|
-
stripPlanningArtifactsSection,
|
|
28
|
-
upsertEpicSection,
|
|
29
|
-
} from '../../../epic-body-sections.js';
|
|
30
|
-
import { Logger } from '../../../Logger.js';
|
|
31
|
-
import { ACCEPTANCE_NA } from '../../../label-constants.js';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Resolve whether Phase 7 should persist an acceptance-table section or
|
|
35
|
-
* apply the `acceptance::n-a` waiver, from the planningRisk envelope derived
|
|
36
|
-
* off the planner-authored risk verdict (`deriveRiskEnvelope`, Epic #3865).
|
|
37
|
-
*
|
|
38
|
-
* @param {import('../../planning-risk.js').PlanningRiskEnvelope|null} planningRisk
|
|
39
|
-
* Derived envelope; `null` (direct invocations without a verdict) never
|
|
40
|
-
* applies the waiver.
|
|
41
|
-
* @param {string|null} acceptanceSpecContent
|
|
42
|
-
* @returns {{ planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope|null, wantsAcceptanceSpec: boolean, applyAcceptanceWaiver: boolean }}
|
|
43
|
-
*/
|
|
44
|
-
export function resolveAcceptancePersistence(
|
|
45
|
-
planningRisk,
|
|
46
|
-
acceptanceSpecContent,
|
|
47
|
-
) {
|
|
48
|
-
const hasAcceptanceContent =
|
|
49
|
-
typeof acceptanceSpecContent === 'string' &&
|
|
50
|
-
acceptanceSpecContent.trim() !== '';
|
|
51
|
-
|
|
52
|
-
if (planningRisk?.acceptanceDisposition === 'not-applicable') {
|
|
53
|
-
return {
|
|
54
|
-
planningRisk,
|
|
55
|
-
wantsAcceptanceSpec: false,
|
|
56
|
-
applyAcceptanceWaiver: true,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
planningRisk: planningRisk ?? null,
|
|
62
|
-
wantsAcceptanceSpec: hasAcceptanceContent,
|
|
63
|
-
applyAcceptanceWaiver: false,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function validatePlanEpicInputs({
|
|
68
|
-
techSpecContent,
|
|
69
|
-
acceptanceSpecContent,
|
|
70
|
-
}) {
|
|
71
|
-
if (typeof techSpecContent !== 'string' || techSpecContent.trim() === '') {
|
|
72
|
-
throw new Error(
|
|
73
|
-
'[Epic Planner] techSpecContent is required and must be non-empty.',
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
if (
|
|
77
|
-
acceptanceSpecContent !== null &&
|
|
78
|
-
(typeof acceptanceSpecContent !== 'string' ||
|
|
79
|
-
acceptanceSpecContent.trim() === '')
|
|
80
|
-
) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
'[Epic Planner] acceptanceSpecContent, when provided, must be a non-empty string.',
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Snapshot which managed planning sections the Epic body already carries.
|
|
89
|
-
*
|
|
90
|
-
* @param {{ body?: string }} epic
|
|
91
|
-
* @returns {{ techSpec: boolean, acceptanceTable: boolean }}
|
|
92
|
-
*/
|
|
93
|
-
export function getExistingSections(epic) {
|
|
94
|
-
const body = epic?.body ?? '';
|
|
95
|
-
return {
|
|
96
|
-
techSpec: hasEpicSection(body, 'techSpec'),
|
|
97
|
-
acceptanceTable: hasEpicSection(body, 'acceptanceTable'),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function hasAllRequestedSections({ existing, wantsAcceptanceSpec }) {
|
|
102
|
-
return Boolean(
|
|
103
|
-
existing.techSpec &&
|
|
104
|
-
(wantsAcceptanceSpec ? existing.acceptanceTable : true),
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Persist the host-authored Tech Spec (and optional Acceptance Table) as
|
|
110
|
-
* managed sections of the Epic body.
|
|
111
|
-
*
|
|
112
|
-
* @returns {Promise<{
|
|
113
|
-
* persisted: boolean,
|
|
114
|
-
* reason: 'already-planned'|'persisted'|'force-replan',
|
|
115
|
-
* techSpecPersisted: boolean,
|
|
116
|
-
* acceptanceTable: 'persisted'|'waived'|'none',
|
|
117
|
-
* }>}
|
|
118
|
-
*/
|
|
119
|
-
export async function planEpic(
|
|
120
|
-
epicId,
|
|
121
|
-
provider,
|
|
122
|
-
{ techSpecContent, acceptanceSpecContent = null },
|
|
123
|
-
_settings = {},
|
|
124
|
-
{ force = false, planningRisk = null } = {},
|
|
125
|
-
) {
|
|
126
|
-
validatePlanEpicInputs({
|
|
127
|
-
techSpecContent,
|
|
128
|
-
acceptanceSpecContent,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
Logger.info(`[Epic Planner] Fetching Epic #${epicId}...`);
|
|
132
|
-
const epic = await provider.getEpic(epicId);
|
|
133
|
-
|
|
134
|
-
if (!epic) {
|
|
135
|
-
throw new Error(`Epic #${epicId} not found.`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const { wantsAcceptanceSpec, applyAcceptanceWaiver } =
|
|
139
|
-
resolveAcceptancePersistence(planningRisk, acceptanceSpecContent);
|
|
140
|
-
|
|
141
|
-
Logger.info(
|
|
142
|
-
`[Epic Planner] Acceptance disposition: ${planningRisk?.acceptanceDisposition ?? 'unspecified'}` +
|
|
143
|
-
(applyAcceptanceWaiver
|
|
144
|
-
? ` — applying ${ACCEPTANCE_NA} waiver (no acceptance-table section).`
|
|
145
|
-
: wantsAcceptanceSpec
|
|
146
|
-
? ' — persisting the ## Acceptance Table section.'
|
|
147
|
-
: ' — no acceptance-spec content supplied.'),
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const existing = getExistingSections(epic);
|
|
151
|
-
if (!force && hasAllRequestedSections({ existing, wantsAcceptanceSpec })) {
|
|
152
|
-
Logger.warn(
|
|
153
|
-
`[Epic Planner] Epic #${epicId} body already carries all requested planning sections. Aborting to prevent an unintended overwrite. Use --force to re-plan.`,
|
|
154
|
-
);
|
|
155
|
-
return {
|
|
156
|
-
persisted: false,
|
|
157
|
-
reason: 'already-planned',
|
|
158
|
-
techSpecPersisted: existing.techSpec,
|
|
159
|
-
acceptanceTable: existing.acceptanceTable ? 'persisted' : 'none',
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Section-scoped writes: each upsert replaces only its own managed
|
|
164
|
-
// region; the ideation sections and any operator-authored prose are
|
|
165
|
-
// byte-preserved. The retired `## Planning Artifacts` checklist is
|
|
166
|
-
// stripped so re-planned historical Epics stop advertising the old
|
|
167
|
-
// context-ticket links (the legacy tickets themselves are ignored).
|
|
168
|
-
let newBody = stripPlanningArtifactsSection(epic.body ?? '');
|
|
169
|
-
newBody = upsertEpicSection(newBody, 'techSpec', techSpecContent);
|
|
170
|
-
|
|
171
|
-
let acceptanceTable = 'none';
|
|
172
|
-
if (wantsAcceptanceSpec) {
|
|
173
|
-
newBody = upsertEpicSection(
|
|
174
|
-
newBody,
|
|
175
|
-
'acceptanceTable',
|
|
176
|
-
acceptanceSpecContent,
|
|
177
|
-
);
|
|
178
|
-
acceptanceTable = 'persisted';
|
|
179
|
-
} else if (applyAcceptanceWaiver) {
|
|
180
|
-
// Acceptance transition: was present, now waived (acceptance::n-a).
|
|
181
|
-
// Strip the stale table so the close-time reconciler cannot read a
|
|
182
|
-
// section the planner no longer stands behind.
|
|
183
|
-
if (existing.acceptanceTable) {
|
|
184
|
-
Logger.info(
|
|
185
|
-
`[Epic Planner] Acceptance disposition now waived — removing the stale ## Acceptance Table section from Epic #${epicId}.`,
|
|
186
|
-
);
|
|
187
|
-
newBody = stripEpicSection(newBody, 'acceptanceTable');
|
|
188
|
-
}
|
|
189
|
-
acceptanceTable = 'waived';
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** @type {{ add?: string[], remove?: string[] }} */
|
|
193
|
-
const labelMutations = {};
|
|
194
|
-
if (applyAcceptanceWaiver) {
|
|
195
|
-
labelMutations.add = [ACCEPTANCE_NA];
|
|
196
|
-
} else if (
|
|
197
|
-
wantsAcceptanceSpec &&
|
|
198
|
-
(epic.labels ?? []).includes(ACCEPTANCE_NA)
|
|
199
|
-
) {
|
|
200
|
-
labelMutations.remove = [ACCEPTANCE_NA];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
Logger.info(
|
|
204
|
-
`[Epic Planner] Updating Epic #${epicId} body with the planning sections...`,
|
|
205
|
-
);
|
|
206
|
-
await provider.updateTicket(epicId, {
|
|
207
|
-
body: newBody,
|
|
208
|
-
...(labelMutations.add || labelMutations.remove
|
|
209
|
-
? { labels: labelMutations }
|
|
210
|
-
: {}),
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
if (force) {
|
|
214
|
-
// Preserve the regeneration audit trail the retired per-ticket
|
|
215
|
-
// overwrite used to leave. Best-effort — never fail the persist on a
|
|
216
|
-
// comment post error.
|
|
217
|
-
try {
|
|
218
|
-
await provider.postComment(epicId, {
|
|
219
|
-
type: 'notification',
|
|
220
|
-
body: '♻️ **Regeneration Audit**: the Tech Spec / Acceptance Table sections of this Epic body were regenerated in place by a `/plan --force` re-plan. Content outside the managed sections was preserved.',
|
|
221
|
-
});
|
|
222
|
-
} catch (_err) {
|
|
223
|
-
// Swallow: audit comment is advisory.
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
Logger.info(`[Epic Planner] Epic #${epicId} updated successfully.`);
|
|
228
|
-
Logger.info(`[Epic Planner] Planning pipeline complete!`);
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
persisted: true,
|
|
232
|
-
reason: force ? 'force-replan' : 'persisted',
|
|
233
|
-
techSpecPersisted: true,
|
|
234
|
-
acceptanceTable,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* phases/run-spec-phase.js — orchestrator for Phase 7 (spec).
|
|
3
|
-
*
|
|
4
|
-
* Wires the planEpic persist phase, the Tech Spec freshness advisory, the
|
|
5
|
-
* `agent::review-spec` label flip, the planning-state checkpoint upsert, and
|
|
6
|
-
* the temp-file cleanup into a single sequential flow.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import path from 'node:path';
|
|
10
|
-
import { verifyBddRunnerPendingTag } from '../../../bdd-runner-detect.js';
|
|
11
|
-
import { Logger } from '../../../Logger.js';
|
|
12
|
-
import { AGENT_LABELS, TYPE_LABELS } from '../../../label-constants.js';
|
|
13
|
-
import { cleanupPhaseTempFiles } from '../../../plan-phase-cleanup.js';
|
|
14
|
-
import { PROJECT_ROOT } from '../../../project-root.js';
|
|
15
|
-
import { acquireEpicPlanLease } from '../../epic-plan-lease-guard.js';
|
|
16
|
-
import {
|
|
17
|
-
initialize as initializePlanState,
|
|
18
|
-
read as readPlanState,
|
|
19
|
-
write as writePlanState,
|
|
20
|
-
} from '../../epic-plan-state-store.js';
|
|
21
|
-
import { resolveReviewRouting } from '../../plan-review-routing.js';
|
|
22
|
-
import { deriveRiskEnvelope } from '../../planning-risk.js';
|
|
23
|
-
import {
|
|
24
|
-
formatMissingSectionMessage,
|
|
25
|
-
validateSpecSections,
|
|
26
|
-
} from '../../spec-section-validator.js';
|
|
27
|
-
import { upsertStructuredComment } from '../../ticketing.js';
|
|
28
|
-
import { planEpic } from './plan-epic.js';
|
|
29
|
-
import { runSpecFreshnessCheck } from './spec-freshness.js';
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Render the `risk-verdict` structured-comment body: a reviewer-readable
|
|
33
|
-
* axis table plus the canonical fenced-JSON record (verdict + derived
|
|
34
|
-
* envelope) downstream tooling parses.
|
|
35
|
-
*
|
|
36
|
-
* @param {{ epicId: number, riskVerdict: import('../../planning-risk.js').RiskVerdict, planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope }} input
|
|
37
|
-
* @returns {string}
|
|
38
|
-
*/
|
|
39
|
-
function buildRiskVerdictCommentBody({ epicId, riskVerdict, planningRisk }) {
|
|
40
|
-
const axisRows = planningRisk.axes.map(
|
|
41
|
-
(entry) => `| ${entry.axis} | ${entry.level} | ${entry.rationale} |`,
|
|
42
|
-
);
|
|
43
|
-
const axisTable =
|
|
44
|
-
axisRows.length > 0
|
|
45
|
-
? ['| Axis | Level | Rationale |', '| --- | --- | --- |', ...axisRows]
|
|
46
|
-
: ['_No risk axes apply (planner-asserted)._'];
|
|
47
|
-
const record = {
|
|
48
|
-
kind: 'risk-verdict',
|
|
49
|
-
epicId,
|
|
50
|
-
verdict: riskVerdict,
|
|
51
|
-
planningRisk,
|
|
52
|
-
};
|
|
53
|
-
// Story #4145 — when the disposition was forced to not-applicable because
|
|
54
|
-
// no BDD runner exists, make the waiver operator-visible in the rendered
|
|
55
|
-
// comment (not just the fenced JSON record) so a reviewer sees why an
|
|
56
|
-
// otherwise-required AC table was waived.
|
|
57
|
-
const waiverNote = planningRisk.acceptanceWaivedReason
|
|
58
|
-
? ['', `> ⚠️ **Acceptance waived** — ${planningRisk.acceptanceWaivedReason}`]
|
|
59
|
-
: [];
|
|
60
|
-
return [
|
|
61
|
-
`### 🧭 Planning Risk Verdict — ${planningRisk.overallLevel} · ${planningRisk.gateDecision}`,
|
|
62
|
-
'',
|
|
63
|
-
riskVerdict.summary,
|
|
64
|
-
'',
|
|
65
|
-
...axisTable,
|
|
66
|
-
...waiverNote,
|
|
67
|
-
'',
|
|
68
|
-
'```json',
|
|
69
|
-
JSON.stringify(record, null, 2),
|
|
70
|
-
'```',
|
|
71
|
-
].join('\n');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async function setEpicLabel(provider, epicId, targetLabel) {
|
|
75
|
-
const planningLabels = [AGENT_LABELS.REVIEW_SPEC, AGENT_LABELS.READY];
|
|
76
|
-
await provider.updateTicket(epicId, {
|
|
77
|
-
labels: {
|
|
78
|
-
add: [targetLabel],
|
|
79
|
-
remove: planningLabels.filter((l) => l !== targetLabel),
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Execute the spec phase end to end.
|
|
86
|
-
*
|
|
87
|
-
* @param {number} epicId
|
|
88
|
-
* @param {import('../../../ITicketingProvider.js').ITicketingProvider} provider
|
|
89
|
-
* @param {{ techSpecContent: string, acceptanceSpecContent?: string|null }} artifacts
|
|
90
|
-
* @param {object} settings
|
|
91
|
-
* @param {{ force?: boolean, forceReview?: boolean, steal?: boolean, config?: object, riskVerdict?: import('../../planning-risk.js').RiskVerdict }} [opts]
|
|
92
|
-
* @returns {Promise<{ epicId: number, techSpecPersisted: boolean, acceptanceTable: 'persisted'|'waived'|'none', checkpoint: object, planningRisk: import('../../planning-risk.js').PlanningRiskEnvelope, reviewRouting: import('../../plan-review-routing.js').ReviewRoutingEnvelope }>}
|
|
93
|
-
*/
|
|
94
|
-
export async function runSpecPhase(
|
|
95
|
-
epicId,
|
|
96
|
-
provider,
|
|
97
|
-
{ techSpecContent, acceptanceSpecContent = null },
|
|
98
|
-
settings = {},
|
|
99
|
-
{
|
|
100
|
-
force = false,
|
|
101
|
-
forceReview = false,
|
|
102
|
-
steal = false,
|
|
103
|
-
config,
|
|
104
|
-
riskVerdict,
|
|
105
|
-
} = {},
|
|
106
|
-
) {
|
|
107
|
-
// Hard cutover (Epic #3865): the planner-authored risk verdict is the
|
|
108
|
-
// sole risk source. Derive the envelope up front so a missing verdict
|
|
109
|
-
// fails closed before any GitHub mutation.
|
|
110
|
-
if (!riskVerdict || !Array.isArray(riskVerdict.axes)) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
'[epic-plan-spec] risk verdict is required — author risk-verdict.json via the epic-plan-spec-author Skill and pass it with --risk-verdict.',
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Story #4403 (Finding 3): the "## Delivery Slicing" presence gate — the
|
|
117
|
-
// Phase 8-side anchor the Holistic Consolidation pass reconciles against —
|
|
118
|
-
// is validated here, against the in-memory authored content, before any
|
|
119
|
-
// GitHub mutation (lease acquisition, Epic body write, structured
|
|
120
|
-
// comments). This replaces the retired standalone `epic-plan-spec-validate.js`
|
|
121
|
-
// CLI / Phase 7.5 workflow step, whose documented ordering ran the check
|
|
122
|
-
// AFTER the persist path had already written to GitHub and deleted the
|
|
123
|
-
// temp file it read — so the "blocking gate" could never actually block.
|
|
124
|
-
const sectionCheck = validateSpecSections({ body: techSpecContent });
|
|
125
|
-
if (!sectionCheck.ok) {
|
|
126
|
-
throw new Error(
|
|
127
|
-
formatMissingSectionMessage({
|
|
128
|
-
techspecPath: `Epic #${epicId} authored Tech Spec`,
|
|
129
|
-
missing: sectionCheck.missing,
|
|
130
|
-
}),
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Story #4145 — probe the project's BDD runner. When none is detected
|
|
135
|
-
// (`fallback === true`, e.g. a node:test repo with no tests/features/**),
|
|
136
|
-
// the acceptance disposition is forced to not-applicable inside
|
|
137
|
-
// deriveRiskEnvelope: an authored AC table could never be reconciled by
|
|
138
|
-
// `@epic-<id>-ac-*` feature tags, so /deliver finalize would otherwise
|
|
139
|
-
// abort and require a manual `acceptance::n-a`. The probe is static and
|
|
140
|
-
// best-effort — a detection failure degrades to "runner present" (no
|
|
141
|
-
// forced waiver), preserving the BDD-repo path, and never blocks Phase 7.
|
|
142
|
-
let bddRunner = null;
|
|
143
|
-
try {
|
|
144
|
-
bddRunner = await verifyBddRunnerPendingTag({ cwd: PROJECT_ROOT });
|
|
145
|
-
} catch (err) {
|
|
146
|
-
Logger.warn(
|
|
147
|
-
`[epic-plan-spec] BDD runner probe skipped (${err.message}); acceptance disposition derived from risk axes only.`,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
const planningRisk = deriveRiskEnvelope(riskVerdict, { bddRunner });
|
|
151
|
-
if (planningRisk.acceptanceWaivedReason) {
|
|
152
|
-
Logger.info(
|
|
153
|
-
`[epic-plan-spec] Acceptance disposition forced to not-applicable for Epic #${epicId}: ${planningRisk.acceptanceWaivedReason}`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const epic = await provider.getEpic(epicId);
|
|
158
|
-
if (!epic) {
|
|
159
|
-
throw new Error(`[epic-plan-spec] Epic #${epicId} not found.`);
|
|
160
|
-
}
|
|
161
|
-
if (!epic.labels?.includes(TYPE_LABELS.EPIC)) {
|
|
162
|
-
throw new Error(
|
|
163
|
-
`[epic-plan-spec] Ticket #${epicId} is not a ${TYPE_LABELS.EPIC}.`,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Workflow-guards (Story #3481): acquire the Epic-lease before any Phase 7
|
|
168
|
-
// mutation so two concurrent /plan runs cannot both drive this Epic. The
|
|
169
|
-
// guard fails closed (audit #3513) — any foreign assignee refuses here and
|
|
170
|
-
// the CLI exits non-zero naming the owner, unless `--steal` transfers it.
|
|
171
|
-
await acquireEpicPlanLease({ provider, epicId, config, steal });
|
|
172
|
-
|
|
173
|
-
await initializePlanState({ provider, epicId });
|
|
174
|
-
|
|
175
|
-
const planResult = await planEpic(
|
|
176
|
-
epicId,
|
|
177
|
-
provider,
|
|
178
|
-
{ techSpecContent, acceptanceSpecContent },
|
|
179
|
-
settings,
|
|
180
|
-
{
|
|
181
|
-
force,
|
|
182
|
-
planningRisk,
|
|
183
|
-
},
|
|
184
|
-
);
|
|
185
|
-
const specChanged = planResult?.persisted !== false;
|
|
186
|
-
|
|
187
|
-
const afterPlan = await provider.getEpic(epicId);
|
|
188
|
-
|
|
189
|
-
// Story #2635 — cross-validate the authored Tech Spec body against the
|
|
190
|
-
// base branch and surface any stale path-shaped references. Story #4324:
|
|
191
|
-
// with the Tech Spec folded into the Epic body, the advisory comment
|
|
192
|
-
// lands on the Epic itself. Non-blocking: a missing base ref, an
|
|
193
|
-
// unreadable temp directory, or a provider failure downgrades to a
|
|
194
|
-
// warning so Phase 7 never fails on the advisory check.
|
|
195
|
-
const baseBranchRef = settings?.baseBranch ?? 'main';
|
|
196
|
-
const tempRoot = path.resolve(
|
|
197
|
-
PROJECT_ROOT,
|
|
198
|
-
settings?.paths?.tempRoot ?? 'temp',
|
|
199
|
-
);
|
|
200
|
-
const freshness = await runSpecFreshnessCheck({
|
|
201
|
-
epicId,
|
|
202
|
-
techSpecContent,
|
|
203
|
-
baseBranchRef,
|
|
204
|
-
tempRoot,
|
|
205
|
-
provider,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Story #1585 (Epic #1471): the baseline-snapshot fork was previously
|
|
209
|
-
// performed here at plan-time. It now runs at first-story-init time
|
|
210
|
-
// inside `lib/story-init/branch-initializer.js#bootstrapWorktree` so
|
|
211
|
-
// `/plan` remains git-state-free. `forkAndCommitEpicSnapshot` and
|
|
212
|
-
// `forkMainToEpic` remain exported for that caller.
|
|
213
|
-
|
|
214
|
-
const reviewRouting = resolveReviewRouting({ planningRisk, forceReview });
|
|
215
|
-
|
|
216
|
-
// Record the planner-authored verdict as a structured artifact — the
|
|
217
|
-
// audit trail the retired regex classifier never produced (Epic #3865).
|
|
218
|
-
await upsertStructuredComment(
|
|
219
|
-
provider,
|
|
220
|
-
epicId,
|
|
221
|
-
'risk-verdict',
|
|
222
|
-
buildRiskVerdictCommentBody({ epicId, riskVerdict, planningRisk }),
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
const currentState =
|
|
226
|
-
(await readPlanState({ provider, epicId })) ??
|
|
227
|
-
(await initializePlanState({ provider, epicId }));
|
|
228
|
-
const checkpoint = await writePlanState({
|
|
229
|
-
provider,
|
|
230
|
-
epicId,
|
|
231
|
-
state: {
|
|
232
|
-
...currentState,
|
|
233
|
-
planningRisk,
|
|
234
|
-
riskVerdict,
|
|
235
|
-
reviewRouting: {
|
|
236
|
-
decision: reviewRouting.decision,
|
|
237
|
-
requiresStop: reviewRouting.requiresStop,
|
|
238
|
-
forceReviewApplied: reviewRouting.forceReviewApplied,
|
|
239
|
-
},
|
|
240
|
-
spec: {
|
|
241
|
-
...currentState.spec,
|
|
242
|
-
techSpecPersisted: planResult?.techSpecPersisted === true,
|
|
243
|
-
acceptanceTable: planResult?.acceptanceTable ?? 'none',
|
|
244
|
-
completedAt: new Date().toISOString(),
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
Logger.info(`[epic-plan-spec] Review routing: ${reviewRouting.decision}.`);
|
|
250
|
-
Logger.info(`[epic-plan-spec] ${reviewRouting.operatorMessage}`);
|
|
251
|
-
|
|
252
|
-
// Story #4019 (refining #3905): a spec-phase rerun that changed nothing
|
|
253
|
-
// (planEpic short-circuited on `already-planned`) MUST NOT demote a
|
|
254
|
-
// fully-decomposed `agent::ready` Epic back to `agent::review-spec` —
|
|
255
|
-
// there is no new spec content to review. The demotion fires only when
|
|
256
|
-
// the spec actually persisted/changed, or when the Epic is not at
|
|
257
|
-
// `agent::ready` (where the flip is the normal forward transition).
|
|
258
|
-
const epicLabels = afterPlan.labels ?? [];
|
|
259
|
-
const skipDemotion = !specChanged && epicLabels.includes(AGENT_LABELS.READY);
|
|
260
|
-
let labelTransition;
|
|
261
|
-
if (skipDemotion) {
|
|
262
|
-
labelTransition = 'kept-ready';
|
|
263
|
-
Logger.info(
|
|
264
|
-
`[epic-plan-spec] Spec unchanged (${planResult?.reason ?? 'already-planned'}) and Epic #${epicId} is ${AGENT_LABELS.READY} — keeping ${AGENT_LABELS.READY} (no demotion to ${AGENT_LABELS.REVIEW_SPEC}).`,
|
|
265
|
-
);
|
|
266
|
-
} else {
|
|
267
|
-
labelTransition = 'review-spec';
|
|
268
|
-
Logger.info(
|
|
269
|
-
`[epic-plan-spec] Flipping Epic #${epicId} to ${AGENT_LABELS.REVIEW_SPEC}...`,
|
|
270
|
-
);
|
|
271
|
-
await setEpicLabel(provider, epicId, AGENT_LABELS.REVIEW_SPEC);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const cleanup = await cleanupPhaseTempFiles({ phase: 'spec', epicId });
|
|
275
|
-
|
|
276
|
-
const acceptanceSummary =
|
|
277
|
-
planResult?.acceptanceTable === 'persisted'
|
|
278
|
-
? ' + ## Acceptance Table section'
|
|
279
|
-
: planResult?.acceptanceTable === 'waived'
|
|
280
|
-
? ' (acceptance waived)'
|
|
281
|
-
: '';
|
|
282
|
-
const freshnessSummary =
|
|
283
|
-
freshness.stale > 0 || freshness.ambiguous > 0
|
|
284
|
-
? ` ⚠️ Spec freshness: ${freshness.stale} stale / ${freshness.ambiguous} ambiguous reference(s) — see ${freshness.reportPath ?? 'report'}.`
|
|
285
|
-
: '';
|
|
286
|
-
Logger.info(
|
|
287
|
-
`[epic-plan-spec] ✅ Spec phase complete for Epic #${epicId}. Tech Spec sections folded into the Epic body${acceptanceSummary}.${freshnessSummary}`,
|
|
288
|
-
);
|
|
289
|
-
if (cleanup.deleted.length > 0) {
|
|
290
|
-
Logger.info(
|
|
291
|
-
`[epic-plan-spec] 🧹 Cleaned up ${cleanup.deleted.length} temp file(s).`,
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return {
|
|
296
|
-
epicId,
|
|
297
|
-
techSpecPersisted: planResult?.techSpecPersisted === true,
|
|
298
|
-
acceptanceTable: planResult?.acceptanceTable ?? 'none',
|
|
299
|
-
checkpoint,
|
|
300
|
-
cleanup,
|
|
301
|
-
freshness,
|
|
302
|
-
planningRisk,
|
|
303
|
-
reviewRouting,
|
|
304
|
-
specChanged,
|
|
305
|
-
labelTransition,
|
|
306
|
-
};
|
|
307
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* phases/spec-freshness.js — Tech Spec freshness check phase.
|
|
3
|
-
*
|
|
4
|
-
* Cross-validates the authored Tech Spec body against the base branch and
|
|
5
|
-
* surfaces any stale path-shaped references on the Epic (Story #4324: the
|
|
6
|
-
* Tech Spec is folded into the Epic body, so the Epic is the comment
|
|
7
|
-
* target). Two side effects, both best-effort and non-blocking:
|
|
8
|
-
*
|
|
9
|
-
* 1. Write the full `{ stale, fresh, ambiguous }` report to
|
|
10
|
-
* `<tempRoot>/epic-<id>-spec-freshness.json` so downstream tooling
|
|
11
|
-
* (the `--code-freshness` health check on the roadmap, or an
|
|
12
|
-
* operator inspecting the run) can read it without re-probing git.
|
|
13
|
-
* 2. When `stale.length > 0`, upsert a `spec-freshness` structured
|
|
14
|
-
* comment on the Epic listing each suspect citation.
|
|
15
|
-
* The comment is upserted, so re-running spec re-renders the same
|
|
16
|
-
* comment in place rather than spamming the issue.
|
|
17
|
-
*
|
|
18
|
-
* Caller signals are aggressive in containment — any error in this path
|
|
19
|
-
* is downgraded to a warning. Phase 7 must not fail because a doc-author
|
|
20
|
-
* cited a path the validator can't probe (e.g. shallow clone, base ref
|
|
21
|
-
* not fetched). The non-blocking contract is the load-bearing AC.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import { mkdir, writeFile } from 'node:fs/promises';
|
|
25
|
-
import path from 'node:path';
|
|
26
|
-
import { Logger } from '../../../Logger.js';
|
|
27
|
-
import {
|
|
28
|
-
renderSpecFreshnessComment,
|
|
29
|
-
validateSpecFreshness,
|
|
30
|
-
} from '../../spec-freshness.js';
|
|
31
|
-
import { upsertStructuredComment } from '../../ticketing.js';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @param {object} opts
|
|
35
|
-
* @param {number} opts.epicId
|
|
36
|
-
* @param {string} opts.techSpecContent
|
|
37
|
-
* @param {string} opts.baseBranchRef
|
|
38
|
-
* @param {string} opts.tempRoot
|
|
39
|
-
* @param {import('../../../ITicketingProvider.js').ITicketingProvider} opts.provider
|
|
40
|
-
* @param {Function} [opts.validator] - Testing seam (defaults to validateSpecFreshness).
|
|
41
|
-
* @param {Function} [opts.commentUpserter] - Testing seam (defaults to upsertStructuredComment).
|
|
42
|
-
* @param {Function} [opts.fileWriter] - Testing seam (defaults to fs writeFile/mkdir wrapper).
|
|
43
|
-
* @returns {Promise<{ stale: number, ambiguous: number, fresh: number, reportPath: string|null, commentPosted: boolean }>}
|
|
44
|
-
*/
|
|
45
|
-
export async function runSpecFreshnessCheck({
|
|
46
|
-
epicId,
|
|
47
|
-
techSpecContent,
|
|
48
|
-
baseBranchRef,
|
|
49
|
-
tempRoot,
|
|
50
|
-
provider,
|
|
51
|
-
validator = validateSpecFreshness,
|
|
52
|
-
commentUpserter = upsertStructuredComment,
|
|
53
|
-
fileWriter = async (filePath, body) => {
|
|
54
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
55
|
-
await writeFile(filePath, body, 'utf8');
|
|
56
|
-
},
|
|
57
|
-
}) {
|
|
58
|
-
try {
|
|
59
|
-
const report = validator(techSpecContent, { baseBranchRef });
|
|
60
|
-
const reportPath = path.join(
|
|
61
|
-
tempRoot,
|
|
62
|
-
`epic-${epicId}-spec-freshness.json`,
|
|
63
|
-
);
|
|
64
|
-
const payload = {
|
|
65
|
-
epicId,
|
|
66
|
-
baseBranchRef,
|
|
67
|
-
generatedAt: new Date().toISOString(),
|
|
68
|
-
summary: {
|
|
69
|
-
stale: report.stale.length,
|
|
70
|
-
ambiguous: report.ambiguous.length,
|
|
71
|
-
fresh: report.fresh.length,
|
|
72
|
-
},
|
|
73
|
-
...report,
|
|
74
|
-
};
|
|
75
|
-
await fileWriter(reportPath, `${JSON.stringify(payload, null, 2)}\n`);
|
|
76
|
-
|
|
77
|
-
let commentPosted = false;
|
|
78
|
-
if (report.stale.length > 0 && Number.isFinite(epicId)) {
|
|
79
|
-
const body = renderSpecFreshnessComment(report, {
|
|
80
|
-
baseBranchRef,
|
|
81
|
-
epicId,
|
|
82
|
-
});
|
|
83
|
-
await commentUpserter(provider, epicId, 'spec-freshness', body);
|
|
84
|
-
commentPosted = true;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (report.stale.length > 0 || report.ambiguous.length > 0) {
|
|
88
|
-
Logger.warn(
|
|
89
|
-
`[epic-plan-spec] Tech Spec freshness: ${report.stale.length} stale, ${report.ambiguous.length} ambiguous, ${report.fresh.length} fresh against ${baseBranchRef}. Report: ${reportPath}.`,
|
|
90
|
-
);
|
|
91
|
-
} else {
|
|
92
|
-
Logger.info(
|
|
93
|
-
`[epic-plan-spec] Tech Spec freshness: ${report.fresh.length} fresh references against ${baseBranchRef}. No drift detected.`,
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
stale: report.stale.length,
|
|
99
|
-
ambiguous: report.ambiguous.length,
|
|
100
|
-
fresh: report.fresh.length,
|
|
101
|
-
reportPath,
|
|
102
|
-
commentPosted,
|
|
103
|
-
};
|
|
104
|
-
} catch (err) {
|
|
105
|
-
Logger.warn(
|
|
106
|
-
`[epic-plan-spec] Tech Spec freshness check skipped: ${err.message}`,
|
|
107
|
-
);
|
|
108
|
-
return {
|
|
109
|
-
stale: 0,
|
|
110
|
-
ambiguous: 0,
|
|
111
|
-
fresh: 0,
|
|
112
|
-
reportPath: null,
|
|
113
|
-
commentPosted: false,
|
|
114
|
-
error: err.message,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
}
|