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
|
@@ -366,14 +366,19 @@ function resolveCoverageGate(userBlock) {
|
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
/**
|
|
369
|
-
* Framework defaults for `delivery.quality.codingGuardrails`.
|
|
370
|
-
*
|
|
371
|
-
*
|
|
369
|
+
* Framework defaults for `delivery.quality.codingGuardrails`.
|
|
370
|
+
*
|
|
371
|
+
* `miDropMustRefactor` was retired in Story #4531: schema-validated,
|
|
372
|
+
* defaulted, and resolved, but never consumed — the gate it named
|
|
373
|
+
* (`quality-preview.js`'s `computeExitCode`) short-circuits on `miExit`
|
|
374
|
+
* (derived from the already-consumed `gates.maintainability.tolerance`)
|
|
375
|
+
* before this value is ever read. `maintainability.tolerance` is the one
|
|
376
|
+
* documented MI-drop control now; see `lib/migrations/index.js` for the
|
|
377
|
+
* consumer-config migration that strips a leftover key on upgrade.
|
|
372
378
|
*/
|
|
373
379
|
export const CODING_GUARDRAILS_DEFAULTS = Object.freeze({
|
|
374
380
|
cyclomaticFlag: 8,
|
|
375
381
|
cyclomaticMustFix: 12,
|
|
376
|
-
miDropMustRefactor: 1.5,
|
|
377
382
|
requireSiblingTest: false,
|
|
378
383
|
});
|
|
379
384
|
|
|
@@ -393,8 +398,6 @@ export function resolveCodingGuardrails(userBlock) {
|
|
|
393
398
|
cyclomaticFlag: userBlock.cyclomaticFlag ?? defaults.cyclomaticFlag,
|
|
394
399
|
cyclomaticMustFix:
|
|
395
400
|
userBlock.cyclomaticMustFix ?? defaults.cyclomaticMustFix,
|
|
396
|
-
miDropMustRefactor:
|
|
397
|
-
userBlock.miDropMustRefactor ?? defaults.miDropMustRefactor,
|
|
398
401
|
requireSiblingTest:
|
|
399
402
|
typeof userBlock.requireSiblingTest === 'boolean'
|
|
400
403
|
? userBlock.requireSiblingTest
|
|
@@ -402,9 +405,10 @@ export function resolveCodingGuardrails(userBlock) {
|
|
|
402
405
|
};
|
|
403
406
|
}
|
|
404
407
|
|
|
408
|
+
// autoRefresh.miDropCap was retired alongside codingGuardrails.
|
|
409
|
+
// miDropMustRefactor in Story #4531 — same unconsumed-knob shape, same fix.
|
|
405
410
|
const AUTO_REFRESH_DEFAULTS = Object.freeze({
|
|
406
411
|
enabled: true,
|
|
407
|
-
miDropCap: 1.5,
|
|
408
412
|
crapJumpCap: 5,
|
|
409
413
|
scope: 'diff',
|
|
410
414
|
});
|
|
@@ -416,7 +420,6 @@ function resolveAutoRefresh(userBlock) {
|
|
|
416
420
|
if (userBlock == null || typeof userBlock !== 'object') {
|
|
417
421
|
return {
|
|
418
422
|
enabled: defaults.enabled,
|
|
419
|
-
miDropCap: defaults.miDropCap,
|
|
420
423
|
crapJumpCap: defaults.crapJumpCap,
|
|
421
424
|
scope: defaults.scope,
|
|
422
425
|
};
|
|
@@ -429,12 +432,6 @@ function resolveAutoRefresh(userBlock) {
|
|
|
429
432
|
typeof userBlock.enabled === 'boolean'
|
|
430
433
|
? userBlock.enabled
|
|
431
434
|
: defaults.enabled,
|
|
432
|
-
miDropCap:
|
|
433
|
-
typeof userBlock.miDropCap === 'number' &&
|
|
434
|
-
Number.isFinite(userBlock.miDropCap) &&
|
|
435
|
-
userBlock.miDropCap >= 0
|
|
436
|
-
? userBlock.miDropCap
|
|
437
|
-
: defaults.miDropCap,
|
|
438
435
|
crapJumpCap:
|
|
439
436
|
typeof userBlock.crapJumpCap === 'number' &&
|
|
440
437
|
Number.isFinite(userBlock.crapJumpCap) &&
|
|
@@ -3,18 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Post-reshape, only `delivery.deliverRunner` and `delivery.codeReview` are
|
|
5
5
|
* configurable via this accessor; everything else lives in framework-internal
|
|
6
|
-
* constants exported alongside (`
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
* `delivery.codeReview`).
|
|
6
|
+
* constants exported alongside (`DEFAULT_DECOMPOSER`).
|
|
7
|
+
* `delivery.epicAudit` was removed on v2 (Story-only delivery — no
|
|
8
|
+
* epic-audit runner; remediation policy lives on `delivery.codeReview`).
|
|
10
9
|
*/
|
|
11
10
|
|
|
12
|
-
/** Hardcoded story-merge retry policy (was `orchestration.runners.storyMergeRetry`). */
|
|
13
|
-
export const DEFAULT_STORY_MERGE_RETRY = Object.freeze({
|
|
14
|
-
maxAttempts: 3,
|
|
15
|
-
backoffMs: Object.freeze([250, 500, 1000]),
|
|
16
|
-
});
|
|
17
|
-
|
|
18
11
|
/** Hardcoded decomposer concurrency cap (was `orchestration.runners.decomposer.concurrencyCap`). */
|
|
19
12
|
export const DEFAULT_DECOMPOSER = Object.freeze({
|
|
20
13
|
concurrencyCap: 3,
|
|
@@ -33,14 +26,13 @@ export const DEFAULT_DECOMPOSER = Object.freeze({
|
|
|
33
26
|
* reduces wall-clock time where dependencies allow. See `deliver.md` and
|
|
34
27
|
* `agentrc-reference.json` `delivery.deliverRunner.concurrencyCap`.
|
|
35
28
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
29
|
+
* Story #4545 removed the sibling `verifyConcurrencyCap`: the
|
|
30
|
+
* `verifyWaveResults` loop it claimed to bound never existed in the tree, and
|
|
31
|
+
* its only reader was the retired execution-analysis CLI, which echoed the
|
|
32
|
+
* number into a report rather than bounding anything.
|
|
40
33
|
*/
|
|
41
34
|
const DEFAULT_DELIVER_RUNNER = Object.freeze({
|
|
42
35
|
concurrencyCap: 3,
|
|
43
|
-
verifyConcurrencyCap: 4,
|
|
44
36
|
});
|
|
45
37
|
|
|
46
38
|
/**
|
|
@@ -59,9 +51,8 @@ export const DEFAULT_CODE_REVIEW = Object.freeze({
|
|
|
59
51
|
*
|
|
60
52
|
* @param {object | null | undefined} config
|
|
61
53
|
* @returns {{
|
|
62
|
-
* deliverRunner: { concurrencyCap: number
|
|
54
|
+
* deliverRunner: { concurrencyCap: number },
|
|
63
55
|
* codeReview: { maxFixAttempts: number, maxFixScopeFiles: number, autoFixSeverity: 'high'|'medium' },
|
|
64
|
-
* storyMergeRetry: { maxAttempts: number, backoffMs: readonly number[] },
|
|
65
56
|
* decomposer: { concurrencyCap: number },
|
|
66
57
|
* }}
|
|
67
58
|
*/
|
|
@@ -73,9 +64,6 @@ export function getRunners(config) {
|
|
|
73
64
|
concurrencyCap:
|
|
74
65
|
deliverRunnerUser.concurrencyCap ??
|
|
75
66
|
DEFAULT_DELIVER_RUNNER.concurrencyCap,
|
|
76
|
-
verifyConcurrencyCap:
|
|
77
|
-
deliverRunnerUser.verifyConcurrencyCap ??
|
|
78
|
-
DEFAULT_DELIVER_RUNNER.verifyConcurrencyCap,
|
|
79
67
|
},
|
|
80
68
|
codeReview: {
|
|
81
69
|
maxFixAttempts:
|
|
@@ -85,7 +73,6 @@ export function getRunners(config) {
|
|
|
85
73
|
autoFixSeverity:
|
|
86
74
|
codeReviewUser.autoFixSeverity ?? DEFAULT_CODE_REVIEW.autoFixSeverity,
|
|
87
75
|
},
|
|
88
|
-
storyMergeRetry: DEFAULT_STORY_MERGE_RETRY,
|
|
89
76
|
decomposer: DEFAULT_DECOMPOSER,
|
|
90
77
|
};
|
|
91
78
|
}
|
|
@@ -13,15 +13,13 @@
|
|
|
13
13
|
* ├─ techspec.md
|
|
14
14
|
* ├─ manifest.md (dispatch manifest)
|
|
15
15
|
* ├─ retro.md (mirror of GitHub retro at Epic close)
|
|
16
|
-
* ├─ perf-report.md (analyzer output, Epic-level)
|
|
17
16
|
* ├─ lifecycle.ndjson (lifecycle bus ledger)
|
|
18
17
|
* ├─ checkpoints/... (pre-v2 epic-runner state store; retained layout)
|
|
19
|
-
* ├─ <name> (
|
|
18
|
+
* ├─ <name> (runArtifactPath escape hatch)
|
|
20
19
|
* └─ stories/
|
|
21
20
|
* └─ story-<sid>/
|
|
22
21
|
* ├─ manifest.md (story dispatch manifest)
|
|
23
22
|
* ├─ signals.ndjson (append-only signals writer)
|
|
24
|
-
* ├─ perf-summary.md
|
|
25
23
|
* └─ <name> (storyArtifactPath escape hatch)
|
|
26
24
|
*
|
|
27
25
|
* Standalone Stories (no parent Epic) follow the same shape under
|
|
@@ -42,11 +40,12 @@
|
|
|
42
40
|
* resolve a *relative* `tempRoot` against the **main checkout root** (the
|
|
43
41
|
* parent of `git rev-parse --git-common-dir`) rather than `process.cwd()`.
|
|
44
42
|
* Without this, a story child that `cd`s into `.worktrees/story-<id>/` before
|
|
45
|
-
*
|
|
43
|
+
* emitting a lifecycle record would append it to
|
|
46
44
|
* `<worktree>/temp/run-N/lifecycle.ndjson`, while the `/deliver` host
|
|
47
45
|
* (running from the main checkout) reads the main-checkout copy — so the
|
|
48
|
-
*
|
|
49
|
-
*
|
|
46
|
+
* host never sees the child's records (the audit-#3513 bug class; its
|
|
47
|
+
* original `story.heartbeat` instance is gone with that emitter, but the
|
|
48
|
+
* divergence applies to every ledger writer). Anchoring the
|
|
50
49
|
* ledger to the git common dir makes the worktree child writer and the
|
|
51
50
|
* main-checkout host reader converge on a single file regardless of cwd. An
|
|
52
51
|
* absolute `tempRoot` is honoured verbatim; only relative roots are anchored.
|
|
@@ -155,11 +154,9 @@ export function tempRootFrom(config) {
|
|
|
155
154
|
: 'temp';
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
const
|
|
157
|
+
const runId = (id) => {
|
|
159
158
|
if (!Number.isInteger(id) || id <= 0) {
|
|
160
|
-
throw new Error(
|
|
161
|
-
`[temp-paths] epicId must be a positive integer; got ${id}`,
|
|
162
|
-
);
|
|
159
|
+
throw new Error(`[temp-paths] runId must be a positive integer; got ${id}`);
|
|
163
160
|
}
|
|
164
161
|
return id;
|
|
165
162
|
};
|
|
@@ -206,19 +203,14 @@ const artifactName = (name) => {
|
|
|
206
203
|
};
|
|
207
204
|
|
|
208
205
|
/**
|
|
209
|
-
* `temp/run-<
|
|
206
|
+
* `temp/run-<id>/` — every run-scoped artifact lives under here.
|
|
210
207
|
*
|
|
211
|
-
* @param {number}
|
|
208
|
+
* @param {number} rid
|
|
212
209
|
* @param {object} [config]
|
|
213
210
|
* @returns {string}
|
|
214
211
|
*/
|
|
215
212
|
export function runTempDir(rid, config) {
|
|
216
|
-
return path.join(anchorTempRoot(tempRootFrom(config)), `run-${
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** @deprecated Use {@link runTempDir}. */
|
|
220
|
-
export function epicTempDir(eid, config) {
|
|
221
|
-
return runTempDir(eid, config);
|
|
213
|
+
return path.join(anchorTempRoot(tempRootFrom(config)), `run-${runId(rid)}`);
|
|
222
214
|
}
|
|
223
215
|
|
|
224
216
|
/**
|
|
@@ -246,7 +238,7 @@ export function storyTempDir(eid, sid, config) {
|
|
|
246
238
|
const parent =
|
|
247
239
|
checkedEid === null
|
|
248
240
|
? path.join(anchorTempRoot(tempRootFrom(config)), 'standalone')
|
|
249
|
-
:
|
|
241
|
+
: runTempDir(checkedEid, config);
|
|
250
242
|
return path.join(parent, 'stories', `story-${storyId(sid)}`);
|
|
251
243
|
}
|
|
252
244
|
|
|
@@ -272,7 +264,7 @@ export function signalsFile(eid, sid, config) {
|
|
|
272
264
|
* needs an on-disk home even though there is no `run-<id>/` directory to
|
|
273
265
|
* anchor the event to.
|
|
274
266
|
*
|
|
275
|
-
* Mirrors `
|
|
267
|
+
* Mirrors `runLedgerPath` exactly, one level down: `eid === null` routes
|
|
276
268
|
* through `storyTempDir`'s standalone branch to
|
|
277
269
|
* `<tempRoot>/standalone/stories/story-<sid>/lifecycle.ndjson`; a real
|
|
278
270
|
* `eid` routes to `<tempRoot>/run-<eid>/stories/story-<sid>/lifecycle.ndjson`,
|
|
@@ -298,14 +290,13 @@ export const storyLedgerPath = (eid, sid, config) =>
|
|
|
298
290
|
* @param {object} [config]
|
|
299
291
|
* @returns {string}
|
|
300
292
|
*/
|
|
301
|
-
export function
|
|
302
|
-
return path.join(
|
|
293
|
+
export function runArtifactPath(eid, name, config) {
|
|
294
|
+
return path.join(runTempDir(eid, config), artifactName(name));
|
|
303
295
|
}
|
|
304
296
|
|
|
305
297
|
/**
|
|
306
298
|
* Escape hatch for a Story-level artifact whose name isn't part of the
|
|
307
|
-
* canonical layout (signals.ndjson +
|
|
308
|
-
* named helpers).
|
|
299
|
+
* canonical layout (signals.ndjson + manifest.md ship named helpers).
|
|
309
300
|
*
|
|
310
301
|
* @param {number} eid
|
|
311
302
|
* @param {number} sid
|
|
@@ -313,37 +304,10 @@ export function epicArtifactPath(eid, name, config) {
|
|
|
313
304
|
* @param {object} [config]
|
|
314
305
|
* @returns {string}
|
|
315
306
|
*/
|
|
316
|
-
|
|
307
|
+
function storyArtifactPath(eid, sid, name, config) {
|
|
317
308
|
return path.join(storyTempDir(eid, sid, config), artifactName(name));
|
|
318
309
|
}
|
|
319
310
|
|
|
320
|
-
// --- Canonical Epic-level filenames (Tech Spec #1032 §tempRoot) ---
|
|
321
|
-
|
|
322
|
-
export const epicTechSpecPath = (eid, config) =>
|
|
323
|
-
epicArtifactPath(eid, 'techspec.md', config);
|
|
324
|
-
export const epicManifestPath = (eid, config) =>
|
|
325
|
-
epicArtifactPath(eid, 'manifest.md', config);
|
|
326
|
-
export const epicRetroMirrorPath = (eid, config) =>
|
|
327
|
-
epicArtifactPath(eid, 'retro.md', config);
|
|
328
|
-
export const epicPerfReportPath = (eid, config) =>
|
|
329
|
-
epicArtifactPath(eid, 'perf-report.md', config);
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* `temp/run-<eid>/epic-perf-report.json` — canonical JSON snapshot of
|
|
333
|
-
* the `epic-perf-report` payload persisted at /deliver close
|
|
334
|
-
* (Epic #3019 / Story #3029 / Task #3040). When present alongside the
|
|
335
|
-
* `epic-perf-report` structured comment, the report is discoverable
|
|
336
|
-
* from the file system without round-tripping the ticketing provider,
|
|
337
|
-
* and the `epic-handoff` structured close comment links it by relative
|
|
338
|
-
* path.
|
|
339
|
-
*
|
|
340
|
-
* @param {number} eid
|
|
341
|
-
* @param {object} [config]
|
|
342
|
-
* @returns {string}
|
|
343
|
-
*/
|
|
344
|
-
export const epicPerfReportJsonPath = (eid, config) =>
|
|
345
|
-
epicArtifactPath(eid, 'epic-perf-report.json', config);
|
|
346
|
-
|
|
347
311
|
/**
|
|
348
312
|
* `temp/run-<eid>/lifecycle.ndjson` — append-only lifecycle bus ledger
|
|
349
313
|
* (Story #2510). The LedgerWriter persists every emitted/completed/failed
|
|
@@ -357,12 +321,10 @@ export const epicPerfReportJsonPath = (eid, config) =>
|
|
|
357
321
|
* @param {object} [config]
|
|
358
322
|
* @returns {string}
|
|
359
323
|
*/
|
|
360
|
-
export const
|
|
361
|
-
|
|
324
|
+
export const runLedgerPath = (eid, config) =>
|
|
325
|
+
runArtifactPath(eid, 'lifecycle.ndjson', config);
|
|
362
326
|
|
|
363
327
|
// --- Canonical Story-level filenames ---
|
|
364
328
|
|
|
365
329
|
export const storyManifestPath = (eid, sid, config) =>
|
|
366
330
|
storyArtifactPath(eid, sid, 'manifest.md', config);
|
|
367
|
-
export const storyPerfSummaryPath = (eid, sid, config) =>
|
|
368
|
-
storyArtifactPath(eid, sid, 'perf-summary.md', config);
|
|
@@ -32,9 +32,11 @@ const EXECUTION_SCHEMA = {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* `delivery.lease` — assignee-as-lease primitive (Story #3480). `ttlMs` is
|
|
35
|
-
* the staleness window: a ticket claim whose owner
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* the staleness window: a ticket claim whose owner's last heartbeat is older
|
|
36
|
+
* than this many milliseconds is reclaimable by another operator. Defaults to
|
|
37
|
+
* 900000 (15 min) in `lib/config/limits.js`. Note the shipped guards fail
|
|
38
|
+
* closed (no live heartbeat source since A22 removed the inert emitter), so
|
|
39
|
+
* a stranded claim is cleared with `--steal` rather than by TTL expiry.
|
|
38
40
|
*/
|
|
39
41
|
const LEASE_SCHEMA = {
|
|
40
42
|
type: 'object',
|
|
@@ -64,7 +66,6 @@ const DELIVER_RUNNER_SCHEMA = {
|
|
|
64
66
|
type: 'object',
|
|
65
67
|
properties: {
|
|
66
68
|
concurrencyCap: { type: 'integer', minimum: 1 },
|
|
67
|
-
verifyConcurrencyCap: { type: 'integer', minimum: 1 },
|
|
68
69
|
},
|
|
69
70
|
additionalProperties: false,
|
|
70
71
|
};
|
|
@@ -137,19 +138,36 @@ const SIGNALS_SCHEMA = {
|
|
|
137
138
|
};
|
|
138
139
|
|
|
139
140
|
/**
|
|
140
|
-
* `delivery.mergeWatch` — knobs consumed by the
|
|
141
|
-
* listener (Story #2896, Epic #2880)
|
|
142
|
-
*
|
|
143
|
-
* `
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
141
|
+
* `delivery.mergeWatch` — knobs consumed by the close-and-land merge wait
|
|
142
|
+
* listener (Story #2896, Epic #2880) and by the close-and-land merge wait
|
|
143
|
+
* (`single-story-close/phases/confirm-merge.js`). `intervalSeconds` is the
|
|
144
|
+
* poll cadence between `gh pr view` probes after the arm.
|
|
145
|
+
*
|
|
146
|
+
* The two budgets are deliberately separate axes (Story #4543):
|
|
147
|
+
*
|
|
148
|
+
* - `maxWaitSeconds` bounds **one invocation** of the merge wait. Its
|
|
149
|
+
* default (300s) fits inside a single host tool invocation, whose
|
|
150
|
+
* ceiling is ~10 minutes; the gates that run before the wait already
|
|
151
|
+
* consume minutes of that. Expiry is NOT a block — the wait returns a
|
|
152
|
+
* resumable `pending` terminal with no label mutation. A headless caller
|
|
153
|
+
* with no such ceiling raises it to keep land-in-one-block semantics.
|
|
154
|
+
* - `maxBudgetSeconds` bounds the **cumulative** wait across resumes,
|
|
155
|
+
* anchored at the PR's `createdAt` so re-entering the wait does not
|
|
156
|
+
* restart the clock. Exhausting *this* is the genuine give-up condition
|
|
157
|
+
* that classifies and blocks.
|
|
158
|
+
*
|
|
159
|
+
* `updateAttempts` caps how many times the wait will bring a
|
|
160
|
+
* behind-the-base PR up to date before giving the branch up as unwinnable,
|
|
161
|
+
* rather than waiting out the budget behind a base it could have merged.
|
|
162
|
+
* All keys default in the consumer when omitted (30s / 300s / 3600s / 3).
|
|
147
163
|
*/
|
|
148
164
|
const MERGE_WATCH_SCHEMA = {
|
|
149
165
|
type: 'object',
|
|
150
166
|
properties: {
|
|
151
167
|
intervalSeconds: { type: 'integer', minimum: 1 },
|
|
168
|
+
maxWaitSeconds: { type: 'integer', minimum: 1 },
|
|
152
169
|
maxBudgetSeconds: { type: 'integer', minimum: 1 },
|
|
170
|
+
updateAttempts: { type: 'integer', minimum: 0 },
|
|
153
171
|
},
|
|
154
172
|
additionalProperties: false,
|
|
155
173
|
};
|
|
@@ -167,8 +185,8 @@ const MERGE_WATCH_SCHEMA = {
|
|
|
167
185
|
// context; false falls back to `subagent_type: general-purpose` (the instant
|
|
168
186
|
// per-consumer revert + the escape for hosts that ignore `.claude/agents/`).
|
|
169
187
|
// `delivery.routing.freshCriticSampleRate` (default 0.2, clamped [0, 1]) is the
|
|
170
|
-
// maker-checker sampling floor forcing a fraction of low-
|
|
171
|
-
// clusters through a fresh critic.
|
|
188
|
+
// maker-checker sampling floor forcing a fraction of low-derived-level
|
|
189
|
+
// acceptance clusters through a fresh critic.
|
|
172
190
|
const ROUTING_SCHEMA = {
|
|
173
191
|
type: 'object',
|
|
174
192
|
properties: {
|
|
@@ -231,9 +249,9 @@ const REFACTOR_STAGE_SCHEMA = {
|
|
|
231
249
|
* `delivery.acceptanceEval` — bounded per-Story acceptance self-eval loop
|
|
232
250
|
* (Story #3819). After the implementation commits land and before the
|
|
233
251
|
* Story-implementation phase flips to `closing`, an independent
|
|
234
|
-
* (fresh-context) critic pass scores the
|
|
235
|
-
* `acceptance[]` item, redrafts the unmet items, and
|
|
236
|
-
* at `maxRounds` redraft rounds.
|
|
252
|
+
* (fresh-context) critic pass scores the caller-injected change set against
|
|
253
|
+
* each inline `acceptance[]` item, redrafts the unmet items, and
|
|
254
|
+
* re-evaluates — capped at `maxRounds` redraft rounds.
|
|
237
255
|
*
|
|
238
256
|
* `maxRounds` is the operator-tunable redraft ceiling (default 2 via
|
|
239
257
|
* `lib/config/acceptance-eval.js`). It is a soft knob inside an
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
// aggregate into per-gate files under `config/gates/`.
|
|
15
15
|
import { GATES_SCHEMA } from './config/gates/index.js';
|
|
16
16
|
|
|
17
|
+
// Story #4531: miDropMustRefactor (here) and autoRefresh.miDropCap (below)
|
|
18
|
+
// were retired. Both were schema-validated, defaulted, and resolved, but
|
|
19
|
+
// never consumed by the gate they were named for — quality-preview.js's
|
|
20
|
+
// computeExitCode short-circuits on miExit (derived from the ALREADY-
|
|
21
|
+
// consumed delivery.quality.gates.maintainability.tolerance) before either
|
|
22
|
+
// knob is ever read. maintainability.tolerance is now the single documented
|
|
23
|
+
// MI-drop control. See lib/migrations/index.js for the consumer-config
|
|
24
|
+
// migration that strips these keys on upgrade (additionalProperties: false
|
|
25
|
+
// below means a leftover key is a hard AJV failure, not a silent no-op).
|
|
17
26
|
const CODING_GUARDRAILS_SCHEMA = {
|
|
18
27
|
type: 'object',
|
|
19
28
|
properties: {
|
|
20
29
|
cyclomaticFlag: { type: 'integer', minimum: 1 },
|
|
21
30
|
cyclomaticMustFix: { type: 'integer', minimum: 1 },
|
|
22
|
-
miDropMustRefactor: { type: 'number', minimum: 0 },
|
|
23
31
|
requireSiblingTest: { type: 'boolean' },
|
|
24
32
|
},
|
|
25
33
|
additionalProperties: false,
|
|
@@ -29,7 +37,6 @@ const AUTO_REFRESH_SCHEMA = {
|
|
|
29
37
|
type: 'object',
|
|
30
38
|
properties: {
|
|
31
39
|
enabled: { type: 'boolean' },
|
|
32
|
-
miDropCap: { type: 'number', minimum: 0 },
|
|
33
40
|
crapJumpCap: { type: 'number', minimum: 0 },
|
|
34
41
|
scope: { type: 'string', enum: ['diff', 'full'] },
|
|
35
42
|
},
|
|
@@ -109,25 +109,57 @@ const PROJECT_SCHEMA = {
|
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* Curated webhook event vocabulary. The webhook channel is gated by an
|
|
112
|
-
* explicit allowlist of event names — the
|
|
113
|
-
*
|
|
114
|
-
*
|
|
112
|
+
* explicit allowlist of event names — the vocabulary mirrors the events the
|
|
113
|
+
* v2 runtime actually emits through `notify()` (Story transitions, merge
|
|
114
|
+
* outcomes, loop lifecycle beats).
|
|
115
|
+
*
|
|
116
|
+
* `story.heartbeat` was retired here (A22): the vocabulary's contract is
|
|
117
|
+
* "events the runtime actually emits", and nothing could emit this one. Its
|
|
118
|
+
* emitter (`emit-story-heartbeat.js`) demanded an `epicId >= 1` while the
|
|
119
|
+
* sole call path (`single-story-init.js` → `setActiveStoryEnv`) passed
|
|
120
|
+
* `epicId: null`, so `CC_EPIC_ID` was never set and the hook that would have
|
|
121
|
+
* fired the beat always short-circuited. Emitter, hook, and schema are all
|
|
122
|
+
* deleted; keeping the name allowlistable would let an operator subscribe to
|
|
123
|
+
* a channel that can never deliver. Removing it from the enum makes a
|
|
124
|
+
* resurrection fail loudly at config-validation time rather than silently
|
|
125
|
+
* never firing.
|
|
115
126
|
*/
|
|
116
127
|
export const WEBHOOK_EVENT_NAMES = Object.freeze([
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
128
|
+
'state-transition',
|
|
129
|
+
'story-merged',
|
|
130
|
+
'story-closing',
|
|
131
|
+
'operator-message',
|
|
132
|
+
'merge.unlanded',
|
|
133
|
+
'merge.flip-failed',
|
|
134
|
+
'loop.tick',
|
|
122
135
|
]);
|
|
123
136
|
|
|
124
137
|
/**
|
|
125
138
|
* Curated GitHub-comment event vocabulary. The comment channel is gated by
|
|
126
139
|
* an explicit allowlist of event names — same model as `webhookEvents`.
|
|
140
|
+
*
|
|
141
|
+
* **Deliberately narrower than {@link WEBHOOK_EVENT_NAMES}**, and the axis
|
|
142
|
+
* is ticket scope, not importance. A comment is written *onto a Story
|
|
143
|
+
* issue*, so only events that are about one Story, and whose message reads
|
|
144
|
+
* as narrative an operator wants durably on the ticket, belong here. The
|
|
145
|
+
* webhook-only remainder — `merge.unlanded`, `merge.flip-failed`,
|
|
146
|
+
* `loop.tick` — are run-scoped or firehose beats;
|
|
147
|
+
* mirroring them onto the ticket would bury the narrative under machine
|
|
148
|
+
* chatter, and `notify()` drops a comment for any dispatch without a
|
|
149
|
+
* resolvable ticket id regardless.
|
|
150
|
+
*
|
|
151
|
+
* `story-closing` IS in scope by that rule (Story-scoped, `level: 'story'`,
|
|
152
|
+
* human-readable — the same shape as `story-merged`) and its earlier
|
|
153
|
+
* absence was an oversight: the event was emittable to webhooks but could
|
|
154
|
+
* not be allowlisted for comments at all. It is in the vocabulary but NOT
|
|
155
|
+
* in the shipped default (`config/github.js` `NOTIFICATIONS_DEFAULTS`) —
|
|
156
|
+
* opting in is an operator choice, not a behaviour change forced on every
|
|
157
|
+
* consumer.
|
|
127
158
|
*/
|
|
128
159
|
export const COMMENT_EVENT_NAMES = Object.freeze([
|
|
129
160
|
'state-transition',
|
|
130
161
|
'story-merged',
|
|
162
|
+
'story-closing',
|
|
131
163
|
'operator-message',
|
|
132
164
|
]);
|
|
133
165
|
|
|
@@ -208,19 +240,14 @@ const GITHUB_SCHEMA = {
|
|
|
208
240
|
// planning.* — inputs to /plan
|
|
209
241
|
// ---------------------------------------------------------------------------
|
|
210
242
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
maxBytes: { type: 'integer', minimum: 1024 },
|
|
220
|
-
summaryMode: { type: 'string', enum: ['auto', 'always', 'never'] },
|
|
221
|
-
},
|
|
222
|
-
additionalProperties: false,
|
|
223
|
-
};
|
|
243
|
+
// Story #4541: `planning.context.{maxBytes, summaryMode}` was retired. The
|
|
244
|
+
// `applyBudget` pass it fed lost its last caller in the v2 cutover, and it
|
|
245
|
+
// bounded a field the envelope builders discarded before shipping the raw seed
|
|
246
|
+
// anyway — so the key resolved but capped nothing. The live bound on
|
|
247
|
+
// planner-context size is the fixed `PLAN_CONTEXT_ENVELOPE_BYTE_CEILING` in
|
|
248
|
+
// `lib/orchestration/plan-context.js`. Setting `planning.context` is now
|
|
249
|
+
// rejected as an additional property, so a resurrected key fails loudly rather
|
|
250
|
+
// than silently doing nothing.
|
|
224
251
|
|
|
225
252
|
/**
|
|
226
253
|
* Story #2634 — `planning.codebaseSnapshot` controls the structural
|
|
@@ -250,7 +277,6 @@ const PLANNING_SCHEMA = {
|
|
|
250
277
|
type: 'object',
|
|
251
278
|
properties: {
|
|
252
279
|
riskHeuristics: LIST_OR_EXTENDER_OF_STRINGS,
|
|
253
|
-
context: PLANNING_CONTEXT_SCHEMA,
|
|
254
280
|
codebaseSnapshot: CODEBASE_SNAPSHOT_SCHEMA,
|
|
255
281
|
// Cross-Story conflict-finding severity gates. Off by default so
|
|
256
282
|
// existing repos keep advisory-only behaviour; flipping either to
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dead-exports-knip.js — the knip driver behind the dead-export ratchet.
|
|
3
|
+
*
|
|
4
|
+
* Owns everything about talking to knip and normalising what comes back:
|
|
5
|
+
* spawning it, reading a pre-captured report, and flattening its report into
|
|
6
|
+
* `{ file, symbol }` rows. `check-dead-exports.js` stays a thin CLI over this.
|
|
7
|
+
*
|
|
8
|
+
* @module lib/dead-exports-knip
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { spawnSync } from 'node:child_process';
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import process from 'node:process';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Spawn `npx knip --reporter json --no-progress` and return the parsed
|
|
17
|
+
* envelope. Never throws — the caller logs the error and treats current rows as
|
|
18
|
+
* empty, which surfaces every baseline row as "removed": loud, but safe.
|
|
19
|
+
*
|
|
20
|
+
* `production` adds knip's `--production` flag, which restricts analysis to
|
|
21
|
+
* entry/project patterns carrying the `!` suffix in `knip.json`. The test globs
|
|
22
|
+
* deliberately lack that suffix, so production mode drops them as entry points
|
|
23
|
+
* and an export reachable only from a test reads as dead. Without those
|
|
24
|
+
* suffixes production mode has no entry patterns at all and reports nothing —
|
|
25
|
+
* `knip.json` and this flag are a matched pair.
|
|
26
|
+
*
|
|
27
|
+
* Exported as a hook so tests can stub the spawn without a working knip
|
|
28
|
+
* workspace.
|
|
29
|
+
*
|
|
30
|
+
* @param {{ cwd?: string, spawn?: typeof spawnSync, production?: boolean }} [opts]
|
|
31
|
+
* @returns {{ ok: true, envelope: unknown } | { ok: false, error: string }}
|
|
32
|
+
*/
|
|
33
|
+
export function runKnip({
|
|
34
|
+
cwd = process.cwd(),
|
|
35
|
+
spawn = spawnSync,
|
|
36
|
+
production = false,
|
|
37
|
+
} = {}) {
|
|
38
|
+
const args = ['knip', '--reporter', 'json', '--no-progress'];
|
|
39
|
+
if (production) args.push('--production');
|
|
40
|
+
const result = spawn(process.platform === 'win32' ? 'npx.cmd' : 'npx', args, {
|
|
41
|
+
cwd,
|
|
42
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
43
|
+
encoding: 'utf-8',
|
|
44
|
+
shell: process.platform === 'win32',
|
|
45
|
+
});
|
|
46
|
+
if (result.error) {
|
|
47
|
+
return { ok: false, error: `spawn failed: ${result.error.message}` };
|
|
48
|
+
}
|
|
49
|
+
const stdout = typeof result.stdout === 'string' ? result.stdout : '';
|
|
50
|
+
if (stdout.trim().length === 0) {
|
|
51
|
+
return { ok: false, error: 'knip produced empty stdout' };
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return { ok: true, envelope: JSON.parse(stdout) };
|
|
55
|
+
} catch (err) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
error: `knip JSON parse failed: ${err?.message ?? err}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Read a pre-captured knip JSON envelope from disk (the `--knip-output` test
|
|
65
|
+
* seam). Returns the parsed envelope or `null` on failure.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} filePath
|
|
68
|
+
* @returns {unknown}
|
|
69
|
+
*/
|
|
70
|
+
export function readKnipOutput(filePath) {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Flatten knip's `--reporter json` output into `{ file, symbol }` rows. Knip
|
|
80
|
+
* emits `{ issues: [{ file, exports: [{ name, ... }], ... }, ...] }`. Only
|
|
81
|
+
* `exports` rows are mapped — the ratchet ignores file-, dependency- and
|
|
82
|
+
* duplicate-level issues, which knip surfaces under separate `rules` keys.
|
|
83
|
+
*
|
|
84
|
+
* @param {unknown} knipEnvelope The parsed knip JSON report.
|
|
85
|
+
* @returns {Array<{ file: string, symbol: string }>}
|
|
86
|
+
*/
|
|
87
|
+
export function extractRowsFromKnip(knipEnvelope) {
|
|
88
|
+
const rows = [];
|
|
89
|
+
if (!knipEnvelope || typeof knipEnvelope !== 'object') return rows;
|
|
90
|
+
const issues = Array.isArray(knipEnvelope.issues) ? knipEnvelope.issues : [];
|
|
91
|
+
for (const issue of issues) {
|
|
92
|
+
const file = issue?.file;
|
|
93
|
+
if (typeof file !== 'string' || file.length === 0) continue;
|
|
94
|
+
const exports_ = Array.isArray(issue.exports) ? issue.exports : [];
|
|
95
|
+
for (const e of exports_) {
|
|
96
|
+
const symbol =
|
|
97
|
+
(e && typeof e.name === 'string' && e.name) ||
|
|
98
|
+
(e && typeof e.symbol === 'string' && e.symbol) ||
|
|
99
|
+
null;
|
|
100
|
+
if (!symbol) continue;
|
|
101
|
+
rows.push({ file, symbol });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return rows;
|
|
105
|
+
}
|