mandrel 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +59 -28
- package/.agents/agents/acceptance-critic.md +20 -9
- package/.agents/agents/story-worker.md +45 -48
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +60 -46
- package/.agents/docs/agentrc-reference.json +8 -13
- package/.agents/docs/configuration.md +33 -57
- package/.agents/docs/execution-reference.md +39 -10
- package/.agents/docs/quality-gates.md +17 -19
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +64 -79
- package/.agents/rules/ci-remediation.md +3 -3
- package/.agents/rules/gherkin-standards.md +10 -0
- package/.agents/rules/git-conventions-reference.md +42 -51
- package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
- package/.agents/schemas/agentrc.schema.json +35 -46
- 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/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 +24 -68
- package/.agents/scripts/agents-bootstrap-github.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 +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- 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/audit-suite/selector.js +323 -23
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -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 +4 -1
- package/.agents/scripts/lib/checks/index.js +1 -1
- 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 +3 -3
- 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-args.js +23 -2
- package/.agents/scripts/lib/close-validation/gates.js +13 -13
- 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/acceptance-eval.js +2 -2
- package/.agents/scripts/lib/config/delivery-routing.js +7 -6
- package/.agents/scripts/lib/config/explain.js +10 -16
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +15 -25
- package/.agents/scripts/lib/config/quality.js +11 -14
- package/.agents/scripts/lib/config/runners.js +8 -21
- package/.agents/scripts/lib/config/temp-paths.js +18 -56
- package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
- package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
- package/.agents/scripts/lib/config-settings-schema.js +48 -22
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/duplicate-search.js +38 -7
- 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 -189
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
- package/.agents/scripts/lib/git-utils.js +0 -14
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +0 -15
- package/.agents/scripts/lib/label-taxonomy.js +1 -12
- package/.agents/scripts/lib/observability/active-story-env.js +42 -163
- 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 +2 -2
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- 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 +43 -45
- package/.agents/scripts/lib/orchestration/change-set.js +103 -0
- package/.agents/scripts/lib/orchestration/code-review.js +70 -191
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
- 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/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 +9 -11
- 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/listeners/README.md +7 -3
- 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/merge-block-class.js +76 -20
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
- package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
- 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/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 +374 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
- 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 +4 -13
- 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 +72 -30
- 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 +12 -8
- 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 +264 -43
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
- package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
- package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
- package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
- package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
- 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 -286
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- 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/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +8 -7
- package/.agents/scripts/lib/story-body/story-body.js +81 -13
- package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/ticket-body-sections.js +0 -14
- package/.agents/scripts/lib/validation-evidence.js +31 -59
- package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/plan-context.js +38 -7
- package/.agents/scripts/plan-critics.js +203 -0
- package/.agents/scripts/plan-persist.js +145 -35
- package/.agents/scripts/plan-run-epilogue.js +83 -38
- 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 +1 -11
- package/.agents/scripts/providers/github/mappers.js +5 -0
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -153
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/quality-preview.js +13 -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 +9 -10
- package/.agents/scripts/single-story-close.js +173 -18
- package/.agents/scripts/single-story-confirm-merge.js +288 -15
- package/.agents/scripts/single-story-init.js +6 -10
- package/.agents/scripts/stories-wave-tick.js +380 -53
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/update-ticket-state.js +8 -50
- 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 +3 -3
- package/.agents/skills/core/scope-triage/SKILL.md +3 -0
- 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 +2 -12
- 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/workflows/audit-architecture.md +3 -4
- package/.agents/workflows/audit-clean-code.md +4 -4
- package/.agents/workflows/audit-documentation.md +4 -5
- package/.agents/workflows/audit-lighthouse.md +8 -0
- package/.agents/workflows/audit-navigability.md +10 -0
- package/.agents/workflows/audit-performance.md +2 -3
- package/.agents/workflows/audit-quality.md +8 -9
- package/.agents/workflows/audit-security.md +1 -2
- package/.agents/workflows/audit-seo.md +10 -0
- package/.agents/workflows/audit-ux-ui.md +7 -0
- package/.agents/workflows/deliver.md +133 -45
- package/.agents/workflows/git-cleanup.md +2 -2
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
- package/.agents/workflows/helpers/code-review.md +14 -12
- package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
- package/.agents/workflows/helpers/deliver-story.md +209 -118
- package/.agents/workflows/helpers/parallel-tooling.md +2 -2
- package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
- package/.agents/workflows/plan.md +239 -19
- package/.agents/workflows/qa-assist.md +6 -6
- package/.agents/workflows/qa-explore.md +3 -3
- package/.agents/workflows/qa-run.md +1 -5
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +62 -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 +17 -9
- 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/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
- package/package.json +2 -2
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- 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/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -53
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- 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 -187
- 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/audit-lens-routing.js +0 -128
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- 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/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
- 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 -21
- 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 -397
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
- package/.agents/scripts/resolve-plan-run.js +0 -117
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* root `npm run lint` walks into the orphan tree, hits the nested config,
|
|
7
7
|
* and fails. The close-time biome block is the canonical symptom.
|
|
8
8
|
*
|
|
9
|
-
* Surface: `
|
|
10
|
-
*
|
|
9
|
+
* Surface: `story-close` preflight, the `/diagnose` CLI, and retro.
|
|
10
|
+
* Surfaced as a blocker so the operator clears the residue
|
|
11
11
|
* with `rm -rf` before close re-runs the validation chain.
|
|
12
12
|
*
|
|
13
13
|
* AutoCorrect is `refuse-and-print`. Recursive deletion under `.worktrees/`
|
|
@@ -21,7 +21,7 @@ const ID = 'worktree-residue-biome';
|
|
|
21
21
|
export default {
|
|
22
22
|
id: ID,
|
|
23
23
|
severity: 'blocker',
|
|
24
|
-
scope: ['
|
|
24
|
+
scope: ['story-close', 'diagnose', 'retro'],
|
|
25
25
|
autoCorrect: 'refuse-and-print',
|
|
26
26
|
detect(state) {
|
|
27
27
|
const orphans = state?.fs?.worktreeBiomeOrphans ?? [];
|
|
@@ -46,6 +46,22 @@ function optionalBooleanFlag(value) {
|
|
|
46
46
|
return coerceBooleanFlag(value);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Parse a positive-integer flag, preserving `undefined` when the flag is
|
|
51
|
+
* absent so a caller can distinguish "not supplied" (fall back to config)
|
|
52
|
+
* from an explicit value. A non-numeric or non-positive value is treated as
|
|
53
|
+
* absent rather than coerced to 0 — a `--max-wait-seconds=abc` typo must not
|
|
54
|
+
* silently become a zero-second wait.
|
|
55
|
+
*
|
|
56
|
+
* @param {unknown} value
|
|
57
|
+
* @returns {number|undefined}
|
|
58
|
+
*/
|
|
59
|
+
function parsePositiveInt(value) {
|
|
60
|
+
if (value === undefined || value === null) return undefined;
|
|
61
|
+
const parsed = Number.parseInt(String(value), 10);
|
|
62
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
/**
|
|
50
66
|
* Standardized CLI argument parser for sprint scripts.
|
|
51
67
|
* Supports options like --epic, --story, --dry-run, --skip-dashboard.
|
|
@@ -63,10 +79,12 @@ export function parseSprintArgs(args = process.argv) {
|
|
|
63
79
|
'skip-validation': { type: 'boolean', default: false },
|
|
64
80
|
'skip-sync': { type: 'boolean', default: false },
|
|
65
81
|
'no-auto-merge': { type: 'boolean', default: false },
|
|
66
|
-
'no-full-scope-crap': { type: 'boolean', default: false },
|
|
67
82
|
// No default — absent means "use delivery.routing.closeAndLand".
|
|
68
83
|
'wait-merge': { type: 'boolean' },
|
|
69
84
|
'no-wait-merge': { type: 'boolean', default: false },
|
|
85
|
+
// Story #4543 — per-run override of `delivery.mergeWatch.maxWaitSeconds`
|
|
86
|
+
// (the merge wait's per-invocation bound). Absent means "use the config".
|
|
87
|
+
'max-wait-seconds': { type: 'string' },
|
|
70
88
|
executor: { type: 'string' },
|
|
71
89
|
cwd: { type: 'string' },
|
|
72
90
|
'recut-of': { type: 'string' },
|
|
@@ -87,13 +105,16 @@ export function parseSprintArgs(args = process.argv) {
|
|
|
87
105
|
skipValidation: coerceBooleanFlag(values['skip-validation']),
|
|
88
106
|
skipSync: coerceBooleanFlag(values['skip-sync']),
|
|
89
107
|
noAutoMerge: coerceBooleanFlag(values['no-auto-merge']),
|
|
90
|
-
noFullScopeCrap: coerceBooleanFlag(values['no-full-scope-crap']),
|
|
91
108
|
// Close-and-land: `--wait-merge` forces land-in-close; `--no-wait-merge`
|
|
92
109
|
// opts out. When neither flag is present (`undefined`),
|
|
93
110
|
// `parseCloseOptions` applies `delivery.routing.closeAndLand` (default
|
|
94
111
|
// true) so attended and headless delivers share the same happy path.
|
|
95
112
|
waitForMerge: optionalBooleanFlag(values['wait-merge']),
|
|
96
113
|
noWaitForMerge: coerceBooleanFlag(values['no-wait-merge']),
|
|
114
|
+
// Story #4543 — raise the merge wait's per-invocation bound for a
|
|
115
|
+
// headless caller with no host tool-invocation ceiling, so it lands in
|
|
116
|
+
// one block instead of returning `pending` at the default 300s.
|
|
117
|
+
maxWaitSeconds: parsePositiveInt(values['max-wait-seconds']),
|
|
97
118
|
executor: values.executor ?? null,
|
|
98
119
|
// Resolve worktree cwd from flag or env. Empty string/whitespace → null.
|
|
99
120
|
cwd:
|
|
@@ -54,22 +54,22 @@ function buildChangedFileScope(baseRef) {
|
|
|
54
54
|
*
|
|
55
55
|
* The baselines gate resolves its compare ref through `resolveScope`,
|
|
56
56
|
* whose environment layer reads `BASELINE_REF`. Threading
|
|
57
|
-
* `origin/<
|
|
57
|
+
* `origin/<baseBranch>` here makes the gate diff head against the epic
|
|
58
58
|
* integration branch instead of the framework-default `origin/main`, so
|
|
59
59
|
* drift that already landed on `main` but is outside the Story's own diff
|
|
60
60
|
* does not surface as a phantom regression. The same convention
|
|
61
|
-
* (`origin/<
|
|
61
|
+
* (`origin/<baseBranch>`) is used by the baseline-attribution and
|
|
62
62
|
* auto-refresh paths, keeping read/compare bases aligned.
|
|
63
63
|
*
|
|
64
64
|
* Returns `null` when no integration branch is supplied (the gate then
|
|
65
65
|
* keeps its existing default-ref / consumer-config behaviour untouched).
|
|
66
66
|
*
|
|
67
|
-
* @param {string|undefined|null}
|
|
67
|
+
* @param {string|undefined|null} baseBranch
|
|
68
68
|
* @returns {{ BASELINE_REF: string } | null}
|
|
69
69
|
*/
|
|
70
|
-
function buildBaselinesGateEnv(
|
|
71
|
-
if (typeof
|
|
72
|
-
return { BASELINE_REF: `origin/${
|
|
70
|
+
function buildBaselinesGateEnv(baseBranch) {
|
|
71
|
+
if (typeof baseBranch !== 'string' || baseBranch.length === 0) return null;
|
|
72
|
+
return { BASELINE_REF: `origin/${baseBranch}` };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -240,11 +240,11 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
|
|
|
240
240
|
* shared in-process runner. The unified `check-baselines` gate is now the
|
|
241
241
|
* single source of truth for per-kind regression enforcement
|
|
242
242
|
* (attribution-wired floor + tolerance + schema).
|
|
243
|
-
* The `
|
|
243
|
+
* The `baseBranch` parameter threads the close run's integration branch
|
|
244
244
|
* into two gates: the `format` gate's `changedFileScope` (existing) and —
|
|
245
245
|
* since Story #3890 — the `check-baselines` gate's `BASELINE_REF` env, so
|
|
246
246
|
* the baselines regression compare diffs head against the epic integration
|
|
247
|
-
* branch (`origin/<
|
|
247
|
+
* branch (`origin/<baseBranch>`) rather than the framework-default
|
|
248
248
|
* `origin/main`. Without this, every child Story on an `epic/<id>` branch
|
|
249
249
|
* re-discovered inherited main-vs-epic drift in untouched files as phantom
|
|
250
250
|
* regressions and worked around it by hand-setting `BASELINE_REF`.
|
|
@@ -268,10 +268,10 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
|
|
|
268
268
|
* none are required, the gate is skipped with a logged reason (via `log`)
|
|
269
269
|
* instead of a blocking failure.
|
|
270
270
|
*
|
|
271
|
-
* @param {{ config?: object,
|
|
271
|
+
* @param {{ config?: object, baseBranch?: string, cwd?: string, packageScripts?: Record<string, string>, presentBaselines?: string[]|Set<string>, log?: (message: string) => void }} [opts]
|
|
272
272
|
* `config` is the canonical resolved config (`{ project, delivery, ... }`);
|
|
273
273
|
* gate commands resolve from `project.commands` and the CRAP toggle from
|
|
274
|
-
* `delivery.quality.gates.crap.enabled`. `
|
|
274
|
+
* `delivery.quality.gates.crap.enabled`. `baseBranch` is the close run's
|
|
275
275
|
* integration branch (`epic/<id>` for Epic-attached Stories, the base
|
|
276
276
|
* branch for standalone Stories). `cwd` is where the `package.json`
|
|
277
277
|
* coverage-script probe and the `baselines/<kind>.json` presence probe
|
|
@@ -285,7 +285,7 @@ function probeBaselinesGate({ config, cwd, presentBaselines } = {}) {
|
|
|
285
285
|
*/
|
|
286
286
|
export function buildDefaultGates({
|
|
287
287
|
config,
|
|
288
|
-
|
|
288
|
+
baseBranch,
|
|
289
289
|
cwd,
|
|
290
290
|
packageScripts,
|
|
291
291
|
presentBaselines,
|
|
@@ -305,9 +305,9 @@ export function buildDefaultGates({
|
|
|
305
305
|
const formatWriteString = resolveFormatWriteCommand(config);
|
|
306
306
|
const formatChangedFileScope =
|
|
307
307
|
formatCheckString === FORMAT_CHECK_FALLBACK
|
|
308
|
-
? buildChangedFileScope(
|
|
308
|
+
? buildChangedFileScope(baseBranch)
|
|
309
309
|
: null;
|
|
310
|
-
const baselinesGateEnv = buildBaselinesGateEnv(
|
|
310
|
+
const baselinesGateEnv = buildBaselinesGateEnv(baseBranch);
|
|
311
311
|
const baselinesDecision = probeBaselinesGate({
|
|
312
312
|
config,
|
|
313
313
|
cwd,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* inputs.js — shared input validator for close-validation projection helpers.
|
|
4
4
|
*
|
|
5
5
|
* Used by `projections/maintainability.js` (and any future projection that
|
|
6
|
-
* shares the same `{ cwd,
|
|
6
|
+
* shares the same `{ cwd, baseBranch, storyBranch, baselinePath }` argument
|
|
7
7
|
* shape) to collapse the inline guard cascade into a single predicate that
|
|
8
8
|
* returns a typed `reason` on failure.
|
|
9
9
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
/**
|
|
17
17
|
* @typedef {Object} ProjectionInputs
|
|
18
18
|
* @property {string} [cwd]
|
|
19
|
-
* @property {string} [
|
|
19
|
+
* @property {string} [baseBranch]
|
|
20
20
|
* @property {string} [storyBranch]
|
|
21
21
|
* @property {string} [baselinePath]
|
|
22
22
|
*/
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
/**
|
|
33
33
|
* @typedef {Object} ValidationFail
|
|
34
34
|
* @property {false} ok
|
|
35
|
-
* @property {'missing-cwd'|'missing-
|
|
35
|
+
* @property {'missing-cwd'|'missing-base-branch'|'missing-story-branch'|'missing-baseline-path'|'no-baseline'} reason
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
*
|
|
41
41
|
* Reason branches (in order):
|
|
42
42
|
* - `missing-cwd` — cwd is falsy
|
|
43
|
-
* - `missing-
|
|
43
|
+
* - `missing-base-branch` — baseBranch is falsy
|
|
44
44
|
* - `missing-story-branch` — storyBranch is falsy
|
|
45
45
|
* - `missing-baseline-path` — baselinePath is falsy
|
|
46
46
|
* - `no-baseline` — loadBaseline returned null/undefined/empty
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
* @returns {ValidationOk | ValidationFail}
|
|
55
55
|
*/
|
|
56
56
|
export function validateProjectionInputs(inputs, opts = {}) {
|
|
57
|
-
const { cwd,
|
|
57
|
+
const { cwd, baseBranch, storyBranch, baselinePath } = inputs ?? {};
|
|
58
58
|
if (!cwd) return { ok: false, reason: 'missing-cwd' };
|
|
59
|
-
if (!
|
|
59
|
+
if (!baseBranch) return { ok: false, reason: 'missing-base-branch' };
|
|
60
60
|
if (!storyBranch) return { ok: false, reason: 'missing-story-branch' };
|
|
61
61
|
if (!baselinePath) return { ok: false, reason: 'missing-baseline-path' };
|
|
62
62
|
|
|
@@ -80,7 +80,7 @@ export function validateProjectionInputs(inputs, opts = {}) {
|
|
|
80
80
|
*/
|
|
81
81
|
export const MISSING_ARG_REASONS = new Set([
|
|
82
82
|
'missing-cwd',
|
|
83
|
-
'missing-
|
|
83
|
+
'missing-base-branch',
|
|
84
84
|
'missing-story-branch',
|
|
85
85
|
'missing-baseline-path',
|
|
86
86
|
]);
|
|
@@ -41,18 +41,18 @@ function normaliseSkipReason(reason) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Refresh `origin/<
|
|
44
|
+
* Refresh `origin/<baseBranch>` so the diff range resolves even when the
|
|
45
45
|
* close script hasn't reached its own pull/rebase step yet. Routed through
|
|
46
46
|
* the shared `(cwd, ref, windowMs)` cache so a story-init fetch in the same
|
|
47
47
|
* wave satisfies the projection without re-hitting origin.
|
|
48
48
|
*
|
|
49
49
|
* @param {string} cwd
|
|
50
|
-
* @param {string}
|
|
50
|
+
* @param {string} baseBranch
|
|
51
51
|
* @param {{ gitSpawn: typeof defaultGitSpawn }} git
|
|
52
52
|
* @returns {{ ok: true } | { ok: false, detail: string }}
|
|
53
53
|
*/
|
|
54
|
-
function refreshEpicRef(cwd,
|
|
55
|
-
const fetchRes = cachedGitFetchSync(cwd,
|
|
54
|
+
function refreshEpicRef(cwd, baseBranch, git) {
|
|
55
|
+
const fetchRes = cachedGitFetchSync(cwd, baseBranch, {
|
|
56
56
|
gitSpawn: git.gitSpawn,
|
|
57
57
|
});
|
|
58
58
|
if (fetchRes.status !== 0) {
|
|
@@ -69,13 +69,13 @@ function refreshEpicRef(cwd, epicBranch, git) {
|
|
|
69
69
|
* the changed-files list. Normalises Windows-style backslash paths to
|
|
70
70
|
* forward slashes so the baseline lookup is platform-agnostic.
|
|
71
71
|
*
|
|
72
|
-
* @param {{ cwd: string,
|
|
72
|
+
* @param {{ cwd: string, baseBranch: string, storyBranch: string, git: { gitSpawn: typeof defaultGitSpawn } }} opts
|
|
73
73
|
* @returns {{ ok: true, files: string[] } | { ok: false, detail: string }}
|
|
74
74
|
*/
|
|
75
|
-
function diffChangedFiles({ cwd,
|
|
75
|
+
function diffChangedFiles({ cwd, baseBranch, storyBranch, git }) {
|
|
76
76
|
try {
|
|
77
77
|
const files = diffNameOnly({
|
|
78
|
-
range: `origin/${
|
|
78
|
+
range: `origin/${baseBranch}...${storyBranch}`,
|
|
79
79
|
cwd,
|
|
80
80
|
gitSpawn: git.gitSpawn,
|
|
81
81
|
});
|
|
@@ -190,7 +190,7 @@ function collectRegressions({
|
|
|
190
190
|
*
|
|
191
191
|
* @param {{
|
|
192
192
|
* cwd: string,
|
|
193
|
-
*
|
|
193
|
+
* baseBranch: string,
|
|
194
194
|
* storyBranch: string,
|
|
195
195
|
* baselinePath: string,
|
|
196
196
|
* tolerance?: number,
|
|
@@ -207,7 +207,7 @@ function collectRegressions({
|
|
|
207
207
|
*/
|
|
208
208
|
export function projectMaintainabilityRegressions({
|
|
209
209
|
cwd,
|
|
210
|
-
|
|
210
|
+
baseBranch,
|
|
211
211
|
storyBranch,
|
|
212
212
|
baselinePath,
|
|
213
213
|
tolerance = DEFAULT_MI_TOLERANCE,
|
|
@@ -216,7 +216,7 @@ export function projectMaintainabilityRegressions({
|
|
|
216
216
|
loadBaseline = getBaseline,
|
|
217
217
|
} = {}) {
|
|
218
218
|
const validation = validateProjectionInputs(
|
|
219
|
-
{ cwd,
|
|
219
|
+
{ cwd, baseBranch, storyBranch, baselinePath },
|
|
220
220
|
{ loadBaseline },
|
|
221
221
|
);
|
|
222
222
|
if (!validation.ok) {
|
|
@@ -227,7 +227,7 @@ export function projectMaintainabilityRegressions({
|
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
const fetchOutcome = refreshEpicRef(cwd,
|
|
230
|
+
const fetchOutcome = refreshEpicRef(cwd, baseBranch, git);
|
|
231
231
|
if (!fetchOutcome.ok) {
|
|
232
232
|
return {
|
|
233
233
|
ok: true,
|
|
@@ -237,7 +237,7 @@ export function projectMaintainabilityRegressions({
|
|
|
237
237
|
};
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
const diffOutcome = diffChangedFiles({ cwd,
|
|
240
|
+
const diffOutcome = diffChangedFiles({ cwd, baseBranch, storyBranch, git });
|
|
241
241
|
if (!diffOutcome.ok) {
|
|
242
242
|
return {
|
|
243
243
|
ok: true,
|
|
@@ -72,21 +72,19 @@ function applyChangedFileScope({ gate, spawnCwd, log }) {
|
|
|
72
72
|
* Worktree locality (Story #1120): when `worktreePath` is supplied, every
|
|
73
73
|
* gate runner is spawned with `cwd: worktreePath` so the gate sees the
|
|
74
74
|
* Story branch's post-rebase tree. Evidence reads/writes still key against
|
|
75
|
-
* `cwd` (the main checkout) because the
|
|
76
|
-
*
|
|
75
|
+
* `cwd` (the main checkout) because the temp tree lives under the main
|
|
76
|
+
* `.git/`. Failure messages name the worktree path.
|
|
77
77
|
*
|
|
78
|
-
* Evidence-aware: when `storyId` is provided alongside
|
|
79
|
-
*
|
|
78
|
+
* Evidence-aware: when `storyId` is provided alongside `standalone: true`,
|
|
79
|
+
* and `useEvidence !== false`, each gate consults
|
|
80
80
|
* `validation-evidence.shouldSkip()` against current HEAD + the gate's
|
|
81
81
|
* command-config hash. A matching record skips the gate; a successful run
|
|
82
82
|
* is recorded so the next caller in the local hot path can skip in turn.
|
|
83
83
|
*
|
|
84
|
-
* Standalone keyspace (Story #4250):
|
|
85
|
-
*
|
|
86
|
-
* the evidence file to the storyId-anchored
|
|
84
|
+
* Standalone keyspace (Story #4250): `standalone: true` routes the evidence
|
|
85
|
+
* file to the storyId-anchored
|
|
87
86
|
* `<tempRoot>/standalone/stories/story-<id>/validation-evidence.json`
|
|
88
|
-
* keyspace
|
|
89
|
-
* (which structurally disabled the cache before).
|
|
87
|
+
* keyspace. v2.0.0 removed the Epic tier and its Epic-keyed keyspace.
|
|
90
88
|
*
|
|
91
89
|
* `onGateStart` is invoked immediately before each gate's runner spawn.
|
|
92
90
|
* story-close uses it to drive `phaseTimer.mark(...)` for per-gate
|
|
@@ -100,7 +98,6 @@ function applyChangedFileScope({ gate, spawnCwd, log }) {
|
|
|
100
98
|
* log?: (m: string) => void,
|
|
101
99
|
* onGateStart?: (gate: Gate) => void,
|
|
102
100
|
* storyId?: number|null,
|
|
103
|
-
* epicId?: number|null,
|
|
104
101
|
* standalone?: boolean,
|
|
105
102
|
* useEvidence?: boolean,
|
|
106
103
|
* evidenceClock?: () => number,
|
|
@@ -118,7 +115,6 @@ export async function runCloseValidation({
|
|
|
118
115
|
log = () => {},
|
|
119
116
|
onGateStart,
|
|
120
117
|
storyId = null,
|
|
121
|
-
epicId = null,
|
|
122
118
|
standalone = false,
|
|
123
119
|
useEvidence = true,
|
|
124
120
|
evidenceClock = () => Date.now(),
|
|
@@ -129,16 +125,12 @@ export async function runCloseValidation({
|
|
|
129
125
|
const failed = [];
|
|
130
126
|
const skipped = [];
|
|
131
127
|
// Evidence is active when a Story id is present AND there is a keyspace to
|
|
132
|
-
// anchor on
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
//
|
|
138
|
-
// keyspace; otherwise the Epic-keyed path resolves under `epicId`.
|
|
139
|
-
const evidenceStoreOpts = { cwd, epicId, standalone };
|
|
140
|
-
// Evidence keys against the main checkout's HEAD because the per-Epic
|
|
141
|
-
// evidence file lives under the main `.git/`. Gate spawn, in contrast,
|
|
128
|
+
// anchor on (`standalone: true` — Story #4250's storyId-anchored
|
|
129
|
+
// keyspace, now the only one).
|
|
130
|
+
const evidenceActive = useEvidence && storyId != null && standalone;
|
|
131
|
+
const evidenceStoreOpts = { cwd, standalone };
|
|
132
|
+
// Evidence keys against the main checkout's HEAD because the evidence
|
|
133
|
+
// file lives under the main `.git/`. Gate spawn, in contrast,
|
|
142
134
|
// runs in the worktree when one is supplied — that's the whole point of
|
|
143
135
|
// Story #1120.
|
|
144
136
|
const spawnCwd = worktreePath ?? cwd;
|
|
@@ -3,19 +3,25 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
6
|
-
import
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { storyTempDir } from '../config/temp-paths.js';
|
|
7
8
|
import { getSpawnCount as defaultGetSpawnCount } from '../gh-exec.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Throw-away ghSpawnCount emitter (Story #1795 / Epic #1788).
|
|
11
12
|
*
|
|
12
13
|
* Writes the current `gh-exec` spawn counter to
|
|
13
|
-
* `temp/
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* `temp/run-<id>/stories/story-<sid>/gh-spawn-count.json`.
|
|
15
|
+
*
|
|
16
|
+
* Story #4545 — its reader is gone: `analyze-execution.js` consumed this file
|
|
17
|
+
* to emit a `ghSpawnCount` field on the `story-perf-summary` payload, and both
|
|
18
|
+
* that CLI and that payload were deleted with the execution-analysis surface.
|
|
19
|
+
* The writer itself already had no production caller before that (the
|
|
20
|
+
* `runPostMergeClose` orchestrator named below went in the v2.0.0 cutover), so
|
|
21
|
+
* this module is production-dead and kept alive only by its own test — the
|
|
22
|
+
* test-importer blind spot the dead-exports ratchet cannot see. It is left in
|
|
23
|
+
* place rather than deleted because reviving spawn telemetry against the live
|
|
24
|
+
* close path is a decision, not a sweep.
|
|
19
25
|
*
|
|
20
26
|
* @param {object} opts
|
|
21
27
|
* @param {number|string} opts.epicId
|
|
@@ -50,7 +56,10 @@ export async function emitGhSpawnCount({
|
|
|
50
56
|
);
|
|
51
57
|
return { status: 'failed', reason: 'counter-read-failed' };
|
|
52
58
|
}
|
|
53
|
-
const targetPath =
|
|
59
|
+
const targetPath = path.join(
|
|
60
|
+
storyTempDir(eid, sid, config),
|
|
61
|
+
'gh-spawn-count.json',
|
|
62
|
+
);
|
|
54
63
|
const payload = {
|
|
55
64
|
kind: 'gh-spawn-count',
|
|
56
65
|
epicId: eid,
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Resolves `.agentrc.json → delivery.acceptanceEval` into the canonical
|
|
5
5
|
* shape the per-Story acceptance self-eval loop consumes. The loop scores
|
|
6
|
-
* the
|
|
7
|
-
* unmet items, and re-evaluates — capped at `maxRounds`
|
|
6
|
+
* the caller-injected change set against each inline `acceptance[]` item,
|
|
7
|
+
* redrafts the unmet items, and re-evaluates — capped at `maxRounds` rounds,
|
|
8
8
|
* then escalates to `agent::blocked` when criteria remain unmet.
|
|
9
9
|
*
|
|
10
10
|
* ## The undisableable cap
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
* full-closure agent that ran before M7-B.
|
|
19
19
|
*
|
|
20
20
|
* `delivery.routing.freshCriticSampleRate` is the **maker-checker sampling
|
|
21
|
-
* floor** (Epic #4478, M7-B, Part 2).
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* clamped into `[0, 1]`; `0` disables
|
|
26
|
-
* every cluster fresh. The default is
|
|
21
|
+
* floor** (Epic #4478, M7-B, Part 2). Ceremony routing sends the acceptance
|
|
22
|
+
* clusters of a change set that touches no sensitive path down the
|
|
23
|
+
* contract-identical *inline* critic path, but a fraction of them are still
|
|
24
|
+
* forced through a *fresh-context* critic so a low derived level never degrades
|
|
25
|
+
* to zero independent checking. The rate is clamped into `[0, 1]`; `0` disables
|
|
26
|
+
* the floor (pure level routing), `1` forces every cluster fresh. The default is
|
|
27
|
+
* `0.2`. See `resolveCeremonyForRisk` in
|
|
27
28
|
* `lib/orchestration/ceremony-routing.js`.
|
|
28
29
|
*
|
|
29
30
|
* Framework-defaults pattern mirrors `lib/config/ci.js#getCiDelivery`.
|
|
@@ -63,13 +63,13 @@ const SECRET_SEGMENT_PATTERNS = Object.freeze([
|
|
|
63
63
|
const KEY_MEANINGS = Object.freeze({
|
|
64
64
|
// project.*
|
|
65
65
|
'project.baseBranch':
|
|
66
|
-
'Default base branch
|
|
66
|
+
'Default base branch Stories branch from and merge back into.',
|
|
67
67
|
'project.paths.agentRoot':
|
|
68
68
|
'Directory holding the distributed agent bundle (instructions, skills, scripts).',
|
|
69
69
|
'project.paths.docsRoot':
|
|
70
70
|
'Directory the mandatory docs-context reads resolve against.',
|
|
71
71
|
'project.paths.tempRoot':
|
|
72
|
-
'Root for gitignored scratch output (per-
|
|
72
|
+
'Root for gitignored scratch output (per-run state, mirrors, logs).',
|
|
73
73
|
'project.docsContextFiles':
|
|
74
74
|
'Authoritative files an agent must read before starting any task.',
|
|
75
75
|
'project.commands.lintBaseline':
|
|
@@ -114,10 +114,6 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
114
114
|
'Allowlist of events that fire a webhook notification.',
|
|
115
115
|
|
|
116
116
|
// planning.*
|
|
117
|
-
'planning.context.maxBytes':
|
|
118
|
-
'Byte budget for the planning-context payload before summary mode kicks in.',
|
|
119
|
-
'planning.context.summaryMode':
|
|
120
|
-
'When the planner switches to a summarized context representation.',
|
|
121
117
|
'planning.codebaseSnapshot.tier':
|
|
122
118
|
'Depth of the structural codebase view threaded into spec authoring.',
|
|
123
119
|
'planning.codebaseSnapshot.include':
|
|
@@ -149,7 +145,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
149
145
|
'delivery.execution.timeoutMs':
|
|
150
146
|
'Per-execution timeout for orchestrated delivery steps.',
|
|
151
147
|
'delivery.lease.ttlMs':
|
|
152
|
-
'Time-to-live for the
|
|
148
|
+
'Time-to-live for the delivery lease before a stale claim is reclaimable.',
|
|
153
149
|
'delivery.ci.watch.pollIntervalMs':
|
|
154
150
|
'Poll cadence (ms) for the merge/CI watch loop.',
|
|
155
151
|
'delivery.ci.watch.maxPolls':
|
|
@@ -161,9 +157,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
161
157
|
'delivery.docsFreshness.paths':
|
|
162
158
|
'Docs whose freshness is checked at delivery time.',
|
|
163
159
|
'delivery.deliverRunner.concurrencyCap':
|
|
164
|
-
'Maximum Stories dispatched in parallel within one wave. Default 3 — conservative by design to keep host-quota consumption predictable. Operators running wide
|
|
165
|
-
'delivery.deliverRunner.verifyConcurrencyCap':
|
|
166
|
-
'Maximum verify steps run in parallel.',
|
|
160
|
+
'Maximum Stories dispatched in parallel within one wave. Default 3 — conservative by design to keep host-quota consumption predictable. Operators running wide waves with adequate parallel-agent quota should raise this to reduce wall-clock time proportionally.',
|
|
167
161
|
'delivery.worktreeIsolation.enabled':
|
|
168
162
|
'Whether each Story runs in its own git worktree.',
|
|
169
163
|
'delivery.worktreeIsolation.root':
|
|
@@ -179,9 +173,9 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
179
173
|
'delivery.worktreeIsolation.bootstrapFiles':
|
|
180
174
|
'Files copied into each new worktree (e.g. .env, .mcp.json, local overrides).',
|
|
181
175
|
'delivery.mergeWatch.intervalSeconds':
|
|
182
|
-
'Poll cadence (seconds) for
|
|
176
|
+
'Poll cadence (seconds) for the close-and-land merge wait after the arm.',
|
|
183
177
|
'delivery.mergeWatch.maxBudgetSeconds':
|
|
184
|
-
'
|
|
178
|
+
'Cumulative wall-clock budget (seconds) across resumes before the merge wait gives up and blocks.',
|
|
185
179
|
'delivery.codeReview.providers':
|
|
186
180
|
'Ordered provider chain the code-review phase consults.',
|
|
187
181
|
'delivery.codeReview.maxFixAttempts':
|
|
@@ -195,7 +189,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
195
189
|
'delivery.routing.freshCriticSampleRate':
|
|
196
190
|
'Fraction of low-risk acceptance clusters forced through a fresh-context critic (maker-checker floor).',
|
|
197
191
|
'delivery.routing.ceremonyProfile':
|
|
198
|
-
'Acceptance-ceremony depth: minimal (always inline), standard (
|
|
192
|
+
'Acceptance-ceremony depth: minimal (always inline), standard (derived-level routed), or strict (always fresh).',
|
|
199
193
|
'delivery.routing.closeAndLand':
|
|
200
194
|
'When true, single-story-close lands through merge in one close (opt out with --no-wait-merge).',
|
|
201
195
|
'delivery.feedbackLoop.auditResultsAutoFile':
|
|
@@ -217,7 +211,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
217
211
|
'delivery.acceptanceEval.maxRounds':
|
|
218
212
|
'Redraft rounds the per-Story acceptance self-eval loop runs before escalating to agent::blocked (default 2; clamped to a hard ceiling that cannot be disabled).',
|
|
219
213
|
'delivery.acceptanceEval.clusterCeiling':
|
|
220
|
-
'Max acceptance criteria one single-delivery acceptance critic scores per fresh-context pass; the
|
|
214
|
+
'Max acceptance criteria one single-delivery acceptance critic scores per fresh-context pass; the Story ACs are split into ceil(totalACs / clusterCeiling) maker-blind critic clusters (default 4; clamped to [1, 8]).',
|
|
221
215
|
|
|
222
216
|
// qa.*
|
|
223
217
|
'qa.featureRoot': 'Root directory holding the QA harness .feature files.',
|
|
@@ -252,7 +246,7 @@ const PREFIX_MEANINGS = Object.freeze([
|
|
|
252
246
|
],
|
|
253
247
|
['delivery.quality', 'Delivery-time quality configuration.'],
|
|
254
248
|
['delivery.signals', 'Threshold for a delivery friction/telemetry signal.'],
|
|
255
|
-
['delivery.mergeWatch', '
|
|
249
|
+
['delivery.mergeWatch', 'Merge-wait poll cadence and wall-clock budget.'],
|
|
256
250
|
[
|
|
257
251
|
'delivery.feedbackLoop',
|
|
258
252
|
'Opt-out toggles for auto-filing non-blocking findings.',
|
|
@@ -282,7 +276,7 @@ const PREFIX_MEANINGS = Object.freeze([
|
|
|
282
276
|
const BLOCK_MEANINGS = Object.freeze({
|
|
283
277
|
project: 'Project identity, paths, and command configuration.',
|
|
284
278
|
github: 'GitHub provider identity and merge/notification policy.',
|
|
285
|
-
planning: 'Inputs and guardrails for /
|
|
279
|
+
planning: 'Inputs and guardrails for /plan.',
|
|
286
280
|
delivery: 'Execution, isolation, quality, and CI settings for delivery.',
|
|
287
281
|
qa: 'Agent-driven QA harness contract.',
|
|
288
282
|
});
|
|
@@ -55,11 +55,13 @@ export const NOTIFICATIONS_DEFAULTS = Object.freeze({
|
|
|
55
55
|
'operator-message',
|
|
56
56
|
]),
|
|
57
57
|
webhookEvents: Object.freeze([
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
58
|
+
'state-transition',
|
|
59
|
+
'story-merged',
|
|
60
|
+
'story-closing',
|
|
61
|
+
'operator-message',
|
|
62
|
+
'merge.unlanded',
|
|
63
|
+
'merge.flip-failed',
|
|
64
|
+
'loop.tick',
|
|
63
65
|
]),
|
|
64
66
|
});
|
|
65
67
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Post-reshape, the surviving operator-configurable keys are split across
|
|
6
6
|
* `planning.*` and `delivery.*`:
|
|
7
7
|
*
|
|
8
|
-
* - `planning.context.{maxBytes, summaryMode}` (planning-context budget)
|
|
9
8
|
* - `delivery.execution.timeoutMs` (per-process execution timeout)
|
|
10
9
|
* - `delivery.lease.ttlMs` (assignee-as-lease staleness window — Story #3480)
|
|
11
10
|
* - `delivery.signals.{rework, retry}` (performance-signal detector
|
|
@@ -17,7 +16,12 @@
|
|
|
17
16
|
* Dropped entirely: `maxInstructionSteps`, `friction.*`, `executionMaxBuffer`,
|
|
18
17
|
* `signals.{churn, idle}`, `delivery.preflight`, `delivery.maxTokenBudget`
|
|
19
18
|
* (planning no longer sizes against a token-budget envelope; session-mass
|
|
20
|
-
* ceilings are absolute in `DEFAULT_MODEL_CAPACITY`)
|
|
19
|
+
* ceilings are absolute in `DEFAULT_MODEL_CAPACITY`), and
|
|
20
|
+
* `planning.context.{maxBytes, summaryMode}` (Story #4541 — the `applyBudget`
|
|
21
|
+
* pass they fed lost its last caller in the v2 cutover, and it bounded a field
|
|
22
|
+
* the envelope builders discarded; the live bound on planner-context size is
|
|
23
|
+
* the fixed `PLAN_CONTEXT_ENVELOPE_BYTE_CEILING` in
|
|
24
|
+
* `lib/orchestration/plan-context.js`).
|
|
21
25
|
*
|
|
22
26
|
* The historic combined accessor `getLimits(config)` is preserved as a
|
|
23
27
|
* compatibility surface: it returns a wrapper carrying the surviving
|
|
@@ -37,10 +41,14 @@ export const SIGNALS_DEFAULTS = Object.freeze({
|
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
43
|
* Default TTL for the assignee-as-lease primitive (Story #3480). A claim
|
|
40
|
-
* whose owner
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
+
* whose owner's last heartbeat is older than this window is considered stale
|
|
45
|
+
* and may be reclaimed by another operator.
|
|
46
|
+
*
|
|
47
|
+
* Note: no shipped caller supplies a real heartbeat — the emitter was inert
|
|
48
|
+
* and was deleted (A22), so the guards anchor liveness to `now` and every
|
|
49
|
+
* foreign claim reads live (fail-closed; clear a stranded claim with
|
|
50
|
+
* `--steal`). This value is therefore only consulted by a caller that threads
|
|
51
|
+
* its own `heartbeatAt`, and is kept as the documented default for that seam.
|
|
44
52
|
*/
|
|
45
53
|
export const LEASE_TTL_MS_DEFAULT = 900000;
|
|
46
54
|
|
|
@@ -51,10 +59,6 @@ export const LIMITS_DEFAULTS = Object.freeze({
|
|
|
51
59
|
maxTickets: 80,
|
|
52
60
|
executionTimeoutMs: 600000,
|
|
53
61
|
leaseTtlMs: LEASE_TTL_MS_DEFAULT,
|
|
54
|
-
planningContext: Object.freeze({
|
|
55
|
-
maxBytes: 50000,
|
|
56
|
-
summaryMode: 'auto',
|
|
57
|
-
}),
|
|
58
62
|
signals: SIGNALS_DEFAULTS,
|
|
59
63
|
});
|
|
60
64
|
|
|
@@ -83,8 +87,7 @@ function mergeSignals(userSignals) {
|
|
|
83
87
|
/**
|
|
84
88
|
* Resolve the surviving limits surface against a `.agentrc.json` shape
|
|
85
89
|
* (post-reshape). `maxTickets` is a framework constant (never read from
|
|
86
|
-
* config); pulls `
|
|
87
|
-
* `executionTimeoutMs` from `delivery.*`, pulls signals from
|
|
90
|
+
* config); pulls `executionTimeoutMs` from `delivery.*`, pulls signals from
|
|
88
91
|
* `delivery.signals.*`.
|
|
89
92
|
*
|
|
90
93
|
* @param {object|undefined} config
|
|
@@ -92,23 +95,14 @@ function mergeSignals(userSignals) {
|
|
|
92
95
|
* maxTickets: number,
|
|
93
96
|
* executionTimeoutMs: number,
|
|
94
97
|
* leaseTtlMs: number,
|
|
95
|
-
* planningContext: { maxBytes: number, summaryMode: string },
|
|
96
98
|
* signals: ReturnType<typeof mergeSignals>,
|
|
97
99
|
* }}
|
|
98
100
|
*/
|
|
99
101
|
export function resolveLimits(config) {
|
|
100
|
-
const planning =
|
|
101
|
-
config?.planning && typeof config.planning === 'object'
|
|
102
|
-
? config.planning
|
|
103
|
-
: {};
|
|
104
102
|
const delivery =
|
|
105
103
|
config?.delivery && typeof config.delivery === 'object'
|
|
106
104
|
? config.delivery
|
|
107
105
|
: {};
|
|
108
|
-
const planningContextUser =
|
|
109
|
-
planning.context && typeof planning.context === 'object'
|
|
110
|
-
? planning.context
|
|
111
|
-
: {};
|
|
112
106
|
const execution =
|
|
113
107
|
delivery.execution && typeof delivery.execution === 'object'
|
|
114
108
|
? delivery.execution
|
|
@@ -120,10 +114,6 @@ export function resolveLimits(config) {
|
|
|
120
114
|
executionTimeoutMs:
|
|
121
115
|
execution.timeoutMs ?? LIMITS_DEFAULTS.executionTimeoutMs,
|
|
122
116
|
leaseTtlMs: lease.ttlMs ?? LIMITS_DEFAULTS.leaseTtlMs,
|
|
123
|
-
planningContext: {
|
|
124
|
-
...LIMITS_DEFAULTS.planningContext,
|
|
125
|
-
...planningContextUser,
|
|
126
|
-
},
|
|
127
117
|
signals: mergeSignals(delivery.signals),
|
|
128
118
|
};
|
|
129
119
|
}
|