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
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* reconcile — dispatching it is pure token spend for a no-op. This module
|
|
13
13
|
* computes that decision **deterministically**, off the same two inputs the
|
|
14
14
|
* critic itself reads (the draft array and the Epic body's Delivery Slicing
|
|
15
|
-
* table), so
|
|
15
|
+
* table), so the planning workflow can skip the sub-agent
|
|
16
16
|
* dispatch when it is provably safe to.
|
|
17
17
|
*
|
|
18
18
|
* **Fail-open by design.** Every ambiguous case — a missing or unparseable
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* Epic body off disk / the GitHub API.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
import { DELIVERY_SLICING_RE as DELIVERY_SLICING_HEADING_RE } from '../
|
|
33
|
+
import { DELIVERY_SLICING_RE as DELIVERY_SLICING_HEADING_RE } from '../ticket-body-sections.js';
|
|
34
34
|
|
|
35
35
|
/** A row is a markdown table line: starts with `|` once trimmed. */
|
|
36
36
|
const TABLE_ROW_RE = /^\|/;
|
|
@@ -123,7 +123,7 @@ export function parseDeliverySlicingTable(epicBody) {
|
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* True when `story` is the recognized wave-0 BDD scaffold Story — identified
|
|
126
|
-
* by the literal `bdd-scaffold` goal token the
|
|
126
|
+
* by the literal `bdd-scaffold` goal token the decomposer prompt
|
|
127
127
|
* skill's WAVE-0 BDD SCAFFOLD STORY section requires. Scaffold Stories are
|
|
128
128
|
* not a Delivery Slicing slice, so they are excluded from the count
|
|
129
129
|
* comparison — BDD-adopting consumer repos still benefit from the
|
|
@@ -145,7 +145,7 @@ function isBddScaffoldStory(story) {
|
|
|
145
145
|
*
|
|
146
146
|
* @param {object} input
|
|
147
147
|
* @param {object[]} input.draftStories - The draft `tickets.json` array
|
|
148
|
-
* (
|
|
148
|
+
* (the decomposer's output) — raw Story ticket objects with
|
|
149
149
|
* top-level `slug` / `depends_on` / `body` (serialized string).
|
|
150
150
|
* @param {string} input.epicBody - The Epic body carrying the folded Tech
|
|
151
151
|
* Spec sections (`## Delivery Slicing` onward).
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module lib/orchestration/context-envelope
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
/** @typedef {'protocolPolicy' | '
|
|
11
|
+
/** @typedef {'protocolPolicy' | 'skillCapsules' | 'hierarchy' | 'acceptanceCriteria' | 'verificationCommands' | 'taskInstructions'} SectionName */
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {object} SectionSource
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
/**
|
|
38
38
|
* @typedef {object} ContextEnvelope
|
|
39
39
|
* @property {'1'} schemaVersion
|
|
40
|
-
* @property {{ id: number, title: string,
|
|
40
|
+
* @property {{ id: number, title: string, skills?: string[], protocolVersion?: string }} task
|
|
41
41
|
* @property {Section[]} sections
|
|
42
42
|
* @property {TicketSnapshot[]} provenance
|
|
43
43
|
* @property {{ maxTokens: number, used: number, elided: string[] }} budget
|
|
@@ -51,7 +51,6 @@ export const PROMPT_SECTION_SEPARATOR =
|
|
|
51
51
|
/** Rendering order for {@link envelopeToPrompt} (not elision priority). */
|
|
52
52
|
export const SECTION_RENDER_ORDER = Object.freeze([
|
|
53
53
|
'protocolPolicy',
|
|
54
|
-
'persona',
|
|
55
54
|
'skillCapsules',
|
|
56
55
|
'hierarchy',
|
|
57
56
|
'acceptanceCriteria',
|
|
@@ -65,7 +64,6 @@ export const DEFAULT_SECTION_PRIORITIES = Object.freeze({
|
|
|
65
64
|
hierarchy: 20,
|
|
66
65
|
acceptanceCriteria: 30,
|
|
67
66
|
verificationCommands: 40,
|
|
68
|
-
persona: 50,
|
|
69
67
|
protocolPolicy: 80,
|
|
70
68
|
taskInstructions: 100,
|
|
71
69
|
});
|
|
@@ -76,7 +74,6 @@ export const DEFAULT_ELIDE_POLICIES = Object.freeze({
|
|
|
76
74
|
hierarchy: 'summarize',
|
|
77
75
|
acceptanceCriteria: 'summarize',
|
|
78
76
|
verificationCommands: 'drop',
|
|
79
|
-
persona: 'summarize',
|
|
80
77
|
protocolPolicy: 'drop',
|
|
81
78
|
taskInstructions: 'drop',
|
|
82
79
|
});
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deliver-recover.js — probe a stranded Story and name its ONE next command
|
|
3
|
+
* (Story #4543).
|
|
4
|
+
*
|
|
5
|
+
* Recovery here is a **read, not a repair**. Every input is already
|
|
6
|
+
* probeable — labels and lease from the ticket, the branch locally and via
|
|
7
|
+
* its tracking ref, the worktree path, the PR by head branch (with state,
|
|
8
|
+
* merge, and checks probes) — so this module is probes, a decision table
|
|
9
|
+
* over `label × PR × branch × worktree`, and one command with the evidence it
|
|
10
|
+
* was derived from. It never mutates anything, and it never prints a menu of
|
|
11
|
+
* options: a menu is what an operator already has, and it is the thing they
|
|
12
|
+
* cannot act on.
|
|
13
|
+
*
|
|
14
|
+
* The strand shapes the table resolves, and why each is real:
|
|
15
|
+
*
|
|
16
|
+
* - `executing` with no PR → resume implementation. The work never reached
|
|
17
|
+
* close.
|
|
18
|
+
* - `closing` with a pending PR → resume the land. The overwhelmingly
|
|
19
|
+
* common shape now that the merge wait is bounded: the wait returned
|
|
20
|
+
* `pending` and something has to pick it back up.
|
|
21
|
+
* - `closing` with a red PR → enter the fix loop. Waiting is pointless; no
|
|
22
|
+
* budget turns a failed check green.
|
|
23
|
+
* - `closing` with a MERGED PR → run confirm. **This is the strand a
|
|
24
|
+
* `/deliver` re-run refuses outright**, because `single-story-init.js`
|
|
25
|
+
* hard-errors on an already-closed Story — so before this surface, the
|
|
26
|
+
* merged-but-label-stale Story had no automated way back.
|
|
27
|
+
* - `done` with a drifted board → run resync. The GitHub Projects bot won
|
|
28
|
+
* the race.
|
|
29
|
+
* - `blocked` → print the class-specific remediation the friction comment
|
|
30
|
+
* already names, rather than inventing a second opinion about a
|
|
31
|
+
* condition that was already classified.
|
|
32
|
+
*
|
|
33
|
+
* The command vocabulary is shared with the terminal envelope
|
|
34
|
+
* (`story-deliver-terminal.js#NEXT_COMMANDS`), so recovery and normal
|
|
35
|
+
* resumption speak one language instead of two dialects for one state.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { gh as defaultGh } from '../gh-exec.js';
|
|
39
|
+
import { gitSpawn as defaultGitSpawn, getStoryBranch } from '../git-utils.js';
|
|
40
|
+
import { deriveChecksStatus } from './merge-poll.js';
|
|
41
|
+
import { NEXT_COMMANDS } from './story-deliver-terminal.js';
|
|
42
|
+
import { STATE_LABELS } from './ticketing.js';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Probe the ticket: state labels, issue open/closed, and the lease holder.
|
|
46
|
+
*
|
|
47
|
+
* @returns {Promise<object>}
|
|
48
|
+
*/
|
|
49
|
+
export async function probeTicket({ provider, storyId }) {
|
|
50
|
+
try {
|
|
51
|
+
const ticket = await provider.getTicket(storyId);
|
|
52
|
+
const labels = Array.isArray(ticket?.labels) ? ticket.labels : [];
|
|
53
|
+
const stateLabel =
|
|
54
|
+
labels.find((l) => typeof l === 'string' && l.startsWith('agent::')) ??
|
|
55
|
+
null;
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
stateLabel,
|
|
59
|
+
labels,
|
|
60
|
+
issueState: ticket?.state ?? null,
|
|
61
|
+
title: ticket?.title ?? null,
|
|
62
|
+
lease: ticket?.assignees?.[0] ?? ticket?.assignee ?? null,
|
|
63
|
+
};
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return { ok: false, error: String(err?.message ?? err) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Probe the Story branch locally and its remote tracking ref, plus the
|
|
71
|
+
* worktree path. Pure git — no network.
|
|
72
|
+
*
|
|
73
|
+
* @returns {object}
|
|
74
|
+
*/
|
|
75
|
+
export function probeBranch({ cwd, storyBranch, config, gitSpawnFn }) {
|
|
76
|
+
const spawn = gitSpawnFn ?? defaultGitSpawn;
|
|
77
|
+
const localRef = spawn(
|
|
78
|
+
cwd,
|
|
79
|
+
'show-ref',
|
|
80
|
+
'--verify',
|
|
81
|
+
'--quiet',
|
|
82
|
+
`refs/heads/${storyBranch}`,
|
|
83
|
+
);
|
|
84
|
+
const remoteRef = spawn(
|
|
85
|
+
cwd,
|
|
86
|
+
'show-ref',
|
|
87
|
+
'--verify',
|
|
88
|
+
'--quiet',
|
|
89
|
+
`refs/remotes/origin/${storyBranch}`,
|
|
90
|
+
);
|
|
91
|
+
const worktreeRoot =
|
|
92
|
+
config?.delivery?.worktreeIsolation?.root ?? '.worktrees';
|
|
93
|
+
const worktrees = spawn(cwd, 'worktree', 'list', '--porcelain');
|
|
94
|
+
const worktreePath =
|
|
95
|
+
worktrees.status === 0 &&
|
|
96
|
+
typeof worktrees.stdout === 'string' &&
|
|
97
|
+
worktrees.stdout.includes(`${worktreeRoot}/${storyBranch}`)
|
|
98
|
+
? `${worktreeRoot}/${storyBranch}`
|
|
99
|
+
: null;
|
|
100
|
+
return {
|
|
101
|
+
local: localRef.status === 0,
|
|
102
|
+
remote: remoteRef.status === 0,
|
|
103
|
+
worktreePath,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Probe the PR for the Story branch. `--state all` is required: a merged PR
|
|
109
|
+
* is no longer `open`, and the merged-but-label-stale strand is precisely
|
|
110
|
+
* the one that matters most here.
|
|
111
|
+
*
|
|
112
|
+
* @returns {Promise<object|null>}
|
|
113
|
+
*/
|
|
114
|
+
export async function probePr({ storyBranch, gh = defaultGh }) {
|
|
115
|
+
try {
|
|
116
|
+
const rows = await gh.pr.list(
|
|
117
|
+
['--head', storyBranch, '--state', 'all'],
|
|
118
|
+
['number', 'url', 'state', 'mergedAt', 'statusCheckRollup'],
|
|
119
|
+
);
|
|
120
|
+
if (!Array.isArray(rows) || rows.length === 0) return null;
|
|
121
|
+
const row = rows[0];
|
|
122
|
+
return {
|
|
123
|
+
number: Number(row?.number) || null,
|
|
124
|
+
url: row?.url ?? null,
|
|
125
|
+
state: row?.state ?? null,
|
|
126
|
+
mergedAt: row?.mergedAt ?? null,
|
|
127
|
+
checksStatus: deriveChecksStatus(row?.statusCheckRollup),
|
|
128
|
+
};
|
|
129
|
+
} catch (err) {
|
|
130
|
+
return { error: String(err?.message ?? err) };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The decision table. Pure: every input is an already-observed probe, so the
|
|
136
|
+
* mapping is testable without git, GitHub, or a clock.
|
|
137
|
+
*
|
|
138
|
+
* Returns exactly one `{ shape, nextCommand, evidence[], detail }` — never a
|
|
139
|
+
* list of candidates.
|
|
140
|
+
*
|
|
141
|
+
* @param {{ storyId: number, ticket: object, branch: object, pr: object|null }} probes
|
|
142
|
+
* @returns {{ shape: string, nextCommand: string|null, detail: string, evidence: string[] }}
|
|
143
|
+
*/
|
|
144
|
+
export function decideRecovery({ storyId, ticket, branch, pr }) {
|
|
145
|
+
const evidence = [
|
|
146
|
+
`label=${ticket?.stateLabel ?? 'none'}`,
|
|
147
|
+
`issue=${ticket?.issueState ?? 'unknown'}`,
|
|
148
|
+
`pr=${pr?.number ? `#${pr.number} ${pr.state ?? '?'}` : 'none'}`,
|
|
149
|
+
`checks=${pr?.checksStatus ?? 'n/a'}`,
|
|
150
|
+
`branch.local=${branch?.local ?? false}`,
|
|
151
|
+
`branch.remote=${branch?.remote ?? false}`,
|
|
152
|
+
`worktree=${branch?.worktreePath ?? 'none'}`,
|
|
153
|
+
`lease=${ticket?.lease ?? 'unclaimed'}`,
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
const label = ticket?.stateLabel;
|
|
157
|
+
const merged = pr?.state === 'MERGED' || Boolean(pr?.mergedAt);
|
|
158
|
+
|
|
159
|
+
// A merged PR outranks every label reading. The code is on the base
|
|
160
|
+
// branch; whatever the label says, the only thing left is the flip + tail.
|
|
161
|
+
if (merged && label !== STATE_LABELS.DONE) {
|
|
162
|
+
return {
|
|
163
|
+
shape: 'merged-label-stale',
|
|
164
|
+
nextCommand: NEXT_COMMANDS.confirmMerge(storyId),
|
|
165
|
+
detail:
|
|
166
|
+
`PR #${pr.number} is MERGED but the Story is at \`${label ?? 'no state label'}\`. ` +
|
|
167
|
+
`A /deliver re-run cannot fix this — single-story-init.js hard-errors on an ` +
|
|
168
|
+
`already-closed Story. The confirm CLI is idempotent and flips the label from ` +
|
|
169
|
+
`the already-merged PR, then runs the land tail.`,
|
|
170
|
+
evidence,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (label === STATE_LABELS.BLOCKED) {
|
|
175
|
+
return {
|
|
176
|
+
shape: 'blocked',
|
|
177
|
+
nextCommand: NEXT_COMMANDS.recover(storyId),
|
|
178
|
+
detail:
|
|
179
|
+
`Story is at \`agent::blocked\`. The block was already classified when it was ` +
|
|
180
|
+
`filed — read the \`friction\` comment on #${storyId} for the class-specific ` +
|
|
181
|
+
`remediation, resolve it, then transition back to \`agent::executing\`. ` +
|
|
182
|
+
`Re-run this probe afterwards to confirm the strand cleared.`,
|
|
183
|
+
evidence,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (label === STATE_LABELS.DONE) {
|
|
188
|
+
return {
|
|
189
|
+
shape: 'done-board-drift',
|
|
190
|
+
nextCommand: NEXT_COMMANDS.resync(storyId),
|
|
191
|
+
detail:
|
|
192
|
+
`Story is \`agent::done\`. Nothing to deliver. If the Projects board still shows ` +
|
|
193
|
+
`it as In Progress, the GitHub built-in workflow won the post-merge race; the ` +
|
|
194
|
+
`resync re-asserts the column and is a no-op otherwise.`,
|
|
195
|
+
evidence,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (label === STATE_LABELS.CLOSING) {
|
|
200
|
+
if (pr?.checksStatus === 'failure') {
|
|
201
|
+
return {
|
|
202
|
+
shape: 'closing-pr-red',
|
|
203
|
+
nextCommand: NEXT_COMMANDS.watchCi(storyId, pr.number),
|
|
204
|
+
detail:
|
|
205
|
+
`PR #${pr.number} has a red required check. Waiting cannot help — fix the ` +
|
|
206
|
+
`failure and push a new commit on \`story-${storyId}\`; auto-merge stays armed ` +
|
|
207
|
+
`across retries.`,
|
|
208
|
+
evidence,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (pr?.number) {
|
|
212
|
+
return {
|
|
213
|
+
shape: 'closing-pr-pending',
|
|
214
|
+
nextCommand: NEXT_COMMANDS.resumeLand(storyId),
|
|
215
|
+
detail:
|
|
216
|
+
`PR #${pr.number} is open and healthy. This is the normal resumable shape after ` +
|
|
217
|
+
`a bounded merge wait returned \`pending\`. The confirm CLI polls it to a ` +
|
|
218
|
+
`confirmed merge and runs the land tail.`,
|
|
219
|
+
evidence,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
shape: 'closing-no-pr',
|
|
224
|
+
nextCommand: NEXT_COMMANDS.close(storyId),
|
|
225
|
+
detail:
|
|
226
|
+
`Story is at \`agent::closing\` but no PR exists for \`story-${storyId}\`. The ` +
|
|
227
|
+
`close did not reach the pull-request phase; re-run it (close is idempotent and ` +
|
|
228
|
+
`reuses an existing PR when one is found).`,
|
|
229
|
+
evidence,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (label === STATE_LABELS.EXECUTING) {
|
|
234
|
+
if (pr?.number) {
|
|
235
|
+
return {
|
|
236
|
+
shape: 'executing-with-pr',
|
|
237
|
+
nextCommand: NEXT_COMMANDS.close(storyId),
|
|
238
|
+
detail:
|
|
239
|
+
`PR #${pr.number} exists but the Story is still \`agent::executing\` — the close ` +
|
|
240
|
+
`opened the PR and then died before the label flip. Re-run close; it reuses the ` +
|
|
241
|
+
`open PR rather than opening a duplicate.`,
|
|
242
|
+
evidence,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
shape: 'executing-no-pr',
|
|
247
|
+
nextCommand: NEXT_COMMANDS.implement(storyId),
|
|
248
|
+
detail:
|
|
249
|
+
`Story is \`agent::executing\` with no PR. Implementation never finished. Re-init ` +
|
|
250
|
+
`(idempotent — it reuses the existing branch and worktree) and resume in the ` +
|
|
251
|
+
`worktree it prints.`,
|
|
252
|
+
evidence,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
shape: 'ready',
|
|
258
|
+
nextCommand: NEXT_COMMANDS.close(storyId),
|
|
259
|
+
detail:
|
|
260
|
+
`Story is at \`${label ?? 'no agent:: state label'}\` — not mid-delivery, so there ` +
|
|
261
|
+
`is no strand to recover. Deliver it normally via /deliver ${storyId}.`,
|
|
262
|
+
evidence,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Probe live state and resolve the single next command. Read-only.
|
|
268
|
+
*
|
|
269
|
+
* @param {object} args
|
|
270
|
+
* @param {number} args.storyId
|
|
271
|
+
* @param {string} args.cwd
|
|
272
|
+
* @param {object} args.provider
|
|
273
|
+
* @param {object} [args.config]
|
|
274
|
+
* @param {object} [args.gh]
|
|
275
|
+
* @param {Function} [args.gitSpawnFn]
|
|
276
|
+
* @returns {Promise<object>}
|
|
277
|
+
*/
|
|
278
|
+
export async function recoverStory({
|
|
279
|
+
storyId,
|
|
280
|
+
cwd,
|
|
281
|
+
provider,
|
|
282
|
+
config,
|
|
283
|
+
gh = defaultGh,
|
|
284
|
+
gitSpawnFn,
|
|
285
|
+
}) {
|
|
286
|
+
const storyBranch = getStoryBranch(storyId);
|
|
287
|
+
const ticket = await probeTicket({ provider, storyId });
|
|
288
|
+
if (!ticket.ok) {
|
|
289
|
+
throw new Error(
|
|
290
|
+
`deliver-recover: could not read Story #${storyId}: ${ticket.error}`,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
const branch = probeBranch({ cwd, storyBranch, config, gitSpawnFn });
|
|
294
|
+
const pr = await probePr({ storyBranch, gh });
|
|
295
|
+
const decision = decideRecovery({ storyId, ticket, branch, pr });
|
|
296
|
+
return {
|
|
297
|
+
storyId,
|
|
298
|
+
storyBranch,
|
|
299
|
+
probes: { ticket, branch, pr },
|
|
300
|
+
...decision,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Render the operator-facing report: the shape, the one command, and the
|
|
306
|
+
* evidence it was derived from — so the operator can check the reasoning
|
|
307
|
+
* rather than trust it.
|
|
308
|
+
*
|
|
309
|
+
* @param {object} recovery
|
|
310
|
+
* @returns {string}
|
|
311
|
+
*/
|
|
312
|
+
export function renderRecovery(recovery) {
|
|
313
|
+
const lines = [
|
|
314
|
+
`Story #${recovery.storyId} — ${recovery.shape}`,
|
|
315
|
+
'',
|
|
316
|
+
recovery.detail,
|
|
317
|
+
'',
|
|
318
|
+
'Evidence:',
|
|
319
|
+
...recovery.evidence.map((e) => ` - ${e}`),
|
|
320
|
+
'',
|
|
321
|
+
];
|
|
322
|
+
if (recovery.nextCommand) {
|
|
323
|
+
lines.push('Next command:', ` ${recovery.nextCommand}`, '');
|
|
324
|
+
} else {
|
|
325
|
+
lines.push('Next command: none — nothing to do.', '');
|
|
326
|
+
}
|
|
327
|
+
return lines.join('\n');
|
|
328
|
+
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* detectors-phase.js — pure
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* detectors-phase.js — pure phase that runs the per-Story signal detectors
|
|
3
|
+
* (rework + retry) over the local NDJSON stream.
|
|
4
|
+
*
|
|
5
|
+
* Story #4545 — this phase has no production caller. Its sequencer
|
|
6
|
+
* (`post-merge-pipeline.js`) went in the v2.0.0 cutover, and the
|
|
7
|
+
* `analyze-execution.js` consumer it fed was deleted with the
|
|
8
|
+
* execution-analysis surface. Kept alive only by its own test — the
|
|
9
|
+
* test-importer blind spot the dead-exports ratchet cannot see.
|
|
5
10
|
*
|
|
6
11
|
* Extracted from `post-merge-pipeline.js` (Story #1770 / Task #1779) to
|
|
7
12
|
* keep the parent sequencer's maintainability score above its baseline
|
|
@@ -39,8 +44,9 @@
|
|
|
39
44
|
* @module lib/orchestration/detectors-phase
|
|
40
45
|
*/
|
|
41
46
|
|
|
47
|
+
import path from 'node:path';
|
|
42
48
|
import { getSignals } from '../config/limits.js';
|
|
43
|
-
import {
|
|
49
|
+
import { storyTempDir } from '../config/temp-paths.js';
|
|
44
50
|
import { Logger } from '../Logger.js';
|
|
45
51
|
import { appendSignal } from '../observability/signals-writer.js';
|
|
46
52
|
import { detectRetry, detectRework } from '../signals/detectors/index.js';
|
|
@@ -114,7 +120,7 @@ function isValidIdPair(eid, sid) {
|
|
|
114
120
|
|
|
115
121
|
/**
|
|
116
122
|
* Run the rework + retry detectors for one Story and persist every
|
|
117
|
-
* emission to `temp/
|
|
123
|
+
* emission to `temp/run-<id>/stories/story-<sid>/signals.ndjson`.
|
|
118
124
|
*
|
|
119
125
|
* @param {{
|
|
120
126
|
* epicId: number|string,
|
|
@@ -159,7 +165,7 @@ export async function detectorsPhase(ctx) {
|
|
|
159
165
|
return { rework: 0, retry: 0 };
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
const tracesPath =
|
|
168
|
+
const tracesPath = path.join(storyTempDir(eid, sid, config), 'traces.ndjson');
|
|
163
169
|
const taskId = resolveLastTaskId(tasks);
|
|
164
170
|
const baseArgs = { tracesPath, epicId: eid, storyId: sid, taskId };
|
|
165
171
|
const common = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* docs-digest.js — per-
|
|
2
|
+
* docs-digest.js — per-run docs digest builder (Story #4338).
|
|
3
3
|
*
|
|
4
4
|
* `/deliver` story sub-agents previously re-read every file in
|
|
5
5
|
* `project.docsContextFiles` on every Story, re-paying the full docs payload
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* Story #4433 extends this module with {@link ensureDocsDigest}, a shared
|
|
17
17
|
* generate-and-write export so the planner-context surface
|
|
18
18
|
* (`plan-context.js` / `authoring-context.js`) can produce a session docs
|
|
19
|
-
* digest without duplicating the mkdir+writeFile plumbing
|
|
20
|
-
* `
|
|
19
|
+
* digest without duplicating the mkdir+writeFile plumbing shared by
|
|
20
|
+
* `plan-context.js` / `authoring-context.js` and the `/deliver` workflow.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import fs from 'node:fs';
|
|
@@ -110,7 +110,7 @@ function renderDocSection(doc) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
* Build the per-
|
|
113
|
+
* Build the per-run docs digest markdown from the configured docs context
|
|
114
114
|
* files. Missing files are skipped silently (the read seam returns only the
|
|
115
115
|
* files it could stat + read). Returns `null` when there is nothing to digest
|
|
116
116
|
* — i.e. `docsContextFiles` is empty/unset — so callers surface a null
|
|
@@ -130,7 +130,7 @@ export async function buildDocsDigest({ docsContextFiles, docsRoot } = {}) {
|
|
|
130
130
|
const header = [
|
|
131
131
|
'# Docs digest',
|
|
132
132
|
'',
|
|
133
|
-
'Per-
|
|
133
|
+
'Per-run outline of the project docs context set. Each entry lists the',
|
|
134
134
|
'file path, byte size, and its heading outline (with line numbers) plus',
|
|
135
135
|
'the first paragraph under each `##` section. Read the full file on demand',
|
|
136
136
|
'when a section looks relevant — do **not** ingest the whole set per Story.',
|
|
@@ -144,10 +144,10 @@ export async function buildDocsDigest({ docsContextFiles, docsRoot } = {}) {
|
|
|
144
144
|
/**
|
|
145
145
|
* Build the docs digest and write it to `outputPath`, returning `null` (no
|
|
146
146
|
* write) when there is nothing to digest. This is the single shared
|
|
147
|
-
* generate-and-persist export both digest producers call: the per-
|
|
148
|
-
*
|
|
147
|
+
* generate-and-persist export both digest producers call: the per-run
|
|
148
|
+
* `/deliver` docs digest (`helpers/deliver-story.md`) and the planner-
|
|
149
149
|
* context digest (`plan-context.js` → `authoring-context.js`, Story
|
|
150
|
-
* #4433). Callers own path construction (temp-root layout,
|
|
150
|
+
* #4433). Callers own path construction (temp-root layout, run id, etc.)
|
|
151
151
|
* so both surfaces can keep — or deliberately share — their own convention;
|
|
152
152
|
* this function only owns "build digest, ensure parent dir, write file".
|
|
153
153
|
*
|
|
@@ -45,11 +45,10 @@
|
|
|
45
45
|
* the shared-editor conflict gate's domain — that finding's rendering is
|
|
46
46
|
* cross-referenced (see `renderMismatch`), not duplicated here.
|
|
47
47
|
*
|
|
48
|
-
*
|
|
49
|
-
* strings
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* see a clear migration nudge without a hard failure mid-flight.
|
|
48
|
+
* String bullets: stories whose `body.changes` items are still bare
|
|
49
|
+
* strings are hard errors — they are pushed to `errors[]` by the
|
|
50
|
+
* validator's body-shape gate before this module runs. There is no
|
|
51
|
+
* silent skip or deprecation nudge.
|
|
53
52
|
*/
|
|
54
53
|
|
|
55
54
|
import { gitSpawn } from '../git-utils.js';
|
|
@@ -319,21 +318,16 @@ export function validateStoryFileAssumptions(opts) {
|
|
|
319
318
|
const entries = collectStoryAssumptionEntries(story);
|
|
320
319
|
|
|
321
320
|
if (entries.length === 0) {
|
|
322
|
-
// Legacy path: this Story carries no object-form entries. Emit a
|
|
323
|
-
// single deprecation warning so the operator sees the migration
|
|
324
|
-
// nudge once per Story rather than per-bullet.
|
|
325
321
|
if (hasLegacyChangeBullets(story)) {
|
|
326
|
-
|
|
327
|
-
`"${slug}" → body.changes uses legacy string bullets without { path, assumption }. Migrate to object form so Phase 8 can verify file-state assumptions. See Story #2636.`,
|
|
322
|
+
errors.push(
|
|
323
|
+
`"${slug}" → body.changes uses legacy string bullets without { path, assumption }. Migrate every bullet to object form so Phase 8 can verify file-state assumptions. See Story #2636.`,
|
|
328
324
|
);
|
|
329
325
|
}
|
|
330
326
|
continue;
|
|
331
327
|
}
|
|
332
328
|
|
|
333
|
-
// Partial-migration warning: some entries are object-form, some are
|
|
334
|
-
// still strings. Surface once so the operator notices the gap.
|
|
335
329
|
if (hasLegacyChangeBullets(story)) {
|
|
336
|
-
|
|
330
|
+
errors.push(
|
|
337
331
|
`"${slug}" → body.changes mixes object-form entries with legacy string bullets. Migrate every bullet for full freshness coverage.`,
|
|
338
332
|
);
|
|
339
333
|
}
|
|
@@ -26,7 +26,7 @@ function resolveBaseBranch(cwd, override) {
|
|
|
26
26
|
if (override) return override;
|
|
27
27
|
try {
|
|
28
28
|
const cfg = resolveConfig({ cwd });
|
|
29
|
-
return cfg?.project?.baseBranch ||
|
|
29
|
+
return cfg?.project?.baseBranch || 'main';
|
|
30
30
|
} catch {
|
|
31
31
|
return 'main';
|
|
32
32
|
}
|
|
@@ -59,6 +59,36 @@ export function planFastForward(ctx) {
|
|
|
59
59
|
return { runnable: true, behind: ff.behind, currentBranch: cur };
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Return HEAD to the branch it started on.
|
|
64
|
+
*
|
|
65
|
+
* {@link maybeCheckout} moves the checkout to `baseBranch` so `merge
|
|
66
|
+
* --ff-only` has somewhere to land. Leaving it there silently relocates the
|
|
67
|
+
* operator: this phase runs from the MAIN checkout — which may be parked on
|
|
68
|
+
* unrelated work — and the close tail can reach it long after the operator
|
|
69
|
+
* walked away (a belated `single-story-confirm-merge --wait`, for instance).
|
|
70
|
+
* Fast-forwarding the base branch is the contract every delivering flow owes
|
|
71
|
+
* the checkout; moving someone off the branch they were using is not, and it
|
|
72
|
+
* is the kind of surprise that gets subsequent work committed to the wrong
|
|
73
|
+
* branch.
|
|
74
|
+
*
|
|
75
|
+
* Best-effort: a failed restore warns and never fails the phase — the
|
|
76
|
+
* fast-forward already succeeded, and `planFastForward` refuses on a dirty
|
|
77
|
+
* tree, so nothing uncommitted is ever at risk here.
|
|
78
|
+
*/
|
|
79
|
+
function restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger }) {
|
|
80
|
+
const original = plan.currentBranch;
|
|
81
|
+
if (!original || original === baseBranch) return;
|
|
82
|
+
const co = checkoutFn(cwd, original);
|
|
83
|
+
if (!co.ok) {
|
|
84
|
+
logger.warn?.(
|
|
85
|
+
`${TAG} ⚠️ checkout left on ${baseBranch}: restoring ${original} failed: ${co.stderr}`,
|
|
86
|
+
);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
logger.info?.(`${TAG} ↩️ restored checkout to ${original}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
62
92
|
function maybeCheckout({ plan, baseBranch, cwd, checkoutFn, logger }) {
|
|
63
93
|
if (!plan.currentBranch || plan.currentBranch === baseBranch) {
|
|
64
94
|
return { ok: true };
|
|
@@ -108,6 +138,9 @@ export function executeFastForward(ctx) {
|
|
|
108
138
|
logger.warn?.(
|
|
109
139
|
`${TAG} ❌ merge --ff-only ${ref} failed: ${mergeRes.stderr}`,
|
|
110
140
|
);
|
|
141
|
+
// We already moved HEAD to run the merge; put it back even on the
|
|
142
|
+
// failure path rather than stranding the operator on the base branch.
|
|
143
|
+
restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger });
|
|
111
144
|
return {
|
|
112
145
|
ok: false,
|
|
113
146
|
applied: false,
|
|
@@ -119,5 +152,6 @@ export function executeFastForward(ctx) {
|
|
|
119
152
|
logger.info?.(
|
|
120
153
|
`${TAG} ✅ fast-forwarded ${baseBranch} by ${plan.behind} commit(s)`,
|
|
121
154
|
);
|
|
155
|
+
restoreBranchIfMoved({ plan, baseBranch, cwd, checkoutFn, logger });
|
|
122
156
|
return { ok: true, applied: true, skipped: false, behind: plan.behind };
|
|
123
157
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* lease-guard-shared.js — Story #3992: single-source the lease-acquisition
|
|
3
3
|
* kernel shared by the three per-surface lease guards.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The per-surface lease guards — today `single-story-lease-guard.js`;
|
|
6
|
+
* historically also the retired Epic-tier deliver/plan guards —
|
|
7
|
+
* each carried their own copy of
|
|
7
8
|
* the operator-handle resolution and the fail-closed acquire wrapper around
|
|
8
9
|
* `ticket-lease.acquireLease` (anchor `heartbeatAt` to `now` so a foreign
|
|
9
10
|
* assignee always reads as a live claim, then throw an operator-facing
|