mandrel 2.31.0 → 2.33.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 +13 -17
- package/.agents/agents/acceptance-critic.md +1 -2
- package/.agents/docs/SDLC.md +12 -9
- package/.agents/docs/agentrc-reference.json +63 -58
- package/.agents/docs/configuration.md +275 -227
- package/.agents/docs/execution-reference.md +13 -14
- package/.agents/docs/quality-gates.md +195 -23
- package/.agents/instructions.md +2 -5
- package/.agents/rules/git-conventions-reference.md +27 -27
- package/.agents/rules/git-conventions.md +4 -2
- package/.agents/rules/known-tooling-behavior.md +66 -30
- package/.agents/rules/testing-standards.md +35 -71
- package/.agents/runtime-deps.json +2 -2
- package/.agents/schemas/agentrc.schema.json +1955 -1410
- package/.agents/schemas/lifecycle/README.md +21 -14
- package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/scripts/README.md +16 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- package/.agents/scripts/audit-to-stories.js +160 -41
- package/.agents/scripts/bootstrap.js +28 -26
- package/.agents/scripts/check-baseline-drift.js +73 -13
- package/.agents/scripts/check-baseline-scope.js +362 -0
- package/.agents/scripts/check-dead-exports.js +9 -1
- package/.agents/scripts/check-gherkin-corpus.js +508 -0
- package/.agents/scripts/check-knip-entries.js +159 -0
- package/.agents/scripts/check-lifecycle-lint.js +108 -124
- package/.agents/scripts/check-schema-references.js +1 -1
- package/.agents/scripts/diagnose-friction.js +7 -4
- package/.agents/scripts/generate-config-docs.js +263 -171
- package/.agents/scripts/install-matrix-assert.js +0 -1
- package/.agents/scripts/lib/ITicketingProvider.js +0 -58
- package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
- package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +81 -35
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +185 -0
- package/.agents/scripts/lib/baselines/envelope.js +41 -60
- package/.agents/scripts/lib/baselines/git-base.js +30 -37
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
- package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
- package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
- package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
- package/.agents/scripts/lib/bdd-step-index.js +326 -0
- package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
- package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
- package/.agents/scripts/lib/checks/loop-health.js +9 -37
- package/.agents/scripts/lib/child-exec.js +193 -0
- package/.agents/scripts/lib/cli/standard-args.js +1 -1
- package/.agents/scripts/lib/cli-args.js +64 -0
- package/.agents/scripts/lib/close-validation/gates.js +2 -2
- package/.agents/scripts/lib/close-validation/runner.js +3 -3
- package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
- package/.agents/scripts/lib/config/commands.js +3 -5
- package/.agents/scripts/lib/config/explain.js +5 -7
- package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
- package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
- package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
- package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
- package/.agents/scripts/lib/config/gates/index.js +5 -2
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
- package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
- package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
- package/.agents/scripts/lib/config/gates/shared.js +58 -9
- package/.agents/scripts/lib/config/github.js +0 -1
- package/.agents/scripts/lib/config/limits.js +3 -48
- package/.agents/scripts/lib/config/qa.js +105 -0
- package/.agents/scripts/lib/config/runners.js +38 -16
- package/.agents/scripts/lib/config/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +245 -56
- package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
- package/.agents/scripts/lib/config-settings-schema.js +386 -39
- package/.agents/scripts/lib/crap-baseline-join.js +126 -9
- package/.agents/scripts/lib/crap-utils.js +84 -520
- package/.agents/scripts/lib/dead-exports-knip.js +79 -10
- package/.agents/scripts/lib/degraded-mode.js +2 -2
- package/.agents/scripts/lib/dependency-parser.js +20 -7
- package/.agents/scripts/lib/doc-tiers.js +3 -3
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
- package/.agents/scripts/lib/findings/provenance-field.js +135 -0
- package/.agents/scripts/lib/findings/route-finding.js +57 -8
- package/.agents/scripts/lib/fs-walk.js +52 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/git-utils.js +16 -36
- package/.agents/scripts/lib/knip-config-resolver.js +181 -0
- package/.agents/scripts/lib/knip-entry-sync.js +508 -0
- package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
- package/.agents/scripts/lib/observability/signal-validator.js +5 -85
- package/.agents/scripts/lib/observability/signals-writer.js +19 -62
- package/.agents/scripts/lib/observability/source-classifier.js +5 -7
- package/.agents/scripts/lib/observability/terse-result.js +3 -3
- package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
- package/.agents/scripts/lib/orchestration/code-review.js +2 -2
- package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
- package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
- package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +7 -26
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +69 -5
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +69 -13
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +49 -0
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +77 -50
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +59 -25
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
- package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +116 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator.js +38 -0
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
- package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
- package/.agents/scripts/lib/signals/detectors/common.js +1 -1
- package/.agents/scripts/lib/signals/index.js +8 -6
- package/.agents/scripts/lib/signals/schema.js +20 -25
- package/.agents/scripts/lib/signals/write.js +8 -8
- package/.agents/scripts/lib/story-body/footer-block.js +97 -0
- package/.agents/scripts/lib/story-body/story-body.js +18 -81
- package/.agents/scripts/lib/temp-retention.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
- package/.agents/scripts/lib/ticket-body-sections.js +4 -5
- package/.agents/scripts/lib/wave-runner/footprint.js +306 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +198 -181
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
- package/.agents/scripts/lib/worktree-manager.js +2 -3
- package/.agents/scripts/lint-label-vocabulary.js +2 -24
- package/.agents/scripts/pr-watch-with-update.js +7 -5
- package/.agents/scripts/providers/github/blocked-by-add.js +25 -10
- package/.agents/scripts/providers/github/cache.js +2 -2
- package/.agents/scripts/providers/github/comments.js +6 -28
- package/.agents/scripts/providers/github/compose.js +0 -15
- package/.agents/scripts/providers/github/errors.js +10 -27
- package/.agents/scripts/providers/github/request-helpers.js +1 -2
- package/.agents/scripts/providers/github/sub-issues.js +10 -218
- package/.agents/scripts/providers/github.js +4 -7
- package/.agents/scripts/prune-baseline-orphans.js +181 -0
- package/.agents/scripts/resolve-stories.js +21 -7
- package/.agents/scripts/run-lint.js +61 -61
- package/.agents/scripts/run-test-profile.js +6 -6
- package/.agents/scripts/run-verify.js +48 -30
- package/.agents/scripts/single-story-close.js +20 -0
- package/.agents/scripts/single-story-init.js +12 -35
- package/.agents/scripts/stories-wave-tick.js +192 -9
- package/.agents/scripts/update-dead-exports-baseline.js +321 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
- package/.agents/skills/skills.index.json +1 -11
- package/.agents/workflows/audit-documentation.md +5 -6
- package/.agents/workflows/audit-to-stories.md +28 -2
- package/.agents/workflows/helpers/audit-lens-core.md +11 -12
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
- package/.agents/workflows/helpers/code-review.md +3 -8
- package/.agents/workflows/helpers/deliver-reference.md +30 -2
- package/.agents/workflows/helpers/deliver-story-reference.md +84 -16
- package/.agents/workflows/helpers/plan-reference.md +76 -0
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
- package/.agents/workflows/mandrel-update.md +10 -10
- package/.agents/workflows/qa-assist.md +15 -20
- package/.agents/workflows/qa-explore.md +9 -8
- package/README.md +1 -1
- package/docs/CHANGELOG.md +58 -0
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
- package/package.json +14 -5
- package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
- package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
- package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
- package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
- package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
- package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
- package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
- package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
- package/.agents/scripts/check-gherkin-placeholders.js +0 -663
- package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
- package/.agents/scripts/lib/audit-suite/cli.js +0 -64
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
- package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
- package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
- package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
- package/.agents/scripts/lib/crap-baseline-index.js +0 -46
- package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
- package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
- package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
- package/.agents/scripts/lib/mutation/config-detector.js +0 -119
- package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
- package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
- package/.agents/scripts/lib/observability/active-story-env.js +0 -170
- package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
- package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
- package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
- package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
- package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
- package/.agents/scripts/lib/planning-corpus.js +0 -37
- package/.agents/scripts/lib/qa/coverage-report.js +0 -181
- package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
- package/.agents/scripts/lib/signals/detectors/index.js +0 -14
- package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
- package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
- package/.agents/scripts/lib/signals/read.js +0 -268
- package/.agents/scripts/lib/signals/span-tree.js +0 -291
- package/.agents/scripts/lib/story-lifecycle.js +0 -194
- package/.agents/scripts/lib/story-plan.js +0 -379
- package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
- package/.agents/scripts/lib/util/phase-timer.js +0 -163
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
- package/.agents/scripts/lint-baseline.js +0 -507
- package/.agents/scripts/providers/github/prs.js +0 -103
- package/.agents/scripts/signals-view.js +0 -309
- package/.agents/scripts/story-plan.js +0 -370
- package/.agents/scripts/sync-branch-from-base.js +0 -149
- package/.agents/scripts/validate-docs-freshness.js +0 -314
- package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
- package/.agents/workflows/helpers/signals.md +0 -112
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// .agents/scripts/prune-baseline-orphans.js — Story #5012.
|
|
4
|
+
//
|
|
5
|
+
// Delete the baseline rows that are provably inert, and nothing else.
|
|
6
|
+
//
|
|
7
|
+
// This is the cheap remedy that makes `check-baseline-scope.js` fair. A gate
|
|
8
|
+
// that hard-fails on a stale row is only defensible while clearing one costs a
|
|
9
|
+
// command rather than a full re-score: the honest alternative — re-derive the
|
|
10
|
+
// whole baseline — spends a coverage run or a full-tree MI pass to express a
|
|
11
|
+
// deletion, which is why stale rows accumulate instead.
|
|
12
|
+
//
|
|
13
|
+
// Two row classes qualify, both decidable without measuring anything:
|
|
14
|
+
//
|
|
15
|
+
// - `absent` — the row's file is gone from disk.
|
|
16
|
+
// - `out-of-scope` — the file is still there, but the gate's own
|
|
17
|
+
// `targetDirs` / `ignoreGlobs` no longer match it.
|
|
18
|
+
//
|
|
19
|
+
// The pruner never adds a row, never restamps `generatedAt` (a fresh stamp
|
|
20
|
+
// over unmeasured rows is the exact failure an age check exists to catch), and
|
|
21
|
+
// recomputes `rollup` through the kind's own arithmetic so the pruned envelope
|
|
22
|
+
// still validates against its schema. An unreadable scope config degrades to
|
|
23
|
+
// orphan-only pruning rather than treating unknown scope as empty scope.
|
|
24
|
+
//
|
|
25
|
+
// Exit codes:
|
|
26
|
+
// 0 nothing to prune (or, without `--check`, the prune was written)
|
|
27
|
+
// 1 `--check` found rows that would be pruned
|
|
28
|
+
// 2 the pruner could not run
|
|
29
|
+
|
|
30
|
+
// Fail-fast if the framework's runtime deps are not installed — must be the
|
|
31
|
+
// first import so the check runs before any third-party-importing sibling
|
|
32
|
+
// module is evaluated (Story #3432).
|
|
33
|
+
import './lib/runtime-deps/ensure-installed.js';
|
|
34
|
+
import { PRUNABLE_KINDS, runPrune } from './lib/baselines/orphan-pruner.js';
|
|
35
|
+
import { runAsCli } from './lib/cli-utils.js';
|
|
36
|
+
import { getQuality } from './lib/config/quality.js';
|
|
37
|
+
import { resolveConfig } from './lib/config-resolver.js';
|
|
38
|
+
|
|
39
|
+
const EXIT_CLEAN = 0;
|
|
40
|
+
const EXIT_WOULD_PRUNE = 1;
|
|
41
|
+
const EXIT_CANNOT_RUN = 2;
|
|
42
|
+
|
|
43
|
+
const HELP = {
|
|
44
|
+
invocation:
|
|
45
|
+
'node .agents/scripts/prune-baseline-orphans.js [--check] [--kind <kind>] [--json]',
|
|
46
|
+
summary:
|
|
47
|
+
"Remove baseline rows whose file is gone from disk or has left the gate's scope. Never adds a row, never restamps generatedAt, never re-scores.",
|
|
48
|
+
flags: [
|
|
49
|
+
['--check', 'Report what would be pruned, write nothing, exit 1 if any.'],
|
|
50
|
+
['--kind <kind>', 'Prune one kind only (repeatable). Default: all.'],
|
|
51
|
+
['--json', 'Emit the report as JSON instead of text.'],
|
|
52
|
+
['--cwd <dir>', 'Repository root to prune. Default: process.cwd().'],
|
|
53
|
+
],
|
|
54
|
+
notes: [
|
|
55
|
+
'Exit codes:\n 0 clean, or pruned\n 1 --check found prunable rows\n 2 the pruner could not run',
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse argv into an options bag. An unknown flag is an error, never a silent
|
|
61
|
+
* no-op — a typo'd `--dry-run` must not read as "write the files".
|
|
62
|
+
*
|
|
63
|
+
* @param {string[]} argv
|
|
64
|
+
* @returns {{ kinds: string[], check: boolean, json: boolean, cwd: string }}
|
|
65
|
+
*/
|
|
66
|
+
export function parseArgs(argv = []) {
|
|
67
|
+
const out = { kinds: [], check: false, json: false, cwd: null };
|
|
68
|
+
let i = 0;
|
|
69
|
+
while (i < argv.length) {
|
|
70
|
+
const arg = argv[i];
|
|
71
|
+
const value = argv[i + 1];
|
|
72
|
+
i += 1;
|
|
73
|
+
if (arg === '--check') out.check = true;
|
|
74
|
+
else if (arg === '--json') out.json = true;
|
|
75
|
+
else if (arg === '--kind') {
|
|
76
|
+
out.kinds.push(value);
|
|
77
|
+
i += 1;
|
|
78
|
+
} else if (arg === '--cwd') {
|
|
79
|
+
out.cwd = value;
|
|
80
|
+
i += 1;
|
|
81
|
+
} else throw new Error(`unknown flag "${arg}" (try --help)`);
|
|
82
|
+
}
|
|
83
|
+
const unknown = out.kinds.filter((k) => !PRUNABLE_KINDS.includes(k));
|
|
84
|
+
if (unknown.length > 0) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`unknown --kind ${unknown.join(', ')}; expected one of ${PRUNABLE_KINDS.join(', ')}`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (out.kinds.length === 0) out.kinds = [...PRUNABLE_KINDS];
|
|
90
|
+
out.cwd = out.cwd ?? process.cwd();
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Render one kind's outcome as indented text lines.
|
|
96
|
+
*
|
|
97
|
+
* @param {object} entry
|
|
98
|
+
* @param {boolean} check
|
|
99
|
+
* @returns {string[]}
|
|
100
|
+
*/
|
|
101
|
+
function renderKind(entry, check) {
|
|
102
|
+
if (!entry.present) return [];
|
|
103
|
+
if (entry.skipped)
|
|
104
|
+
return [` - ${entry.kind}: skipped (${entry.skipReason})`];
|
|
105
|
+
const suffix = entry.degraded
|
|
106
|
+
? ` [orphan-only: ${entry.degradedReason}]`
|
|
107
|
+
: '';
|
|
108
|
+
if (entry.removed.length === 0) {
|
|
109
|
+
return [` - ${entry.kind}: clean${suffix}`];
|
|
110
|
+
}
|
|
111
|
+
const verb = check ? 'would prune' : 'pruned';
|
|
112
|
+
return [
|
|
113
|
+
` - ${entry.kind}: ${verb} ${entry.removed.length} row(s)${suffix}`,
|
|
114
|
+
...entry.removed.map((row) => ` · ${row.reason}: ${row.path}`),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Render the whole report as text.
|
|
120
|
+
*
|
|
121
|
+
* @param {object} report
|
|
122
|
+
* @returns {string}
|
|
123
|
+
*/
|
|
124
|
+
export function formatReport(report) {
|
|
125
|
+
const verb = report.check ? 'would prune' : 'pruned';
|
|
126
|
+
const lines = [
|
|
127
|
+
`[prune-baseline-orphans] ${verb} ${report.removedCount} row(s) across ` +
|
|
128
|
+
`${report.writtenCount} file(s)`,
|
|
129
|
+
...report.kinds.flatMap((entry) => renderKind(entry, report.check)),
|
|
130
|
+
];
|
|
131
|
+
if (report.check && report.removedCount > 0) {
|
|
132
|
+
lines.push(
|
|
133
|
+
'',
|
|
134
|
+
'Run without --check to write the prune:',
|
|
135
|
+
' node .agents/scripts/prune-baseline-orphans.js',
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return lines.join('\n');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* CLI entry point. Returns its exit code rather than calling `process.exit()`,
|
|
143
|
+
* so `runAsCli`'s `propagateExitCode` path settles it through `flushStdio` and
|
|
144
|
+
* an unbounded report is not truncated at a pipe boundary (Story #4783).
|
|
145
|
+
*
|
|
146
|
+
* @returns {Promise<number>}
|
|
147
|
+
*/
|
|
148
|
+
async function main() {
|
|
149
|
+
let opts;
|
|
150
|
+
let report;
|
|
151
|
+
try {
|
|
152
|
+
opts = parseArgs(process.argv.slice(2));
|
|
153
|
+
const config = resolveConfig({ cwd: opts.cwd });
|
|
154
|
+
report = runPrune({
|
|
155
|
+
cwd: opts.cwd,
|
|
156
|
+
kinds: opts.kinds,
|
|
157
|
+
check: opts.check,
|
|
158
|
+
quality: getQuality(config) ?? { gates: {} },
|
|
159
|
+
});
|
|
160
|
+
} catch (err) {
|
|
161
|
+
const message = err?.message ?? String(err);
|
|
162
|
+
process.stdout.write(
|
|
163
|
+
`${JSON.stringify({ schemaVersion: '1', error: message }, null, 2)}\n`,
|
|
164
|
+
);
|
|
165
|
+
return EXIT_CANNOT_RUN;
|
|
166
|
+
}
|
|
167
|
+
process.stdout.write(
|
|
168
|
+
opts.json
|
|
169
|
+
? `${JSON.stringify(report, null, 2)}\n`
|
|
170
|
+
: `${formatReport(report)}\n`,
|
|
171
|
+
);
|
|
172
|
+
return report.check && report.removedCount > 0
|
|
173
|
+
? EXIT_WOULD_PRUNE
|
|
174
|
+
: EXIT_CLEAN;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
runAsCli(import.meta.url, main, {
|
|
178
|
+
source: 'prune-baseline-orphans',
|
|
179
|
+
usage: HELP,
|
|
180
|
+
propagateExitCode: true,
|
|
181
|
+
});
|
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
* What it resolves, per Story:
|
|
12
12
|
* - the issue itself, fetched with **state=all** so an already-landed
|
|
13
13
|
* sibling is present rather than silently dropped;
|
|
14
|
-
* - its dependency edges: the union of body
|
|
15
|
-
* `
|
|
14
|
+
* - its dependency edges: the union of the body's `---` footer
|
|
15
|
+
* (`blocked by #N`, footer-scoped and strict — prose mentioning a blocker
|
|
16
|
+
* elsewhere in the body declares nothing) and native GitHub `blocked_by`
|
|
17
|
+
* edges, read to exhaustion and failing loud rather than degrading to
|
|
18
|
+
* "no edges";
|
|
16
19
|
* - its declared file footprint, as plain path strings, so the scheduler's
|
|
17
20
|
* co-dispatch overlap guard has something to work with.
|
|
18
21
|
*
|
|
@@ -45,7 +48,7 @@ import {
|
|
|
45
48
|
} from './lib/orchestration/resolve-stories.js';
|
|
46
49
|
import { createProvider } from './lib/provider-factory.js';
|
|
47
50
|
import { concurrentMap } from './lib/util/concurrent-map.js';
|
|
48
|
-
import {
|
|
51
|
+
import { paginateRest } from './providers/github/request-helpers.js';
|
|
49
52
|
|
|
50
53
|
export { buildStoriesEnvelope, parseIds, readNativeBlockedBy, toStoryRecord };
|
|
51
54
|
|
|
@@ -111,9 +114,21 @@ export async function fetchStories(provider, ids) {
|
|
|
111
114
|
/**
|
|
112
115
|
* Read native blocked_by edges for every Story in the set.
|
|
113
116
|
*
|
|
117
|
+
* `paginate` is injected rather than imported inside the lib layer so
|
|
118
|
+
* `readNativeBlockedBy` stays provider-agnostic and unit-testable; production
|
|
119
|
+
* passes `paginateRest`, which walks every page (the read used to stop at the
|
|
120
|
+
* first, silently truncating a Story's gates — Story #5046).
|
|
121
|
+
*
|
|
114
122
|
* @returns {Promise<Map<number, number[]>>}
|
|
115
123
|
*/
|
|
116
|
-
export async function readNativeEdges({
|
|
124
|
+
export async function readNativeEdges({
|
|
125
|
+
provider,
|
|
126
|
+
stories,
|
|
127
|
+
owner,
|
|
128
|
+
repo,
|
|
129
|
+
paginate = paginateRest,
|
|
130
|
+
warn = (m) => Logger.warn(m),
|
|
131
|
+
}) {
|
|
117
132
|
const entries = await concurrentMap(
|
|
118
133
|
stories,
|
|
119
134
|
async (story) => [
|
|
@@ -123,7 +138,8 @@ export async function readNativeEdges({ provider, stories, owner, repo }) {
|
|
|
123
138
|
owner,
|
|
124
139
|
repo,
|
|
125
140
|
issueNumber: story.id,
|
|
126
|
-
|
|
141
|
+
paginate,
|
|
142
|
+
warn,
|
|
127
143
|
}),
|
|
128
144
|
],
|
|
129
145
|
{ concurrency: FETCH_CONCURRENCY },
|
|
@@ -197,7 +213,6 @@ export async function runResolveStories(
|
|
|
197
213
|
stories,
|
|
198
214
|
nativeEdges,
|
|
199
215
|
warn: (m) => Logger.warn(m),
|
|
200
|
-
config,
|
|
201
216
|
});
|
|
202
217
|
const foreignDone = await resolveForeignDone({
|
|
203
218
|
provider,
|
|
@@ -209,7 +224,6 @@ export async function runResolveStories(
|
|
|
209
224
|
nativeEdges,
|
|
210
225
|
foreignDone,
|
|
211
226
|
warn: () => {},
|
|
212
|
-
config,
|
|
213
227
|
});
|
|
214
228
|
|
|
215
229
|
stdout.write(
|
|
@@ -21,6 +21,32 @@ import process from 'node:process';
|
|
|
21
21
|
// can spawn directly.
|
|
22
22
|
const useShell = process.platform === 'win32';
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* A Node gate spelled `node .agents/scripts/<script>` — the shape six of the
|
|
26
|
+
* eight tasks share. Spelling it once keeps this list readable as what it
|
|
27
|
+
* actually is (a fan-out roster) instead of a wall of spawn tuples, and keeps
|
|
28
|
+
* adding a gate from costing the module a maintainability regression for the
|
|
29
|
+
* boilerplate rather than the behaviour. Mirrors `run-verify.js`'s `gate()`.
|
|
30
|
+
*
|
|
31
|
+
* Use bare `node` (PATH-resolved) rather than `process.execPath`:
|
|
32
|
+
* `process.execPath` on Windows often expands to `C:\Program
|
|
33
|
+
* Files\nodejs\node.exe`, and spawn(..., { shell: true }) does not quote the
|
|
34
|
+
* executable, so the space breaks invocation.
|
|
35
|
+
*
|
|
36
|
+
* The path is passed WHOLE rather than assembled from a basename. Composing
|
|
37
|
+
* it (`` `.agents/scripts/${script}` ``) reads better and is wrong:
|
|
38
|
+
* `check-knip-entries.js` derives which CLIs something actually invokes by
|
|
39
|
+
* scanning this file's source text for literal script paths, and four of the
|
|
40
|
+
* gates below are invoked from nowhere else. Interpolating the path made them
|
|
41
|
+
* invisible to that derivation, so knip called them dead and the ratchet
|
|
42
|
+
* offered to record live gates as expected-dead — the Story #5012 trap.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} name reported in this driver's own error prefix
|
|
45
|
+
* @param {string} script repo-relative path, spelled as one literal
|
|
46
|
+
* @returns {{ name: string, cmd: string, args: string[] }}
|
|
47
|
+
*/
|
|
48
|
+
const nodeGate = (name, script) => ({ name, cmd: 'node', args: [script] });
|
|
49
|
+
|
|
24
50
|
const tasks = [
|
|
25
51
|
{
|
|
26
52
|
name: 'biome',
|
|
@@ -47,67 +73,41 @@ const tasks = [
|
|
|
47
73
|
'!.worktrees/**',
|
|
48
74
|
],
|
|
49
75
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// let the original `type/epic` typo land in a since-retired
|
|
86
|
-
// planning workflow helper.
|
|
87
|
-
name: 'label-vocabulary',
|
|
88
|
-
cmd: 'node',
|
|
89
|
-
args: ['.agents/scripts/lint-label-vocabulary.js'],
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
// GitHub Actions job-timeout gate (Story #4936). Enumerates every
|
|
93
|
-
// `jobs.<id>` key across `.github/workflows/*.yml` and fails when one
|
|
94
|
-
// sets no `timeout-minutes` (inheriting GitHub's 360-minute default) or
|
|
95
|
-
// sets one above the ceiling. A deadlocked Windows job burned 44 minutes
|
|
96
|
-
// of a runner and withheld the failing required check's logs for the
|
|
97
|
-
// whole time; nothing but this check would have caught the gap.
|
|
98
|
-
name: 'workflow-timeouts',
|
|
99
|
-
cmd: 'node',
|
|
100
|
-
args: ['.agents/scripts/check-workflow-timeouts.js'],
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
// Architecture cycle ratchet (Story #3991). Detects directed import
|
|
104
|
-
// cycles under `.agents/scripts/` and fails on any cycle not in the
|
|
105
|
-
// committed allowlist (`baselines/arch-cycles.json`). Mirrors the
|
|
106
|
-
// ratchet-down semantics of `check-dead-exports.js`.
|
|
107
|
-
name: 'arch-cycles',
|
|
108
|
-
cmd: 'node',
|
|
109
|
-
args: ['.agents/scripts/check-arch-cycles.js'],
|
|
110
|
-
},
|
|
76
|
+
// Lifecycle surface (Story #2227). Enforces (1) no `Promise.all` under
|
|
77
|
+
// `.agents/scripts/lib/orchestration/lifecycle/**` — the ledger is
|
|
78
|
+
// append-only and a parallel write interleaves records; and (2) the
|
|
79
|
+
// auto-merge lockout: the `gh pr merge` literal appears only in
|
|
80
|
+
// `single-story-close/phases/auto-merge.js`. Neither has a biome
|
|
81
|
+
// equivalent. Story #5024 dropped the third rule (the wildcard-observer
|
|
82
|
+
// firewall) with the bus and the `listeners/` directory its predicate
|
|
83
|
+
// required.
|
|
84
|
+
nodeGate('lifecycle-lint', '.agents/scripts/check-lifecycle-lint.js'),
|
|
85
|
+
// Workflow prose surface (Epic #4474 PR5). No workflow may instruct calling
|
|
86
|
+
// an exported library function that has no CLI entrypoint — the measured
|
|
87
|
+
// shim-writing failure mode the /plan collapse killed. See
|
|
88
|
+
// check-workflow-cli-lint.js for the paragraph-level heuristic.
|
|
89
|
+
nodeGate('workflow-cli-lint', '.agents/scripts/check-workflow-cli-lint.js'),
|
|
90
|
+
// Label-vocabulary citations in `.agents/docs/SDLC.md` and
|
|
91
|
+
// `.agents/workflows/**/*.md` (Story #2892). Greps inline backtick code
|
|
92
|
+
// spans for axis-shaped tokens (`type/epic`, etc.) and asserts only the
|
|
93
|
+
// canonical `<axis>::<value>` separator from `lib/label-constants.js`
|
|
94
|
+
// appears. Closes the drift gap that let the original `type/epic` typo land.
|
|
95
|
+
nodeGate('label-vocabulary', '.agents/scripts/lint-label-vocabulary.js'),
|
|
96
|
+
// GitHub Actions job-timeout gate (Story #4936). Fails a `jobs.<id>` that
|
|
97
|
+
// sets no `timeout-minutes` (inheriting GitHub's 360-minute default) or sets
|
|
98
|
+
// one above the ceiling. A deadlocked Windows job burned 44 minutes of a
|
|
99
|
+
// runner and withheld the failing required check's logs for the whole time.
|
|
100
|
+
nodeGate('workflow-timeouts', '.agents/scripts/check-workflow-timeouts.js'),
|
|
101
|
+
// Architecture cycle ratchet (Story #3991). Detects directed import cycles
|
|
102
|
+
// under `.agents/scripts/` and fails on any cycle not in the committed
|
|
103
|
+
// allowlist (`baselines/arch-cycles.json`).
|
|
104
|
+
nodeGate('arch-cycles', '.agents/scripts/check-arch-cycles.js'),
|
|
105
|
+
// Static Gherkin corpus gate (Story #5013): must-compile with the real
|
|
106
|
+
// parser, then must-bind scoped per step root. Opt-in behind
|
|
107
|
+
// `qa.gherkinLint`, so it exits 0 as "not configured" in this repo. Here
|
|
108
|
+
// rather than in run-verify.js so it reaches CI through the same `lint`
|
|
109
|
+
// required check as arch-cycles; listing it in both would double-pay it.
|
|
110
|
+
nodeGate('gherkin-corpus', '.agents/scripts/check-gherkin-corpus.js'),
|
|
111
111
|
];
|
|
112
112
|
|
|
113
113
|
function runTask({ name, cmd, args }) {
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* runner only — set SKIP_PREFLIGHT=0 to include preflight if desired.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { spawnSync } from 'node:child_process';
|
|
12
11
|
import fs from 'node:fs';
|
|
13
12
|
import path from 'node:path';
|
|
14
13
|
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { spawnChild } from './lib/child-exec.js';
|
|
15
15
|
import { runAsCli } from './lib/cli-utils.js';
|
|
16
16
|
import { buildWebhookSafeTestEnv } from './lib/test-env.js';
|
|
17
17
|
import { parseTapOutput } from './lib/test-profile/parse-tap.js';
|
|
@@ -56,13 +56,14 @@ export function parseProfileArgv(argv) {
|
|
|
56
56
|
* @param {object} [opts]
|
|
57
57
|
* @param {string[]} [opts.argv]
|
|
58
58
|
* @param {string} [opts.cwd]
|
|
59
|
-
* @param {
|
|
59
|
+
* @param {Function} [opts.spawn] - Injected child runner; defaults to the
|
|
60
|
+
* shared surface's real `spawnSync`.
|
|
60
61
|
* @param {typeof fs} [opts.fs]
|
|
61
62
|
*/
|
|
62
63
|
export function runTestProfile({
|
|
63
64
|
argv = process.argv.slice(2),
|
|
64
65
|
cwd = ROOT,
|
|
65
|
-
spawn
|
|
66
|
+
spawn,
|
|
66
67
|
fs: fsLike = fs,
|
|
67
68
|
} = {}) {
|
|
68
69
|
const { outDir, topN, testArgv } = parseProfileArgv(argv);
|
|
@@ -75,7 +76,8 @@ export function runTestProfile({
|
|
|
75
76
|
];
|
|
76
77
|
|
|
77
78
|
const started = Date.now();
|
|
78
|
-
const result =
|
|
79
|
+
const result = spawnChild(process.execPath, nodeArgs, {
|
|
80
|
+
run: spawn,
|
|
79
81
|
cwd,
|
|
80
82
|
encoding: 'utf8',
|
|
81
83
|
env: {
|
|
@@ -84,8 +86,6 @@ export function runTestProfile({
|
|
|
84
86
|
FORCE_COLOR: '0',
|
|
85
87
|
NO_COLOR: '1',
|
|
86
88
|
},
|
|
87
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
88
|
-
shell: false,
|
|
89
89
|
});
|
|
90
90
|
const wallDurationMs = Date.now() - started;
|
|
91
91
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* locally, without epic-scoped MI projection or push semantics.
|
|
7
7
|
*
|
|
8
8
|
* Order: audit (SCA) → lint (includes docs:check + the arch-cycles ratchet) →
|
|
9
|
-
* full test suite → unified baselines → the
|
|
10
|
-
*
|
|
9
|
+
* full test suite → unified baselines → the standalone ratchets
|
|
10
|
+
* (dead-exports ×2, context-budget, cyclomatic, schema-references).
|
|
11
11
|
*
|
|
12
12
|
* The `audit` step runs `npm audit --audit-level=high`, matching CI's
|
|
13
13
|
* "Dependency Vulnerability Audit (SCA)" gate so a local green no longer hides
|
|
@@ -27,42 +27,60 @@
|
|
|
27
27
|
* full-tree scan in check-dead-exports.js) to a command that already carries
|
|
28
28
|
* the full test suite.
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Story #5004 closed the last two mirror gaps that were pure omission.
|
|
31
|
+
* `check-cyclomatic.js` (#4923) and `check-schema-references.js` (#4938) were
|
|
32
|
+
* each added to the `baselines` job's standalone-ratchet slot without ever
|
|
33
|
+
* being added here, so a green `verify` still hid both. Like their neighbours
|
|
34
|
+
* they are pure-Node and cost milliseconds.
|
|
35
|
+
*
|
|
36
|
+
* Still NOT mirrored: `check-workflow-citations.js` and
|
|
37
|
+
* `check-baseline-scope.js` run in CI's `baselines` job only —
|
|
38
|
+
* `.agents/rules/known-tooling-behavior.md` entry 2 carries the current
|
|
39
|
+
* coverage table. (`prune-baseline-orphans.js --check` used to sit in that
|
|
40
|
+
* list; it no longer runs in CI at all — the un-attributed duplicate of the
|
|
41
|
+
* scope gate's `extra` direction reds every open PR on inherited rows.) Nor are the CI gates this command structurally cannot
|
|
42
|
+
* reproduce (action pinning, TruffleHog secret scan) — those are catalogued
|
|
43
|
+
* in docs/ci-contract.md. The nightly full-scope re-score
|
|
44
|
+
* (.github/workflows/baseline-drift.yml) is deliberately outside this
|
|
45
|
+
* mirror too: it re-scores the whole tree, which is the cost `verify` exists
|
|
46
|
+
* to avoid paying on every run.
|
|
33
47
|
*/
|
|
34
48
|
|
|
35
49
|
import { spawnSync } from 'node:child_process';
|
|
36
50
|
import { runAsCli } from './lib/cli-utils.js';
|
|
37
51
|
|
|
52
|
+
/**
|
|
53
|
+
* A gate step: `node .agents/scripts/<script>` plus any extra args. Seven of
|
|
54
|
+
* the ten steps share exactly that shape, so spelling it once leaves the list
|
|
55
|
+
* below readable as what it actually is — a gate *order* — instead of a wall
|
|
56
|
+
* of spawn tuples.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} label reported as `failedStep` when the gate exits non-zero
|
|
59
|
+
* @param {string} script basename under `.agents/scripts/`
|
|
60
|
+
* @param {...string} args extra CLI args
|
|
61
|
+
* @returns {{ label: string, cmd: string, args: string[] }}
|
|
62
|
+
*/
|
|
63
|
+
const gate = (label, script, ...args) => ({
|
|
64
|
+
label,
|
|
65
|
+
cmd: 'node',
|
|
66
|
+
args: [`.agents/scripts/${script}`, ...args],
|
|
67
|
+
});
|
|
68
|
+
|
|
38
69
|
const STEPS = [
|
|
39
|
-
{
|
|
40
|
-
label: 'audit',
|
|
41
|
-
cmd: 'npm',
|
|
42
|
-
args: ['audit', '--audit-level=high'],
|
|
43
|
-
},
|
|
70
|
+
{ label: 'audit', cmd: 'npm', args: ['audit', '--audit-level=high'] },
|
|
44
71
|
{ label: 'lint', cmd: 'npm', args: ['run', 'lint'] },
|
|
45
72
|
{ label: 'test', cmd: 'npm', args: ['test'] },
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
label: 'dead-exports-production',
|
|
58
|
-
cmd: 'node',
|
|
59
|
-
args: ['.agents/scripts/check-dead-exports.js', '--production'],
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
label: 'context-budget',
|
|
63
|
-
cmd: 'node',
|
|
64
|
-
args: ['.agents/scripts/check-context-budget.js'],
|
|
65
|
-
},
|
|
73
|
+
gate('baselines', 'check-baselines.js'),
|
|
74
|
+
// Ordered ahead of the dead-exports pair deliberately. When a new CLI is
|
|
75
|
+
// missing from knip.json's entry list, both gates fail — but only this one
|
|
76
|
+
// names the cause. Seeing the ratchet's whole-file diff first is what made
|
|
77
|
+
// "accept the diff" look like the fix during Story #5012.
|
|
78
|
+
gate('knip-entries', 'check-knip-entries.js'),
|
|
79
|
+
gate('dead-exports', 'check-dead-exports.js'),
|
|
80
|
+
gate('dead-exports-production', 'check-dead-exports.js', '--production'),
|
|
81
|
+
gate('context-budget', 'check-context-budget.js'),
|
|
82
|
+
gate('cyclomatic', 'check-cyclomatic.js'),
|
|
83
|
+
gate('schema-references', 'check-schema-references.js'),
|
|
66
84
|
];
|
|
67
85
|
|
|
68
86
|
export function runVerifySteps({
|
|
@@ -44,6 +44,18 @@
|
|
|
44
44
|
* [--no-auto-merge]
|
|
45
45
|
* [--wait-merge | --no-wait-merge]
|
|
46
46
|
* [--merge-watch-mode <sync|async>]
|
|
47
|
+
* [--override-review-block <reason>]
|
|
48
|
+
*
|
|
49
|
+
* `--override-review-block <reason>` is the one sanctioned way
|
|
50
|
+
* past a code-review CRITICAL blocker. A critical finding halts this script
|
|
51
|
+
* before auto-merge, and until this flag existed there was no override at all —
|
|
52
|
+
* so an operator who had read a finding and judged it wrong could only land by
|
|
53
|
+
* running `gh pr merge` themselves, bypassing the gate with nothing written
|
|
54
|
+
* down. The flag does not weaken the gate; it moves that escape hatch into a
|
|
55
|
+
* mandatory-reason audit trail (Story comment + PR comment + a
|
|
56
|
+
* `review-block-overridden` friction signal) and reports
|
|
57
|
+
* `gates.codeReview: "overridden"` on the terminal envelope. A bare or
|
|
58
|
+
* too-short reason fails during option parsing, before any phase runs.
|
|
47
59
|
*
|
|
48
60
|
* `--merge-watch-mode` (Story #4949) overrides `delivery.mergeWatch.mode` for
|
|
49
61
|
* one invocation, on the same explicit-wins-over-config precedence
|
|
@@ -217,6 +229,14 @@ runAsCli(import.meta.url, main, {
|
|
|
217
229
|
'--merge-watch-mode <sync|async>',
|
|
218
230
|
'Override delivery.mergeWatch.mode for this invocation only. `async` caps the merge wait to a short probe window and returns the resumable `pending` terminal instead of holding the foreground slot — pass it on every close of a multi-Story run. An invalid value exits non-zero before any phase runs.',
|
|
219
231
|
],
|
|
232
|
+
[
|
|
233
|
+
'--override-review-block <reason>',
|
|
234
|
+
// Deliberately does not spell the merge CLI invocation: the
|
|
235
|
+
// merge-lockout rule in `check-lifecycle-lint.js` forbids that literal
|
|
236
|
+
// in any string outside `phases/auto-merge.js`, and it is right to —
|
|
237
|
+
// the point of this flag is that arming stays on the one code path.
|
|
238
|
+
'Land despite a Story-scope code-review CRITICAL blocker you have reviewed and judged wrong. The reason is mandatory (≥12 chars) and is recorded on the Story, on the PR, and as a `review-block-overridden` friction signal; the terminal envelope reports `gates.codeReview: "overridden"`. Use this instead of merging the PR by hand with the GitHub CLI — a hand-merge bypasses the gate with no record at all.',
|
|
239
|
+
],
|
|
220
240
|
['--no-evidence', 'Do not reuse or write gate evidence stamps.'],
|
|
221
241
|
['--dry-run', 'Report the plan; mutate nothing.'],
|
|
222
242
|
],
|