mandrel 1.94.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/story-worker.md +12 -13
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +104 -138
- package/.agents/docs/execution-reference.md +17 -20
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +70 -81
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +6 -7
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +54 -214
- 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/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-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/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/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 +2 -2
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +45 -29
- package/.agents/scripts/lib/config/explain.js +55 -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 +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
- package/.agents/scripts/lib/config-settings-schema-quality.js +8 -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 +2 -2
- 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 +1 -1
- package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
- 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-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 +13 -13
- 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/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 +2 -7
- 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/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/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/update-ticket-state.js +6 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +3 -43
- 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 -174
- 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 +16 -29
- 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/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 +2 -1
- 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 +30 -0
- package/lib/migrations/index.js +6 -5
- 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-spec.schema.json +0 -153
- 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/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- 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/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/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/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-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- 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/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/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/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/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run-epilogue.js — real per-run closeout for `/deliver --run`.
|
|
3
|
+
*
|
|
4
|
+
* After the last Story in a multi-Story plan-run lands, this module:
|
|
5
|
+
* 1. Selects the cross-Story audit lens roster over the combined landed
|
|
6
|
+
* tip vs base (deterministic `selectAudits` — host walks lenses).
|
|
7
|
+
* 2. Rolls up friction follow-ups across every Story in the run and
|
|
8
|
+
* files/posts them on the primary Story.
|
|
9
|
+
* 3. Checks sibling Spec/acceptance coherence across Story bodies.
|
|
10
|
+
*
|
|
11
|
+
* There is no inert planner-only path: `planRunEpilogue` enumerates steps
|
|
12
|
+
* and `runPlanRunEpilogue` executes them. Single-Story runs skip the
|
|
13
|
+
* epilogue (`applicable: false`).
|
|
14
|
+
*
|
|
15
|
+
* @module lib/orchestration/run-epilogue
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { selectAudits } from '../audit-suite/index.js';
|
|
19
|
+
import { graduateRetroProposals } from '../feedback-loop/retro-proposals-graduator.js';
|
|
20
|
+
import { gitSpawn } from '../git-utils.js';
|
|
21
|
+
import { Logger } from '../Logger.js';
|
|
22
|
+
import { forEachLine } from '../observability/signals-writer.js';
|
|
23
|
+
import { composeRoutedProposals } from './retro-proposals.js';
|
|
24
|
+
import {
|
|
25
|
+
buildFollowUpsCommentBody,
|
|
26
|
+
resolveFollowUpRepos,
|
|
27
|
+
} from './story-follow-ups.js';
|
|
28
|
+
import { upsertStructuredComment } from './ticketing.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Canonical epilogue step kinds, in execution order.
|
|
32
|
+
* @type {readonly ['audit-roster', 'follow-up-rollup', 'sibling-coherence']}
|
|
33
|
+
*/
|
|
34
|
+
export const RUN_EPILOGUE_STEP_KINDS = Object.freeze([
|
|
35
|
+
'audit-roster',
|
|
36
|
+
'follow-up-rollup',
|
|
37
|
+
'sibling-coherence',
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {string|number|{ id?: string|number, slug?: string }} entry
|
|
42
|
+
* @returns {string|null}
|
|
43
|
+
*/
|
|
44
|
+
function normalizeStoryId(entry) {
|
|
45
|
+
if (typeof entry === 'string') return entry.trim() || null;
|
|
46
|
+
if (typeof entry === 'number' && Number.isInteger(entry)) {
|
|
47
|
+
return String(entry);
|
|
48
|
+
}
|
|
49
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
50
|
+
if (typeof entry.id === 'string' || Number.isInteger(entry.id)) {
|
|
51
|
+
return String(entry.id).trim() || null;
|
|
52
|
+
}
|
|
53
|
+
return typeof entry.slug === 'string' ? entry.slug.trim() || null : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {Array<string|number|{ id?: string|number, slug?: string }>} stories
|
|
58
|
+
* @returns {string[]}
|
|
59
|
+
*/
|
|
60
|
+
function normalizeStoryIds(stories) {
|
|
61
|
+
const list = Array.isArray(stories) ? stories : [];
|
|
62
|
+
const seen = new Set();
|
|
63
|
+
const ids = [];
|
|
64
|
+
for (const entry of list) {
|
|
65
|
+
const id = normalizeStoryId(entry);
|
|
66
|
+
if (!id || seen.has(id)) continue;
|
|
67
|
+
seen.add(id);
|
|
68
|
+
ids.push(id);
|
|
69
|
+
}
|
|
70
|
+
return ids;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Enumerate the ordered epilogue steps for a completed run.
|
|
75
|
+
*
|
|
76
|
+
* @param {object} args
|
|
77
|
+
* @param {string} args.planRunId
|
|
78
|
+
* @param {Array<string|number|{ id?: string|number, slug?: string }>} args.stories
|
|
79
|
+
* @returns {object}
|
|
80
|
+
*/
|
|
81
|
+
export function planRunEpilogue({ planRunId, stories } = {}) {
|
|
82
|
+
const ids = normalizeStoryIds(stories);
|
|
83
|
+
const runId =
|
|
84
|
+
typeof planRunId === 'string' && planRunId.trim() !== ''
|
|
85
|
+
? planRunId.trim()
|
|
86
|
+
: null;
|
|
87
|
+
|
|
88
|
+
if (ids.length <= 1) {
|
|
89
|
+
return {
|
|
90
|
+
applicable: false,
|
|
91
|
+
planRunId: runId,
|
|
92
|
+
stories: ids,
|
|
93
|
+
steps: [],
|
|
94
|
+
reason:
|
|
95
|
+
ids.length === 0
|
|
96
|
+
? 'no Stories in run'
|
|
97
|
+
: 'single-Story run — per-Story close is the end; no run-scoped epilogue',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Positional `/deliver 101 102` has no plan-run label. Synthesize a
|
|
102
|
+
// stable adhoc id from the sorted Story set so the epilogue still
|
|
103
|
+
// anchors comments / audit roster without requiring `--run`.
|
|
104
|
+
const effectiveRunId =
|
|
105
|
+
runId ??
|
|
106
|
+
`adhoc-${[...ids].sort((a, b) => Number(a) - Number(b)).join('-')}`;
|
|
107
|
+
|
|
108
|
+
const steps = [
|
|
109
|
+
{
|
|
110
|
+
kind: 'audit-roster',
|
|
111
|
+
description: `Select cross-Story audit lenses for run ${effectiveRunId}`,
|
|
112
|
+
stories: ids,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
kind: 'follow-up-rollup',
|
|
116
|
+
description: `Friction follow-up roll-up for run ${effectiveRunId}`,
|
|
117
|
+
stories: ids,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
kind: 'sibling-coherence',
|
|
121
|
+
description: `Sibling-coherence check across the ${ids.length} Story specs of run ${effectiveRunId}`,
|
|
122
|
+
stories: ids,
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
applicable: true,
|
|
128
|
+
planRunId: effectiveRunId,
|
|
129
|
+
stories: ids,
|
|
130
|
+
steps,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function listChangedFiles(cwd, baseRef = 'origin/main') {
|
|
135
|
+
try {
|
|
136
|
+
const result = gitSpawn(cwd, 'diff', '--name-only', `${baseRef}...HEAD`);
|
|
137
|
+
if (result.status !== 0) return [];
|
|
138
|
+
return String(result.stdout ?? '')
|
|
139
|
+
.split('\n')
|
|
140
|
+
.map((line) => line.trim())
|
|
141
|
+
.filter(Boolean);
|
|
142
|
+
} catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function executeAuditRoster({ planRunId, stories, cwd, provider }) {
|
|
148
|
+
const primaryId = Number(stories[0]);
|
|
149
|
+
const changedFiles = await listChangedFiles(cwd);
|
|
150
|
+
let selectedAudits = [];
|
|
151
|
+
if (Number.isInteger(primaryId) && primaryId > 0) {
|
|
152
|
+
const selected = await selectAudits({
|
|
153
|
+
ticketId: primaryId,
|
|
154
|
+
gate: 'gate3',
|
|
155
|
+
provider,
|
|
156
|
+
baseBranch: 'main',
|
|
157
|
+
headRef: 'HEAD',
|
|
158
|
+
});
|
|
159
|
+
selectedAudits = Array.isArray(selected?.selectedAudits)
|
|
160
|
+
? selected.selectedAudits
|
|
161
|
+
: Array.isArray(selected)
|
|
162
|
+
? selected
|
|
163
|
+
: [];
|
|
164
|
+
}
|
|
165
|
+
const body = [
|
|
166
|
+
'### plan-run-audit-roster',
|
|
167
|
+
'',
|
|
168
|
+
`Cross-Story audit roster for plan-run \`${planRunId}\`.`,
|
|
169
|
+
'',
|
|
170
|
+
`Changed files considered: ${changedFiles.length}.`,
|
|
171
|
+
'',
|
|
172
|
+
'**Selected lenses** (host MUST walk each against the combined landed diff):',
|
|
173
|
+
...(selectedAudits.length > 0
|
|
174
|
+
? selectedAudits.map((lens) => `- \`${lens}\``)
|
|
175
|
+
: ['- _(none — docs-only or no matching change-set lenses)_']),
|
|
176
|
+
'',
|
|
177
|
+
'```json',
|
|
178
|
+
JSON.stringify(
|
|
179
|
+
{
|
|
180
|
+
planRunId,
|
|
181
|
+
stories: stories.map(Number),
|
|
182
|
+
changedFiles,
|
|
183
|
+
selectedAudits,
|
|
184
|
+
},
|
|
185
|
+
null,
|
|
186
|
+
2,
|
|
187
|
+
),
|
|
188
|
+
'```',
|
|
189
|
+
].join('\n');
|
|
190
|
+
if (Number.isInteger(primaryId) && primaryId > 0) {
|
|
191
|
+
await upsertStructuredComment(
|
|
192
|
+
provider,
|
|
193
|
+
primaryId,
|
|
194
|
+
'plan-run-audit-roster',
|
|
195
|
+
body,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
kind: 'audit-roster',
|
|
200
|
+
selectedAudits,
|
|
201
|
+
changedFileCount: changedFiles.length,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function executeFollowUpRollup({
|
|
206
|
+
planRunId,
|
|
207
|
+
stories,
|
|
208
|
+
provider,
|
|
209
|
+
config,
|
|
210
|
+
cwd,
|
|
211
|
+
}) {
|
|
212
|
+
const signals = [];
|
|
213
|
+
for (const raw of stories) {
|
|
214
|
+
const sid = Number(raw);
|
|
215
|
+
if (!Number.isInteger(sid) || sid <= 0) continue;
|
|
216
|
+
await forEachLine(
|
|
217
|
+
null,
|
|
218
|
+
sid,
|
|
219
|
+
(parsed) => {
|
|
220
|
+
if (!parsed || typeof parsed !== 'object') return;
|
|
221
|
+
const category =
|
|
222
|
+
typeof parsed.category === 'string' ? parsed.category.trim() : '';
|
|
223
|
+
if (!category) return;
|
|
224
|
+
const source = parsed.source === 'framework' ? 'framework' : 'consumer';
|
|
225
|
+
signals.push({ category, source });
|
|
226
|
+
},
|
|
227
|
+
config,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
const repos = resolveFollowUpRepos(config);
|
|
231
|
+
const primaryId = Number(stories[0]);
|
|
232
|
+
const proposals = composeRoutedProposals({
|
|
233
|
+
anchorId: Number.isInteger(primaryId) ? primaryId : 1,
|
|
234
|
+
anchorKind: 'run',
|
|
235
|
+
frameworkRepo: repos.frameworkRepo,
|
|
236
|
+
consumerRepo: repos.consumerRepo,
|
|
237
|
+
signals,
|
|
238
|
+
unresolvedBlockedEvents: [],
|
|
239
|
+
});
|
|
240
|
+
// Patch titles to mention the plan-run token (anchorKind run uses numeric id).
|
|
241
|
+
for (const item of [...proposals.framework, ...proposals.consumer]) {
|
|
242
|
+
item.title = item.title.replace(/plan-run \d+/, `plan-run ${planRunId}`);
|
|
243
|
+
item.body = item.body.replace(/plan-run \d+/g, `plan-run ${planRunId}`);
|
|
244
|
+
}
|
|
245
|
+
const graduated = await graduateRetroProposals({
|
|
246
|
+
epicId: primaryId,
|
|
247
|
+
provider,
|
|
248
|
+
config,
|
|
249
|
+
currentRepo: repos.currentRepo,
|
|
250
|
+
frameworkRepo: (() => {
|
|
251
|
+
const [owner, repo] = repos.frameworkRepo.split('/');
|
|
252
|
+
return { owner, repo };
|
|
253
|
+
})(),
|
|
254
|
+
routedProposals: proposals,
|
|
255
|
+
cwd,
|
|
256
|
+
});
|
|
257
|
+
if (Number.isInteger(primaryId) && primaryId > 0) {
|
|
258
|
+
const body = buildFollowUpsCommentBody({
|
|
259
|
+
storyId: primaryId,
|
|
260
|
+
proposals,
|
|
261
|
+
graduated,
|
|
262
|
+
}).replace(
|
|
263
|
+
`from Story #${primaryId}`,
|
|
264
|
+
`from plan-run \`${planRunId}\` (primary Story #${primaryId})`,
|
|
265
|
+
);
|
|
266
|
+
await upsertStructuredComment(provider, primaryId, 'follow-ups', body);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
kind: 'follow-up-rollup',
|
|
270
|
+
signalCount: signals.length,
|
|
271
|
+
filed: graduated.filed?.length ?? 0,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function extractSection(body, heading) {
|
|
276
|
+
if (typeof body !== 'string') return '';
|
|
277
|
+
const re = new RegExp(
|
|
278
|
+
`(?:^|\\n)## ${heading}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`,
|
|
279
|
+
'i',
|
|
280
|
+
);
|
|
281
|
+
const match = body.match(re);
|
|
282
|
+
return match ? match[1].trim() : '';
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function executeSiblingCoherence({ planRunId, stories, provider }) {
|
|
286
|
+
const findings = [];
|
|
287
|
+
const bodies = [];
|
|
288
|
+
for (const raw of stories) {
|
|
289
|
+
const sid = Number(raw);
|
|
290
|
+
if (!Number.isInteger(sid) || sid <= 0) continue;
|
|
291
|
+
const ticket = await provider.getTicket(sid);
|
|
292
|
+
bodies.push({
|
|
293
|
+
id: sid,
|
|
294
|
+
title: ticket?.title ?? '',
|
|
295
|
+
acceptance: extractSection(ticket?.body ?? '', 'Acceptance'),
|
|
296
|
+
spec: extractSection(ticket?.body ?? '', 'Spec'),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
const withAcceptance = bodies.filter((b) => b.acceptance.length > 0);
|
|
300
|
+
if (withAcceptance.length > 0 && withAcceptance.length < bodies.length) {
|
|
301
|
+
const missing = bodies
|
|
302
|
+
.filter((b) => b.acceptance.length === 0)
|
|
303
|
+
.map((b) => `#${b.id}`);
|
|
304
|
+
findings.push(
|
|
305
|
+
`Stories missing ## Acceptance while siblings declare ACs: ${missing.join(', ')}`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
// Detect identical non-empty Spec blobs (likely copy-paste drift).
|
|
309
|
+
const specMap = new Map();
|
|
310
|
+
for (const b of bodies) {
|
|
311
|
+
if (!b.spec) continue;
|
|
312
|
+
const key = b.spec.replace(/\s+/g, ' ').slice(0, 400);
|
|
313
|
+
if (!specMap.has(key)) specMap.set(key, []);
|
|
314
|
+
specMap.get(key).push(b.id);
|
|
315
|
+
}
|
|
316
|
+
for (const ids of specMap.values()) {
|
|
317
|
+
if (ids.length > 1) {
|
|
318
|
+
findings.push(
|
|
319
|
+
`Duplicate ## Spec prose across Stories ${ids.map((id) => `#${id}`).join(', ')} — split or dedupe.`,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const primaryId = Number(stories[0]);
|
|
324
|
+
const body = [
|
|
325
|
+
'### plan-run-sibling-coherence',
|
|
326
|
+
'',
|
|
327
|
+
`Sibling-coherence check for plan-run \`${planRunId}\`.`,
|
|
328
|
+
'',
|
|
329
|
+
findings.length === 0
|
|
330
|
+
? '_No coherence findings._'
|
|
331
|
+
: findings.map((f) => `- ${f}`).join('\n'),
|
|
332
|
+
'',
|
|
333
|
+
'```json',
|
|
334
|
+
JSON.stringify(
|
|
335
|
+
{ planRunId, stories: stories.map(Number), findings },
|
|
336
|
+
null,
|
|
337
|
+
2,
|
|
338
|
+
),
|
|
339
|
+
'```',
|
|
340
|
+
].join('\n');
|
|
341
|
+
if (Number.isInteger(primaryId) && primaryId > 0) {
|
|
342
|
+
await upsertStructuredComment(
|
|
343
|
+
provider,
|
|
344
|
+
primaryId,
|
|
345
|
+
'plan-run-sibling-coherence',
|
|
346
|
+
body,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return { kind: 'sibling-coherence', findings };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Execute the per-run epilogue. Throws only on programmer misuse; step
|
|
354
|
+
* failures are collected into `errors[]`.
|
|
355
|
+
*
|
|
356
|
+
* @param {object} args
|
|
357
|
+
* @param {string} args.planRunId
|
|
358
|
+
* @param {Array<string|number>} args.stories
|
|
359
|
+
* @param {object} args.provider
|
|
360
|
+
* @param {object} [args.config]
|
|
361
|
+
* @param {string} [args.cwd]
|
|
362
|
+
* @returns {Promise<object>}
|
|
363
|
+
*/
|
|
364
|
+
export async function runPlanRunEpilogue({
|
|
365
|
+
planRunId,
|
|
366
|
+
stories,
|
|
367
|
+
provider,
|
|
368
|
+
config,
|
|
369
|
+
cwd = process.cwd(),
|
|
370
|
+
} = {}) {
|
|
371
|
+
const plan = planRunEpilogue({ planRunId, stories });
|
|
372
|
+
if (!plan.applicable) {
|
|
373
|
+
return { ...plan, results: [], errors: [] };
|
|
374
|
+
}
|
|
375
|
+
if (!provider || typeof provider.getTicket !== 'function') {
|
|
376
|
+
throw new TypeError('runPlanRunEpilogue requires a ticketing provider');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const results = [];
|
|
380
|
+
const errors = [];
|
|
381
|
+
for (const step of plan.steps) {
|
|
382
|
+
try {
|
|
383
|
+
if (step.kind === 'audit-roster') {
|
|
384
|
+
results.push(
|
|
385
|
+
await executeAuditRoster({
|
|
386
|
+
planRunId: plan.planRunId,
|
|
387
|
+
stories: plan.stories,
|
|
388
|
+
cwd,
|
|
389
|
+
provider,
|
|
390
|
+
}),
|
|
391
|
+
);
|
|
392
|
+
} else if (step.kind === 'follow-up-rollup') {
|
|
393
|
+
results.push(
|
|
394
|
+
await executeFollowUpRollup({
|
|
395
|
+
planRunId: plan.planRunId,
|
|
396
|
+
stories: plan.stories,
|
|
397
|
+
provider,
|
|
398
|
+
config,
|
|
399
|
+
cwd,
|
|
400
|
+
}),
|
|
401
|
+
);
|
|
402
|
+
} else if (step.kind === 'sibling-coherence') {
|
|
403
|
+
results.push(
|
|
404
|
+
await executeSiblingCoherence({
|
|
405
|
+
planRunId: plan.planRunId,
|
|
406
|
+
stories: plan.stories,
|
|
407
|
+
provider,
|
|
408
|
+
}),
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
const message = err?.message ?? String(err);
|
|
413
|
+
Logger.warn(`[run-epilogue] step ${step.kind} failed: ${message}`);
|
|
414
|
+
errors.push({ kind: step.kind, message });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
applicable: true,
|
|
420
|
+
planRunId: plan.planRunId,
|
|
421
|
+
stories: plan.stories,
|
|
422
|
+
steps: plan.steps,
|
|
423
|
+
results,
|
|
424
|
+
errors,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* phases/auto-merge.js — enable GitHub native auto-merge on the PR.
|
|
3
3
|
*
|
|
4
|
-
* Mirrors the
|
|
4
|
+
* Mirrors the v2 `single-story-close.js` finalize call shape: squash strategy, delete
|
|
5
5
|
* the branch on merge. Non-fatal — returns `{ enabled: false, reason }`
|
|
6
6
|
* on any failure so the caller can fall back to the operator-merges-button
|
|
7
7
|
* path.
|
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
* the caller raises that to a thrown error so auto-merge is not enabled.
|
|
22
22
|
*
|
|
23
23
|
* Delegates the `runCodeReview` invocation to `runStoryReviewCore`
|
|
24
|
-
* (exported from `story-close/phases/code-review.js`) so
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* (exported from `story-close/phases/code-review.js`) so the close path
|
|
25
|
+
* shares a single invocation pattern (Story #3653). When `planningRisk`
|
|
26
|
+
* is omitted, loads it from the Story's `story-plan-state` checkpoint.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { parsePrNumberFromUrl } from '../../../github-url.js';
|
|
30
30
|
import { runStoryReviewCore } from '../../story-close/phases/code-review.js';
|
|
31
|
+
import { resolveStoryPlanningRisk } from '../../story-plan-state.js';
|
|
31
32
|
import { postStructuredComment } from '../../ticketing/state.js';
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -71,6 +72,79 @@ export function buildStoryReviewCrossRefBody({
|
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
async function invokeStoryReviewCore({
|
|
76
|
+
storyId,
|
|
77
|
+
storyBranch,
|
|
78
|
+
baseBranch,
|
|
79
|
+
prNumber,
|
|
80
|
+
provider,
|
|
81
|
+
planningRisk,
|
|
82
|
+
runCodeReviewFn,
|
|
83
|
+
runLocalLensReviewFn,
|
|
84
|
+
progress,
|
|
85
|
+
}) {
|
|
86
|
+
return runStoryReviewCore({
|
|
87
|
+
storyId,
|
|
88
|
+
baseRef: baseBranch,
|
|
89
|
+
headRef: storyBranch,
|
|
90
|
+
commentTargetId: prNumber,
|
|
91
|
+
provider,
|
|
92
|
+
planningRisk: await resolveStoryPlanningRisk({
|
|
93
|
+
provider,
|
|
94
|
+
storyId,
|
|
95
|
+
planningRisk,
|
|
96
|
+
}),
|
|
97
|
+
progress,
|
|
98
|
+
progressTag: 'REVIEW',
|
|
99
|
+
runCodeReviewFn,
|
|
100
|
+
// Forward the seam only when the caller injects it; otherwise
|
|
101
|
+
// `runStoryReviewCore` uses its default local-lens pass. `undefined`
|
|
102
|
+
// deep-merges to the default via the destructuring default there.
|
|
103
|
+
...(runLocalLensReviewFn ? { runLocalLensReviewFn } : {}),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function postStoryReviewCrossRef({
|
|
108
|
+
provider,
|
|
109
|
+
storyId,
|
|
110
|
+
prUrl,
|
|
111
|
+
prNumber,
|
|
112
|
+
result,
|
|
113
|
+
severity,
|
|
114
|
+
progress,
|
|
115
|
+
}) {
|
|
116
|
+
if (result.posted && Number.isInteger(result.postedCommentId)) {
|
|
117
|
+
const commentUrl = `${prUrl}#issuecomment-${result.postedCommentId}`;
|
|
118
|
+
const body = buildStoryReviewCrossRefBody({
|
|
119
|
+
prUrl,
|
|
120
|
+
prNumber,
|
|
121
|
+
commentUrl,
|
|
122
|
+
severity,
|
|
123
|
+
});
|
|
124
|
+
try {
|
|
125
|
+
await postStructuredComment(provider, storyId, 'notification', body);
|
|
126
|
+
progress(
|
|
127
|
+
'REVIEW',
|
|
128
|
+
`📝 Cross-reference comment posted on Story #${storyId} → ${commentUrl}`,
|
|
129
|
+
);
|
|
130
|
+
return true;
|
|
131
|
+
} catch (err) {
|
|
132
|
+
progress(
|
|
133
|
+
'REVIEW',
|
|
134
|
+
`⚠️ Failed to post Story cross-reference comment: ${err?.message ?? err}`,
|
|
135
|
+
);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!result.posted) {
|
|
140
|
+
progress(
|
|
141
|
+
'REVIEW',
|
|
142
|
+
'⚠️ Skipping Story cross-reference comment: PR-side review comment did not post.',
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
74
148
|
/**
|
|
75
149
|
* Run the Story-scope code review against `main`, post the structured
|
|
76
150
|
* findings comment to the PR, and add a one-line cross-reference comment
|
|
@@ -93,6 +167,7 @@ export function buildStoryReviewCrossRefBody({
|
|
|
93
167
|
* prUrl: string,
|
|
94
168
|
* prNumber: number|null,
|
|
95
169
|
* provider: object,
|
|
170
|
+
* planningRisk?: object|null, // omit to load from story-plan-state
|
|
96
171
|
* runCodeReviewFn: Function,
|
|
97
172
|
* runLocalLensReviewFn?: Function,
|
|
98
173
|
* progress: (tag: string, msg: string) => void,
|
|
@@ -115,6 +190,7 @@ export async function runStoryScopeReview({
|
|
|
115
190
|
prUrl,
|
|
116
191
|
prNumber,
|
|
117
192
|
provider,
|
|
193
|
+
planningRisk,
|
|
118
194
|
runCodeReviewFn,
|
|
119
195
|
runLocalLensReviewFn,
|
|
120
196
|
progress,
|
|
@@ -132,19 +208,16 @@ export async function runStoryScopeReview({
|
|
|
132
208
|
`Running Story-scope code review for Story #${storyId} (${baseBranch}...${storyBranch}) → PR #${prNumber}...`,
|
|
133
209
|
);
|
|
134
210
|
|
|
135
|
-
const result = await
|
|
211
|
+
const result = await invokeStoryReviewCore({
|
|
136
212
|
storyId,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
213
|
+
storyBranch,
|
|
214
|
+
baseBranch,
|
|
215
|
+
prNumber,
|
|
140
216
|
provider,
|
|
141
|
-
|
|
142
|
-
progressTag: 'REVIEW',
|
|
217
|
+
planningRisk,
|
|
143
218
|
runCodeReviewFn,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// deep-merges to the default via the destructuring default there.
|
|
147
|
-
...(runLocalLensReviewFn ? { runLocalLensReviewFn } : {}),
|
|
219
|
+
runLocalLensReviewFn,
|
|
220
|
+
progress,
|
|
148
221
|
});
|
|
149
222
|
|
|
150
223
|
const sev = result.severity ?? {
|
|
@@ -158,34 +231,15 @@ export async function runStoryScopeReview({
|
|
|
158
231
|
`Findings — critical:${sev.critical} high:${sev.high} medium:${sev.medium} suggestion:${sev.suggestion}. Posted to PR #${prNumber}: ${result.posted}.`,
|
|
159
232
|
);
|
|
160
233
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
await postStructuredComment(provider, storyId, 'notification', body);
|
|
172
|
-
crossRefPosted = true;
|
|
173
|
-
progress(
|
|
174
|
-
'REVIEW',
|
|
175
|
-
`📝 Cross-reference comment posted on Story #${storyId} → ${commentUrl}`,
|
|
176
|
-
);
|
|
177
|
-
} catch (err) {
|
|
178
|
-
progress(
|
|
179
|
-
'REVIEW',
|
|
180
|
-
`⚠️ Failed to post Story cross-reference comment: ${err?.message ?? err}`,
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
} else if (!result.posted) {
|
|
184
|
-
progress(
|
|
185
|
-
'REVIEW',
|
|
186
|
-
'⚠️ Skipping Story cross-reference comment: PR-side review comment did not post.',
|
|
187
|
-
);
|
|
188
|
-
}
|
|
234
|
+
const crossRefPosted = await postStoryReviewCrossRef({
|
|
235
|
+
provider,
|
|
236
|
+
storyId,
|
|
237
|
+
prUrl,
|
|
238
|
+
prNumber,
|
|
239
|
+
result,
|
|
240
|
+
severity: sev,
|
|
241
|
+
progress,
|
|
242
|
+
});
|
|
189
243
|
|
|
190
244
|
return {
|
|
191
245
|
halted: !!result.halted,
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { parseSprintArgs } from '../../../cli-args.js';
|
|
13
|
+
import { getDeliveryRouting } from '../../../config/delivery-routing.js';
|
|
13
14
|
import { PROJECT_ROOT } from '../../../project-root.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -27,11 +28,12 @@ function resolveFlag(paramValue, parsedValue, defaultValue) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* Resolve the `waitForMerge` option:
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* `--wait-merge` / injected
|
|
34
|
-
*
|
|
31
|
+
* Resolve the `waitForMerge` option:
|
|
32
|
+
* 1. `--no-wait-merge` / injected opt-out always wins (stop at
|
|
33
|
+
* `agent::closing`).
|
|
34
|
+
* 2. Explicit `--wait-merge` / injected true forces land-in-close.
|
|
35
|
+
* 3. Otherwise default from `delivery.routing.closeAndLand` (true) so
|
|
36
|
+
* attended and headless delivers share the close-and-land happy path.
|
|
35
37
|
*
|
|
36
38
|
* @param {{ waitForMergeParam, noWaitForMergeParam, parsed }} raw
|
|
37
39
|
* @returns {boolean}
|
|
@@ -41,13 +43,12 @@ function resolveWaitForMerge({
|
|
|
41
43
|
noWaitForMergeParam,
|
|
42
44
|
parsed,
|
|
43
45
|
}) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
return resolveFlag(waitForMergeParam, parsed.waitForMerge, false);
|
|
46
|
+
if (resolveFlag(noWaitForMergeParam, parsed.noWaitForMerge, false)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const explicit = waitForMergeParam ?? parsed.waitForMerge;
|
|
50
|
+
if (typeof explicit === 'boolean') return explicit;
|
|
51
|
+
return getDeliveryRouting().closeAndLand;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -75,7 +76,9 @@ export function parseCloseOptions({
|
|
|
75
76
|
skipSync: !!skipSyncParam,
|
|
76
77
|
noAutoMerge: !!noAutoMergeParam,
|
|
77
78
|
noFullScopeCrap: !!noFullScopeCrapParam,
|
|
78
|
-
|
|
79
|
+
// Preserve undefined so resolveWaitForMerge can apply the
|
|
80
|
+
// closeAndLand config default when neither flag was injected.
|
|
81
|
+
waitForMerge: waitForMergeParam,
|
|
79
82
|
noWaitForMerge: !!noWaitForMergeParam,
|
|
80
83
|
}
|
|
81
84
|
: parseSprintArgs();
|