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
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-ledger-event.js — shared validate-and-append core for the
|
|
3
|
+
* merge-terminal lifecycle emitters (Story #4539).
|
|
4
|
+
*
|
|
5
|
+
* `emit-merge-unlanded.js` and `emit-merge-flip-failed.js` report the two
|
|
6
|
+
* terminal outcomes a landing attempt can reach without ending at
|
|
7
|
+
* `agent::done`. They share everything except their schema and their
|
|
8
|
+
* payload's meaning, so the Ajv compile/cache, the scope→ledger routing,
|
|
9
|
+
* and the NDJSON append live here once rather than being copy-pasted.
|
|
10
|
+
*
|
|
11
|
+
* Like its callers, this is a bare `appendFileSync` rather than a bus
|
|
12
|
+
* publish: these events fire from the `single-story-close` flow, which has
|
|
13
|
+
* no bus at all, so a direct append keeps the call site dependency-free.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
|
|
20
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
21
|
+
import addFormats from 'ajv-formats';
|
|
22
|
+
|
|
23
|
+
import { storyLedgerPath } from '../../config/temp-paths.js';
|
|
24
|
+
|
|
25
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const SCHEMA_DIR = path.resolve(
|
|
27
|
+
__dirname,
|
|
28
|
+
'..',
|
|
29
|
+
'..',
|
|
30
|
+
'..',
|
|
31
|
+
'..',
|
|
32
|
+
'schemas',
|
|
33
|
+
'lifecycle',
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The scopes a merge-terminal event may be WRITTEN with. v2.0.0 removed the
|
|
38
|
+
* Epic tier, so `'story'` is the only emittable scope.
|
|
39
|
+
*
|
|
40
|
+
* Note the deliberate asymmetry with the `merge.unlanded` /
|
|
41
|
+
* `merge.flip-failed` schema enums, which still accept `'epic'`: archived
|
|
42
|
+
* ledger records carry `scope: 'epic'` and the schemas must keep validating
|
|
43
|
+
* them on read. The value stays READABLE; only the writer path is gone —
|
|
44
|
+
* the same split `merge-block-class.js` keeps for `predicate-refused`.
|
|
45
|
+
*/
|
|
46
|
+
const VALID_SCOPES = new Set(['story']);
|
|
47
|
+
|
|
48
|
+
/** @type {Map<string, Function>} */
|
|
49
|
+
const _validators = new Map();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Compile (once) and return the validator for a lifecycle schema file.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} schemaFile Basename under `.agents/schemas/lifecycle/`.
|
|
55
|
+
* @returns {Function}
|
|
56
|
+
*/
|
|
57
|
+
function getValidator(schemaFile) {
|
|
58
|
+
const cached = _validators.get(schemaFile);
|
|
59
|
+
if (cached) return cached;
|
|
60
|
+
const schema = JSON.parse(
|
|
61
|
+
readFileSync(path.resolve(SCHEMA_DIR, schemaFile), 'utf8'),
|
|
62
|
+
);
|
|
63
|
+
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
64
|
+
addFormats(ajv);
|
|
65
|
+
const validator = ajv.compile(schema);
|
|
66
|
+
_validators.set(schemaFile, validator);
|
|
67
|
+
return validator;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Assert the fields every merge-terminal event shares. Throws with the
|
|
72
|
+
* caller's own emitter name so the message stays attributable.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} emitter
|
|
75
|
+
* @param {{ scope: string, ticketId: number, prNumber: number, reason: string, elapsedSeconds: number }} fields
|
|
76
|
+
*/
|
|
77
|
+
export function assertMergeTerminalFields(
|
|
78
|
+
emitter,
|
|
79
|
+
{ scope, ticketId, prNumber, reason, elapsedSeconds },
|
|
80
|
+
) {
|
|
81
|
+
if (!VALID_SCOPES.has(scope)) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`${emitter}: scope "${scope}" must be one of: ${[...VALID_SCOPES].join(', ')}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (!Number.isInteger(ticketId) || ticketId < 1) {
|
|
87
|
+
throw new Error(`${emitter}: ticketId must be a positive integer`);
|
|
88
|
+
}
|
|
89
|
+
if (!Number.isInteger(prNumber) || prNumber < 1) {
|
|
90
|
+
throw new Error(`${emitter}: prNumber must be a positive integer`);
|
|
91
|
+
}
|
|
92
|
+
if (typeof reason !== 'string' || reason.length === 0) {
|
|
93
|
+
throw new Error(`${emitter}: reason must be a non-empty string`);
|
|
94
|
+
}
|
|
95
|
+
if (typeof elapsedSeconds !== 'number' || elapsedSeconds < 0) {
|
|
96
|
+
throw new Error(`${emitter}: elapsedSeconds must be a non-negative number`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Validate a payload against its lifecycle schema and append exactly one
|
|
102
|
+
* NDJSON record to the scope-resolved ledger.
|
|
103
|
+
*
|
|
104
|
+
* @param {object} args
|
|
105
|
+
* @param {string} args.emitter Caller name, for error attribution.
|
|
106
|
+
* @param {string} args.schemaFile Basename under `schemas/lifecycle/`.
|
|
107
|
+
* @param {object} args.payload The event payload (already assembled).
|
|
108
|
+
* @param {number} args.ticketId
|
|
109
|
+
* @param {string} args.timestamp
|
|
110
|
+
* @param {object} [args.config]
|
|
111
|
+
* @param {string} [args.ledgerPath] Override for tests / non-default layouts.
|
|
112
|
+
* @returns {{ ledgerPath: string, record: object }}
|
|
113
|
+
*/
|
|
114
|
+
export function appendLedgerEvent({
|
|
115
|
+
emitter,
|
|
116
|
+
schemaFile,
|
|
117
|
+
payload,
|
|
118
|
+
ticketId,
|
|
119
|
+
timestamp,
|
|
120
|
+
config,
|
|
121
|
+
ledgerPath: ledgerPathOverride,
|
|
122
|
+
}) {
|
|
123
|
+
const validator = getValidator(schemaFile);
|
|
124
|
+
if (!validator(payload)) {
|
|
125
|
+
const detail = (validator.errors ?? [])
|
|
126
|
+
.map((e) => `${e.instancePath || '/'} ${e.message}`)
|
|
127
|
+
.join('; ');
|
|
128
|
+
throw new Error(`${emitter}: payload failed schema validation: ${detail}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const ledgerPath =
|
|
132
|
+
ledgerPathOverride ?? storyLedgerPath(null, ticketId, config);
|
|
133
|
+
mkdirSync(path.dirname(ledgerPath), { recursive: true });
|
|
134
|
+
const record = {
|
|
135
|
+
kind: 'emitted',
|
|
136
|
+
ts: timestamp,
|
|
137
|
+
event: payload.event,
|
|
138
|
+
payload,
|
|
139
|
+
};
|
|
140
|
+
appendFileSync(ledgerPath, `${JSON.stringify(record)}\n`, 'utf8');
|
|
141
|
+
return { ledgerPath, record };
|
|
142
|
+
}
|
|
@@ -9,14 +9,12 @@
|
|
|
9
9
|
* appends an inspectable `emitted` line a reconciler can read for
|
|
10
10
|
* forward-progress evidence.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* heartbeat carries Story-phase info for a single in-flight Story and is
|
|
14
|
-
* always Epic-scoped (its ledger path is `epicLedgerPath(epicId)`). A
|
|
15
|
-
* host loop is not bound to a Story tier, so `loop.tick` carries a
|
|
12
|
+
* A host loop is not bound to a Story tier, so `loop.tick` carries a
|
|
16
13
|
* free-form `loopName`, a monotonic `round` counter, the loop's
|
|
17
|
-
* configured `cadence` label, and a per-round `status
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* configured `cadence` label, and a per-round `status`. It is now the only
|
|
15
|
+
* forward-progress beat: the Story-scoped `story.heartbeat` it was once
|
|
16
|
+
* contrasted against was Epic-scoped by construction, could never fire under
|
|
17
|
+
* v2 (which has no Epics), and was deleted (A22).
|
|
20
18
|
*
|
|
21
19
|
* Bus path (Story acceptance: "Emitting a loop.tick event THROUGH the
|
|
22
20
|
* lifecycle bus appends a record to the per-run ledger"): this helper
|
|
@@ -39,15 +37,15 @@
|
|
|
39
37
|
* Ledger path resolution: a caller supplies EITHER an explicit
|
|
40
38
|
* `ledgerPath` (the host-loop case — the loop owns where its ledger
|
|
41
39
|
* lives) OR an `epicId`, in which case the canonical
|
|
42
|
-
* `
|
|
43
|
-
* in the same `temp/
|
|
40
|
+
* `runLedgerPath(epicId)` is used so an Epic-scoped loop's ticks land
|
|
41
|
+
* in the same `temp/run-<id>/lifecycle.ndjson` the rest of the run
|
|
44
42
|
* reads. Exactly one of the two MUST be supplied.
|
|
45
43
|
*/
|
|
46
44
|
|
|
47
45
|
import path from 'node:path';
|
|
48
46
|
import { fileURLToPath } from 'node:url';
|
|
49
47
|
|
|
50
|
-
import {
|
|
48
|
+
import { runLedgerPath } from '../../config/temp-paths.js';
|
|
51
49
|
import { createBus } from './bus.js';
|
|
52
50
|
import { createLedgerWriter } from './ledger-writer.js';
|
|
53
51
|
|
|
@@ -65,8 +63,8 @@ const SCHEMA_DIR = path.resolve(
|
|
|
65
63
|
const VALID_STATUSES = new Set(['running', 'done', 'blocked']);
|
|
66
64
|
|
|
67
65
|
/**
|
|
68
|
-
* Parse `temp/
|
|
69
|
-
* `<dir>/
|
|
66
|
+
* Parse `temp/run-<id>/lifecycle.ndjson` (or any
|
|
67
|
+
* `<dir>/run-<id>/lifecycle.ndjson`) back into `{ tempRoot, epicId }`
|
|
70
68
|
* so a LedgerWriter — which is constructed from `{ epicId, tempRoot }`
|
|
71
69
|
* rather than a raw path — can be bound to the supplied ledger path.
|
|
72
70
|
*
|
|
@@ -79,13 +77,13 @@ const VALID_STATUSES = new Set(['running', 'done', 'blocked']);
|
|
|
79
77
|
* @returns {{ tempRoot: string, epicId: number }}
|
|
80
78
|
*/
|
|
81
79
|
function decomposeLedgerPath(ledgerPath) {
|
|
82
|
-
const
|
|
83
|
-
const tempRoot = path.dirname(
|
|
84
|
-
const
|
|
85
|
-
const m = /^
|
|
80
|
+
const runDir = path.dirname(ledgerPath);
|
|
81
|
+
const tempRoot = path.dirname(runDir);
|
|
82
|
+
const runDirName = path.basename(runDir);
|
|
83
|
+
const m = /^run-(\d+)$/.exec(runDirName);
|
|
86
84
|
if (!m) {
|
|
87
85
|
throw new Error(
|
|
88
|
-
`emitLoopTick: ledgerPath does not match <tempRoot>/
|
|
86
|
+
`emitLoopTick: ledgerPath does not match <tempRoot>/run-<id>/lifecycle.ndjson layout (got ${ledgerPath})`,
|
|
89
87
|
);
|
|
90
88
|
}
|
|
91
89
|
const epicId = Number.parseInt(m[1], 10);
|
|
@@ -104,7 +102,7 @@ function decomposeLedgerPath(ledgerPath) {
|
|
|
104
102
|
* One of running|done|blocked.
|
|
105
103
|
* @param {string} [opts.timestamp] ISO-8601 wall clock. Defaults to now().
|
|
106
104
|
* @param {number} [opts.epicId] When supplied (and no `ledgerPath`),
|
|
107
|
-
* the canonical `
|
|
105
|
+
* the canonical `runLedgerPath(epicId)`
|
|
108
106
|
* is used for the ledger.
|
|
109
107
|
* @param {object} [opts.config] Optional resolved config for tempRoot
|
|
110
108
|
* (only consulted on the `epicId` path).
|
|
@@ -158,7 +156,7 @@ export async function emitLoopTick(opts) {
|
|
|
158
156
|
if (!Number.isInteger(epicId) || epicId < 1) {
|
|
159
157
|
throw new Error('emitLoopTick: epicId must be a positive integer');
|
|
160
158
|
}
|
|
161
|
-
ledgerPath =
|
|
159
|
+
ledgerPath = runLedgerPath(epicId, config);
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
const payload = {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-merge-flip-failed.js — Story #4539.
|
|
3
|
+
*
|
|
4
|
+
* Appends a single `merge.flip-failed` NDJSON record when a delivery run
|
|
5
|
+
* observed a **confirmed merge** but the `agent::closing → agent::done`
|
|
6
|
+
* label write itself failed.
|
|
7
|
+
*
|
|
8
|
+
* Why this is not `merge.unlanded`: the merge landed. Reporting it as
|
|
9
|
+
* unlanded points the operator at branch protection, required checks, and
|
|
10
|
+
* poll budgets — none of which are the fault — while the real remedy is a
|
|
11
|
+
* re-run of `single-story-confirm-merge.js`, which is idempotent and flips
|
|
12
|
+
* the label from the already-merged PR. The two events are deliberately
|
|
13
|
+
* distinct so the ledger attributes a label-write API failure differently
|
|
14
|
+
* from a merge that never happened.
|
|
15
|
+
*
|
|
16
|
+
* The Story is still transitioned to `agent::blocked` by the caller: a
|
|
17
|
+
* merged PR whose Story sits at `agent::closing` is exactly the silent
|
|
18
|
+
* strand the must-land contract exists to prevent, so it terminates
|
|
19
|
+
* explicitly — but it terminates with the truth.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
appendLedgerEvent,
|
|
24
|
+
assertMergeTerminalFields,
|
|
25
|
+
} from './emit-ledger-event.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The only block class this event carries. Distinct from every
|
|
29
|
+
* `merge.unlanded` attribution (`MERGE_UNLANDED_BLOCK_CLASSES`) because the
|
|
30
|
+
* merge is not in question here — only the label write is.
|
|
31
|
+
*/
|
|
32
|
+
export const MERGED_FLIP_FAILED_BLOCK_CLASS = 'merged-flip-failed';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Append exactly one `merge.flip-failed` record to the resolved ledger.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} opts
|
|
38
|
+
* @param {'story'} opts.scope
|
|
39
|
+
* @param {number} opts.ticketId The storyId.
|
|
40
|
+
* @param {number} opts.prNumber The PR that merged.
|
|
41
|
+
* @param {string} opts.reason What failed on the label write.
|
|
42
|
+
* @param {number} opts.elapsedSeconds Elapsed poll time when the flip failed.
|
|
43
|
+
* @param {string} [opts.timestamp]
|
|
44
|
+
* @param {object} [opts.config]
|
|
45
|
+
* @param {string} [opts.ledgerPath]
|
|
46
|
+
* @returns {{ ledgerPath: string, record: object }}
|
|
47
|
+
*/
|
|
48
|
+
export function emitMergeFlipFailed(opts) {
|
|
49
|
+
const {
|
|
50
|
+
scope,
|
|
51
|
+
ticketId,
|
|
52
|
+
prNumber,
|
|
53
|
+
reason,
|
|
54
|
+
elapsedSeconds,
|
|
55
|
+
timestamp = new Date().toISOString(),
|
|
56
|
+
config,
|
|
57
|
+
ledgerPath,
|
|
58
|
+
} = opts ?? {};
|
|
59
|
+
|
|
60
|
+
assertMergeTerminalFields('emitMergeFlipFailed', {
|
|
61
|
+
scope,
|
|
62
|
+
ticketId,
|
|
63
|
+
prNumber,
|
|
64
|
+
reason,
|
|
65
|
+
elapsedSeconds,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return appendLedgerEvent({
|
|
69
|
+
emitter: 'emitMergeFlipFailed',
|
|
70
|
+
schemaFile: 'merge.flip-failed.schema.json',
|
|
71
|
+
payload: {
|
|
72
|
+
event: 'merge.flip-failed',
|
|
73
|
+
scope,
|
|
74
|
+
ticketId,
|
|
75
|
+
prNumber,
|
|
76
|
+
blockClass: MERGED_FLIP_FAILED_BLOCK_CLASS,
|
|
77
|
+
reason,
|
|
78
|
+
elapsedSeconds,
|
|
79
|
+
timestamp,
|
|
80
|
+
},
|
|
81
|
+
ticketId,
|
|
82
|
+
timestamp,
|
|
83
|
+
config,
|
|
84
|
+
ledgerPath,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -6,23 +6,16 @@
|
|
|
6
6
|
* finishes its work without a confirmed merge. Pattern mirrors
|
|
7
7
|
* `emit-story-heartbeat.js`: direct schema validation via Ajv followed by
|
|
8
8
|
* a synchronous `appendFileSync` — this event is NOT routed through the
|
|
9
|
-
* bus (unlike `emit-loop-tick.js`) because it
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* which has no bus at all. A bare append keeps both call sites simple
|
|
13
|
-
* and dependency-free.
|
|
9
|
+
* bus (unlike `emit-loop-tick.js`) because it fires from the standalone
|
|
10
|
+
* `single-story-close` flow, which has no bus at all. A bare append keeps
|
|
11
|
+
* the call site simple and dependency-free.
|
|
14
12
|
*
|
|
15
|
-
* Ledger destination
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `temp/standalone/stories/story-<id>/lifecycle.ndjson`. `ticketId`
|
|
22
|
-
* is the storyId. The standalone `single-story-close` path has no
|
|
23
|
-
* parent Epic to anchor a `temp/epic-<id>/` directory to, mirroring
|
|
24
|
-
* the `eid === null` standalone convention `signalsFile` already
|
|
25
|
-
* uses for Story-level signals.
|
|
13
|
+
* Ledger destination (Story #4426 AC4): `storyLedgerPath(null, ticketId)`
|
|
14
|
+
* — the standalone story-scope destination
|
|
15
|
+
* `temp/standalone/stories/story-<id>/lifecycle.ndjson`, where `ticketId`
|
|
16
|
+
* is the storyId. The `single-story-close` path has no parent Epic to
|
|
17
|
+
* anchor a run directory to, mirroring the `eid === null` standalone
|
|
18
|
+
* convention `signalsFile` already uses for Story-level signals.
|
|
26
19
|
*
|
|
27
20
|
* A caller may always override the destination via `ledgerPath` (tests,
|
|
28
21
|
* or a future caller with a non-default temp layout).
|
|
@@ -57,50 +50,20 @@
|
|
|
57
50
|
* `predicate-refused` / a classified arm failure directly.
|
|
58
51
|
*/
|
|
59
52
|
|
|
60
|
-
import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
|
|
61
|
-
import path from 'node:path';
|
|
62
|
-
import { fileURLToPath } from 'node:url';
|
|
63
|
-
|
|
64
|
-
import Ajv2020 from 'ajv/dist/2020.js';
|
|
65
|
-
import addFormats from 'ajv-formats';
|
|
66
|
-
|
|
67
|
-
import { epicLedgerPath, storyLedgerPath } from '../../config/temp-paths.js';
|
|
68
53
|
import { isValidBlockClass } from '../merge-block-class.js';
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
'..',
|
|
74
|
-
'..',
|
|
75
|
-
'..',
|
|
76
|
-
'..',
|
|
77
|
-
'schemas',
|
|
78
|
-
'lifecycle',
|
|
79
|
-
'merge.unlanded.schema.json',
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const VALID_SCOPES = new Set(['epic', 'story']);
|
|
83
|
-
|
|
84
|
-
let _validator;
|
|
85
|
-
|
|
86
|
-
function getValidator() {
|
|
87
|
-
if (_validator) return _validator;
|
|
88
|
-
const schema = JSON.parse(readFileSync(SCHEMA_PATH, 'utf8'));
|
|
89
|
-
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
90
|
-
addFormats(ajv);
|
|
91
|
-
_validator = ajv.compile(schema);
|
|
92
|
-
return _validator;
|
|
93
|
-
}
|
|
54
|
+
import {
|
|
55
|
+
appendLedgerEvent,
|
|
56
|
+
assertMergeTerminalFields,
|
|
57
|
+
} from './emit-ledger-event.js';
|
|
94
58
|
|
|
95
59
|
/**
|
|
96
60
|
* Append exactly one `merge.unlanded` NDJSON record to the resolved
|
|
97
61
|
* lifecycle ledger.
|
|
98
62
|
*
|
|
99
63
|
* @param {object} opts
|
|
100
|
-
* @param {'
|
|
64
|
+
* @param {'story'} opts.scope Which delivery path is reporting the
|
|
101
65
|
* unlanded merge.
|
|
102
|
-
* @param {number} opts.ticketId
|
|
103
|
-
* storyId when `scope === 'story'`.
|
|
66
|
+
* @param {number} opts.ticketId The storyId.
|
|
104
67
|
* @param {number} opts.prNumber The PR number that did not land.
|
|
105
68
|
* @param {string} opts.blockClass A valid `merge.unlanded` attribution
|
|
106
69
|
* (`MERGE_UNLANDED_BLOCK_CLASSES` in
|
|
@@ -130,64 +93,35 @@ export function emitMergeUnlanded(opts) {
|
|
|
130
93
|
ledgerPath: ledgerPathOverride,
|
|
131
94
|
} = opts ?? {};
|
|
132
95
|
|
|
133
|
-
|
|
134
|
-
throw new Error(
|
|
135
|
-
`emitMergeUnlanded: scope "${scope}" must be one of: ${[...VALID_SCOPES].join(', ')}`,
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
if (!Number.isInteger(ticketId) || ticketId < 1) {
|
|
139
|
-
throw new Error('emitMergeUnlanded: ticketId must be a positive integer');
|
|
140
|
-
}
|
|
141
|
-
if (!Number.isInteger(prNumber) || prNumber < 1) {
|
|
142
|
-
throw new Error('emitMergeUnlanded: prNumber must be a positive integer');
|
|
143
|
-
}
|
|
144
|
-
if (!isValidBlockClass(blockClass)) {
|
|
145
|
-
throw new Error(
|
|
146
|
-
`emitMergeUnlanded: blockClass "${blockClass}" is not a recognised merge-block-class value`,
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
if (typeof reason !== 'string' || reason.length === 0) {
|
|
150
|
-
throw new Error('emitMergeUnlanded: reason must be a non-empty string');
|
|
151
|
-
}
|
|
152
|
-
if (typeof elapsedSeconds !== 'number' || elapsedSeconds < 0) {
|
|
153
|
-
throw new Error(
|
|
154
|
-
'emitMergeUnlanded: elapsedSeconds must be a non-negative number',
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const payload = {
|
|
159
|
-
event: 'merge.unlanded',
|
|
96
|
+
assertMergeTerminalFields('emitMergeUnlanded', {
|
|
160
97
|
scope,
|
|
161
98
|
ticketId,
|
|
162
99
|
prNumber,
|
|
163
|
-
blockClass,
|
|
164
100
|
reason,
|
|
165
101
|
elapsedSeconds,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const validator = getValidator();
|
|
170
|
-
if (!validator(payload)) {
|
|
171
|
-
const detail = (validator.errors ?? [])
|
|
172
|
-
.map((e) => `${e.instancePath || '/'} ${e.message}`)
|
|
173
|
-
.join('; ');
|
|
102
|
+
});
|
|
103
|
+
if (!isValidBlockClass(blockClass)) {
|
|
174
104
|
throw new Error(
|
|
175
|
-
`emitMergeUnlanded:
|
|
105
|
+
`emitMergeUnlanded: blockClass "${blockClass}" is not a recognised merge-block-class value`,
|
|
176
106
|
);
|
|
177
107
|
}
|
|
178
108
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
109
|
+
return appendLedgerEvent({
|
|
110
|
+
emitter: 'emitMergeUnlanded',
|
|
111
|
+
schemaFile: 'merge.unlanded.schema.json',
|
|
112
|
+
payload: {
|
|
113
|
+
event: 'merge.unlanded',
|
|
114
|
+
scope,
|
|
115
|
+
ticketId,
|
|
116
|
+
prNumber,
|
|
117
|
+
blockClass,
|
|
118
|
+
reason,
|
|
119
|
+
elapsedSeconds,
|
|
120
|
+
timestamp,
|
|
121
|
+
},
|
|
122
|
+
ticketId,
|
|
123
|
+
timestamp,
|
|
124
|
+
config,
|
|
125
|
+
ledgerPath: ledgerPathOverride,
|
|
126
|
+
});
|
|
193
127
|
}
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
27
27
|
import path from 'node:path';
|
|
28
|
+
import { runTempDir } from '../../config/temp-paths.js';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Static deny-list pulled from the Tech Spec § Security & Privacy. Keys
|
|
@@ -85,7 +86,7 @@ export class LedgerWriter {
|
|
|
85
86
|
* @param {object} opts
|
|
86
87
|
* @param {number} opts.epicId
|
|
87
88
|
* @param {string} opts.tempRoot - absolute or repo-relative path; the
|
|
88
|
-
* writer resolves `temp/
|
|
89
|
+
* writer resolves `temp/run-<id>/lifecycle.ndjson` underneath.
|
|
89
90
|
* @param {() => number} [opts.now] - injectable clock for tests.
|
|
90
91
|
*/
|
|
91
92
|
constructor(opts) {
|
|
@@ -101,7 +102,9 @@ export class LedgerWriter {
|
|
|
101
102
|
}
|
|
102
103
|
this._epicId = opts.epicId;
|
|
103
104
|
this._tempRoot = opts.tempRoot;
|
|
104
|
-
this._epicDir =
|
|
105
|
+
this._epicDir = runTempDir(this._epicId, {
|
|
106
|
+
project: { paths: { tempRoot: this._tempRoot } },
|
|
107
|
+
});
|
|
105
108
|
this._ledgerPath = path.join(this._epicDir, 'lifecycle.ndjson');
|
|
106
109
|
this._now = typeof opts.now === 'function' ? opts.now : Date.now;
|
|
107
110
|
}
|
|
@@ -127,7 +130,7 @@ export class LedgerWriter {
|
|
|
127
130
|
* The naive optimization (cache "ensured" after the first call) is
|
|
128
131
|
* unsound when a listener moves the ledger directory mid-handler —
|
|
129
132
|
* which is exactly what the Cleaner does on Wave 8 (Story #2259):
|
|
130
|
-
* it renames `temp/
|
|
133
|
+
* it renames `temp/run-<id>/` under `archive/` between the listener
|
|
131
134
|
* body and the bus's `onCompleted` hook fire-time, and the next
|
|
132
135
|
* append (the `completed` record for the outer event) would land
|
|
133
136
|
* in a vanished directory. `mkdirSync({recursive: true})` is
|
|
@@ -1,45 +1,27 @@
|
|
|
1
1
|
# Lifecycle Listeners
|
|
2
2
|
|
|
3
3
|
Each listener in this directory subscribes to one or more lifecycle bus
|
|
4
|
-
events and performs a single side effect. The
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`/deliver`'s Phase 6 / 7.5 / 8 / 8.5 markdown invocations:
|
|
4
|
+
events and performs a single side effect. The full close-tail roster and
|
|
5
|
+
event taxonomy live in [`docs/LIFECYCLE.md`](../../../../../../docs/LIFECYCLE.md)
|
|
6
|
+
— that document is the SSOT. This README only indexes the **files that still
|
|
7
|
+
live in this folder**.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
`emitted` record on disk before any listener body runs (MUST be first).
|
|
12
|
-
- `acceptance-reconciler.js` — gates Finalize on close-time acceptance
|
|
13
|
-
coverage (`epic.close.end → acceptance.reconcile.*`).
|
|
14
|
-
- `finalizer.js` — opens the PR on `acceptance.reconcile.{ok,waived}` and
|
|
15
|
-
emits `epic.merge.ready`.
|
|
16
|
-
- `automerge-armer.js` — arms `gh pr merge --auto --squash --delete-branch`
|
|
17
|
-
on `epic.merge.ready`.
|
|
18
|
-
- `automerge-predicate.js` — evaluates the clean-sprint predicate and
|
|
19
|
-
emits `epic.merge.{ready,blocked}`.
|
|
20
|
-
- `branch-cleaner.js` — reaps story/epic branches on `epic.cleanup.start`.
|
|
21
|
-
- `merge-watcher.js` — polls `gh pr view` after `epic.merge.armed` until
|
|
22
|
-
the PR's `mergeCommit` is observed, then emits `epic.merge.confirmed`.
|
|
23
|
-
- `cleaner.js` — archives `temp/epic-<id>/` and emits the terminal
|
|
24
|
-
`epic.cleanup.* → epic.complete` sequence on `epic.merge.confirmed`.
|
|
25
|
-
- `label-transitioner.js` — flips the Epic ticket to `agent::done` (and
|
|
26
|
-
closes it as completed, idempotently) on `epic.complete`. Skipped when
|
|
27
|
-
no provider is wired. Re-homed onto this chain after the 2026-07-11
|
|
28
|
-
incident (merged Epics stranding at `agent::executing`): the original
|
|
29
|
-
LabelTransitioner died with the in-process runner stratum (#3936) and
|
|
30
|
-
the flip had no owner.
|
|
31
|
-
- `checkpoint-pointer-writer.js` — persists `{ lastCompletedSeqId, phase }`
|
|
32
|
-
on every `*.end` event.
|
|
9
|
+
## Files here
|
|
33
10
|
|
|
34
|
-
|
|
35
|
-
|
|
11
|
+
- [`watcher.js`](./watcher.js) — the CI-poll loop (`watchPrToTerminal`)
|
|
12
|
+
driven by `pr-watch-with-update.js`.
|
|
36
13
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
|
|
14
|
+
`merge-watcher.js` was deleted in Story #4545: the Epic-era `MergeWatcher`
|
|
15
|
+
listener had no production caller after the v2.0.0 Story-only cutover. The
|
|
16
|
+
poll defaults and `deriveChecksStatus` the live close path did import from it
|
|
17
|
+
now live in
|
|
18
|
+
[`lib/orchestration/merge-poll.js`](../../merge-poll.js), a home the close
|
|
19
|
+
path owns.
|
|
20
|
+
|
|
21
|
+
Other close-tail side effects (ledger write, finalize/PR open, automerge
|
|
22
|
+
arm, branch cleanup, label transition) are owned by the Story delivery
|
|
23
|
+
path (`helpers/deliver-story` / `single-story-close.js`) rather than a
|
|
24
|
+
`buildDefaultListenerChain` factory in this directory.
|
|
43
25
|
|
|
44
26
|
## Idempotency contract
|
|
45
27
|
|
|
@@ -50,10 +32,6 @@ canonical pattern is a per-instance `Set<seqId>` checked at the top of
|
|
|
50
32
|
the listener body; the second invocation returns early without mutating
|
|
51
33
|
external state.
|
|
52
34
|
|
|
53
|
-
The seqId guard is the only correctness requirement we surface from the
|
|
54
|
-
bus contract — downstream idempotency primitives (label-state diff,
|
|
55
|
-
marker-keyed upsert, NDJSON dedupe by seqId) layer on top of it.
|
|
56
|
-
|
|
57
35
|
## Side-effect firewall
|
|
58
36
|
|
|
59
37
|
Listeners MAY:
|
|
@@ -61,13 +39,13 @@ Listeners MAY:
|
|
|
61
39
|
- read tickets via the injected `provider`,
|
|
62
40
|
- write tickets via the injected `transitionTicketState`,
|
|
63
41
|
- upsert structured comments via the injected `upsertStructuredComment`,
|
|
64
|
-
- append to per-
|
|
42
|
+
- append to per-run ledger / signals files under `tempRoot`.
|
|
65
43
|
|
|
66
44
|
Listeners MUST NOT:
|
|
67
45
|
|
|
68
46
|
- `bus.emit()` from inside a listener body (sequential mediator
|
|
69
|
-
contract — the bus cannot re-
|
|
70
|
-
- import
|
|
47
|
+
contract — the bus cannot re-enter safely),
|
|
48
|
+
- import runner state directly,
|
|
71
49
|
- mutate cross-cutting globals.
|
|
72
50
|
|
|
73
51
|
Trace observers (`bus.on('*', fn)`) live under
|