mandrel 1.93.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +59 -73
- package/.agents/agents/acceptance-critic.md +129 -0
- package/.agents/agents/story-worker.md +161 -0
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +108 -136
- package/.agents/docs/execution-reference.md +44 -22
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +107 -108
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +224 -0
- package/.agents/rules/git-conventions.md +42 -223
- package/.agents/rules/security-baseline.md +5 -0
- package/.agents/rules/testing-standards.md +106 -13
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +71 -201
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/acceptance-eval.js +62 -18
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-context-budget.js +62 -5
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/diagnose-friction.js +0 -6
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +160 -22
- package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +103 -0
- package/.agents/scripts/lib/config/explain.js +57 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +3 -8
- package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +39 -4
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +112 -3
- package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/provider-factory.js +1 -1
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/post-structured-comment.js +38 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/sync-claude-agents.js +165 -0
- package/.agents/scripts/update-ticket-state.js +37 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
- package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +8 -418
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +3 -3
- package/.agents/workflows/deliver.md +122 -131
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +3 -2
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +46 -0
- package/lib/cli/registry.js +95 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +5 -3
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer-mobile.md +0 -120
- package/.agents/personas/engineer-web.md +0 -111
- package/.agents/personas/engineer.md +0 -119
- package/.agents/personas/product.md +0 -94
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/refactorer.md +0 -113
- package/.agents/personas/security-engineer.md +0 -112
- package/.agents/personas/sre.md +0 -86
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/personas/ux-designer.md +0 -95
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -590
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-decompose.js +0 -54
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-plan-spec.js +0 -64
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/plan-critics.js +0 -199
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -335
- package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
- package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
- package/.agents/skills/core/code-simplification/SKILL.md +0 -389
- package/.agents/skills/core/context-engineering/SKILL.md +0 -309
- package/.agents/skills/core/context-engineering/examples.md +0 -58
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
- package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
- package/.agents/skills/core/idea-refinement/examples.md +0 -437
- package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
- package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
- package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
- package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
- package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
- package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
- package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
- package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
- package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
- package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
- package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
- package/.agents/workflows/helpers/deliver-epic.md +0 -955
- package/.agents/workflows/helpers/deliver-stories.md +0 -440
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -351
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* emit-story-dispatch-end.js — Story #3900.
|
|
3
|
-
*
|
|
4
|
-
* Programmatic helper that appends a single `story.dispatch.end` NDJSON
|
|
5
|
-
* record to `temp/epic-<id>/lifecycle.ndjson` for one recorded Story.
|
|
6
|
-
*
|
|
7
|
-
* Why this exists:
|
|
8
|
-
* The `wave-tick.js` in-flight reconciler (and the `--check-idle`
|
|
9
|
-
* watchdog) compute "in-flight" Stories as those carrying a
|
|
10
|
-
* `story.dispatch.start` record WITHOUT a matching `story.dispatch.end`.
|
|
11
|
-
* Before this Story the only producer of `story.dispatch.end` was
|
|
12
|
-
* `lib/orchestration/wave-session.js`, which nothing imports outside
|
|
13
|
-
* tests — so every dispatched Story stayed "in-flight" forever and the
|
|
14
|
-
* idle watchdog flagged completed Stories as stalled. The host-LLM driven
|
|
15
|
-
* `/deliver` path closes a wave through `epic-execute-record-wave.js`,
|
|
16
|
-
* so that CLI is the correct place to emit the matching dispatch-end per
|
|
17
|
-
* recorded Story.
|
|
18
|
-
*
|
|
19
|
-
* The emit mirrors the thin direct-append shape of
|
|
20
|
-
* `lifecycle-emit-story-dispatch.js` (start) and `emit-story-heartbeat.js`:
|
|
21
|
-
* one schema-validated `emitted`-kind record, no full listener chain. It is
|
|
22
|
-
* best-effort at the call site — a failed append must not block the wave
|
|
23
|
-
* loop, so callers wrap it and log.
|
|
24
|
-
*
|
|
25
|
-
* Schema contract (story.dispatch.end.schema.json):
|
|
26
|
-
* { storyId, outcome: done|blocked|failed|skipped, durationMs }
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
|
|
30
|
-
import path from 'node:path';
|
|
31
|
-
import { fileURLToPath } from 'node:url';
|
|
32
|
-
|
|
33
|
-
import Ajv2020 from 'ajv/dist/2020.js';
|
|
34
|
-
import addFormats from 'ajv-formats';
|
|
35
|
-
|
|
36
|
-
import { epicLedgerPath } from '../../config/temp-paths.js';
|
|
37
|
-
|
|
38
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
|
-
const SCHEMA_PATH = path.resolve(
|
|
40
|
-
__dirname,
|
|
41
|
-
'..',
|
|
42
|
-
'..',
|
|
43
|
-
'..',
|
|
44
|
-
'..',
|
|
45
|
-
'schemas',
|
|
46
|
-
'lifecycle',
|
|
47
|
-
'story.dispatch.end.schema.json',
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const VALID_OUTCOMES = new Set(['done', 'blocked', 'failed', 'skipped']);
|
|
51
|
-
|
|
52
|
-
let _validator;
|
|
53
|
-
|
|
54
|
-
function getValidator() {
|
|
55
|
-
if (_validator) return _validator;
|
|
56
|
-
const schema = JSON.parse(readFileSync(SCHEMA_PATH, 'utf8'));
|
|
57
|
-
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
58
|
-
addFormats(ajv);
|
|
59
|
-
_validator = ajv.compile(schema);
|
|
60
|
-
return _validator;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Append exactly one `story.dispatch.end` NDJSON record to the Epic ledger.
|
|
65
|
-
*
|
|
66
|
-
* @param {object} opts
|
|
67
|
-
* @param {number} opts.epicId Parent Epic — required for the ledger path.
|
|
68
|
-
* @param {number} opts.storyId Story whose dispatch settled.
|
|
69
|
-
* @param {string} opts.outcome One of done|blocked|failed|skipped.
|
|
70
|
-
* @param {number} [opts.durationMs=0] Wall-clock dispatch duration in ms.
|
|
71
|
-
* Defaults to 0 when the host loop does
|
|
72
|
-
* not track per-Story timing.
|
|
73
|
-
* @param {string} [opts.timestamp] ISO-8601 wall clock. Defaults to now().
|
|
74
|
-
* @param {object} [opts.config] Optional resolved config for tempRoot.
|
|
75
|
-
* @param {string} [opts.ledgerPath] Override for tests.
|
|
76
|
-
* @returns {{ ledgerPath: string, record: object }}
|
|
77
|
-
*/
|
|
78
|
-
export function emitStoryDispatchEnd(opts) {
|
|
79
|
-
const {
|
|
80
|
-
epicId,
|
|
81
|
-
storyId,
|
|
82
|
-
outcome,
|
|
83
|
-
durationMs = 0,
|
|
84
|
-
timestamp = new Date().toISOString(),
|
|
85
|
-
config,
|
|
86
|
-
ledgerPath: ledgerPathOverride,
|
|
87
|
-
} = opts ?? {};
|
|
88
|
-
|
|
89
|
-
if (!Number.isInteger(epicId) || epicId < 1) {
|
|
90
|
-
throw new Error('emitStoryDispatchEnd: epicId must be a positive integer');
|
|
91
|
-
}
|
|
92
|
-
if (!Number.isInteger(storyId) || storyId < 1) {
|
|
93
|
-
throw new Error('emitStoryDispatchEnd: storyId must be a positive integer');
|
|
94
|
-
}
|
|
95
|
-
if (!VALID_OUTCOMES.has(outcome)) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`emitStoryDispatchEnd: outcome "${outcome}" must be one of: ${[...VALID_OUTCOMES].join(', ')}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
if (!Number.isInteger(durationMs) || durationMs < 0) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
'emitStoryDispatchEnd: durationMs must be a non-negative integer',
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const payload = { storyId, outcome, durationMs };
|
|
107
|
-
|
|
108
|
-
const validator = getValidator();
|
|
109
|
-
if (!validator(payload)) {
|
|
110
|
-
const detail = (validator.errors ?? [])
|
|
111
|
-
.map((e) => `${e.instancePath || '/'} ${e.message}`)
|
|
112
|
-
.join('; ');
|
|
113
|
-
throw new Error(
|
|
114
|
-
`emitStoryDispatchEnd: payload failed schema validation: ${detail}`,
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const ledgerPath = ledgerPathOverride ?? epicLedgerPath(epicId, config);
|
|
119
|
-
mkdirSync(path.dirname(ledgerPath), { recursive: true });
|
|
120
|
-
const record = {
|
|
121
|
-
kind: 'emitted',
|
|
122
|
-
ts: timestamp,
|
|
123
|
-
event: 'story.dispatch.end',
|
|
124
|
-
payload,
|
|
125
|
-
};
|
|
126
|
-
appendFileSync(ledgerPath, `${JSON.stringify(record)}\n`, 'utf8');
|
|
127
|
-
return { ledgerPath, record };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Map a recorded Story status (`done`/`blocked`/`failed`) to the
|
|
132
|
-
* `story.dispatch.end` outcome enum. The status taxonomy is a strict subset
|
|
133
|
-
* of the outcome enum, so the mapping is identity for the three values the
|
|
134
|
-
* record-wave projection produces. Unknown values throw rather than emit a
|
|
135
|
-
* schema-invalid record.
|
|
136
|
-
*
|
|
137
|
-
* @param {string} status
|
|
138
|
-
* @returns {string}
|
|
139
|
-
*/
|
|
140
|
-
export function storyStatusToDispatchOutcome(status) {
|
|
141
|
-
if (!VALID_OUTCOMES.has(status)) {
|
|
142
|
-
throw new Error(
|
|
143
|
-
`storyStatusToDispatchOutcome: unknown story status "${status}"`,
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
return status;
|
|
147
|
-
}
|
|
@@ -1,384 +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
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Classify a `reconcileAcceptanceSpec` result envelope into the typed
|
|
40
|
-
* outcome event the listener should emit. Pure function — exported so
|
|
41
|
-
* unit tests can drive every branch without a bus instance.
|
|
42
|
-
*
|
|
43
|
-
* The reconciler exposes a four-value `status` discriminant:
|
|
44
|
-
* - `'waived'` → the Epic carries `acceptance::n-a` (or no linked
|
|
45
|
-
* spec under `--skip-when-waived`). Emit
|
|
46
|
-
* `acceptance.reconcile.waived` with reason
|
|
47
|
-
* `'waiver'`. Story #2893 split this out from
|
|
48
|
-
* `.skipped` so the Finalizer can subscribe to
|
|
49
|
-
* `.waived` and route waived Epics through to PR
|
|
50
|
-
* creation, while empty-spec Epics still
|
|
51
|
-
* terminate without a PR via `.skipped`.
|
|
52
|
-
* - `'empty-spec'` → the linked spec exists but declares zero AC IDs.
|
|
53
|
-
* Treated as "no work to do"; emit `.skipped` with
|
|
54
|
-
* reason `'empty-spec'` so operators see the
|
|
55
|
-
* outcome explicitly (no silent skip).
|
|
56
|
-
* - `'ok'` → the spec has AC IDs and every one is covered by
|
|
57
|
-
* a non-pending scenario. Emit `.ok`.
|
|
58
|
-
* - `'gap'` → at least one AC is pending or missing. Emit
|
|
59
|
-
* `.failed` carrying a compact reason summary;
|
|
60
|
-
* the listener then emits `epic.blocked` to flip
|
|
61
|
-
* the Epic ticket.
|
|
62
|
-
*
|
|
63
|
-
* @param {object|undefined|null} result reconciler envelope.
|
|
64
|
-
* @returns {{ outcome: 'ok'|'waived'|'skipped'|'failed', reason?: string }}
|
|
65
|
-
*/
|
|
66
|
-
export function classifyReconcileResult(result) {
|
|
67
|
-
if (!result || typeof result !== 'object') {
|
|
68
|
-
return { outcome: 'failed', reason: 'reconciler-no-result' };
|
|
69
|
-
}
|
|
70
|
-
const status = result.status;
|
|
71
|
-
if (status === 'waived') {
|
|
72
|
-
return { outcome: 'waived', reason: 'waiver' };
|
|
73
|
-
}
|
|
74
|
-
if (status === 'empty-spec') {
|
|
75
|
-
return { outcome: 'skipped', reason: 'empty-spec' };
|
|
76
|
-
}
|
|
77
|
-
if (status === 'ok') {
|
|
78
|
-
return { outcome: 'ok' };
|
|
79
|
-
}
|
|
80
|
-
if (status === 'gap') {
|
|
81
|
-
const missing = Array.isArray(result.missing) ? result.missing : [];
|
|
82
|
-
const pending = Array.isArray(result.pending) ? result.pending : [];
|
|
83
|
-
const parts = [];
|
|
84
|
-
if (missing.length > 0) parts.push(`missing=${missing.join(',')}`);
|
|
85
|
-
if (pending.length > 0) parts.push(`pending=${pending.join(',')}`);
|
|
86
|
-
const reason =
|
|
87
|
-
parts.length > 0 ? `gap:${parts.join(';')}` : 'gap:unspecified';
|
|
88
|
-
return { outcome: 'failed', reason };
|
|
89
|
-
}
|
|
90
|
-
// Unknown status — fail closed so the operator sees the surprise.
|
|
91
|
-
return { outcome: 'failed', reason: `unknown-status:${String(status)}` };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* AcceptanceReconciler — instantiate one per Epic run and call
|
|
96
|
-
* `register()` to wire it onto the bus. Stateless w.r.t. the system
|
|
97
|
-
* under orchestration; per-run state is the `(event, seqId)`
|
|
98
|
-
* idempotency cache + the classification log.
|
|
99
|
-
*/
|
|
100
|
-
export class AcceptanceReconciler {
|
|
101
|
-
/**
|
|
102
|
-
* @param {object} opts
|
|
103
|
-
* @param {object} opts.bus Lifecycle bus instance (must expose
|
|
104
|
-
* `on()` and `emit()`).
|
|
105
|
-
* @param {number} opts.epicId Epic ticket id.
|
|
106
|
-
* @param {string} [opts.cwd] Working directory passed through to the
|
|
107
|
-
* reconciler helper. Defaults to `process.cwd()`.
|
|
108
|
-
* @param {object} [opts.provider] Ticketing provider — injected into
|
|
109
|
-
* the reconciler call so the lifecycle bus does not need to
|
|
110
|
-
* construct one itself.
|
|
111
|
-
* @param {object} [opts.config] Resolved orchestration config —
|
|
112
|
-
* injected for the same reason.
|
|
113
|
-
* @param {Function} [opts.reconcileAcceptanceSpecFn] Override of the
|
|
114
|
-
* helper for tests; defaults to the production export.
|
|
115
|
-
* @param {{ info?: Function, warn?: Function, debug?: Function }} [opts.logger]
|
|
116
|
-
*/
|
|
117
|
-
constructor(opts = {}) {
|
|
118
|
-
if (
|
|
119
|
-
!opts.bus ||
|
|
120
|
-
typeof opts.bus.on !== 'function' ||
|
|
121
|
-
typeof opts.bus.emit !== 'function'
|
|
122
|
-
) {
|
|
123
|
-
throw new TypeError(
|
|
124
|
-
'AcceptanceReconciler requires a bus with on() and emit()',
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
if (!Number.isInteger(opts.epicId) || opts.epicId < 1) {
|
|
128
|
-
throw new TypeError('AcceptanceReconciler requires a numeric epicId');
|
|
129
|
-
}
|
|
130
|
-
this.bus = opts.bus;
|
|
131
|
-
this.epicId = opts.epicId;
|
|
132
|
-
this.cwd = opts.cwd ?? process.cwd();
|
|
133
|
-
this.provider = opts.provider ?? null;
|
|
134
|
-
this.config = opts.config ?? null;
|
|
135
|
-
this.reconcileAcceptanceSpecFn =
|
|
136
|
-
opts.reconcileAcceptanceSpecFn ?? defaultReconcileAcceptanceSpec;
|
|
137
|
-
this.logger = opts.logger ?? console;
|
|
138
|
-
/** @type {Set<string>} `${event}:${seqId}` keys we've handled. */
|
|
139
|
-
this._seen = new Set();
|
|
140
|
-
/**
|
|
141
|
-
* Classification log — mirrors the BlockerHandler "no silent skip"
|
|
142
|
-
* surface so tests can confirm every `epic.close.end` we observed
|
|
143
|
-
* was classified into exactly one outcome.
|
|
144
|
-
*
|
|
145
|
-
* @type {Array<{ event: string, seqId: number, outcome: string, reason?: string }>}
|
|
146
|
-
*/
|
|
147
|
-
this.classifications = [];
|
|
148
|
-
this.events = Object.freeze(['epic.close.end']);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Register this listener on the bus. Returns an array of unsubscribe
|
|
153
|
-
* functions (one per event) for test teardown.
|
|
154
|
-
*/
|
|
155
|
-
register() {
|
|
156
|
-
return this.events.map((event) =>
|
|
157
|
-
this.bus.on(event, async (ctx) => this.handle(ctx)),
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Bus listener body. The bus passes `{ event, seqId, payload }`. The
|
|
163
|
-
* listener:
|
|
164
|
-
* 1. Idempotently short-circuits a repeat `(event, seqId)`.
|
|
165
|
-
* 2. Emits `acceptance.reconcile.start`.
|
|
166
|
-
* 3. Runs `reconcileAcceptanceSpec` with injected provider/config.
|
|
167
|
-
* 4. Emits exactly one of `.ok` / `.skipped` / `.failed`.
|
|
168
|
-
* 5. On `.failed`, additionally emits `epic.blocked` so the
|
|
169
|
-
* downstream listener trio (label flip + structured comment +
|
|
170
|
-
* notify) fires the operator-visible blocker side effects.
|
|
171
|
-
*
|
|
172
|
-
* The listener does NOT throw on reconciler failures: the bus's
|
|
173
|
-
* `onFailed` boundary already persists the originating
|
|
174
|
-
* `epic.close.end` record; surfacing a throw here would short-circuit
|
|
175
|
-
* other `epic.close.end` listeners (e.g. trace logger) and is not
|
|
176
|
-
* needed for correctness — the `acceptance.reconcile.failed` +
|
|
177
|
-
* `epic.blocked` emits are the cascade contract.
|
|
178
|
-
*
|
|
179
|
-
* @param {{ event: string, seqId: number, payload: object }} ctx
|
|
180
|
-
*/
|
|
181
|
-
async handle({ event, seqId, payload }) {
|
|
182
|
-
const key = `${event}:${seqId}`;
|
|
183
|
-
if (this._seen.has(key)) {
|
|
184
|
-
this.classifications.push({
|
|
185
|
-
event,
|
|
186
|
-
seqId,
|
|
187
|
-
outcome: 'skipped',
|
|
188
|
-
reason: 'duplicate-seqId',
|
|
189
|
-
});
|
|
190
|
-
this.logger.debug?.(
|
|
191
|
-
`[AcceptanceReconciler] skip duplicate ${key} (idempotent)`,
|
|
192
|
-
);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
this._seen.add(key);
|
|
196
|
-
|
|
197
|
-
const epicIdFromPayload = Number(payload?.epicId);
|
|
198
|
-
const epicId = Number.isInteger(epicIdFromPayload)
|
|
199
|
-
? epicIdFromPayload
|
|
200
|
-
: this.epicId;
|
|
201
|
-
|
|
202
|
-
// 1. Start emit. The downstream ledger-diff `reconcile-ordering`
|
|
203
|
-
// assert checks for `acceptance.reconcile.ok` before `pr.created`,
|
|
204
|
-
// but operators want to see the `.start` marker in the trace too.
|
|
205
|
-
try {
|
|
206
|
-
await this.bus.emit('acceptance.reconcile.start', { epicId });
|
|
207
|
-
} catch (err) {
|
|
208
|
-
// Schema validation against a known-good payload should never
|
|
209
|
-
// throw; if it does, surface and bail — there's no point running
|
|
210
|
-
// the reconciler when we cannot announce its outcome.
|
|
211
|
-
this.classifications.push({
|
|
212
|
-
event,
|
|
213
|
-
seqId,
|
|
214
|
-
outcome: 'failed',
|
|
215
|
-
reason: `start-emit-failed:${err?.message ?? err}`,
|
|
216
|
-
});
|
|
217
|
-
this.logger.warn?.(
|
|
218
|
-
`[AcceptanceReconciler] acceptance.reconcile.start emit failed: ${err?.message ?? err}`,
|
|
219
|
-
);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// 2. Run the reconciler. The helper itself throws on hard errors
|
|
224
|
-
// (no linked spec + no waiver, etc.); convert those into
|
|
225
|
-
// `.failed` emits rather than re-propagating, so the cascade
|
|
226
|
-
// contract holds even when the spec is malformed.
|
|
227
|
-
let result;
|
|
228
|
-
let thrown = null;
|
|
229
|
-
try {
|
|
230
|
-
result = await this.reconcileAcceptanceSpecFn({
|
|
231
|
-
epicId,
|
|
232
|
-
cwd: this.cwd,
|
|
233
|
-
injectedProvider: this.provider ?? undefined,
|
|
234
|
-
injectedConfig: this.config ?? undefined,
|
|
235
|
-
loggerImpl: this.logger,
|
|
236
|
-
// Honour `acceptance::n-a` — the helper already returns
|
|
237
|
-
// `status: 'waived'` for that label, but `skipWhenWaived: true`
|
|
238
|
-
// additionally tolerates a missing acceptance-table section under
|
|
239
|
-
// the waiver (we want the same forgiving stance the inline
|
|
240
|
-
// finalize call had).
|
|
241
|
-
skipWhenWaived: true,
|
|
242
|
-
// Close time is the one place the verification outcome is
|
|
243
|
-
// recorded into the Epic body's ## Acceptance Table section
|
|
244
|
-
// (section-scoped write, Story #4324).
|
|
245
|
-
writeDispositions: true,
|
|
246
|
-
});
|
|
247
|
-
} catch (err) {
|
|
248
|
-
thrown = err;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const baseRead = thrown == null && result != null;
|
|
252
|
-
|
|
253
|
-
if (thrown != null) {
|
|
254
|
-
const reason = `reconcile-threw:${thrown?.message ?? thrown}`;
|
|
255
|
-
await this._emitFailure({ event, seqId, baseRead, reason });
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const classification = classifyReconcileResult(result);
|
|
260
|
-
if (classification.outcome === 'ok') {
|
|
261
|
-
await this._emitOk({ event, seqId, baseRead });
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
if (classification.outcome === 'waived') {
|
|
265
|
-
await this._emitWaived({
|
|
266
|
-
event,
|
|
267
|
-
seqId,
|
|
268
|
-
baseRead,
|
|
269
|
-
reason: classification.reason ?? 'waiver',
|
|
270
|
-
});
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
if (classification.outcome === 'skipped') {
|
|
274
|
-
await this._emitSkipped({
|
|
275
|
-
event,
|
|
276
|
-
seqId,
|
|
277
|
-
baseRead,
|
|
278
|
-
reason: classification.reason ?? 'skipped',
|
|
279
|
-
});
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
await this._emitFailure({
|
|
283
|
-
event,
|
|
284
|
-
seqId,
|
|
285
|
-
baseRead,
|
|
286
|
-
reason: classification.reason ?? 'gap',
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Emit `acceptance.reconcile.ok` and record the classification.
|
|
292
|
-
* Helper carved out so each branch in `handle()` reads as a single
|
|
293
|
-
* decision.
|
|
294
|
-
*/
|
|
295
|
-
async _emitOk({ event, seqId, baseRead }) {
|
|
296
|
-
this.classifications.push({ event, seqId, outcome: 'ok' });
|
|
297
|
-
try {
|
|
298
|
-
await this.bus.emit('acceptance.reconcile.ok', { baseRead });
|
|
299
|
-
} catch (err) {
|
|
300
|
-
this.logger.warn?.(
|
|
301
|
-
`[AcceptanceReconciler] acceptance.reconcile.ok emit failed (swallowed): ${err?.message ?? err}`,
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Emit `acceptance.reconcile.waived` for the `acceptance::n-a` path.
|
|
308
|
-
* Story #2893 split this out of `.skipped` so the Finalizer can
|
|
309
|
-
* subscribe to `.waived` and route waived Epics through to PR
|
|
310
|
-
* creation. The schema pins `reason` to `'waiver'`.
|
|
311
|
-
*/
|
|
312
|
-
async _emitWaived({ event, seqId, baseRead, reason }) {
|
|
313
|
-
this.classifications.push({ event, seqId, outcome: 'waived', reason });
|
|
314
|
-
try {
|
|
315
|
-
await this.bus.emit('acceptance.reconcile.waived', {
|
|
316
|
-
baseRead,
|
|
317
|
-
reason,
|
|
318
|
-
});
|
|
319
|
-
} catch (err) {
|
|
320
|
-
this.logger.warn?.(
|
|
321
|
-
`[AcceptanceReconciler] acceptance.reconcile.waived emit failed (swallowed): ${err?.message ?? err}`,
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Emit `acceptance.reconcile.skipped` carrying a typed `reason`. The
|
|
328
|
-
* schema requires `reason` to be non-empty so callers always pass one
|
|
329
|
-
* (no silent skip).
|
|
330
|
-
*/
|
|
331
|
-
async _emitSkipped({ event, seqId, baseRead, reason }) {
|
|
332
|
-
this.classifications.push({ event, seqId, outcome: 'skipped', reason });
|
|
333
|
-
try {
|
|
334
|
-
await this.bus.emit('acceptance.reconcile.skipped', {
|
|
335
|
-
baseRead,
|
|
336
|
-
reason,
|
|
337
|
-
});
|
|
338
|
-
} catch (err) {
|
|
339
|
-
this.logger.warn?.(
|
|
340
|
-
`[AcceptanceReconciler] acceptance.reconcile.skipped emit failed (swallowed): ${err?.message ?? err}`,
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Emit `acceptance.reconcile.failed` and then `epic.blocked`, in that
|
|
347
|
-
* order. The `epic.blocked` emit drives the LabelTransitioner /
|
|
348
|
-
* StructuredCommentPoster / NotifyDispatcher trio so the operator
|
|
349
|
-
* sees the blocker label flip + structured comment + webhook,
|
|
350
|
-
* exactly as a `story.blocked` cascade would.
|
|
351
|
-
*
|
|
352
|
-
* Failures inside the `epic.blocked` emit are swallowed (the
|
|
353
|
-
* `.failed` record is already on the ledger; double-throwing here
|
|
354
|
-
* would mask the original reason).
|
|
355
|
-
*/
|
|
356
|
-
async _emitFailure({ event, seqId, baseRead, reason }) {
|
|
357
|
-
this.classifications.push({ event, seqId, outcome: 'failed', reason });
|
|
358
|
-
try {
|
|
359
|
-
await this.bus.emit('acceptance.reconcile.failed', {
|
|
360
|
-
baseRead,
|
|
361
|
-
reason,
|
|
362
|
-
});
|
|
363
|
-
} catch (err) {
|
|
364
|
-
this.logger.warn?.(
|
|
365
|
-
`[AcceptanceReconciler] acceptance.reconcile.failed emit failed (swallowed): ${err?.message ?? err}`,
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
await this.bus.emit('epic.blocked', {
|
|
370
|
-
reason: `acceptance-reconcile:${reason}`,
|
|
371
|
-
});
|
|
372
|
-
} catch (err) {
|
|
373
|
-
this.logger.warn?.(
|
|
374
|
-
`[AcceptanceReconciler] epic.blocked emit failed (swallowed): ${err?.message ?? err}`,
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/** Test helper — wipe the idempotency cache. */
|
|
380
|
-
reset() {
|
|
381
|
-
this._seen.clear();
|
|
382
|
-
this.classifications = [];
|
|
383
|
-
}
|
|
384
|
-
}
|