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
|
@@ -1,465 +0,0 @@
|
|
|
1
|
-
// .agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js
|
|
2
|
-
/**
|
|
3
|
-
* AcceptanceReconciler — lifecycle listener that gates Finalize on the
|
|
4
|
-
* close-time acceptance-spec reconciliation. Story #2253 (Epic #2172):
|
|
5
|
-
* the reconciliation moves *ahead* of the push + `gh pr create` call so
|
|
6
|
-
* that AC coverage gaps block PR creation (review High-2).
|
|
7
|
-
*
|
|
8
|
-
* Subscribes to:
|
|
9
|
-
* - `epic.close.end` → emit `acceptance.reconcile.start`, run the
|
|
10
|
-
* `reconcileAcceptanceSpec` helper, emit one of
|
|
11
|
-
* `acceptance.reconcile.ok | .waived | .skipped | .failed`, and on
|
|
12
|
-
* `.failed` also emit `epic.blocked` so the LabelTransitioner /
|
|
13
|
-
* StructuredCommentPoster / NotifyDispatcher trio fire the blocker
|
|
14
|
-
* side effects exactly as a `story.blocked` cascade would.
|
|
15
|
-
*
|
|
16
|
-
* The Finalizer listener subscribes ONLY to `acceptance.reconcile.ok`,
|
|
17
|
-
* so this listener is the authoritative safety gate ahead of any push
|
|
18
|
-
* or PR-create work. The legacy `epic-deliver-finalize.js` shim still
|
|
19
|
-
* exists for backwards compatibility, but its in-line reconciliation
|
|
20
|
-
* call is replaced by the event-driven path.
|
|
21
|
-
*
|
|
22
|
-
* Idempotency contract (Acceptance Spec AC-10):
|
|
23
|
-
* - Per-instance `Set<string>` of `${event}:${seqId}` keys. A repeat
|
|
24
|
-
* `(event, seqId)` short-circuits without re-running reconciliation
|
|
25
|
-
* and emits no events.
|
|
26
|
-
* - The reconciler helper's only write is the section-scoped
|
|
27
|
-
* disposition record inside the Epic body's ## Acceptance Table
|
|
28
|
-
* region (Story #4324) — itself idempotent — so the seqId guard is
|
|
29
|
-
* the only defence the listener needs.
|
|
30
|
-
*
|
|
31
|
-
* Side-effect firewall: the listener owns the reconciliation call and
|
|
32
|
-
* the four outcome emits. It does NOT mutate labels, post comments, or
|
|
33
|
-
* call `notify` directly — those are downstream listener concerns.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
import { reconcileAcceptanceSpec as defaultReconcileAcceptanceSpec } from '../../../../acceptance-spec-reconciler.js';
|
|
37
|
-
import { DELIVERY_SINGLE_LABEL } from '../../deliver-route.js';
|
|
38
|
-
import { read as readEpicRunState } from '../../epic-run-state-store.js';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Default single-delivery resolver (Epic #4475, M4-B, design §2c). Decides
|
|
42
|
-
* whether the Epic under reconciliation is the single-delivery shape — the
|
|
43
|
-
* signal that flips a `waived` reconcile into a hard failure (the back gate
|
|
44
|
-
* of the non-waivable epic-level acceptance contract). Two sources, primary
|
|
45
|
-
* first:
|
|
46
|
-
*
|
|
47
|
-
* 1. `epic-run-state.deliveryShape === 'single'` — the durable checkpoint
|
|
48
|
-
* the single-delivery prepare writes.
|
|
49
|
-
* 2. The `delivery::single` label on the Epic ticket — the plan-time marker.
|
|
50
|
-
*
|
|
51
|
-
* Best-effort + fail-open-to-fan-out: any probe failure (null provider in a
|
|
52
|
-
* unit fixture, a GitHub read error) degrades to `false` (treat as fan-out),
|
|
53
|
-
* so the defence-in-depth back gate never *invents* a block — the front gate
|
|
54
|
-
* (prepare refusing `acceptance::n-a`) is the primary guard. Tests inject
|
|
55
|
-
* `resolveSingleFn` directly to bypass the probes.
|
|
56
|
-
*
|
|
57
|
-
* @param {{ provider?: object|null, epicId: number, config?: object|null }} args
|
|
58
|
-
* @returns {Promise<boolean>}
|
|
59
|
-
*/
|
|
60
|
-
export async function defaultResolveSingle({ provider, epicId }) {
|
|
61
|
-
if (!provider) return false;
|
|
62
|
-
try {
|
|
63
|
-
const checkpoint = await readEpicRunState({ provider, epicId });
|
|
64
|
-
if (checkpoint?.deliveryShape === 'single') return true;
|
|
65
|
-
} catch {
|
|
66
|
-
// Fall through to the label probe.
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
const epic = await provider.getTicket(epicId);
|
|
70
|
-
const labels = Array.isArray(epic?.labels) ? epic.labels : [];
|
|
71
|
-
return labels.some(
|
|
72
|
-
(l) => (typeof l === 'string' ? l : l?.name) === DELIVERY_SINGLE_LABEL,
|
|
73
|
-
);
|
|
74
|
-
} catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Classify a `reconcileAcceptanceSpec` result envelope into the typed
|
|
81
|
-
* outcome event the listener should emit. Pure function — exported so
|
|
82
|
-
* unit tests can drive every branch without a bus instance.
|
|
83
|
-
*
|
|
84
|
-
* The reconciler exposes a four-value `status` discriminant:
|
|
85
|
-
* - `'waived'` → the Epic carries `acceptance::n-a` (or no linked
|
|
86
|
-
* spec under `--skip-when-waived`). Emit
|
|
87
|
-
* `acceptance.reconcile.waived` with reason
|
|
88
|
-
* `'waiver'`. Story #2893 split this out from
|
|
89
|
-
* `.skipped` so the Finalizer can subscribe to
|
|
90
|
-
* `.waived` and route waived Epics through to PR
|
|
91
|
-
* creation, while empty-spec Epics still
|
|
92
|
-
* terminate without a PR via `.skipped`.
|
|
93
|
-
* **Non-waivable under single delivery (Epic #4475,
|
|
94
|
-
* M4-B, design §2c):** when `opts.single` is true the
|
|
95
|
-
* epic-level reconcile is the ONLY acceptance gate
|
|
96
|
-
* left, so a `waived` status is treated as a hard
|
|
97
|
-
* `failed` (reason `single-delivery-non-waivable`)
|
|
98
|
-
* instead of passing through — the back gate that
|
|
99
|
-
* forecloses the cohort's dilution (waived reconcile
|
|
100
|
-
* as the sole gate). The front gate (prepare refusing
|
|
101
|
-
* `acceptance::n-a`) already blocks this at seed time;
|
|
102
|
-
* this is defence in depth.
|
|
103
|
-
* - `'empty-spec'` → the linked spec exists but declares zero AC IDs.
|
|
104
|
-
* Treated as "no work to do"; emit `.skipped` with
|
|
105
|
-
* reason `'empty-spec'` so operators see the
|
|
106
|
-
* outcome explicitly (no silent skip).
|
|
107
|
-
* - `'ok'` → the spec has AC IDs and every one is covered by
|
|
108
|
-
* a non-pending scenario. Emit `.ok`.
|
|
109
|
-
* - `'gap'` → at least one AC is pending or missing. Emit
|
|
110
|
-
* `.failed` carrying a compact reason summary;
|
|
111
|
-
* the listener then emits `epic.blocked` to flip
|
|
112
|
-
* the Epic ticket.
|
|
113
|
-
*
|
|
114
|
-
* @param {object|undefined|null} result reconciler envelope.
|
|
115
|
-
* @param {{ single?: boolean }} [opts] `single: true` flips a `waived` status
|
|
116
|
-
* into a hard `failed` (the non-waivable epic reconcile back gate).
|
|
117
|
-
* @returns {{ outcome: 'ok'|'waived'|'skipped'|'failed', reason?: string }}
|
|
118
|
-
*/
|
|
119
|
-
export function classifyReconcileResult(result, opts = {}) {
|
|
120
|
-
const single = opts?.single === true;
|
|
121
|
-
if (!result || typeof result !== 'object') {
|
|
122
|
-
return { outcome: 'failed', reason: 'reconciler-no-result' };
|
|
123
|
-
}
|
|
124
|
-
const status = result.status;
|
|
125
|
-
if (status === 'waived') {
|
|
126
|
-
if (single) {
|
|
127
|
-
return {
|
|
128
|
-
outcome: 'failed',
|
|
129
|
-
reason: 'single-delivery-non-waivable',
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
return { outcome: 'waived', reason: 'waiver' };
|
|
133
|
-
}
|
|
134
|
-
if (status === 'empty-spec') {
|
|
135
|
-
return { outcome: 'skipped', reason: 'empty-spec' };
|
|
136
|
-
}
|
|
137
|
-
if (status === 'ok') {
|
|
138
|
-
return { outcome: 'ok' };
|
|
139
|
-
}
|
|
140
|
-
if (status === 'gap') {
|
|
141
|
-
const missing = Array.isArray(result.missing) ? result.missing : [];
|
|
142
|
-
const pending = Array.isArray(result.pending) ? result.pending : [];
|
|
143
|
-
const parts = [];
|
|
144
|
-
if (missing.length > 0) parts.push(`missing=${missing.join(',')}`);
|
|
145
|
-
if (pending.length > 0) parts.push(`pending=${pending.join(',')}`);
|
|
146
|
-
const reason =
|
|
147
|
-
parts.length > 0 ? `gap:${parts.join(';')}` : 'gap:unspecified';
|
|
148
|
-
return { outcome: 'failed', reason };
|
|
149
|
-
}
|
|
150
|
-
// Unknown status — fail closed so the operator sees the surprise.
|
|
151
|
-
return { outcome: 'failed', reason: `unknown-status:${String(status)}` };
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* AcceptanceReconciler — instantiate one per Epic run and call
|
|
156
|
-
* `register()` to wire it onto the bus. Stateless w.r.t. the system
|
|
157
|
-
* under orchestration; per-run state is the `(event, seqId)`
|
|
158
|
-
* idempotency cache + the classification log.
|
|
159
|
-
*/
|
|
160
|
-
export class AcceptanceReconciler {
|
|
161
|
-
/**
|
|
162
|
-
* @param {object} opts
|
|
163
|
-
* @param {object} opts.bus Lifecycle bus instance (must expose
|
|
164
|
-
* `on()` and `emit()`).
|
|
165
|
-
* @param {number} opts.epicId Epic ticket id.
|
|
166
|
-
* @param {string} [opts.cwd] Working directory passed through to the
|
|
167
|
-
* reconciler helper. Defaults to `process.cwd()`.
|
|
168
|
-
* @param {object} [opts.provider] Ticketing provider — injected into
|
|
169
|
-
* the reconciler call so the lifecycle bus does not need to
|
|
170
|
-
* construct one itself.
|
|
171
|
-
* @param {object} [opts.config] Resolved orchestration config —
|
|
172
|
-
* injected for the same reason.
|
|
173
|
-
* @param {Function} [opts.reconcileAcceptanceSpecFn] Override of the
|
|
174
|
-
* helper for tests; defaults to the production export.
|
|
175
|
-
* @param {Function} [opts.resolveSingleFn] Override of the single-delivery
|
|
176
|
-
* resolver for tests (Epic #4475, M4-B); defaults to `defaultResolveSingle`
|
|
177
|
-
* (checkpoint `deliveryShape` → `delivery::single` label).
|
|
178
|
-
* @param {{ info?: Function, warn?: Function, debug?: Function }} [opts.logger]
|
|
179
|
-
*/
|
|
180
|
-
constructor(opts = {}) {
|
|
181
|
-
if (
|
|
182
|
-
!opts.bus ||
|
|
183
|
-
typeof opts.bus.on !== 'function' ||
|
|
184
|
-
typeof opts.bus.emit !== 'function'
|
|
185
|
-
) {
|
|
186
|
-
throw new TypeError(
|
|
187
|
-
'AcceptanceReconciler requires a bus with on() and emit()',
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
if (!Number.isInteger(opts.epicId) || opts.epicId < 1) {
|
|
191
|
-
throw new TypeError('AcceptanceReconciler requires a numeric epicId');
|
|
192
|
-
}
|
|
193
|
-
this.bus = opts.bus;
|
|
194
|
-
this.epicId = opts.epicId;
|
|
195
|
-
this.cwd = opts.cwd ?? process.cwd();
|
|
196
|
-
this.provider = opts.provider ?? null;
|
|
197
|
-
this.config = opts.config ?? null;
|
|
198
|
-
this.reconcileAcceptanceSpecFn =
|
|
199
|
-
opts.reconcileAcceptanceSpecFn ?? defaultReconcileAcceptanceSpec;
|
|
200
|
-
this.resolveSingleFn = opts.resolveSingleFn ?? defaultResolveSingle;
|
|
201
|
-
this.logger = opts.logger ?? console;
|
|
202
|
-
/** @type {Set<string>} `${event}:${seqId}` keys we've handled. */
|
|
203
|
-
this._seen = new Set();
|
|
204
|
-
/**
|
|
205
|
-
* Classification log — mirrors the BlockerHandler "no silent skip"
|
|
206
|
-
* surface so tests can confirm every `epic.close.end` we observed
|
|
207
|
-
* was classified into exactly one outcome.
|
|
208
|
-
*
|
|
209
|
-
* @type {Array<{ event: string, seqId: number, outcome: string, reason?: string }>}
|
|
210
|
-
*/
|
|
211
|
-
this.classifications = [];
|
|
212
|
-
this.events = Object.freeze(['epic.close.end']);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Register this listener on the bus. Returns an array of unsubscribe
|
|
217
|
-
* functions (one per event) for test teardown.
|
|
218
|
-
*/
|
|
219
|
-
register() {
|
|
220
|
-
return this.events.map((event) =>
|
|
221
|
-
this.bus.on(event, async (ctx) => this.handle(ctx)),
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Bus listener body. The bus passes `{ event, seqId, payload }`. The
|
|
227
|
-
* listener:
|
|
228
|
-
* 1. Idempotently short-circuits a repeat `(event, seqId)`.
|
|
229
|
-
* 2. Emits `acceptance.reconcile.start`.
|
|
230
|
-
* 3. Runs `reconcileAcceptanceSpec` with injected provider/config.
|
|
231
|
-
* 4. Emits exactly one of `.ok` / `.skipped` / `.failed`.
|
|
232
|
-
* 5. On `.failed`, additionally emits `epic.blocked` so the
|
|
233
|
-
* downstream listener trio (label flip + structured comment +
|
|
234
|
-
* notify) fires the operator-visible blocker side effects.
|
|
235
|
-
*
|
|
236
|
-
* The listener does NOT throw on reconciler failures: the bus's
|
|
237
|
-
* `onFailed` boundary already persists the originating
|
|
238
|
-
* `epic.close.end` record; surfacing a throw here would short-circuit
|
|
239
|
-
* other `epic.close.end` listeners (e.g. trace logger) and is not
|
|
240
|
-
* needed for correctness — the `acceptance.reconcile.failed` +
|
|
241
|
-
* `epic.blocked` emits are the cascade contract.
|
|
242
|
-
*
|
|
243
|
-
* @param {{ event: string, seqId: number, payload: object }} ctx
|
|
244
|
-
*/
|
|
245
|
-
async handle({ event, seqId, payload }) {
|
|
246
|
-
const key = `${event}:${seqId}`;
|
|
247
|
-
if (this._seen.has(key)) {
|
|
248
|
-
this.classifications.push({
|
|
249
|
-
event,
|
|
250
|
-
seqId,
|
|
251
|
-
outcome: 'skipped',
|
|
252
|
-
reason: 'duplicate-seqId',
|
|
253
|
-
});
|
|
254
|
-
this.logger.debug?.(
|
|
255
|
-
`[AcceptanceReconciler] skip duplicate ${key} (idempotent)`,
|
|
256
|
-
);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
this._seen.add(key);
|
|
260
|
-
|
|
261
|
-
const epicIdFromPayload = Number(payload?.epicId);
|
|
262
|
-
const epicId = Number.isInteger(epicIdFromPayload)
|
|
263
|
-
? epicIdFromPayload
|
|
264
|
-
: this.epicId;
|
|
265
|
-
|
|
266
|
-
// 1. Start emit. The downstream ledger-diff `reconcile-ordering`
|
|
267
|
-
// assert checks for `acceptance.reconcile.ok` before `pr.created`,
|
|
268
|
-
// but operators want to see the `.start` marker in the trace too.
|
|
269
|
-
try {
|
|
270
|
-
await this.bus.emit('acceptance.reconcile.start', { epicId });
|
|
271
|
-
} catch (err) {
|
|
272
|
-
// Schema validation against a known-good payload should never
|
|
273
|
-
// throw; if it does, surface and bail — there's no point running
|
|
274
|
-
// the reconciler when we cannot announce its outcome.
|
|
275
|
-
this.classifications.push({
|
|
276
|
-
event,
|
|
277
|
-
seqId,
|
|
278
|
-
outcome: 'failed',
|
|
279
|
-
reason: `start-emit-failed:${err?.message ?? err}`,
|
|
280
|
-
});
|
|
281
|
-
this.logger.warn?.(
|
|
282
|
-
`[AcceptanceReconciler] acceptance.reconcile.start emit failed: ${err?.message ?? err}`,
|
|
283
|
-
);
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// 2. Run the reconciler. The helper itself throws on hard errors
|
|
288
|
-
// (no linked spec + no waiver, etc.); convert those into
|
|
289
|
-
// `.failed` emits rather than re-propagating, so the cascade
|
|
290
|
-
// contract holds even when the spec is malformed.
|
|
291
|
-
let result;
|
|
292
|
-
let thrown = null;
|
|
293
|
-
try {
|
|
294
|
-
result = await this.reconcileAcceptanceSpecFn({
|
|
295
|
-
epicId,
|
|
296
|
-
cwd: this.cwd,
|
|
297
|
-
injectedProvider: this.provider ?? undefined,
|
|
298
|
-
injectedConfig: this.config ?? undefined,
|
|
299
|
-
loggerImpl: this.logger,
|
|
300
|
-
// Honour `acceptance::n-a` — the helper already returns
|
|
301
|
-
// `status: 'waived'` for that label, but `skipWhenWaived: true`
|
|
302
|
-
// additionally tolerates a missing acceptance-table section under
|
|
303
|
-
// the waiver (we want the same forgiving stance the inline
|
|
304
|
-
// finalize call had).
|
|
305
|
-
skipWhenWaived: true,
|
|
306
|
-
// Close time is the one place the verification outcome is
|
|
307
|
-
// recorded into the Epic body's ## Acceptance Table section
|
|
308
|
-
// (section-scoped write, Story #4324).
|
|
309
|
-
writeDispositions: true,
|
|
310
|
-
});
|
|
311
|
-
} catch (err) {
|
|
312
|
-
thrown = err;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const baseRead = thrown == null && result != null;
|
|
316
|
-
|
|
317
|
-
if (thrown != null) {
|
|
318
|
-
const reason = `reconcile-threw:${thrown?.message ?? thrown}`;
|
|
319
|
-
await this._emitFailure({ event, seqId, baseRead, reason });
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Resolve the delivery shape before classifying: under single delivery a
|
|
324
|
-
// `waived` reconcile is non-waivable (design §2c). Best-effort — a probe
|
|
325
|
-
// failure degrades to `false` (fan-out pass-through), never inventing a
|
|
326
|
-
// block.
|
|
327
|
-
let single = false;
|
|
328
|
-
try {
|
|
329
|
-
single = await this.resolveSingleFn({
|
|
330
|
-
provider: this.provider,
|
|
331
|
-
epicId,
|
|
332
|
-
config: this.config,
|
|
333
|
-
});
|
|
334
|
-
} catch (err) {
|
|
335
|
-
this.logger.warn?.(
|
|
336
|
-
`[AcceptanceReconciler] single-delivery probe failed (treating as fan-out): ${err?.message ?? err}`,
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const classification = classifyReconcileResult(result, { single });
|
|
341
|
-
if (classification.outcome === 'ok') {
|
|
342
|
-
await this._emitOk({ event, seqId, baseRead });
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (classification.outcome === 'waived') {
|
|
346
|
-
await this._emitWaived({
|
|
347
|
-
event,
|
|
348
|
-
seqId,
|
|
349
|
-
baseRead,
|
|
350
|
-
reason: classification.reason ?? 'waiver',
|
|
351
|
-
});
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
if (classification.outcome === 'skipped') {
|
|
355
|
-
await this._emitSkipped({
|
|
356
|
-
event,
|
|
357
|
-
seqId,
|
|
358
|
-
baseRead,
|
|
359
|
-
reason: classification.reason ?? 'skipped',
|
|
360
|
-
});
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
await this._emitFailure({
|
|
364
|
-
event,
|
|
365
|
-
seqId,
|
|
366
|
-
baseRead,
|
|
367
|
-
reason: classification.reason ?? 'gap',
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Emit `acceptance.reconcile.ok` and record the classification.
|
|
373
|
-
* Helper carved out so each branch in `handle()` reads as a single
|
|
374
|
-
* decision.
|
|
375
|
-
*/
|
|
376
|
-
async _emitOk({ event, seqId, baseRead }) {
|
|
377
|
-
this.classifications.push({ event, seqId, outcome: 'ok' });
|
|
378
|
-
try {
|
|
379
|
-
await this.bus.emit('acceptance.reconcile.ok', { baseRead });
|
|
380
|
-
} catch (err) {
|
|
381
|
-
this.logger.warn?.(
|
|
382
|
-
`[AcceptanceReconciler] acceptance.reconcile.ok emit failed (swallowed): ${err?.message ?? err}`,
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Emit `acceptance.reconcile.waived` for the `acceptance::n-a` path.
|
|
389
|
-
* Story #2893 split this out of `.skipped` so the Finalizer can
|
|
390
|
-
* subscribe to `.waived` and route waived Epics through to PR
|
|
391
|
-
* creation. The schema pins `reason` to `'waiver'`.
|
|
392
|
-
*/
|
|
393
|
-
async _emitWaived({ event, seqId, baseRead, reason }) {
|
|
394
|
-
this.classifications.push({ event, seqId, outcome: 'waived', reason });
|
|
395
|
-
try {
|
|
396
|
-
await this.bus.emit('acceptance.reconcile.waived', {
|
|
397
|
-
baseRead,
|
|
398
|
-
reason,
|
|
399
|
-
});
|
|
400
|
-
} catch (err) {
|
|
401
|
-
this.logger.warn?.(
|
|
402
|
-
`[AcceptanceReconciler] acceptance.reconcile.waived emit failed (swallowed): ${err?.message ?? err}`,
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Emit `acceptance.reconcile.skipped` carrying a typed `reason`. The
|
|
409
|
-
* schema requires `reason` to be non-empty so callers always pass one
|
|
410
|
-
* (no silent skip).
|
|
411
|
-
*/
|
|
412
|
-
async _emitSkipped({ event, seqId, baseRead, reason }) {
|
|
413
|
-
this.classifications.push({ event, seqId, outcome: 'skipped', reason });
|
|
414
|
-
try {
|
|
415
|
-
await this.bus.emit('acceptance.reconcile.skipped', {
|
|
416
|
-
baseRead,
|
|
417
|
-
reason,
|
|
418
|
-
});
|
|
419
|
-
} catch (err) {
|
|
420
|
-
this.logger.warn?.(
|
|
421
|
-
`[AcceptanceReconciler] acceptance.reconcile.skipped emit failed (swallowed): ${err?.message ?? err}`,
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Emit `acceptance.reconcile.failed` and then `epic.blocked`, in that
|
|
428
|
-
* order. The `epic.blocked` emit drives the LabelTransitioner /
|
|
429
|
-
* StructuredCommentPoster / NotifyDispatcher trio so the operator
|
|
430
|
-
* sees the blocker label flip + structured comment + webhook,
|
|
431
|
-
* exactly as a `story.blocked` cascade would.
|
|
432
|
-
*
|
|
433
|
-
* Failures inside the `epic.blocked` emit are swallowed (the
|
|
434
|
-
* `.failed` record is already on the ledger; double-throwing here
|
|
435
|
-
* would mask the original reason).
|
|
436
|
-
*/
|
|
437
|
-
async _emitFailure({ event, seqId, baseRead, reason }) {
|
|
438
|
-
this.classifications.push({ event, seqId, outcome: 'failed', reason });
|
|
439
|
-
try {
|
|
440
|
-
await this.bus.emit('acceptance.reconcile.failed', {
|
|
441
|
-
baseRead,
|
|
442
|
-
reason,
|
|
443
|
-
});
|
|
444
|
-
} catch (err) {
|
|
445
|
-
this.logger.warn?.(
|
|
446
|
-
`[AcceptanceReconciler] acceptance.reconcile.failed emit failed (swallowed): ${err?.message ?? err}`,
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
try {
|
|
450
|
-
await this.bus.emit('epic.blocked', {
|
|
451
|
-
reason: `acceptance-reconcile:${reason}`,
|
|
452
|
-
});
|
|
453
|
-
} catch (err) {
|
|
454
|
-
this.logger.warn?.(
|
|
455
|
-
`[AcceptanceReconciler] epic.blocked emit failed (swallowed): ${err?.message ?? err}`,
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/** Test helper — wipe the idempotency cache. */
|
|
461
|
-
reset() {
|
|
462
|
-
this._seen.clear();
|
|
463
|
-
this.classifications = [];
|
|
464
|
-
}
|
|
465
|
-
}
|