mandrel 1.94.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +116 -99
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +45 -51
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +498 -1287
- package/.agents/docs/agentrc-reference.json +185 -80
- package/.agents/docs/configuration.md +132 -190
- package/.agents/docs/execution-reference.md +51 -25
- package/.agents/docs/quality-gates.md +25 -33
- package/.agents/docs/workflows.md +8 -8
- package/.agents/instructions.md +113 -139
- package/.agents/rules/ci-remediation.md +11 -15
- package/.agents/rules/git-conventions-reference.md +48 -58
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +83 -254
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +22 -66
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +7 -10
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +328 -28
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
- package/.agents/scripts/lib/checks/index.js +3 -2
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +39 -9
- package/.agents/scripts/lib/close-validation/gates.js +15 -15
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +52 -35
- package/.agents/scripts/lib/config/explain.js +61 -48
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +29 -80
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +12 -15
- package/.agents/scripts/lib/config/runners.js +20 -66
- package/.agents/scripts/lib/config/temp-paths.js +30 -63
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
- package/.agents/scripts/lib/config-settings-schema.js +100 -60
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +242 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -190
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
- package/.agents/scripts/lib/git-utils.js +32 -20
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +10 -38
- package/.agents/scripts/lib/label-taxonomy.js +10 -55
- package/.agents/scripts/lib/observability/active-story-env.js +44 -165
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +5 -5
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
- package/.agents/scripts/lib/orchestration/code-review.js +78 -436
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
- package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -281
- package/.agents/scripts/lib/preflight-runner.js +4 -4
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +17 -19
- package/.agents/scripts/lib/story-body/story-body.js +130 -75
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
- package/.agents/scripts/lib/validation-evidence.js +32 -60
- package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +102 -80
- package/.agents/scripts/plan-persist.js +230 -279
- package/.agents/scripts/plan-run-epilogue.js +142 -0
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +13 -39
- package/.agents/scripts/providers/github/mappers.js +5 -12
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -156
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +25 -21
- package/.agents/scripts/single-story-close.js +178 -26
- package/.agents/scripts/single-story-confirm-merge.js +313 -24
- package/.agents/scripts/single-story-init.js +35 -30
- package/.agents/scripts/stories-wave-tick.js +85 -10
- package/.agents/scripts/story-plan.js +28 -49
- package/.agents/scripts/update-ticket-state.js +14 -65
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
- package/.agents/skills/core/scope-triage/SKILL.md +31 -172
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +3 -53
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +6 -7
- package/.agents/workflows/audit-clean-code.md +7 -7
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +9 -10
- package/.agents/workflows/audit-lighthouse.md +11 -3
- package/.agents/workflows/audit-navigability.md +13 -2
- package/.agents/workflows/audit-performance.md +5 -6
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +11 -12
- package/.agents/workflows/audit-security.md +4 -5
- package/.agents/workflows/audit-seo.md +13 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +10 -3
- package/.agents/workflows/deliver.md +177 -176
- package/.agents/workflows/git-cleanup.md +5 -6
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +75 -196
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
- package/.agents/workflows/helpers/deliver-story.md +606 -0
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +3 -3
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +277 -145
- package/.agents/workflows/qa-assist.md +27 -33
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -6
- package/README.md +9 -8
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +70 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +12 -8
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -66
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -464
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- package/.agents/workflows/helpers/single-story-deliver.md +0 -557
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Subscribes to:
|
|
7
7
|
* - `pr.created` → resolve the required-check names from GitHub at
|
|
8
|
-
* runtime via `gh pr checks <pr> --required`,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* expires), then emit `epic.watch.end` with the outcome map.
|
|
8
|
+
* runtime via `gh pr checks <pr> --required`, then poll until every
|
|
9
|
+
* check reaches a terminal state (or a per-listener wall-clock
|
|
10
|
+
* deadline expires), recording the outcome in `classifications`.
|
|
12
11
|
*
|
|
13
12
|
* Critical contract:
|
|
14
13
|
* - Required-check **names** are resolved from `gh pr checks` at
|
|
@@ -28,11 +27,13 @@
|
|
|
28
27
|
* re-runs the poll loop (which is itself idempotent: the outcome map
|
|
29
28
|
* always reflects the live GitHub state).
|
|
30
29
|
*
|
|
31
|
-
* Side-effect firewall: the listener
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
30
|
+
* Side-effect firewall: the listener shells out to `gh` and records
|
|
31
|
+
* its outcome in the in-memory `classifications` log. It does NOT
|
|
32
|
+
* mutate ticket labels, post comments, call `notify`, or emit on the
|
|
33
|
+
* bus — the production consumer (`pr-watch-with-update.js`) drives
|
|
34
|
+
* `watchPrToTerminal` directly without a bus, and the retired
|
|
35
|
+
* `epic.watch.start` / `epic.watch.end` bus events went with the
|
|
36
|
+
* Epic-orchestration stratum.
|
|
36
37
|
*/
|
|
37
38
|
|
|
38
39
|
import { spawnSync } from 'node:child_process';
|
|
@@ -40,20 +41,20 @@ import { spawnSync } from 'node:child_process';
|
|
|
40
41
|
import { parsePrNumberFromUrl } from '../../../github-url.js';
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
* Map `gh pr checks` `state` values to the canonical outcome
|
|
44
|
-
*
|
|
45
|
-
* in-flight checks. Pure — exported for
|
|
46
|
-
* and reviewable.
|
|
44
|
+
* Map `gh pr checks` `state` values to the canonical lowercase outcome
|
|
45
|
+
* vocabulary (`success` | `failure` | `timed_out` | `skipped`), with a
|
|
46
|
+
* fourth `'pending'` sentinel for in-flight checks. Pure — exported for
|
|
47
|
+
* tests so the pin is explicit and reviewable.
|
|
47
48
|
*
|
|
48
49
|
* `gh` returns capitalized SCREAMING_SNAKE values (`SUCCESS`,
|
|
49
|
-
* `FAILURE`, `TIMED_OUT`, etc.)
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* `
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
50
|
+
* `FAILURE`, `TIMED_OUT`, etc.). An empty / queued / in_progress state
|
|
51
|
+
* collapses to `'pending'` so the poll loop can distinguish "still
|
|
52
|
+
* running" from terminal outcomes. `'pending'` is intentionally NOT a
|
|
53
|
+
* terminal outcome — `reduceOutcomes` is called only on the live state,
|
|
54
|
+
* and the final outcome map gates on `allTerminal()` so no `'pending'`
|
|
55
|
+
* ever leaks into a finished watch. Unknown / non-pending unrecognized
|
|
56
|
+
* values collapse to `'skipped'` so any future GitHub state we haven't
|
|
57
|
+
* enumerated still maps into the vocabulary.
|
|
57
58
|
*/
|
|
58
59
|
/**
|
|
59
60
|
* The raw check-state tokens `normalizeCheckState` recognizes (lowercased).
|
|
@@ -264,8 +265,8 @@ export function parseGhPrChecks(stdout) {
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
/**
|
|
267
|
-
* Reduce a list of check entries to the `{ checkName: outcome }`
|
|
268
|
-
*
|
|
268
|
+
* Reduce a list of check entries to the canonical `{ checkName: outcome }`
|
|
269
|
+
* map. Pure — exported for tests.
|
|
269
270
|
*
|
|
270
271
|
* When `gh` returns the same `name` more than once (parallel matrix
|
|
271
272
|
* builds, retries), the LAST entry wins. The poll loop calls this on
|
|
@@ -431,9 +432,9 @@ export async function pollUntilTerminal({
|
|
|
431
432
|
* @param {{status:number,stdout:string,stderr:string}} [opts.firstProbe]
|
|
432
433
|
* Optional already-issued `gh pr checks` result. When the caller (the
|
|
433
434
|
* `Watcher` listener) has already probed once to resolve the required
|
|
434
|
-
* names
|
|
435
|
-
*
|
|
436
|
-
*
|
|
435
|
+
* check names, it threads that result here so the loop does not
|
|
436
|
+
* double-spend the first `gh pr checks` call. Omit it (the CLI path)
|
|
437
|
+
* and the loop issues the first probe itself.
|
|
437
438
|
* @returns {Promise<{
|
|
438
439
|
* outcomes: object,
|
|
439
440
|
* requiredChecks: string[],
|
|
@@ -466,8 +467,8 @@ export async function watchPrToTerminal({
|
|
|
466
467
|
firstProbe,
|
|
467
468
|
}) {
|
|
468
469
|
// First probe: resolve the required-check name set at runtime. Reuse a
|
|
469
|
-
// caller-supplied probe (the listener already issued one
|
|
470
|
-
//
|
|
470
|
+
// caller-supplied probe (the listener already issued one to resolve the
|
|
471
|
+
// required check names) so we never double-spend the first `gh` call.
|
|
471
472
|
const first = firstProbe ?? ghPrChecksFn({ prUrl, cwd });
|
|
472
473
|
// `gh` exits 8 when checks are still pending; this is expected and
|
|
473
474
|
// does not indicate failure. Any other non-zero status with no
|
|
@@ -619,12 +620,8 @@ export class Watcher {
|
|
|
619
620
|
* @param {{ info?: Function, warn?: Function, debug?: Function }} [opts.logger]
|
|
620
621
|
*/
|
|
621
622
|
constructor(opts = {}) {
|
|
622
|
-
if (
|
|
623
|
-
|
|
624
|
-
typeof opts.bus.on !== 'function' ||
|
|
625
|
-
typeof opts.bus.emit !== 'function'
|
|
626
|
-
) {
|
|
627
|
-
throw new TypeError('Watcher requires a bus with on() and emit()');
|
|
623
|
+
if (!opts.bus || typeof opts.bus.on !== 'function') {
|
|
624
|
+
throw new TypeError('Watcher requires a bus with on()');
|
|
628
625
|
}
|
|
629
626
|
this.bus = opts.bus;
|
|
630
627
|
this.cwd = opts.cwd ?? process.cwd();
|
|
@@ -688,11 +685,10 @@ export class Watcher {
|
|
|
688
685
|
return;
|
|
689
686
|
}
|
|
690
687
|
|
|
691
|
-
// First probe: resolve the required-check name set at runtime
|
|
692
|
-
//
|
|
693
|
-
//
|
|
694
|
-
//
|
|
695
|
-
// double-spending the first `gh pr checks` call.
|
|
688
|
+
// First probe: resolve the required-check name set at runtime BEFORE
|
|
689
|
+
// the (potentially long) poll loop runs. We thread this probe into
|
|
690
|
+
// `watchPrToTerminal` (via `firstProbe`) so the shared loop reuses it
|
|
691
|
+
// instead of double-spending the first `gh pr checks` call.
|
|
696
692
|
const first = this.ghPrChecksFn({ prUrl, cwd: this.cwd });
|
|
697
693
|
const firstEntries = parseGhPrChecks(first.stdout);
|
|
698
694
|
if (firstEntries.length === 0 && first.status !== 0 && first.status !== 8) {
|
|
@@ -710,45 +706,24 @@ export class Watcher {
|
|
|
710
706
|
|
|
711
707
|
const requiredChecks = firstEntries.map((e) => e.name);
|
|
712
708
|
|
|
713
|
-
try {
|
|
714
|
-
await this.bus.emit('epic.watch.start', { prUrl, requiredChecks });
|
|
715
|
-
} catch (err) {
|
|
716
|
-
this.classifications.push({
|
|
717
|
-
event,
|
|
718
|
-
seqId,
|
|
719
|
-
outcome: 'failed',
|
|
720
|
-
reason: `start-emit-failed:${err?.message ?? err}`,
|
|
721
|
-
});
|
|
722
|
-
this.logger.warn?.(
|
|
723
|
-
`[Watcher] epic.watch.start emit failed: ${err?.message ?? err}`,
|
|
724
|
-
);
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
|
|
728
709
|
// Delegate the poll + BEHIND-recovery loop to the shared plain
|
|
729
710
|
// primitive so the CLI (`pr-watch-with-update.js`) and this listener
|
|
730
711
|
// run identical logic.
|
|
731
|
-
const {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
ghPrViewFn: this.ghPrViewFn,
|
|
747
|
-
ghPrUpdateBranchFn: this.ghPrUpdateBranchFn,
|
|
748
|
-
sleepFn: this.sleepFn,
|
|
749
|
-
logger: this.logger,
|
|
750
|
-
firstProbe: first,
|
|
751
|
-
});
|
|
712
|
+
const { polls, updatesApplied, resumesApplied, terminal, stillRunning } =
|
|
713
|
+
await watchPrToTerminal({
|
|
714
|
+
prUrl,
|
|
715
|
+
cwd: this.cwd,
|
|
716
|
+
maxPolls: this.maxPolls,
|
|
717
|
+
maxUpdates: this.maxUpdates,
|
|
718
|
+
maxResumes: this.maxResumes,
|
|
719
|
+
pollIntervalMs: this.pollIntervalMs,
|
|
720
|
+
ghPrChecksFn: this.ghPrChecksFn,
|
|
721
|
+
ghPrViewFn: this.ghPrViewFn,
|
|
722
|
+
ghPrUpdateBranchFn: this.ghPrUpdateBranchFn,
|
|
723
|
+
sleepFn: this.sleepFn,
|
|
724
|
+
logger: this.logger,
|
|
725
|
+
firstProbe: first,
|
|
726
|
+
});
|
|
752
727
|
|
|
753
728
|
// `still-running` (slow CI, not red) is a distinct classification from
|
|
754
729
|
// a genuine `timed-out` — reserved for a check that never went
|
|
@@ -768,16 +743,6 @@ export class Watcher {
|
|
|
768
743
|
resumesApplied,
|
|
769
744
|
requiredChecks: requiredChecks.length,
|
|
770
745
|
});
|
|
771
|
-
try {
|
|
772
|
-
await this.bus.emit('epic.watch.end', {
|
|
773
|
-
prUrl,
|
|
774
|
-
checkOutcomes: emitOutcomes,
|
|
775
|
-
});
|
|
776
|
-
} catch (err) {
|
|
777
|
-
this.logger.warn?.(
|
|
778
|
-
`[Watcher] epic.watch.end emit failed (swallowed): ${err?.message ?? err}`,
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
746
|
}
|
|
782
747
|
|
|
783
748
|
reset() {
|
|
@@ -40,28 +40,17 @@ function formatClock(iso) {
|
|
|
40
40
|
* mapping is stable across runs.
|
|
41
41
|
*/
|
|
42
42
|
const PHASE_BY_PREFIX = Object.freeze({
|
|
43
|
-
'epic.snapshot': 'Snapshot',
|
|
44
|
-
'epic.plan': 'Plan',
|
|
45
43
|
'story.dispatch': 'Waves',
|
|
46
44
|
'story.merged': 'Waves',
|
|
47
45
|
'story.blocked': 'Waves',
|
|
48
|
-
'epic.blocked': 'Waves',
|
|
49
|
-
'epic.close': 'Close-tail',
|
|
50
|
-
'acceptance.reconcile': 'Acceptance Reconciliation',
|
|
51
|
-
'epic.finalize': 'Finalize',
|
|
52
46
|
'pr.created': 'Finalize',
|
|
53
|
-
'epic.watch': 'Watch',
|
|
54
|
-
'epic.automerge': 'Automerge',
|
|
55
|
-
'epic.merge': 'Automerge',
|
|
56
|
-
'epic.cleanup': 'Cleanup',
|
|
57
|
-
'epic.complete': 'Complete',
|
|
58
47
|
'notification.emitted': 'Notifications',
|
|
59
48
|
'checkpoint.written': 'Checkpoint',
|
|
60
49
|
});
|
|
61
50
|
|
|
62
51
|
function phaseFor(eventName) {
|
|
63
|
-
// Match longest prefix first so `
|
|
64
|
-
// `
|
|
52
|
+
// Match longest prefix first so `story.dispatch.start` resolves before
|
|
53
|
+
// `story.dispatch` would match an unrelated `story.*` block.
|
|
65
54
|
const keys = Object.keys(PHASE_BY_PREFIX).sort((a, b) => b.length - a.length);
|
|
66
55
|
for (const k of keys) {
|
|
67
56
|
if (eventName === k || eventName.startsWith(`${k}.`)) {
|
|
@@ -277,7 +266,7 @@ export function render(ledger, opts = {}) {
|
|
|
277
266
|
*
|
|
278
267
|
* The wildcard-firewall rule (Tech Spec § Bus contract) requires that
|
|
279
268
|
* trace observers do NOT import any module that mutates GitHub state,
|
|
280
|
-
* the worktree, or the filesystem outside `temp/
|
|
269
|
+
* the worktree, or the filesystem outside `temp/run-<id>/`. This
|
|
281
270
|
* module satisfies that constraint: the only filesystem writes are to
|
|
282
271
|
* the companion path under the same temp directory the ledger lives
|
|
283
272
|
* in.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/orchestration/lint-baseline-service.js
|
|
3
3
|
*
|
|
4
|
-
* Captures the
|
|
5
|
-
* from the inline implementation that used to live in
|
|
6
|
-
* so the coordinator no longer reaches into
|
|
7
|
-
* `node:fs` directly. Tests can exercise the service with a stubbed exec
|
|
4
|
+
* Captures the lint baseline (see `lint-baseline.js capture`). Extracted
|
|
5
|
+
* from the inline implementation that used to live in the deleted
|
|
6
|
+
* `dispatch-engine.js` entry seam so the coordinator no longer reaches into
|
|
7
|
+
* `node:child_process` or `node:fs` directly. Tests can exercise the service with a stubbed exec
|
|
8
8
|
* adapter and no filesystem interaction.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* merge-block-class.js — Story #4426 (Epic #4425, slice 1: foundation).
|
|
4
4
|
*
|
|
5
|
-
* Shared block-class classifier
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* inventing its own ad hoc diagnosis.
|
|
5
|
+
* Shared block-class classifier for the `single-story-close` must-land
|
|
6
|
+
* terminal step and `deliver-recover`, so a headless delivery run that
|
|
7
|
+
* finishes its work without a confirmed merge is attributable to exactly one
|
|
8
|
+
* class from ONE decision logic, instead of each caller inventing its own ad
|
|
9
|
+
* hoc diagnosis. (It was written to serve an epic-path terminal too; the v2
|
|
10
|
+
* cutover left `single-story-close` as the only delivery path.)
|
|
12
11
|
*
|
|
13
12
|
* Block classes (Epic #4425 Goal; `predicate-refused` added by #4472):
|
|
14
13
|
* - `checks-pending-timeout` The watch/poll budget was
|
|
@@ -16,6 +15,24 @@
|
|
|
16
15
|
* were still pending/running — not
|
|
17
16
|
* a hard block, the run simply ran
|
|
18
17
|
* out of time.
|
|
18
|
+
* - `checks-failed` A required check went RED — red
|
|
19
|
+
* checks that branch protection does
|
|
20
|
+
* not require are NOT this class
|
|
21
|
+
* (see `failingChecksBlockMerge`). A
|
|
22
|
+
* definitive terminal the merge wait
|
|
23
|
+
* must fail fast on (Story #4543):
|
|
24
|
+
* before this class the in-close poll
|
|
25
|
+
* read only `state`/`mergedAt`, so a
|
|
26
|
+
* check that failed at minute one
|
|
27
|
+
* burned the entire budget and then
|
|
28
|
+
* classified as
|
|
29
|
+
* `branch-protection-human-required`
|
|
30
|
+
* (the exhaustion probe sees
|
|
31
|
+
* `mergeStateStatus: BLOCKED` with
|
|
32
|
+
* checks settled) — sending the
|
|
33
|
+
* operator to diagnose branch
|
|
34
|
+
* protection instead of the red check
|
|
35
|
+
* that is actually in their way.
|
|
19
36
|
* - `branch-protection-human-required` GitHub reports the PR needs a
|
|
20
37
|
* human action: a required review
|
|
21
38
|
* that hasn't been granted, or a
|
|
@@ -38,7 +55,7 @@
|
|
|
38
55
|
* a red/pending required check, an
|
|
39
56
|
* unreadable check probe, a dirty
|
|
40
57
|
* structured-signal verdict, or a
|
|
41
|
-
* `
|
|
58
|
+
* (retired `requireChecks` policy
|
|
42
59
|
* block on a checks-less repo (#4472).
|
|
43
60
|
* The must-land contract previously
|
|
44
61
|
* only covered post-arm poll
|
|
@@ -47,20 +64,27 @@
|
|
|
47
64
|
* this class makes it attributable.
|
|
48
65
|
*
|
|
49
66
|
* Pure function, no I/O: callers pass in the already-observed
|
|
50
|
-
* arm-result / PR-probe / budget signals (from
|
|
51
|
-
*
|
|
67
|
+
* arm-result / PR-probe / budget signals (from the close path's merge wait,
|
|
68
|
+
* a raw `gh pr view` read, or the standalone
|
|
52
69
|
* `single-story-confirm-merge.js` poll) and get back a
|
|
53
70
|
* `{ blockClass, reason }` verdict ready to hand to `emitMergeUnlanded`
|
|
54
71
|
* (`emit-merge-unlanded.js`).
|
|
55
72
|
*/
|
|
56
73
|
|
|
74
|
+
import { failingChecksBlockMerge } from './merge-poll.js';
|
|
75
|
+
|
|
57
76
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
77
|
+
* Every class `classifyMergeBlock` can return. Order is the evaluation
|
|
78
|
+
* priority documented on `classifyMergeBlock` below, NOT an arbitrary
|
|
79
|
+
* listing — earlier entries are checked first when a real input happens to
|
|
80
|
+
* satisfy more than one heuristic.
|
|
81
|
+
*
|
|
82
|
+
* Started as the four classes named in the Epic #4425 Goal; Story #4543
|
|
83
|
+
* added `checks-failed` so a red required check is attributable as itself
|
|
84
|
+
* rather than being absorbed by the timeout or branch-protection verdicts.
|
|
62
85
|
*/
|
|
63
86
|
export const BLOCK_CLASSES = Object.freeze([
|
|
87
|
+
'checks-failed',
|
|
64
88
|
'checks-pending-timeout',
|
|
65
89
|
'branch-protection-human-required',
|
|
66
90
|
'arm-failure',
|
|
@@ -70,10 +94,12 @@ export const BLOCK_CLASSES = Object.freeze([
|
|
|
70
94
|
/**
|
|
71
95
|
* The full set of block-class values a `merge.unlanded` record may carry.
|
|
72
96
|
* This is the classifier's four outputs PLUS `predicate-refused` (#4472),
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
97
|
+
* emitted DIRECTLY for a headless refusal that never reached the
|
|
98
|
+
* poll-exhaustion classifier — so it is a valid attribution value even though
|
|
99
|
+
* `classifyMergeBlock` never produces it. (The Epic-era listeners that used to
|
|
100
|
+
* emit it, AutomergePredicate and AutomergeArmer, are gone; the value stays
|
|
101
|
+
* because archived `merge.unlanded` records carry it and the schema enum
|
|
102
|
+
* must keep validating them.) `isValidBlockClass` (and the `merge.unlanded` schema enum)
|
|
77
103
|
* validate against this broader set; the classifier's own reachability
|
|
78
104
|
* invariant stays scoped to `BLOCK_CLASSES`.
|
|
79
105
|
*/
|
|
@@ -121,6 +147,12 @@ function describeApiRaceFallback(prProbe, budget) {
|
|
|
121
147
|
if (prProbe?.error) {
|
|
122
148
|
return `PR probe error: ${prProbe.error}`;
|
|
123
149
|
}
|
|
150
|
+
// Red checks that do not gate the merge (step 1b declined them). Name the
|
|
151
|
+
// situation precisely: the operator must NOT be sent to fix the red check,
|
|
152
|
+
// because auto-merge was free to land this PR and did not.
|
|
153
|
+
if (prProbe?.checksStatus === 'failure') {
|
|
154
|
+
return `PR did not land although its failing checks are not required (mergeStateStatus=${prProbe?.mergeStateStatus ?? 'n/a'}); the red checks are not the block — check that auto-merge is still armed`;
|
|
155
|
+
}
|
|
124
156
|
if (budget && budget.exhausted === true) {
|
|
125
157
|
return `watch budget exhausted with an unrecognised checks status (${prProbe?.checksStatus ?? 'unknown'})`;
|
|
126
158
|
}
|
|
@@ -137,6 +169,12 @@ function describeApiRaceFallback(prProbe, budget) {
|
|
|
137
169
|
* rejection surfaced AT arm time still routes to
|
|
138
170
|
* `branch-protection-human-required` rather than the generic
|
|
139
171
|
* `arm-failure`.
|
|
172
|
+
* 1b. A red required check — `checks-failed` (Story #4543). Evaluated
|
|
173
|
+
* before every budget and probe signal because it is *definitive*:
|
|
174
|
+
* no amount of remaining budget turns a failed check green, and on a
|
|
175
|
+
* protected branch it also presents as `mergeStateStatus: 'BLOCKED'`,
|
|
176
|
+
* so leaving it to step 3 would attribute the operator's red test run
|
|
177
|
+
* to branch protection.
|
|
140
178
|
* 2. Budget exhaustion while checks were still in flight —
|
|
141
179
|
* `checks-pending-timeout`. Evaluated BEFORE the human-required
|
|
142
180
|
* probe signals because on a protected branch GitHub reports
|
|
@@ -164,9 +202,10 @@ function describeApiRaceFallback(prProbe, budget) {
|
|
|
164
202
|
* (`REVIEW_REQUIRED`, `APPROVED`, …).
|
|
165
203
|
* @param {string} [input.prProbe.mergeStateStatus] GitHub merge-state
|
|
166
204
|
* status (`BLOCKED`, `BEHIND`, `CLEAN`, …).
|
|
167
|
-
* @param {string} [input.prProbe.checksStatus] Aggregate
|
|
168
|
-
*
|
|
169
|
-
* `still-running` | `failure` | `unknown`)
|
|
205
|
+
* @param {string} [input.prProbe.checksStatus] Aggregate status across ALL
|
|
206
|
+
* checks observed on the last probe (`success` | `pending` |
|
|
207
|
+
* `still-running` | `failure` | `unknown`) — required-ness is decided by
|
|
208
|
+
* `mergeStateStatus`, not by this field.
|
|
170
209
|
* @param {string} [input.prProbe.error] Set when the probe call itself
|
|
171
210
|
* errored (network / API failure reading the PR).
|
|
172
211
|
* @param {object} [input.budget] Poll-budget accounting.
|
|
@@ -205,6 +244,23 @@ export function classifyMergeBlock(input) {
|
|
|
205
244
|
const checksPendingEvidence =
|
|
206
245
|
checksStatus === 'pending' || checksStatus === 'still-running';
|
|
207
246
|
|
|
247
|
+
// 1b. A required check is RED. Definitive — no remaining budget makes a
|
|
248
|
+
// failed check pass — so this precedes both the budget branch and the
|
|
249
|
+
// BLOCKED-merge-state heuristic, which would otherwise attribute the red
|
|
250
|
+
// check to branch protection on any protected base.
|
|
251
|
+
//
|
|
252
|
+
// Gated on `failingChecksBlockMerge` rather than the raw rollup status:
|
|
253
|
+
// `checksStatus: 'failure'` covers optional checks too, and naming an
|
|
254
|
+
// optional red check as THE block sends the operator to fix a check that
|
|
255
|
+
// was never gating the merge. A red-but-not-gating PR that still failed to
|
|
256
|
+
// land falls through to the fallback, whose reason says exactly that.
|
|
257
|
+
if (failingChecksBlockMerge(prProbe)) {
|
|
258
|
+
return {
|
|
259
|
+
blockClass: 'checks-failed',
|
|
260
|
+
reason: `a required check failed (mergeStateStatus=${prProbe?.mergeStateStatus ?? 'n/a'})`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
208
264
|
// 2. Budget exhausted while checks were still in flight. Ordered
|
|
209
265
|
// before the human-required probe signals: `mergeStateStatus:
|
|
210
266
|
// 'BLOCKED'` is the steady state on a protected branch while required
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* merge-poll.js — merge-wait constants and check-rollup derivation owned by
|
|
3
|
+
* the close path.
|
|
4
|
+
*
|
|
5
|
+
* Story #4545 — these three symbols used to live in the Epic-era
|
|
6
|
+
* `lifecycle/listeners/merge-watcher.js`. That listener class had no
|
|
7
|
+
* production caller after the v2.0.0 Story-only cutover, but it was not
|
|
8
|
+
* importer-less: the live close path (`single-story-close/phases/confirm-merge.js`)
|
|
9
|
+
* and `deliver-recover.js` both reached into it for the poll defaults and
|
|
10
|
+
* `deriveChecksStatus`. Relocating them here lets the listener go without
|
|
11
|
+
* leaving the close path importing a lifecycle module it does not otherwise
|
|
12
|
+
* participate in.
|
|
13
|
+
*
|
|
14
|
+
* Sits beside `merge-block-class.js`, its sole consumer pairing:
|
|
15
|
+
* `deriveChecksStatus` produces the `prProbe.checksStatus` value that
|
|
16
|
+
* `classifyMergeBlock` reads.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default poll interval and cumulative budget for the merge wait. The schema
|
|
21
|
+
* in `.agents/schemas/agentrc.schema.json` exposes these as
|
|
22
|
+
* `delivery.mergeWatch.intervalSeconds` (default 30) and
|
|
23
|
+
* `delivery.mergeWatch.maxBudgetSeconds` (default 3600). Hard-coding the same
|
|
24
|
+
* numbers here keeps the close path self-contained when no config is wired in
|
|
25
|
+
* (e.g. unit tests).
|
|
26
|
+
*/
|
|
27
|
+
export const DEFAULT_INTERVAL_SECONDS = 30;
|
|
28
|
+
export const DEFAULT_MAX_BUDGET_SECONDS = 3600;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Pure: derive an aggregate `checksStatus` (`success` | `still-running` |
|
|
32
|
+
* `failure` | `unknown`) from a `statusCheckRollup` array (`gh pr view --json
|
|
33
|
+
* statusCheckRollup` shape: `{ status, conclusion }` per check). Mirrors the
|
|
34
|
+
* values `classifyMergeBlock` expects on `prProbe.checksStatus`.
|
|
35
|
+
*
|
|
36
|
+
* **Scope: EVERY check reported on the PR, required or not.** The rollup
|
|
37
|
+
* carries no required-vs-optional discriminator (`gh`'s projection has no
|
|
38
|
+
* `isRequired` field), so `failure` here means "something on this PR is red",
|
|
39
|
+
* NOT "the merge is blocked". Use {@link failingChecksBlockMerge} before
|
|
40
|
+
* treating a `failure` as terminal.
|
|
41
|
+
*/
|
|
42
|
+
export function deriveChecksStatus(statusCheckRollup) {
|
|
43
|
+
if (!Array.isArray(statusCheckRollup) || statusCheckRollup.length === 0) {
|
|
44
|
+
return 'unknown';
|
|
45
|
+
}
|
|
46
|
+
let anyPending = false;
|
|
47
|
+
for (const check of statusCheckRollup) {
|
|
48
|
+
const conclusion = String(check?.conclusion ?? '').toUpperCase();
|
|
49
|
+
const status = String(check?.status ?? '').toUpperCase();
|
|
50
|
+
if (['FAILURE', 'CANCELLED', 'TIMED_OUT', 'ERROR'].includes(conclusion)) {
|
|
51
|
+
return 'failure';
|
|
52
|
+
}
|
|
53
|
+
if (status !== 'COMPLETED') {
|
|
54
|
+
anyPending = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return anyPending ? 'still-running' : 'success';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The one `mergeStateStatus` value that means GitHub itself is gating the
|
|
62
|
+
* merge. See {@link failingChecksBlockMerge}.
|
|
63
|
+
*/
|
|
64
|
+
const MERGE_GATED_STATE = 'BLOCKED';
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Pure: does the PR's RED check status actually gate the merge?
|
|
68
|
+
*
|
|
69
|
+
* `deriveChecksStatus` aggregates the whole rollup, so it reports `failure`
|
|
70
|
+
* for a red check of any kind. Branch protection — and therefore GitHub
|
|
71
|
+
* native auto-merge — gates only on REQUIRED checks. A red optional check
|
|
72
|
+
* (an advisory bot, or a `CANCELLED` superseded workflow run, which the
|
|
73
|
+
* rollup derivation counts as a failure) says nothing about whether the PR
|
|
74
|
+
* will land: auto-merge lands it regardless. Treating that as terminal is
|
|
75
|
+
* what stranded a Story `agent::blocked` on a PR that merged anyway.
|
|
76
|
+
*
|
|
77
|
+
* `mergeStateStatus` is GitHub's own verdict, computed against the live
|
|
78
|
+
* branch-protection rules, so it supplies the required-vs-optional
|
|
79
|
+
* discrimination the rollup lacks:
|
|
80
|
+
*
|
|
81
|
+
* - `BLOCKED` — merging is gated. With red checks observed, the red
|
|
82
|
+
* required check is the gate.
|
|
83
|
+
* - `UNSTABLE` — "mergeable with non-passing commit status": the red
|
|
84
|
+
* checks are NOT required. Auto-merge will land it.
|
|
85
|
+
* - `CLEAN` / `BEHIND` / `UNKNOWN` / absent — not evidence that the red
|
|
86
|
+
* check gates the merge.
|
|
87
|
+
*
|
|
88
|
+
* Deliberately conservative: only `BLOCKED` returns `true`. A transient
|
|
89
|
+
* `UNKNOWN` (GitHub has not finished computing the merge state) or a token
|
|
90
|
+
* that cannot see the field degrades to "keep waiting" — the caller's poll
|
|
91
|
+
* budget still bounds the wait and the budget-exhausted classification still
|
|
92
|
+
* fires. The asymmetry is intentional: failing to fail fast costs poll time,
|
|
93
|
+
* whereas failing fast wrongly costs a merged-but-`agent::blocked` strand
|
|
94
|
+
* that only an operator can unpick.
|
|
95
|
+
*
|
|
96
|
+
* @param {{ checksStatus?: string, mergeStateStatus?: string }} [prProbe]
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
export function failingChecksBlockMerge(prProbe) {
|
|
100
|
+
if (prProbe?.checksStatus !== 'failure') return false;
|
|
101
|
+
return (
|
|
102
|
+
String(prProbe?.mergeStateStatus ?? '').toUpperCase() === MERGE_GATED_STATE
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* phase-runner.js — Lightweight wrappers for "named phase" error handling.
|
|
3
3
|
*
|
|
4
|
-
* Many orchestration entry points (story-init
|
|
5
|
-
*
|
|
4
|
+
* Many orchestration entry points (`single-story-init.js`,
|
|
5
|
+
* `single-story-close.js`, and other phase modules) repeat the same
|
|
6
|
+
* `try { ... } catch (err) {
|
|
6
7
|
* logger.error('[phase=foo] ' + err.message); ... }` block. These two
|
|
7
8
|
* helpers consolidate that pattern.
|
|
8
9
|
*
|