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
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* post-merge-pipeline.js — sequencer for the post-merge phases of
|
|
3
|
-
* `story-close`.
|
|
4
|
-
*
|
|
5
|
-
* After the Story branch is merged into the Epic branch, several best-effort
|
|
6
|
-
* cleanup + reporting phases must run:
|
|
7
|
-
*
|
|
8
|
-
* 1. worktree-reap — remove the per-Story worktree.
|
|
9
|
-
* 2. branch-cleanup — delete the Story branch (local + remote).
|
|
10
|
-
* 3. ticket-closure — transition the Story to agent::done
|
|
11
|
-
* and run cascade completion.
|
|
12
|
-
* 4. notification — fire the story-complete webhook.
|
|
13
|
-
* 5. dashboard-refresh — regenerate the dispatch manifest.
|
|
14
|
-
* 6. temp-cleanup — delete the per-Story manifest pair under
|
|
15
|
-
* `temp/epic-<eid>/stories/story-<sid>/manifest.{md,json}`
|
|
16
|
-
* (Epic #1030 Story #1040). Falls back to the
|
|
17
|
-
* legacy flat `temp/story-manifest-<id>.{md,json}`
|
|
18
|
-
* layout when `epicId` is unknown — both paths
|
|
19
|
-
* are tried so partial migrations don't leak
|
|
20
|
-
* files in either layout.
|
|
21
|
-
* 7. detectors — fire rework + retry signal detectors against
|
|
22
|
-
* this Story's `traces.ndjson` and persist each
|
|
23
|
-
* emission to `signals.ndjson` BEFORE the
|
|
24
|
-
* analyzer renders the perf-summary comment.
|
|
25
|
-
* 8. perf-summary — shell out to `analyze-execution.js` so the
|
|
26
|
-
* analyzer is the single writer of the
|
|
27
|
-
* `<!-- structured:story-perf-summary -->`
|
|
28
|
-
* comment on the Story ticket.
|
|
29
|
-
*
|
|
30
|
-
* Each phase is wrapped by `runPhase` so a single failure does not abort
|
|
31
|
-
* the rest of the close-out — the same best-effort contract that the
|
|
32
|
-
* pre-extraction inline code provided. Phase return values are merged into
|
|
33
|
-
* a `state` object whose shape `runStoryClose` consumes to build the final
|
|
34
|
-
* structured result.
|
|
35
|
-
*
|
|
36
|
-
* The phase implementations live under `./post-merge/phases/` (one file
|
|
37
|
-
* per phase) — this module is a pure sequencer that imports each phase,
|
|
38
|
-
* re-exports them for backwards compatibility, and runs them in order
|
|
39
|
-
* via `runPhase`.
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
import { execFileSync } from 'node:child_process';
|
|
43
|
-
import path from 'node:path';
|
|
44
|
-
import { Logger } from '../Logger.js';
|
|
45
|
-
import { detectorsPhase } from './detectors-phase.js';
|
|
46
|
-
import { runPhase } from './phase-runner.js';
|
|
47
|
-
import { branchCleanupPhase } from './post-merge/phases/branch-cleanup.js';
|
|
48
|
-
import { dashboardRefreshPhase } from './post-merge/phases/dashboard-refresh.js';
|
|
49
|
-
import { notificationPhase } from './post-merge/phases/notification.js';
|
|
50
|
-
import { tempCleanupPhase } from './post-merge/phases/temp-cleanup.js';
|
|
51
|
-
import { ticketClosurePhase } from './post-merge/phases/ticket-closure.js';
|
|
52
|
-
import {
|
|
53
|
-
createWorktreeReapState,
|
|
54
|
-
worktreeReapPhase,
|
|
55
|
-
} from './post-merge/phases/worktree-reap.js';
|
|
56
|
-
|
|
57
|
-
export {
|
|
58
|
-
branchCleanupPhase,
|
|
59
|
-
dashboardRefreshPhase,
|
|
60
|
-
detectorsPhase,
|
|
61
|
-
notificationPhase,
|
|
62
|
-
tempCleanupPhase,
|
|
63
|
-
ticketClosurePhase,
|
|
64
|
-
worktreeReapPhase,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
function reapPhaseLogger(progress) {
|
|
68
|
-
return progress ?? (() => {});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* perfSummaryPhase — shells out to `analyze-execution.js --story <sid>
|
|
73
|
-
* --epic <eid> --phase-timings <path>` so the analyzer is the single
|
|
74
|
-
* writer of the `<!-- structured:story-perf-summary -->` comment on the
|
|
75
|
-
* Story ticket (Epic #1030 Story #1046). Replaces the legacy
|
|
76
|
-
* `<!-- structured:phase-timings -->` post that lived inline in
|
|
77
|
-
* `post-merge-close.js`.
|
|
78
|
-
*
|
|
79
|
-
* Best-effort: any failure (missing analyzer, non-zero exit, no path
|
|
80
|
-
* supplied) logs a warning and resolves — the merge has already
|
|
81
|
-
* succeeded and we would rather lose the perf summary than roll back
|
|
82
|
-
* closure.
|
|
83
|
-
*
|
|
84
|
-
* @param {{
|
|
85
|
-
* storyId: number|string,
|
|
86
|
-
* epicId: number|string,
|
|
87
|
-
* phaseTimingsPath: string|null|undefined,
|
|
88
|
-
* projectRoot?: string,
|
|
89
|
-
* progress?: Function,
|
|
90
|
-
* logger?: object,
|
|
91
|
-
* spawnFn?: typeof execFileSync,
|
|
92
|
-
* }} ctx
|
|
93
|
-
* @returns {Promise<{ status: 'ok'|'skipped'|'failed', reason?: string }>}
|
|
94
|
-
*/
|
|
95
|
-
export async function perfSummaryPhase(ctx) {
|
|
96
|
-
const {
|
|
97
|
-
storyId,
|
|
98
|
-
epicId,
|
|
99
|
-
phaseTimingsPath,
|
|
100
|
-
projectRoot,
|
|
101
|
-
progress,
|
|
102
|
-
logger,
|
|
103
|
-
spawnFn = execFileSync,
|
|
104
|
-
} = ctx;
|
|
105
|
-
const log = reapPhaseLogger(progress);
|
|
106
|
-
if (!phaseTimingsPath) {
|
|
107
|
-
log('PERF', '⏭️ Skipping perf-summary (no phase-timings path provided)');
|
|
108
|
-
return { status: 'skipped', reason: 'no-phase-timings-path' };
|
|
109
|
-
}
|
|
110
|
-
const root = projectRoot ?? process.cwd();
|
|
111
|
-
const analyzerPath = path.join(
|
|
112
|
-
root,
|
|
113
|
-
'.agents',
|
|
114
|
-
'scripts',
|
|
115
|
-
'analyze-execution.js',
|
|
116
|
-
);
|
|
117
|
-
const args = [
|
|
118
|
-
analyzerPath,
|
|
119
|
-
'--story',
|
|
120
|
-
String(storyId),
|
|
121
|
-
'--epic',
|
|
122
|
-
String(epicId),
|
|
123
|
-
'--phase-timings',
|
|
124
|
-
phaseTimingsPath,
|
|
125
|
-
];
|
|
126
|
-
log(
|
|
127
|
-
'PERF',
|
|
128
|
-
`Running analyzer: analyze-execution.js --story ${storyId} --epic ${epicId}`,
|
|
129
|
-
);
|
|
130
|
-
try {
|
|
131
|
-
spawnFn(process.execPath, args, {
|
|
132
|
-
cwd: root,
|
|
133
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
134
|
-
});
|
|
135
|
-
log('PERF', '✅ story-perf-summary posted');
|
|
136
|
-
return { status: 'ok' };
|
|
137
|
-
} catch (err) {
|
|
138
|
-
const reason = err?.message ?? String(err);
|
|
139
|
-
logger?.warn?.(
|
|
140
|
-
`[post-merge-pipeline] ⚠️ analyze-execution failed (non-fatal): ${reason}`,
|
|
141
|
-
);
|
|
142
|
-
return { status: 'failed', reason };
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export const DEFAULT_POST_MERGE_PHASES = Object.freeze([
|
|
147
|
-
{
|
|
148
|
-
name: 'worktree-reap',
|
|
149
|
-
fn: worktreeReapPhase,
|
|
150
|
-
stateKey: 'worktreeReap',
|
|
151
|
-
fallback: createWorktreeReapState({
|
|
152
|
-
status: 'failed',
|
|
153
|
-
reason: 'phase-error',
|
|
154
|
-
}),
|
|
155
|
-
},
|
|
156
|
-
{ name: 'branch-cleanup', fn: branchCleanupPhase, stateKey: 'branchCleanup' },
|
|
157
|
-
{ name: 'ticket-closure', fn: ticketClosurePhase, stateKey: 'ticketClosure' },
|
|
158
|
-
{ name: 'notification', fn: notificationPhase },
|
|
159
|
-
{
|
|
160
|
-
name: 'dashboard-refresh',
|
|
161
|
-
fn: dashboardRefreshPhase,
|
|
162
|
-
stateKey: 'manifestUpdated',
|
|
163
|
-
},
|
|
164
|
-
{ name: 'temp-cleanup', fn: tempCleanupPhase },
|
|
165
|
-
// Detectors MUST run before `perf-summary`. The perf phase shells out
|
|
166
|
-
// to `analyze-execution.js`, which reads the per-Story signals stream
|
|
167
|
-
// to author the `<!-- structured:story-perf-summary -->` comment;
|
|
168
|
-
// emitting rework/retry events first ensures the rendered surface
|
|
169
|
-
// reflects this Story's signals.
|
|
170
|
-
{ name: 'detectors', fn: detectorsPhase, stateKey: 'detectors' },
|
|
171
|
-
{ name: 'perf-summary', fn: perfSummaryPhase, stateKey: 'perfSummary' },
|
|
172
|
-
]);
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Sequence the post-merge phases of `story-close`. Every phase runs
|
|
176
|
-
* under `runPhase` so a single failure logs `[phase=<name>] <err>` and the
|
|
177
|
-
* pipeline keeps going. Each phase's return value is recorded under its
|
|
178
|
-
* `stateKey` (when defined) on the returned state object.
|
|
179
|
-
*
|
|
180
|
-
* @param {object} ctx Phase collaborators (provider, notify,
|
|
181
|
-
* logger, progress, etc.).
|
|
182
|
-
* @param {Array<{name: string, fn: Function, stateKey?: string, fallback?: any}>} [phases]
|
|
183
|
-
* Phase descriptors. Defaults to `DEFAULT_POST_MERGE_PHASES`.
|
|
184
|
-
* @returns {Promise<object>} Aggregated state from each phase.
|
|
185
|
-
*/
|
|
186
|
-
export async function runPostMergePipeline(
|
|
187
|
-
ctx,
|
|
188
|
-
phases = DEFAULT_POST_MERGE_PHASES,
|
|
189
|
-
) {
|
|
190
|
-
const logger = ctx.logger ?? Logger;
|
|
191
|
-
const state = {
|
|
192
|
-
worktreeReap: createWorktreeReapState(),
|
|
193
|
-
branchCleanup: { localDeleted: false, remoteDeleted: false },
|
|
194
|
-
ticketClosure: { closedTickets: [], cascadedTo: [], cascadeFailed: [] },
|
|
195
|
-
manifestUpdated: false,
|
|
196
|
-
};
|
|
197
|
-
for (const phase of phases) {
|
|
198
|
-
const value = await runPhase(phase.name, () => phase.fn(ctx, state), {
|
|
199
|
-
logger,
|
|
200
|
-
fallback: phase.fallback,
|
|
201
|
-
});
|
|
202
|
-
if (phase.stateKey && value !== undefined) state[phase.stateKey] = value;
|
|
203
|
-
}
|
|
204
|
-
return state;
|
|
205
|
-
}
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* preflight-cache.js — Epic #3019 / Story #3027.
|
|
3
|
-
*
|
|
4
|
-
* Cache adapter for the snapshot/DAG envelope produced by
|
|
5
|
-
* `epic-deliver-preflight.js` so `epic-deliver-prepare.js` can skip the
|
|
6
|
-
* second walk of Epic → Story when the underlying Epic ticket
|
|
7
|
-
* has not drifted between the two operator invocations.
|
|
8
|
-
*
|
|
9
|
-
* Contract:
|
|
10
|
-
* - Cache file lives at `<cwd>/temp/epic-<epicId>/preflight-snapshot.json`.
|
|
11
|
-
* - Envelope shape:
|
|
12
|
-
* {
|
|
13
|
-
* epicId: number,
|
|
14
|
-
* baseSha: string, // deterministic fingerprint of the Epic
|
|
15
|
-
* // snapshot returned by provider.getTicket
|
|
16
|
-
* capturedAt: string, // ISO-8601 timestamp
|
|
17
|
-
* epic: object, // the snapshot from runSnapshotPhase
|
|
18
|
-
* stories: object[], // the open Story tickets from runBuildWaveDagPhase
|
|
19
|
-
* waves: Array<Array<object>>, // wave DAG (ids + labels preserved)
|
|
20
|
-
* }
|
|
21
|
-
* - `computeBaseSha(epic)` derives the cache key from the same provider
|
|
22
|
-
* call (`getTicket(epicId)`) used to walk the hierarchy. The hash
|
|
23
|
-
* covers the Epic's id, body, labels (sorted), and (when present)
|
|
24
|
-
* `updatedAt` — the same fields that drive Story discovery and the
|
|
25
|
-
* acceptance start gate (the Epic body's ## Acceptance Table).
|
|
26
|
-
* - Cache miss is signalled by `readCache` returning `null`. Callers
|
|
27
|
-
* MUST fall back to a fresh snapshot/DAG pass.
|
|
28
|
-
* - `writeCache` creates the parent directory recursively and writes
|
|
29
|
-
* atomically (write to `<path>.tmp` then rename).
|
|
30
|
-
*
|
|
31
|
-
* The module is pure JS / node:fs — no provider dependency — so tests
|
|
32
|
-
* can exercise it without spinning up a GitHub mock.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
import { createHash } from 'node:crypto';
|
|
36
|
-
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
37
|
-
import path from 'node:path';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Resolve the on-disk path for an Epic's preflight cache.
|
|
41
|
-
*
|
|
42
|
-
* @param {{ epicId: number, cwd?: string }} args
|
|
43
|
-
* @returns {string}
|
|
44
|
-
*/
|
|
45
|
-
export function preflightCachePath({ epicId, cwd }) {
|
|
46
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
47
|
-
throw new TypeError(
|
|
48
|
-
'preflightCachePath: epicId must be a positive integer',
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
const root = cwd ?? process.cwd();
|
|
52
|
-
return path.join(root, 'temp', `epic-${epicId}`, 'preflight-snapshot.json');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Per-ticket fingerprint fields shared by the Epic and each Story in the
|
|
57
|
-
* cache key: id, body, sorted labels, and updatedAt. Story bodies carry
|
|
58
|
-
* the dependency edges, so hashing them means a Story-dependency edit
|
|
59
|
-
* forces a cache miss (Story #4019 — the previous Epic-only key let
|
|
60
|
-
* dependency edits slip through unnoticed).
|
|
61
|
-
*
|
|
62
|
-
* @param {{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }} ticket
|
|
63
|
-
* @returns {{ id: number|string|null, body: string, labels: string[], updatedAt: string|null }}
|
|
64
|
-
*/
|
|
65
|
-
function ticketFingerprint(ticket) {
|
|
66
|
-
const t = ticket && typeof ticket === 'object' ? ticket : {};
|
|
67
|
-
return {
|
|
68
|
-
id: t.id ?? t.number ?? null,
|
|
69
|
-
body: typeof t.body === 'string' ? t.body : '',
|
|
70
|
-
labels: Array.isArray(t.labels) ? [...t.labels].map(String).sort() : [],
|
|
71
|
-
updatedAt: typeof t.updatedAt === 'string' ? t.updatedAt : null,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Stable string fingerprint of an Epic snapshot **plus its Story
|
|
77
|
-
* dependency state**. The hash is keyed on the exact fields
|
|
78
|
-
* `runSnapshotPhase` reads (`getTicket(epicId)` return value) and on each
|
|
79
|
-
* Story's id/body/labels/updatedAt, so that any drift the snapshot or
|
|
80
|
-
* wave-DAG phases would observe — including a Story-dependency edit —
|
|
81
|
-
* forces a cache miss (Story #4019).
|
|
82
|
-
*
|
|
83
|
-
* Labels are sorted to absorb GitHub's non-deterministic label order
|
|
84
|
-
* across responses; stories are sorted by id so enumeration order never
|
|
85
|
-
* perturbs the key. The hash is sha256; we return the full hex digest so
|
|
86
|
-
* the cache key is collision-resistant for the lifetime of a delivery.
|
|
87
|
-
*
|
|
88
|
-
* @param {{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }} epic
|
|
89
|
-
* @param {Array<{ id?: number|string, number?: number|string, body?: string, labels?: string[], updatedAt?: string }>} [stories]
|
|
90
|
-
* @returns {string}
|
|
91
|
-
*/
|
|
92
|
-
export function computeBaseSha(epic, stories = []) {
|
|
93
|
-
if (!epic || typeof epic !== 'object') {
|
|
94
|
-
throw new TypeError('computeBaseSha: epic snapshot must be an object');
|
|
95
|
-
}
|
|
96
|
-
const epicPrint = ticketFingerprint(epic);
|
|
97
|
-
const storyPrints = (Array.isArray(stories) ? stories : [])
|
|
98
|
-
.map(ticketFingerprint)
|
|
99
|
-
.sort((a, b) => Number(a.id ?? 0) - Number(b.id ?? 0));
|
|
100
|
-
const payload = JSON.stringify({ ...epicPrint, stories: storyPrints });
|
|
101
|
-
return createHash('sha256').update(payload).digest('hex');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Read the cached preflight envelope from disk. Returns `null` when the
|
|
106
|
-
* file is missing or unreadable — callers MUST treat that as a cache
|
|
107
|
-
* miss and fall back to a fresh snapshot/DAG pass.
|
|
108
|
-
*
|
|
109
|
-
* The function intentionally swallows `ENOENT` and JSON-parse errors so
|
|
110
|
-
* a stale or partially-written file does not poison `epic-deliver-prepare`.
|
|
111
|
-
*
|
|
112
|
-
* @param {{ epicId: number, cwd?: string }} args
|
|
113
|
-
* @returns {Promise<object | null>}
|
|
114
|
-
*/
|
|
115
|
-
export async function readPreflightCache({ epicId, cwd }) {
|
|
116
|
-
const cachePath = preflightCachePath({ epicId, cwd });
|
|
117
|
-
let raw;
|
|
118
|
-
try {
|
|
119
|
-
raw = await readFile(cachePath, 'utf8');
|
|
120
|
-
} catch (err) {
|
|
121
|
-
if (err && err.code === 'ENOENT') return null;
|
|
122
|
-
throw err;
|
|
123
|
-
}
|
|
124
|
-
try {
|
|
125
|
-
const parsed = JSON.parse(raw);
|
|
126
|
-
if (!parsed || typeof parsed !== 'object') return null;
|
|
127
|
-
if (parsed.epicId !== epicId) return null;
|
|
128
|
-
if (typeof parsed.baseSha !== 'string' || !parsed.baseSha) return null;
|
|
129
|
-
if (!parsed.epic || typeof parsed.epic !== 'object') return null;
|
|
130
|
-
if (!Array.isArray(parsed.stories)) return null;
|
|
131
|
-
if (!Array.isArray(parsed.waves)) return null;
|
|
132
|
-
return parsed;
|
|
133
|
-
} catch {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Persist the preflight envelope to disk. Writes atomically via tmp +
|
|
140
|
-
* rename so concurrent readers never observe a partial file.
|
|
141
|
-
*
|
|
142
|
-
* @param {{ epicId: number, baseSha: string, epic: object, stories: object[], waves: Array<Array<object>>, cwd?: string, capturedAt?: string }} args
|
|
143
|
-
* @returns {Promise<{ cachePath: string, baseSha: string }>}
|
|
144
|
-
*/
|
|
145
|
-
export async function writePreflightCache({
|
|
146
|
-
epicId,
|
|
147
|
-
baseSha,
|
|
148
|
-
epic,
|
|
149
|
-
stories,
|
|
150
|
-
waves,
|
|
151
|
-
cwd,
|
|
152
|
-
capturedAt,
|
|
153
|
-
}) {
|
|
154
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
155
|
-
throw new TypeError(
|
|
156
|
-
'writePreflightCache: epicId must be a positive integer',
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
if (typeof baseSha !== 'string' || !baseSha) {
|
|
160
|
-
throw new TypeError(
|
|
161
|
-
'writePreflightCache: baseSha must be a non-empty string',
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
if (!epic || typeof epic !== 'object') {
|
|
165
|
-
throw new TypeError('writePreflightCache: epic must be an object');
|
|
166
|
-
}
|
|
167
|
-
if (!Array.isArray(stories)) {
|
|
168
|
-
throw new TypeError('writePreflightCache: stories must be an array');
|
|
169
|
-
}
|
|
170
|
-
if (!Array.isArray(waves)) {
|
|
171
|
-
throw new TypeError('writePreflightCache: waves must be an array');
|
|
172
|
-
}
|
|
173
|
-
const cachePath = preflightCachePath({ epicId, cwd });
|
|
174
|
-
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
175
|
-
const envelope = {
|
|
176
|
-
epicId,
|
|
177
|
-
baseSha,
|
|
178
|
-
capturedAt: capturedAt ?? new Date().toISOString(),
|
|
179
|
-
epic,
|
|
180
|
-
stories,
|
|
181
|
-
waves,
|
|
182
|
-
};
|
|
183
|
-
const tmp = `${cachePath}.tmp`;
|
|
184
|
-
await writeFile(tmp, `${JSON.stringify(envelope, null, 2)}\n`, 'utf8');
|
|
185
|
-
await rename(tmp, cachePath);
|
|
186
|
-
return { cachePath, baseSha };
|
|
187
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
// .agents/scripts/lib/orchestration/recurring-failure-detector.js
|
|
2
|
-
/**
|
|
3
|
-
* recurring-failure-detector.js — Story #3062 / Epic #3051.
|
|
4
|
-
*
|
|
5
|
-
* Pure helper that scans a per-Epic lifecycle ledger for
|
|
6
|
-
* `close-validate.end` `emitted` records and groups them by `failedGate`.
|
|
7
|
-
* Returns one finding per gate that appears in **two or more distinct
|
|
8
|
-
* Stories** within the same Epic. Findings are the substrate
|
|
9
|
-
* `/deliver` consumes when upserting the cross-Story
|
|
10
|
-
* `recurring-failure-class` structured comment on the Epic ticket.
|
|
11
|
-
*
|
|
12
|
-
* The helper is intentionally pure: no GitHub I/O, no global state. It
|
|
13
|
-
* accepts either a pre-parsed `records[]` array (the hot path used by
|
|
14
|
-
* `wave-tick` once it has already read the ledger for its in-flight
|
|
15
|
-
* reconciliation) or a `ledgerPath` string (the convenience path that
|
|
16
|
-
* reads + parses NDJSON on its own). When both are supplied,
|
|
17
|
-
* `records` wins — the caller already paid the parse cost.
|
|
18
|
-
*
|
|
19
|
-
* Finding shape (sorted lexicographically by `gate` for determinism):
|
|
20
|
-
*
|
|
21
|
-
* { gate: string, storyIds: number[], firstSeenAt: string, lastSeenAt: string }
|
|
22
|
-
*
|
|
23
|
-
* - `storyIds` is the deduplicated, ascending list of Story IDs that
|
|
24
|
-
* recorded a `close-validate.end` with `ok: false` and this gate.
|
|
25
|
-
* - `firstSeenAt` / `lastSeenAt` are ISO-8601 strings pulled from the
|
|
26
|
-
* ledger record's top-level `ts` (set by `LedgerWriter.buildEmitted`),
|
|
27
|
-
* which is the canonical wall-clock for the event.
|
|
28
|
-
*
|
|
29
|
-
* @module lib/orchestration/recurring-failure-detector
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Detect recurring failure classes across Stories within one Epic.
|
|
36
|
-
*
|
|
37
|
-
* @param {number} epicId Positive integer — the Epic the ledger belongs
|
|
38
|
-
* to. Used only for validation (the helper does not filter records by
|
|
39
|
-
* epicId; the ledger is already epic-scoped on disk).
|
|
40
|
-
* @param {object} [opts]
|
|
41
|
-
* @param {Array<object>} [opts.records] Pre-parsed NDJSON records. Each
|
|
42
|
-
* entry is the object emitted by `LedgerWriter.buildEmitted`
|
|
43
|
-
* (`{ kind, seqId, ts, event, payload }`).
|
|
44
|
-
* @param {string} [opts.ledgerPath] Filesystem path to `lifecycle.ndjson`.
|
|
45
|
-
* Read + parsed only when `records` is absent. A missing file returns
|
|
46
|
-
* an empty findings array (no throw).
|
|
47
|
-
* @returns {Array<{gate: string, storyIds: number[], firstSeenAt: string, lastSeenAt: string}>}
|
|
48
|
-
*/
|
|
49
|
-
export function detectRecurringFailures(epicId, opts = {}) {
|
|
50
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
51
|
-
throw new TypeError(
|
|
52
|
-
'detectRecurringFailures: epicId must be a positive integer',
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
const records = resolveRecords(opts);
|
|
56
|
-
if (records.length === 0) return [];
|
|
57
|
-
|
|
58
|
-
/** @type {Map<string, {storyIds: Set<number>, firstSeenAt: string, lastSeenAt: string}>} */
|
|
59
|
-
const byGate = new Map();
|
|
60
|
-
for (const record of records) {
|
|
61
|
-
const finding = extractFailedGateRecord(record);
|
|
62
|
-
if (!finding) continue;
|
|
63
|
-
const { gate, storyId, ts } = finding;
|
|
64
|
-
const bucket = byGate.get(gate);
|
|
65
|
-
if (!bucket) {
|
|
66
|
-
byGate.set(gate, {
|
|
67
|
-
storyIds: new Set([storyId]),
|
|
68
|
-
firstSeenAt: ts,
|
|
69
|
-
lastSeenAt: ts,
|
|
70
|
-
});
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
bucket.storyIds.add(storyId);
|
|
74
|
-
if (ts < bucket.firstSeenAt) bucket.firstSeenAt = ts;
|
|
75
|
-
if (ts > bucket.lastSeenAt) bucket.lastSeenAt = ts;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const findings = [];
|
|
79
|
-
for (const [gate, bucket] of byGate) {
|
|
80
|
-
if (bucket.storyIds.size < 2) continue;
|
|
81
|
-
findings.push({
|
|
82
|
-
gate,
|
|
83
|
-
storyIds: Array.from(bucket.storyIds).sort((a, b) => a - b),
|
|
84
|
-
firstSeenAt: bucket.firstSeenAt,
|
|
85
|
-
lastSeenAt: bucket.lastSeenAt,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
findings.sort((a, b) => (a.gate < b.gate ? -1 : a.gate > b.gate ? 1 : 0));
|
|
89
|
-
return findings;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Resolve the records array from caller opts. Pre-parsed `records` wins
|
|
94
|
-
* over a `ledgerPath` so callers that already loaded the file (e.g.
|
|
95
|
-
* `wave-tick.js` doing its in-flight reconciliation) don't pay the parse
|
|
96
|
-
* cost twice. A missing ledger file is treated as "no records" — the
|
|
97
|
-
* tick must remain stateless and must not throw when nothing has
|
|
98
|
-
* happened yet on this Epic.
|
|
99
|
-
*
|
|
100
|
-
* @param {object} opts
|
|
101
|
-
* @returns {Array<object>}
|
|
102
|
-
*/
|
|
103
|
-
function resolveRecords(opts) {
|
|
104
|
-
if (Array.isArray(opts.records)) return opts.records;
|
|
105
|
-
if (typeof opts.ledgerPath !== 'string' || opts.ledgerPath.length === 0) {
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
108
|
-
if (!existsSync(opts.ledgerPath)) return [];
|
|
109
|
-
let raw;
|
|
110
|
-
try {
|
|
111
|
-
raw = readFileSync(opts.ledgerPath, 'utf8');
|
|
112
|
-
} catch {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
if (!raw) return [];
|
|
116
|
-
const out = [];
|
|
117
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
118
|
-
if (!line) continue;
|
|
119
|
-
try {
|
|
120
|
-
out.push(JSON.parse(line));
|
|
121
|
-
} catch {
|
|
122
|
-
// Malformed line — skip; the ledger is append-only NDJSON and a
|
|
123
|
-
// partial write at process death is the only realistic source of
|
|
124
|
-
// un-parseable lines. The next tick will see the completed line.
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return out;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Decide whether a ledger record is a `close-validate.end` `emitted`
|
|
132
|
-
* payload carrying a failed gate, and if so extract the
|
|
133
|
-
* `(gate, storyId, ts)` triple the bucketing loop consumes. Returns
|
|
134
|
-
* `null` for any record that doesn't satisfy every guard.
|
|
135
|
-
*
|
|
136
|
-
* @param {object} record
|
|
137
|
-
* @returns {{gate: string, storyId: number, ts: string} | null}
|
|
138
|
-
*/
|
|
139
|
-
function extractFailedGateRecord(record) {
|
|
140
|
-
if (!record || record.kind !== 'emitted') return null;
|
|
141
|
-
if (record.event !== 'close-validate.end') return null;
|
|
142
|
-
const payload = record.payload;
|
|
143
|
-
if (!payload || typeof payload !== 'object') return null;
|
|
144
|
-
if (payload.ok !== false) return null;
|
|
145
|
-
const gate = payload.failedGate;
|
|
146
|
-
if (typeof gate !== 'string' || gate.length === 0) return null;
|
|
147
|
-
const storyId = payload.storyId;
|
|
148
|
-
if (!Number.isInteger(storyId) || storyId <= 0) return null;
|
|
149
|
-
const ts = typeof record.ts === 'string' && record.ts ? record.ts : '';
|
|
150
|
-
if (!ts) return null;
|
|
151
|
-
return { gate, storyId, ts };
|
|
152
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* phases/checks.js — retro Phase 3: self-healing checks integration.
|
|
3
|
-
*
|
|
4
|
-
* Story #1290: invoke the self-healing checks registry with scope:'retro'
|
|
5
|
-
* (read-only by construction — `runChecks` throws on autoFix:true under
|
|
6
|
-
* this scope). Failures degrade gracefully to an empty findings list so
|
|
7
|
-
* the retro never blocks on a probe error.
|
|
8
|
-
*
|
|
9
|
-
* Also owns the pure `appendChecksSection` helper that splices the
|
|
10
|
-
* findings table into the composed retro body just above the
|
|
11
|
-
* `<!-- retro-complete: ... -->` terminator.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { runChecks as defaultRunChecks } from '../../../checks/index.js';
|
|
15
|
-
import { assembleState as defaultAssembleState } from '../../../checks/state.js';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Story #1290: invoke the self-healing checks registry with scope:'retro'
|
|
19
|
-
* (read-only by construction — `runChecks` throws on autoFix:true under
|
|
20
|
-
* this scope). Failures degrade gracefully to an empty findings list so
|
|
21
|
-
* the retro never blocks on a probe error.
|
|
22
|
-
*/
|
|
23
|
-
export async function collectRetroFindings({
|
|
24
|
-
runChecksFn = defaultRunChecks,
|
|
25
|
-
assembleStateFn = defaultAssembleState,
|
|
26
|
-
cwd,
|
|
27
|
-
logger,
|
|
28
|
-
}) {
|
|
29
|
-
try {
|
|
30
|
-
const state = await assembleStateFn({ scope: 'retro', cwd });
|
|
31
|
-
const result = await runChecksFn({
|
|
32
|
-
scope: 'retro',
|
|
33
|
-
autoFix: false,
|
|
34
|
-
state,
|
|
35
|
-
});
|
|
36
|
-
return Array.isArray(result?.findings) ? result.findings : [];
|
|
37
|
-
} catch (err) {
|
|
38
|
-
logger?.warn?.(
|
|
39
|
-
`[retro-runner] runChecks(scope:'retro') failed (continuing with empty findings): ${err?.message ?? err}`,
|
|
40
|
-
);
|
|
41
|
-
return [];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Pure: append a "Self-Healing Checks" section to the retro body, listing
|
|
47
|
-
* each finding's id, severity, summary, and fixCommand. When `findings` is
|
|
48
|
-
* empty, the body is returned unchanged — this preserves the compact
|
|
49
|
-
* "🟢 Clean sprint" shape under a clean manifest.
|
|
50
|
-
*
|
|
51
|
-
* The section is inserted **before** the `<!-- retro-complete: ... -->`
|
|
52
|
-
* terminating marker so the marker stays at the end of the body (the
|
|
53
|
-
* deliver pipeline searches for it as the EOF sentinel).
|
|
54
|
-
*
|
|
55
|
-
* Output format mirrors `/diagnose`'s renderTable for fixCommand display:
|
|
56
|
-
* the same literal shell command appears verbatim in a fenced code block
|
|
57
|
-
* so operators can copy-paste it.
|
|
58
|
-
*
|
|
59
|
-
* @param {string} body
|
|
60
|
-
* @param {Array<import('../../../checks/index.js').Finding>} findings
|
|
61
|
-
* @returns {string}
|
|
62
|
-
*/
|
|
63
|
-
export function appendChecksSection(body, findings) {
|
|
64
|
-
if (!Array.isArray(findings) || findings.length === 0) return body;
|
|
65
|
-
const section = renderFindingsSection(findings);
|
|
66
|
-
const markerRe = /(<!--\s*retro-complete:[^>]*-->\s*)$/;
|
|
67
|
-
if (markerRe.test(body)) {
|
|
68
|
-
return body.replace(markerRe, `${section}\n$1`);
|
|
69
|
-
}
|
|
70
|
-
return `${body}\n${section}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function escapeCell(value) {
|
|
74
|
-
return String(value ?? '').replace(/\|/g, '\\|');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function renderFindingRow(f) {
|
|
78
|
-
const id = escapeCell(f?.id);
|
|
79
|
-
const severity = escapeCell(f?.severity);
|
|
80
|
-
const summary = escapeCell(f?.summary);
|
|
81
|
-
const fixCommand = escapeCell(f?.fixCommand);
|
|
82
|
-
return `| ${id} | ${severity} | ${summary} | \`${fixCommand}\` |`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function renderFindingsSection(findings) {
|
|
86
|
-
return [
|
|
87
|
-
'### Self-Healing Checks',
|
|
88
|
-
'',
|
|
89
|
-
'| ID | Severity | Summary | Fix Command |',
|
|
90
|
-
'| --- | --- | --- | --- |',
|
|
91
|
-
...findings.map(renderFindingRow),
|
|
92
|
-
'',
|
|
93
|
-
].join('\n');
|
|
94
|
-
}
|