mandrel 1.58.0 → 1.60.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 +100 -98
- package/.agents/docs/SDLC.md +140 -141
- package/.agents/docs/configuration.md +16 -16
- package/.agents/docs/workflows.md +7 -8
- package/.agents/instructions.md +12 -11
- package/.agents/personas/architect.md +1 -1
- package/.agents/personas/product.md +1 -1
- package/.agents/personas/project-manager.md +14 -14
- package/.agents/personas/technical-writer.md +1 -1
- package/.agents/rules/changelog-style.md +5 -5
- package/.agents/rules/git-conventions.md +3 -3
- package/.agents/schemas/agentrc.schema.json +3 -3
- package/.agents/schemas/audit-rules.json +20 -0
- package/.agents/schemas/dispatch-manifest.json +4 -4
- package/.agents/schemas/epic-spec.schema.json +15 -45
- package/.agents/schemas/lifecycle/README.md +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/README.md +1 -1
- package/.agents/scripts/acceptance-eval.js +21 -4
- package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
- package/.agents/scripts/analyze-execution.js +2 -2
- package/.agents/scripts/assert-branch.js +1 -3
- package/.agents/scripts/audit-to-stories.js +1 -1
- package/.agents/scripts/bootstrap.js +1 -1
- package/.agents/scripts/check-arch-cycles.js +360 -0
- package/.agents/scripts/check-doc-links.js +2 -3
- package/.agents/scripts/coverage-capture.js +24 -3
- package/.agents/scripts/diagnose-friction.js +1 -1
- package/.agents/scripts/dispatcher.js +2 -2
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/epic-audit-prepare.js +3 -3
- package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
- package/.agents/scripts/epic-deliver-preflight.js +11 -9
- package/.agents/scripts/epic-deliver-prepare.js +13 -5
- package/.agents/scripts/epic-execute-record-wave.js +5 -5
- package/.agents/scripts/epic-plan-healthcheck.js +6 -10
- package/.agents/scripts/epic-plan-spec-validate.js +1 -1
- package/.agents/scripts/epic-reconcile.js +11 -29
- package/.agents/scripts/evidence-gate.js +2 -2
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/git-rebase-and-resolve.js +1 -1
- package/.agents/scripts/hierarchy-gate.js +40 -24
- package/.agents/scripts/lib/ITicketingProvider.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
- package/.agents/scripts/lib/baseline-snapshot.js +7 -7
- package/.agents/scripts/lib/baselines/kinds/coverage.js +33 -149
- package/.agents/scripts/lib/baselines/kinds/duplication.js +27 -116
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +192 -0
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +34 -133
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +31 -124
- package/.agents/scripts/lib/baselines/kinds/mutation.js +25 -111
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +59 -0
- package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +37 -0
- package/.agents/scripts/lib/baselines/writer.js +1 -1
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/close-validation/commands.js +188 -0
- package/.agents/scripts/lib/close-validation/gates.js +235 -0
- package/.agents/scripts/lib/close-validation/process.js +101 -0
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +1 -1
- package/.agents/scripts/lib/close-validation/runner.js +325 -0
- package/.agents/scripts/lib/close-validation/telemetry.js +70 -0
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/quality.js +6 -6
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-resolver.js +2 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
- package/.agents/scripts/lib/config-settings-schema.js +3 -3
- package/.agents/scripts/lib/coverage-capture.js +147 -4
- package/.agents/scripts/lib/cpu-pool.js +14 -0
- package/.agents/scripts/lib/crap-utils.js +6 -11
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +87 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +10 -10
- package/.agents/scripts/lib/git-utils.js +24 -22
- package/.agents/scripts/lib/label-constants.js +3 -4
- package/.agents/scripts/lib/label-taxonomy.js +3 -8
- package/.agents/scripts/lib/maintainability-engine.js +1 -1
- package/.agents/scripts/lib/maintainability-utils.js +4 -187
- package/.agents/scripts/lib/observability/perf-report-readers.js +32 -23
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +81 -7
- package/.agents/scripts/lib/orchestration/code-review.js +95 -82
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
- package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +14 -37
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +22 -22
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +206 -58
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +27 -3
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +28 -8
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +13 -41
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +2 -3
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -8
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +103 -0
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +22 -64
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +38 -76
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +10 -10
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +8 -20
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
- package/.agents/scripts/lib/orchestration/file-assumptions.js +6 -5
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +144 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +3 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +8 -8
- package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +7 -7
- package/.agents/scripts/lib/orchestration/preflight-cache.js +36 -13
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
- package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
- package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +5 -60
- package/.agents/scripts/lib/orchestration/review-providers/native.js +7 -6
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +105 -0
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +7 -59
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -4
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +32 -35
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +1 -2
- package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +451 -503
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +8 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +47 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +2 -2
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +358 -54
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +3 -2
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +32 -5
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +5 -18
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +3 -3
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +33 -16
- package/.agents/scripts/lib/orchestration/story-reachability.js +47 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
- package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +4 -35
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +44 -73
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +16 -7
- package/.agents/scripts/lib/orchestration/ticketing/state.js +53 -439
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +471 -0
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +3 -3
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +2 -8
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +1 -1
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
- package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
- package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
- package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
- package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
- package/.agents/scripts/lib/project-root.js +17 -0
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/spec/index.js +1 -1
- package/.agents/scripts/lib/spec/loader.js +2 -2
- package/.agents/scripts/lib/spec/state.js +7 -16
- package/.agents/scripts/lib/story-adjacency.js +76 -0
- package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
- package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
- package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
- package/.agents/scripts/lib/story-lifecycle.js +9 -9
- package/.agents/scripts/lib/story-plan.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
- package/.agents/scripts/lib/transpile.js +93 -0
- package/.agents/scripts/lib/wave-runner/tick.js +4 -153
- package/.agents/scripts/lib/workers/crap-worker.js +1 -1
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +20 -2
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +90 -0
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +26 -8
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +74 -0
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/mappers.js +2 -2
- package/.agents/scripts/providers/github/tickets.js +114 -10
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/retro-run.js +2 -2
- package/.agents/scripts/run-lint.js +10 -1
- package/.agents/scripts/run-tests.js +24 -4
- package/.agents/scripts/single-story-init.js +1 -1
- package/.agents/scripts/stories-wave-tick.js +13 -10
- package/.agents/scripts/story-close.js +1 -1
- package/.agents/scripts/story-init.js +162 -26
- package/.agents/scripts/story-phase.js +5 -5
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/sync-branch-from-base.js +2 -2
- package/.agents/scripts/validate-docs-freshness.js +1 -1
- package/.agents/scripts/wave-tick.js +1 -1
- package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
- package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
- package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
- package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
- package/.agents/skills/core/scope-triage/SKILL.md +9 -10
- package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
- package/.agents/skills/skills.index.json +7 -7
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +1 -1
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/workflows/agents-update.md +2 -2
- package/.agents/workflows/audit-architecture.md +2 -2
- package/.agents/workflows/audit-clean-code.md +2 -2
- package/.agents/workflows/audit-dependencies.md +1 -1
- package/.agents/workflows/audit-devops.md +1 -1
- package/.agents/workflows/audit-documentation.md +226 -0
- package/.agents/workflows/audit-lighthouse.md +1 -1
- package/.agents/workflows/audit-performance.md +2 -2
- package/.agents/workflows/audit-privacy.md +1 -1
- package/.agents/workflows/audit-quality.md +2 -2
- package/.agents/workflows/audit-security.md +2 -2
- package/.agents/workflows/audit-seo.md +1 -1
- package/.agents/workflows/audit-sre.md +1 -1
- package/.agents/workflows/audit-to-stories.md +10 -10
- package/.agents/workflows/audit-ux-ui.md +1 -1
- package/.agents/workflows/deliver.md +85 -0
- package/.agents/workflows/explain.md +3 -3
- package/.agents/workflows/git-merge-pr.md +1 -1
- package/.agents/workflows/git-pr-all.md +13 -10
- package/.agents/workflows/git-push.md +6 -3
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/code-review.md +5 -5
- package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +59 -66
- package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
- package/.agents/workflows/helpers/diagnose.md +1 -1
- package/.agents/workflows/helpers/epic-audit.md +6 -6
- package/.agents/workflows/helpers/epic-deliver-story.md +28 -39
- package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
- package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
- package/.agents/workflows/helpers/epic-testing.md +3 -3
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
- package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
- package/.agents/workflows/helpers/signals.md +1 -1
- package/.agents/workflows/helpers/single-story-deliver.md +12 -11
- package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
- package/.agents/workflows/onboard.md +21 -20
- package/.agents/workflows/plan.md +89 -0
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/qa-run-harness.md +1 -1
- package/README.md +17 -20
- package/docs/CHANGELOG.md +1149 -0
- package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
- package/lib/cli/__tests__/update-reexec.test.js +513 -0
- package/lib/cli/init.js +338 -0
- package/lib/cli/update.js +413 -52
- package/package.json +3 -1
- package/.agents/scripts/lib/auto-refresh-baselines.js +0 -308
- package/.agents/scripts/lib/close-validation.js +0 -897
- package/.agents/scripts/lib/orchestration/cascade-grouping.js +0 -275
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +0 -69
- package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +0 -221
- package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +0 -123
- package/.agents/scripts/lib/task-utils.js +0 -26
- package/.agents/scripts/story-deliver-prepare.js +0 -267
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* close-validation/runner.js — The `runCloseValidation` orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Runs typecheck, lint, test, format check, and maintainability/coverage/
|
|
5
|
+
* CRAP regression checks before the story merge so drift is caught in the
|
|
6
|
+
* worktree rather than at pre-push time on the Epic branch. All gates
|
|
7
|
+
* inherit stdio so the operator sees the raw output; the returned summary
|
|
8
|
+
* surfaces actionable hints on failure.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
recordPass as defaultRecordPass,
|
|
13
|
+
shouldSkip as defaultShouldSkip,
|
|
14
|
+
hashCommandConfig,
|
|
15
|
+
} from '../validation-evidence.js';
|
|
16
|
+
import {
|
|
17
|
+
isFormatterEligible,
|
|
18
|
+
listChangedFilesForFormatGate,
|
|
19
|
+
} from './commands.js';
|
|
20
|
+
import { DEFAULT_GATES, partitionGates } from './gates.js';
|
|
21
|
+
import { defaultGateRunner } from './process.js';
|
|
22
|
+
import { defaultGetHeadSha } from './projections/head-sha.js';
|
|
23
|
+
|
|
24
|
+
/** @typedef {import('./gates.js').Gate} Gate */
|
|
25
|
+
|
|
26
|
+
function applyChangedFileScope({ gate, spawnCwd, log }) {
|
|
27
|
+
if (!gate.changedFileScope) {
|
|
28
|
+
return { gate, cmd: gate.cmd, args: gate.args, skip: false };
|
|
29
|
+
}
|
|
30
|
+
const changedFiles = listChangedFilesForFormatGate({
|
|
31
|
+
cwd: spawnCwd,
|
|
32
|
+
baseRef: gate.changedFileScope.baseRef,
|
|
33
|
+
});
|
|
34
|
+
// Filter to the formatter-eligible subset before deciding to skip. A
|
|
35
|
+
// non-empty diff that contains zero formatter-eligible files (e.g. a
|
|
36
|
+
// docs-only Story) must take the skip path, not invoke biome with only
|
|
37
|
+
// ineligible paths — biome reports "No files were processed" and exits 1
|
|
38
|
+
// in that case (Story #3410).
|
|
39
|
+
const eligibleFiles = changedFiles.filter(isFormatterEligible);
|
|
40
|
+
if (eligibleFiles.length === 0) {
|
|
41
|
+
log(
|
|
42
|
+
`[close-validation] ⏭ ${gate.name} skipped (no formatter-eligible changed files)`,
|
|
43
|
+
);
|
|
44
|
+
return { gate, cmd: gate.cmd, args: gate.args, skip: true };
|
|
45
|
+
}
|
|
46
|
+
const args =
|
|
47
|
+
gate.args[gate.args.length - 1] === '.'
|
|
48
|
+
? gate.args.slice(0, -1)
|
|
49
|
+
: gate.args;
|
|
50
|
+
log(
|
|
51
|
+
`[close-validation] ↳ ${gate.name} scoped to ${eligibleFiles.length} formatter-eligible changed file(s) from ${gate.changedFileScope.baseRef}...HEAD`,
|
|
52
|
+
);
|
|
53
|
+
return {
|
|
54
|
+
gate,
|
|
55
|
+
cmd: gate.cmd,
|
|
56
|
+
args: [...args, ...eligibleFiles],
|
|
57
|
+
skip: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Run every gate sequentially. Stops collecting after the first failure but
|
|
63
|
+
* still returns a summary so the caller decides how to surface the result.
|
|
64
|
+
*
|
|
65
|
+
* Worktree locality (Story #1120): when `worktreePath` is supplied, every
|
|
66
|
+
* gate runner is spawned with `cwd: worktreePath` so the gate sees the
|
|
67
|
+
* Story branch's post-rebase tree. Evidence reads/writes still key against
|
|
68
|
+
* `cwd` (the main checkout) because the per-Epic temp tree lives under
|
|
69
|
+
* the main `.git/`. Failure messages name the worktree path.
|
|
70
|
+
*
|
|
71
|
+
* Evidence-aware: when both `storyId` and `epicId` are provided and
|
|
72
|
+
* `useEvidence !== false`, each gate consults `validation-evidence
|
|
73
|
+
* .shouldSkip()` against current HEAD + the gate's command-config hash. A
|
|
74
|
+
* matching record skips the gate; a successful run is recorded so the
|
|
75
|
+
* next caller in the local hot path can skip in turn.
|
|
76
|
+
*
|
|
77
|
+
* `onGateStart` is invoked immediately before each gate's runner spawn.
|
|
78
|
+
* story-close uses it to drive `phaseTimer.mark(...)` for per-gate
|
|
79
|
+
* wall-clock telemetry. Errors thrown from the hook propagate.
|
|
80
|
+
*
|
|
81
|
+
* @param {{
|
|
82
|
+
* cwd: string,
|
|
83
|
+
* worktreePath?: string,
|
|
84
|
+
* gates?: Gate[],
|
|
85
|
+
* runner?: (cmd: string, args: string[], opts: { cwd: string, signal?: AbortSignal, gateName?: string, log?: (m: string) => void }) => Promise<{ status: number }> | { status: number },
|
|
86
|
+
* log?: (m: string) => void,
|
|
87
|
+
* onGateStart?: (gate: Gate) => void,
|
|
88
|
+
* storyId?: number|null,
|
|
89
|
+
* epicId?: number|null,
|
|
90
|
+
* useEvidence?: boolean,
|
|
91
|
+
* evidenceClock?: () => number,
|
|
92
|
+
* getHeadSha?: (cwd: string) => string|null,
|
|
93
|
+
* recordPass?: typeof defaultRecordPass,
|
|
94
|
+
* shouldSkip?: typeof defaultShouldSkip,
|
|
95
|
+
* }} opts
|
|
96
|
+
* @returns {{ ok: boolean, failed: Array<{ gate: Gate, status: number, cwd: string }>, skipped: Array<{ gate: Gate, reason: string }> }}
|
|
97
|
+
*/
|
|
98
|
+
export async function runCloseValidation({
|
|
99
|
+
cwd,
|
|
100
|
+
worktreePath,
|
|
101
|
+
gates = DEFAULT_GATES,
|
|
102
|
+
runner = defaultGateRunner,
|
|
103
|
+
log = () => {},
|
|
104
|
+
onGateStart,
|
|
105
|
+
storyId = null,
|
|
106
|
+
epicId = null,
|
|
107
|
+
useEvidence = true,
|
|
108
|
+
evidenceClock = () => Date.now(),
|
|
109
|
+
getHeadSha = (resolvedCwd) => defaultGetHeadSha(resolvedCwd),
|
|
110
|
+
recordPass = defaultRecordPass,
|
|
111
|
+
shouldSkip = defaultShouldSkip,
|
|
112
|
+
} = {}) {
|
|
113
|
+
const failed = [];
|
|
114
|
+
const skipped = [];
|
|
115
|
+
const evidenceActive = useEvidence && storyId != null && epicId != null;
|
|
116
|
+
// Evidence keys against the main checkout's HEAD because the per-Epic
|
|
117
|
+
// evidence file lives under the main `.git/`. Gate spawn, in contrast,
|
|
118
|
+
// runs in the worktree when one is supplied — that's the whole point of
|
|
119
|
+
// Story #1120.
|
|
120
|
+
const spawnCwd = worktreePath ?? cwd;
|
|
121
|
+
const headSha = evidenceActive ? getHeadSha(spawnCwd) : null;
|
|
122
|
+
|
|
123
|
+
// Helper closures so the parallel and serial passes share evidence
|
|
124
|
+
// bookkeeping bit-for-bit.
|
|
125
|
+
|
|
126
|
+
/** Returns a `{ skip: true }` verdict when evidence makes the gate redundant. */
|
|
127
|
+
const evidenceVerdict = (gate, configHash) => {
|
|
128
|
+
if (!(evidenceActive && headSha)) return { skip: false };
|
|
129
|
+
const verdict = shouldSkip(
|
|
130
|
+
{
|
|
131
|
+
storyId,
|
|
132
|
+
gateName: gate.name,
|
|
133
|
+
currentSha: headSha,
|
|
134
|
+
configHash,
|
|
135
|
+
inputFingerprint: gate.inputFingerprint ?? null,
|
|
136
|
+
},
|
|
137
|
+
{ cwd, epicId },
|
|
138
|
+
);
|
|
139
|
+
if (verdict.skip) {
|
|
140
|
+
const tsHint = verdict.record?.timestamp
|
|
141
|
+
? ` recorded ${verdict.record.timestamp}`
|
|
142
|
+
: '';
|
|
143
|
+
log(
|
|
144
|
+
`[close-validation] ⏭ ${gate.name} skipped (${verdict.reason}: SHA=${headSha.slice(0, 7)}${tsHint})`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return verdict;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const recordIfActive = (gate, configHash, durationMs) => {
|
|
151
|
+
if (!(evidenceActive && headSha)) return;
|
|
152
|
+
try {
|
|
153
|
+
recordPass(
|
|
154
|
+
{
|
|
155
|
+
storyId,
|
|
156
|
+
gateName: gate.name,
|
|
157
|
+
sha: headSha,
|
|
158
|
+
configHash,
|
|
159
|
+
exitCode: 0,
|
|
160
|
+
durationMs,
|
|
161
|
+
inputFingerprint: gate.inputFingerprint ?? null,
|
|
162
|
+
},
|
|
163
|
+
{ cwd, epicId },
|
|
164
|
+
);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
log(
|
|
167
|
+
`[close-validation] ⚠ failed to record evidence for ${gate.name}: ${err?.message ?? err}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Run a single gate. When `gate.run` is a function the gate executes
|
|
174
|
+
* **in process** (Story #1973 / Task #1984 — per-kind baseline gates
|
|
175
|
+
* removed their `child_process.spawn(node check-<kind>.js)` arm and
|
|
176
|
+
* call `compare(head, base)` directly). The `run` callable receives
|
|
177
|
+
* the same `(cmd, args, opts)` argv shape as `runner` so it slots into
|
|
178
|
+
* the existing contract without churn at the runner boundary.
|
|
179
|
+
* Otherwise the supplied `runner` is used (default: spawn).
|
|
180
|
+
*
|
|
181
|
+
* @returns {Promise<{ status: number }>}
|
|
182
|
+
*/
|
|
183
|
+
const dispatchGate = async (gate, signal) => {
|
|
184
|
+
log(
|
|
185
|
+
`[close-validation] ▶ ${gate.name}${worktreePath ? ` (cwd=${worktreePath})` : ''}`,
|
|
186
|
+
);
|
|
187
|
+
if (typeof onGateStart === 'function') onGateStart(gate);
|
|
188
|
+
const dispatcher = typeof gate.run === 'function' ? gate.run : runner;
|
|
189
|
+
const result = await dispatcher(gate.cmd, gate.args, {
|
|
190
|
+
cwd: spawnCwd,
|
|
191
|
+
gateName: gate.name,
|
|
192
|
+
log,
|
|
193
|
+
signal,
|
|
194
|
+
...(gate.env ? { env: gate.env } : {}),
|
|
195
|
+
});
|
|
196
|
+
return { status: result?.status ?? 1 };
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const { independent, serial } = partitionGates(gates);
|
|
200
|
+
|
|
201
|
+
// ── Phase 1: independent gates in parallel ──────────────────────────
|
|
202
|
+
// First non-zero exit pins `firstFailure` and aborts every in-flight
|
|
203
|
+
// sibling via SIGTERM. Other gates' results are still awaited (so we
|
|
204
|
+
// never leak children) but their non-zero status is intentionally
|
|
205
|
+
// dropped: only one error surfaces.
|
|
206
|
+
const ac = new AbortController();
|
|
207
|
+
let firstIndepFailure = null;
|
|
208
|
+
|
|
209
|
+
const indepTasks = independent.map(async (gate) => {
|
|
210
|
+
let execution;
|
|
211
|
+
try {
|
|
212
|
+
execution = applyChangedFileScope({ gate, spawnCwd, log });
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (!firstIndepFailure) {
|
|
215
|
+
firstIndepFailure = { gate, status: 1, cwd: spawnCwd };
|
|
216
|
+
log(
|
|
217
|
+
`[close-validation] ✖ ${gate.name} failed to resolve changed-file scope: ${err?.message ?? err}`,
|
|
218
|
+
);
|
|
219
|
+
ac.abort();
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (execution.skip) {
|
|
224
|
+
skipped.push({ gate, reason: 'no-changed-files' });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const configHash = hashCommandConfig({
|
|
228
|
+
cmd: execution.cmd,
|
|
229
|
+
args: execution.args,
|
|
230
|
+
cwd: spawnCwd,
|
|
231
|
+
});
|
|
232
|
+
const verdict = evidenceVerdict(gate, configHash);
|
|
233
|
+
if (verdict.skip) {
|
|
234
|
+
skipped.push({ gate, reason: verdict.reason });
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const startedAt = evidenceActive ? evidenceClock() : 0;
|
|
238
|
+
let result;
|
|
239
|
+
try {
|
|
240
|
+
result = await dispatchGate(
|
|
241
|
+
{ ...gate, cmd: execution.cmd, args: execution.args },
|
|
242
|
+
ac.signal,
|
|
243
|
+
);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
result = { status: 1, error: err };
|
|
246
|
+
}
|
|
247
|
+
if (result.status !== 0) {
|
|
248
|
+
if (!firstIndepFailure) {
|
|
249
|
+
firstIndepFailure = { gate, status: result.status, cwd: spawnCwd };
|
|
250
|
+
ac.abort();
|
|
251
|
+
}
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
log(`[close-validation] ✓ ${gate.name}`);
|
|
255
|
+
recordIfActive(
|
|
256
|
+
gate,
|
|
257
|
+
configHash,
|
|
258
|
+
evidenceActive ? evidenceClock() - startedAt : 0,
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
await Promise.all(indepTasks);
|
|
263
|
+
|
|
264
|
+
if (firstIndepFailure) {
|
|
265
|
+
failed.push(firstIndepFailure);
|
|
266
|
+
log(
|
|
267
|
+
`[close-validation] ✖ ${firstIndepFailure.gate.name} failed (exit ${firstIndepFailure.status}) in ${spawnCwd}`,
|
|
268
|
+
);
|
|
269
|
+
if (firstIndepFailure.gate.hint) {
|
|
270
|
+
log(`[close-validation] hint: ${firstIndepFailure.gate.hint}`);
|
|
271
|
+
}
|
|
272
|
+
return { ok: false, failed, skipped };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ── Phase 2: serial gates in declared order ─────────────────────────
|
|
276
|
+
for (const gate of serial) {
|
|
277
|
+
let execution;
|
|
278
|
+
try {
|
|
279
|
+
execution = applyChangedFileScope({ gate, spawnCwd, log });
|
|
280
|
+
} catch (err) {
|
|
281
|
+
failed.push({ gate, status: 1, cwd: spawnCwd });
|
|
282
|
+
log(
|
|
283
|
+
`[close-validation] ✖ ${gate.name} failed to resolve changed-file scope: ${err?.message ?? err}`,
|
|
284
|
+
);
|
|
285
|
+
if (gate.hint) log(`[close-validation] hint: ${gate.hint}`);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
if (execution.skip) {
|
|
289
|
+
skipped.push({ gate, reason: 'no-changed-files' });
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const configHash = hashCommandConfig({
|
|
293
|
+
cmd: execution.cmd,
|
|
294
|
+
args: execution.args,
|
|
295
|
+
cwd: spawnCwd,
|
|
296
|
+
});
|
|
297
|
+
const verdict = evidenceVerdict(gate, configHash);
|
|
298
|
+
if (verdict.skip) {
|
|
299
|
+
skipped.push({ gate, reason: verdict.reason });
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const startedAt = evidenceActive ? evidenceClock() : 0;
|
|
303
|
+
const result = await dispatchGate({
|
|
304
|
+
...gate,
|
|
305
|
+
cmd: execution.cmd,
|
|
306
|
+
args: execution.args,
|
|
307
|
+
});
|
|
308
|
+
if (result.status !== 0) {
|
|
309
|
+
failed.push({ gate, status: result.status, cwd: spawnCwd });
|
|
310
|
+
log(
|
|
311
|
+
`[close-validation] ✖ ${gate.name} failed (exit ${result.status}) in ${spawnCwd}`,
|
|
312
|
+
);
|
|
313
|
+
if (gate.hint) log(`[close-validation] hint: ${gate.hint}`);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
log(`[close-validation] ✓ ${gate.name}`);
|
|
317
|
+
recordIfActive(
|
|
318
|
+
gate,
|
|
319
|
+
configHash,
|
|
320
|
+
evidenceActive ? evidenceClock() - startedAt : 0,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return { ok: failed.length === 0, failed, skipped };
|
|
325
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* close-validation/telemetry.js — gh-spawn telemetry emitter.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
6
|
+
import { storyArtifactPath } from '../config/temp-paths.js';
|
|
7
|
+
import { getSpawnCount as defaultGetSpawnCount } from '../gh-exec.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Throw-away ghSpawnCount emitter (Story #1795 / Epic #1788).
|
|
11
|
+
*
|
|
12
|
+
* Writes the current `gh-exec` spawn counter to
|
|
13
|
+
* `temp/epic-<eid>/stories/story-<sid>/gh-spawn-count.json` so the
|
|
14
|
+
* `analyze-execution.js` child process can read it and emit a
|
|
15
|
+
* `ghSpawnCount` field on the `story-perf-summary` payload. The Story-
|
|
16
|
+
* close orchestrator calls this inside `runPostMergeClose` right before
|
|
17
|
+
* the perf-summary phase, capturing every `gh` invocation from preflight
|
|
18
|
+
* through the merge in one counter snapshot.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} opts
|
|
21
|
+
* @param {number|string} opts.epicId
|
|
22
|
+
* @param {number|string} opts.storyId
|
|
23
|
+
* @param {object} [opts.config] - Resolved config bag so `tempRoot`
|
|
24
|
+
* resolution honours the consumer's configured path.
|
|
25
|
+
* @param {() => number} [opts.getSpawnCountFn=defaultGetSpawnCount] - Test seam.
|
|
26
|
+
* @param {typeof defaultWriteFile} [opts.writeFileFn=defaultWriteFile] - Test seam.
|
|
27
|
+
* @param {{ warn?: (s: string) => void }} [opts.logger] - Best-effort
|
|
28
|
+
* failure-path logger; never throws.
|
|
29
|
+
* @returns {Promise<{ status: 'ok'|'failed', path?: string, ghSpawnCount?: number, reason?: string }>}
|
|
30
|
+
*/
|
|
31
|
+
export async function emitGhSpawnCount({
|
|
32
|
+
epicId,
|
|
33
|
+
storyId,
|
|
34
|
+
config,
|
|
35
|
+
getSpawnCountFn = defaultGetSpawnCount,
|
|
36
|
+
writeFileFn = defaultWriteFile,
|
|
37
|
+
logger,
|
|
38
|
+
} = {}) {
|
|
39
|
+
const eid = Number(epicId);
|
|
40
|
+
const sid = Number(storyId);
|
|
41
|
+
if (!Number.isInteger(eid) || eid < 1 || !Number.isInteger(sid) || sid < 1) {
|
|
42
|
+
return { status: 'failed', reason: 'invalid-ids' };
|
|
43
|
+
}
|
|
44
|
+
let ghSpawnCount;
|
|
45
|
+
try {
|
|
46
|
+
ghSpawnCount = getSpawnCountFn();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
logger?.warn?.(
|
|
49
|
+
`[close-validation] gh-spawn-count read failed: ${err?.message ?? err}`,
|
|
50
|
+
);
|
|
51
|
+
return { status: 'failed', reason: 'counter-read-failed' };
|
|
52
|
+
}
|
|
53
|
+
const targetPath = storyArtifactPath(eid, sid, 'gh-spawn-count.json', config);
|
|
54
|
+
const payload = {
|
|
55
|
+
kind: 'gh-spawn-count',
|
|
56
|
+
epicId: eid,
|
|
57
|
+
storyId: sid,
|
|
58
|
+
ghSpawnCount,
|
|
59
|
+
capturedAt: new Date().toISOString(),
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
await writeFileFn(targetPath, JSON.stringify(payload, null, 2));
|
|
63
|
+
return { status: 'ok', path: targetPath, ghSpawnCount };
|
|
64
|
+
} catch (err) {
|
|
65
|
+
logger?.warn?.(
|
|
66
|
+
`[close-validation] gh-spawn-count emit failed: ${err?.message ?? err}`,
|
|
67
|
+
);
|
|
68
|
+
return { status: 'failed', reason: 'write-failed' };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* codebase-snapshot.js — Bounded structural view of the consumer repo.
|
|
3
3
|
*
|
|
4
|
-
* Story #2634 (sibling to #2635 spec-freshness). `/
|
|
4
|
+
* Story #2634 (sibling to #2635 spec-freshness). `/plan` Phase 7
|
|
5
5
|
* authors PRD + Tech Spec from documentation alone — `architecture.md`,
|
|
6
6
|
* `data-dictionary.md`, `decisions.md`, `patterns.md`. When those docs
|
|
7
7
|
* drift from the real source tree, the Architect persona cites modules
|
|
@@ -113,7 +113,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
113
113
|
|
|
114
114
|
// planning.*
|
|
115
115
|
'planning.maxTickets':
|
|
116
|
-
'Upper bound on tickets a single /
|
|
116
|
+
'Upper bound on tickets a single /plan run may create.',
|
|
117
117
|
'planning.context.maxBytes':
|
|
118
118
|
'Byte budget for the planning-context payload before summary mode kicks in.',
|
|
119
119
|
'planning.context.summaryMode':
|
|
@@ -121,7 +121,7 @@ export const MAINTAINABILITY_GATE_DEFAULTS = Object.freeze({
|
|
|
121
121
|
* --write` autofix spawn. The SIGKILL → exit 124 mapping mirrors
|
|
122
122
|
* `gates.coverage.timeoutMs` (Story #2142).
|
|
123
123
|
*/
|
|
124
|
-
|
|
124
|
+
const FORMAT_AUTOFIX_DEFAULTS = Object.freeze({
|
|
125
125
|
timeoutMs: 60_000,
|
|
126
126
|
});
|
|
127
127
|
|
|
@@ -259,7 +259,7 @@ export function resolveMaintainabilityCrap(
|
|
|
259
259
|
* `targetDirs` + a scalar `tolerance` (when set) + scoping inherited
|
|
260
260
|
* from `gateScoping`.
|
|
261
261
|
*/
|
|
262
|
-
|
|
262
|
+
function resolveMaintainabilityQuality(userBlock, gateScoping) {
|
|
263
263
|
const defaults = MAINTAINABILITY_GATE_DEFAULTS;
|
|
264
264
|
const scoping = {
|
|
265
265
|
defaultScope: gateScoping?.scope ?? DEFAULT_GATE_SCOPING.scope,
|
|
@@ -321,7 +321,7 @@ function resolvePositiveIntegerMs(value, defaultMs) {
|
|
|
321
321
|
*/
|
|
322
322
|
const FORMAT_AUTOFIX_KEYS = new Set(['timeoutMs']);
|
|
323
323
|
|
|
324
|
-
|
|
324
|
+
function resolveFormatAutofix(userBlock) {
|
|
325
325
|
const defaults = FORMAT_AUTOFIX_DEFAULTS;
|
|
326
326
|
if (userBlock == null || typeof userBlock !== 'object') {
|
|
327
327
|
return { timeoutMs: defaults.timeoutMs };
|
|
@@ -336,7 +336,7 @@ export function resolveFormatAutofix(userBlock) {
|
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
/** Resolve the coverage gate. Owns `coveragePath` and `timeoutMs`. */
|
|
339
|
-
|
|
339
|
+
function resolveCoverageGate(userBlock) {
|
|
340
340
|
const defaults = COVERAGE_GATE_DEFAULTS;
|
|
341
341
|
if (userBlock == null || typeof userBlock !== 'object') {
|
|
342
342
|
return {
|
|
@@ -402,7 +402,7 @@ export function resolveCodingGuardrails(userBlock) {
|
|
|
402
402
|
};
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
-
|
|
405
|
+
const AUTO_REFRESH_DEFAULTS = Object.freeze({
|
|
406
406
|
enabled: true,
|
|
407
407
|
miDropCap: 1.5,
|
|
408
408
|
crapJumpCap: 5,
|
|
@@ -411,7 +411,7 @@ export const AUTO_REFRESH_DEFAULTS = Object.freeze({
|
|
|
411
411
|
|
|
412
412
|
const AUTO_REFRESH_KEYS = new Set(Object.keys(AUTO_REFRESH_DEFAULTS));
|
|
413
413
|
|
|
414
|
-
|
|
414
|
+
function resolveAutoRefresh(userBlock) {
|
|
415
415
|
const defaults = AUTO_REFRESH_DEFAULTS;
|
|
416
416
|
if (userBlock == null || typeof userBlock !== 'object') {
|
|
417
417
|
return {
|
|
@@ -29,7 +29,7 @@ export const DEFAULT_DECOMPOSER = Object.freeze({
|
|
|
29
29
|
* host has adequate parallel-agent quota, operators should raise
|
|
30
30
|
* `delivery.deliverRunner.concurrencyCap` — wall-clock time falls
|
|
31
31
|
* proportionally to the extra concurrency. The safe default is a tuning
|
|
32
|
-
* knob, not a performance ceiling. See `epic
|
|
32
|
+
* knob, not a performance ceiling. See `helpers/deliver-epic.md` § Phase 2b and
|
|
33
33
|
* `agentrc-reference.json` `delivery.deliverRunner.concurrencyCap` for details.
|
|
34
34
|
*
|
|
35
35
|
* **`verifyConcurrencyCap`** (Epic #3019 Tech Spec §1.4 / Story #3024) is a
|
|
@@ -44,7 +44,7 @@ const DEFAULT_DELIVER_RUNNER = Object.freeze({
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Default auto-fix loop ceilings for /
|
|
47
|
+
* Default auto-fix loop ceilings for /deliver Phase 4 (epic-audit)
|
|
48
48
|
* and Phase 5 (code-review). Operators override via
|
|
49
49
|
* `delivery.epicAudit.*` and `delivery.codeReview.*` in `.agentrc.json`
|
|
50
50
|
* (Story #2611, Epic #2586).
|
|
@@ -77,7 +77,7 @@ export function resolveWorkingPath({
|
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
* One-shot environment-aware runtime resolution. Returns the trio of runtime
|
|
80
|
-
* signals consumed across `/
|
|
80
|
+
* signals consumed across `/deliver`: whether worktree isolation is on
|
|
81
81
|
* for this process, the session id for claim labels, and whether we're in a
|
|
82
82
|
* Claude Code web session. Each signal also records its **source** so the
|
|
83
83
|
* `story-init` startup log can name why the value is what it is.
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* parent of `git rev-parse --git-common-dir`) rather than `process.cwd()`.
|
|
45
45
|
* Without this, a story child that `cd`s into `.worktrees/story-<id>/` before
|
|
46
46
|
* calling `story-phase.js` would append `story.heartbeat` records to
|
|
47
|
-
* `<worktree>/temp/epic-N/lifecycle.ndjson`, while the `/
|
|
47
|
+
* `<worktree>/temp/epic-N/lifecycle.ndjson`, while the `/deliver` host
|
|
48
48
|
* (running from the main checkout) reads the main-checkout copy — so the
|
|
49
49
|
* idle-watchdog never sees heartbeats and the Epic-lease guard silently
|
|
50
50
|
* reclaims live foreign claims (the audit-#3513 bug class). Anchoring the
|
|
@@ -335,7 +335,7 @@ export const epicPerfReportPath = (eid, config) =>
|
|
|
335
335
|
|
|
336
336
|
/**
|
|
337
337
|
* `temp/epic-<eid>/epic-perf-report.json` — canonical JSON snapshot of
|
|
338
|
-
* the `epic-perf-report` payload persisted at /
|
|
338
|
+
* the `epic-perf-report` payload persisted at /deliver close
|
|
339
339
|
* (Epic #3019 / Story #3029 / Task #3040). When present alongside the
|
|
340
340
|
* `epic-perf-report` structured comment, the report is discoverable
|
|
341
341
|
* from the file system without round-tripping the ticketing provider,
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
|
|
25
25
|
import fs from 'node:fs';
|
|
26
26
|
import path from 'node:path';
|
|
27
|
-
import { fileURLToPath } from 'node:url';
|
|
28
27
|
import { getCiDelivery } from './config/ci.js';
|
|
29
28
|
import { getCommands } from './config/commands.js';
|
|
30
29
|
import { getGitHub } from './config/github.js';
|
|
@@ -34,6 +33,7 @@ import { validateOrchestrationConfig } from './config/validate-orchestration.js'
|
|
|
34
33
|
import { getWorktreeIsolation } from './config/worktree-isolation.js';
|
|
35
34
|
import { getAgentrcValidator } from './config-schema.js';
|
|
36
35
|
import { loadEnv } from './env-loader.js';
|
|
36
|
+
import { PROJECT_ROOT } from './project-root.js';
|
|
37
37
|
|
|
38
38
|
export { getAcceptanceEval } from './config/acceptance-eval.js';
|
|
39
39
|
export { BASELINES_DEFAULTS, getBaselines } from './config/baselines.js';
|
|
@@ -64,10 +64,7 @@ export {
|
|
|
64
64
|
export { resolveListValue } from './config/shared.js';
|
|
65
65
|
export { validateOrchestrationConfig } from './config/validate-orchestration.js';
|
|
66
66
|
export { WORKTREE_ISOLATION_DEFAULTS } from './config/worktree-isolation.js';
|
|
67
|
-
|
|
68
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
69
|
-
// scripts/lib/ → scripts/ → .agents/ → project root
|
|
70
|
-
export const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
67
|
+
export { PROJECT_ROOT } from './project-root.js';
|
|
71
68
|
|
|
72
69
|
// Cache keyed by absolute root path so callers passing different cwds
|
|
73
70
|
// (e.g. per-worktree) each get their own resolved config.
|
|
@@ -203,7 +203,7 @@ const MERGE_WATCH_SCHEMA = {
|
|
|
203
203
|
};
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
|
-
* `delivery.epicAudit` — bounded-retry knobs for /
|
|
206
|
+
* `delivery.epicAudit` — bounded-retry knobs for /deliver Phase 4
|
|
207
207
|
* (epic-audit). `maxFixAttempts` caps how many times the auto-fix loop
|
|
208
208
|
* retries a single finding (Story #2611, Epic #2586). `maxFixScopeFiles`
|
|
209
209
|
* caps how many files a single auto-fix may touch before escalating to
|
|
@@ -237,7 +237,7 @@ const CI_DELIVERY_SCHEMA = {
|
|
|
237
237
|
// Story #2899 (Epic #2880) — `delivery.preflight.*` thresholds consumed
|
|
238
238
|
// by `epic-deliver-preflight.js`. When any value is exceeded the CLI
|
|
239
239
|
// surfaces a breach in its envelope and the workflow flips the Epic to
|
|
240
|
-
// `agent::blocked` (see /
|
|
240
|
+
// `agent::blocked` (see /deliver Phase 1 prelude).
|
|
241
241
|
const PREFLIGHT_SCHEMA = {
|
|
242
242
|
type: 'object',
|
|
243
243
|
properties: {
|
|
@@ -102,7 +102,7 @@ export const QUALITY_SCHEMA = {
|
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
104
|
* `delivery.codeReview` — sibling to `delivery.epicAudit`. Same bounded
|
|
105
|
-
* retry + scope cap, applied to /
|
|
105
|
+
* retry + scope cap, applied to /deliver Phase 5 (code-review).
|
|
106
106
|
*/
|
|
107
107
|
export const CODE_REVIEW_SCHEMA = {
|
|
108
108
|
type: 'object',
|
|
@@ -205,7 +205,7 @@ const GITHUB_SCHEMA = {
|
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
// ---------------------------------------------------------------------------
|
|
208
|
-
// planning.* — inputs to /
|
|
208
|
+
// planning.* — inputs to /plan
|
|
209
209
|
// ---------------------------------------------------------------------------
|
|
210
210
|
|
|
211
211
|
/**
|
|
@@ -224,7 +224,7 @@ const PLANNING_CONTEXT_SCHEMA = {
|
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
226
|
* Story #2634 — `planning.codebaseSnapshot` controls the structural
|
|
227
|
-
* view of the consumer repo threaded into `/
|
|
227
|
+
* view of the consumer repo threaded into `/plan` Phase 7 spec
|
|
228
228
|
* authoring. Absent / partial entries resolve to defaults inside
|
|
229
229
|
* `lib/codebase-snapshot.js#resolveSnapshotConfig` — the schema only
|
|
230
230
|
* enforces shape (correct enum value, well-formed glob arrays).
|
|
@@ -287,7 +287,7 @@ const PLANNING_SCHEMA = {
|
|
|
287
287
|
};
|
|
288
288
|
|
|
289
289
|
// ---------------------------------------------------------------------------
|
|
290
|
-
// delivery.* — /
|
|
290
|
+
// delivery.* — /deliver + story-deliver consume. The full block of
|
|
291
291
|
// per-key sub-schemas lives in `config-settings-schema-delivery.js` (refs
|
|
292
292
|
// #3457); DELIVERY_SCHEMA is imported above and referenced unchanged below.
|
|
293
293
|
// ---------------------------------------------------------------------------
|