mandrel 2.31.0 → 2.32.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 +4 -4
- package/.agents/docs/agentrc-reference.json +61 -57
- package/.agents/docs/configuration.md +274 -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 +0 -1
- package/.agents/schemas/agentrc.schema.json +1939 -1400
- 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 +7 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- 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 +136 -0
- package/.agents/scripts/check-lifecycle-lint.js +36 -112
- 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 +0 -1
- 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/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +237 -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/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/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-entry-sync.js +469 -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 +6 -0
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +0 -1
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +5 -15
- 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-sizing.js +1 -1
- 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/story-body.js +12 -59
- 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/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/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 +0 -2
- 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/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 +2 -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 +2 -1
- package/.agents/workflows/helpers/deliver-story-reference.md +27 -16
- 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 +42 -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 +12 -3
- 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
|
@@ -72,8 +72,6 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
72
72
|
'Root for gitignored scratch output (per-run state, mirrors, logs).',
|
|
73
73
|
'project.docsContextFiles':
|
|
74
74
|
'Authoritative files an agent must read before starting any task.',
|
|
75
|
-
'project.commands.lintBaseline':
|
|
76
|
-
'Lint command the close-validation chain runs.',
|
|
77
75
|
'project.commands.test': 'Test command the close-validation chain runs.',
|
|
78
76
|
'project.commands.typecheck':
|
|
79
77
|
'Typecheck command (null disables the typecheck gate).',
|
|
@@ -136,8 +134,6 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
136
134
|
// delivery.*
|
|
137
135
|
'delivery.execution.timeoutMs':
|
|
138
136
|
'Per-execution timeout for orchestrated delivery steps.',
|
|
139
|
-
'delivery.lease.ttlMs':
|
|
140
|
-
'Time-to-live for the delivery lease before a stale claim is reclaimable.',
|
|
141
137
|
'delivery.ci.watch.pollIntervalMs':
|
|
142
138
|
'Poll cadence (ms) for the merge/CI watch loop.',
|
|
143
139
|
'delivery.ci.watch.maxPolls':
|
|
@@ -147,7 +143,7 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
147
143
|
'delivery.ci.autoMerge':
|
|
148
144
|
'Merge posture: trust-ci merges on green checks; strict also requires a clean review gate.',
|
|
149
145
|
'delivery.docsFreshness.paths':
|
|
150
|
-
'Docs
|
|
146
|
+
'Docs the audit-documentation lens folds into its target set.',
|
|
151
147
|
'delivery.deliverRunner.concurrencyCap':
|
|
152
148
|
'Maximum Stories dispatched in parallel within one wave. Default 3 — conservative by design to keep host-quota consumption predictable. Operators running wide waves with adequate parallel-agent quota should raise this to reduce wall-clock time proportionally.',
|
|
153
149
|
'delivery.worktreeIsolation.enabled':
|
|
@@ -202,8 +198,6 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
202
198
|
'Whether a dedicated refactor stage runs during delivery.',
|
|
203
199
|
'delivery.acceptanceEval.maxRounds':
|
|
204
200
|
'Redraft rounds the per-Story acceptance self-eval loop runs before escalating to agent::blocked (default 2; clamped to a hard ceiling that cannot be disabled).',
|
|
205
|
-
'delivery.acceptanceEval.clusterCeiling':
|
|
206
|
-
'Max acceptance criteria one single-delivery acceptance critic scores per fresh-context pass; the Story ACs are split into ceil(totalACs / clusterCeiling) maker-blind critic clusters (default 4; clamped to [1, 8]).',
|
|
207
201
|
|
|
208
202
|
// qa.*
|
|
209
203
|
'qa.featureRoot': 'Root directory holding the QA harness .feature files.',
|
|
@@ -257,6 +251,10 @@ const PREFIX_MEANINGS = Object.freeze([
|
|
|
257
251
|
'QA harness deployment target (baseUrl, per-environment sign-in seam, allowWrites gate).',
|
|
258
252
|
],
|
|
259
253
|
['qa.personas', 'QA harness persona / credential mapping.'],
|
|
254
|
+
[
|
|
255
|
+
'qa.gherkinLint',
|
|
256
|
+
'Static Gherkin corpus gate: per-scope feature/step roots plus the exemption-tag and step-waiver escapes.',
|
|
257
|
+
],
|
|
260
258
|
]);
|
|
261
259
|
|
|
262
260
|
/**
|
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { gateBase } from './shared.js';
|
|
4
4
|
|
|
5
5
|
const BUNDLE_DECLARATION = {
|
|
6
6
|
type: 'object',
|
|
7
|
+
description: 'One built artifact the bundle-size gate weighs.',
|
|
7
8
|
required: ['name', 'path', 'limit'],
|
|
8
9
|
properties: {
|
|
9
|
-
name: {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
name: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
minLength: 1,
|
|
13
|
+
description: 'Label the rollup row is keyed by.',
|
|
14
|
+
},
|
|
15
|
+
path: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
minLength: 1,
|
|
18
|
+
description: 'Glob or path of the built artifact to measure.',
|
|
19
|
+
},
|
|
20
|
+
limit: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
minLength: 1,
|
|
23
|
+
description: 'Human size ceiling (e.g. `"180 kB"`).',
|
|
24
|
+
},
|
|
12
25
|
},
|
|
13
26
|
additionalProperties: false,
|
|
14
27
|
};
|
|
15
28
|
|
|
16
29
|
export const BUNDLE_SIZE_GATE = {
|
|
17
30
|
type: 'object',
|
|
31
|
+
description:
|
|
32
|
+
'Built-artifact size ratchet for web targets. Off by default — it needs declared bundles.',
|
|
18
33
|
properties: {
|
|
19
|
-
...
|
|
20
|
-
|
|
34
|
+
...gateBase({
|
|
35
|
+
enabled: false,
|
|
36
|
+
baselinePath: 'baselines/bundle-size.json',
|
|
37
|
+
tolerance: { kind: 'percent', value: 0 },
|
|
38
|
+
floors: { '*': {} },
|
|
39
|
+
}),
|
|
40
|
+
bundles: {
|
|
41
|
+
type: 'array',
|
|
42
|
+
items: BUNDLE_DECLARATION,
|
|
43
|
+
description:
|
|
44
|
+
'The artifacts to weigh. Empty means the gate has nothing to do.',
|
|
45
|
+
default: [],
|
|
46
|
+
},
|
|
21
47
|
},
|
|
22
48
|
additionalProperties: false,
|
|
23
49
|
};
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { COVERAGE_GATE_DEFAULTS } from '../quality.js';
|
|
4
|
+
import { gateBase, SAFE_STRING } from './shared.js';
|
|
4
5
|
|
|
5
6
|
export const COVERAGE_GATE = {
|
|
6
7
|
type: 'object',
|
|
8
|
+
description:
|
|
9
|
+
'Line/branch/function coverage ratchet, read from the Istanbul JSON summary the project test run emits.',
|
|
7
10
|
properties: {
|
|
8
|
-
...
|
|
9
|
-
|
|
11
|
+
...gateBase({
|
|
12
|
+
enabled: COVERAGE_GATE_DEFAULTS.enabled,
|
|
13
|
+
baselinePath: COVERAGE_GATE_DEFAULTS.baselinePath,
|
|
14
|
+
tolerance: COVERAGE_GATE_DEFAULTS.tolerance,
|
|
15
|
+
floors: COVERAGE_GATE_DEFAULTS.floors,
|
|
16
|
+
}),
|
|
17
|
+
coveragePath: {
|
|
18
|
+
...SAFE_STRING,
|
|
19
|
+
minLength: 1,
|
|
20
|
+
description:
|
|
21
|
+
'Repo-relative path to the Istanbul `coverage-final.json` the capture step writes and the gate reads.',
|
|
22
|
+
default: COVERAGE_GATE_DEFAULTS.coveragePath,
|
|
23
|
+
},
|
|
10
24
|
// Story #2136 / Task #2142 — bounded timeout for `npm run test:coverage`.
|
|
11
25
|
// Wired into `runCapture` via `spawnSync({ timeout, killSignal })`. A
|
|
12
26
|
// SIGKILL fired by the timeout is translated to exit code 124 (the GNU
|
|
13
27
|
// `timeout` convention) so close-validation can branch on "hang" vs.
|
|
14
|
-
// "test failed".
|
|
15
|
-
timeoutMs: {
|
|
28
|
+
// "test failed".
|
|
29
|
+
timeoutMs: {
|
|
30
|
+
type: 'integer',
|
|
31
|
+
minimum: 1,
|
|
32
|
+
description:
|
|
33
|
+
'Bounded timeout (ms) for the `npm run test:coverage` capture spawn. A SIGKILL at the budget boundary maps to exit 124 so close-validation can tell a hang from a test failure.',
|
|
34
|
+
default: COVERAGE_GATE_DEFAULTS.timeoutMs,
|
|
35
|
+
},
|
|
16
36
|
},
|
|
17
37
|
additionalProperties: false,
|
|
18
38
|
};
|
|
@@ -18,9 +18,19 @@
|
|
|
18
18
|
*/
|
|
19
19
|
export const INCREMENTAL_COVERAGE_SCHEMA = {
|
|
20
20
|
type: 'object',
|
|
21
|
+
description:
|
|
22
|
+
'Story #4981 — opt-in incremental coverage-capture + CRAP-join scoping. Default (key absent) preserves today’s full-repo behaviour byte-for-byte. When `enabled: true`, `coverage-capture.js` scopes `npm run test:coverage` to the files changed against `baseRef` (default: the gate’s own `--ref` / `main`), and the CRAP join treats a method in a file the diff did not touch as resolved by its committed baseline row instead of requiring fresh coverage for it.',
|
|
21
23
|
properties: {
|
|
22
|
-
enabled: {
|
|
23
|
-
|
|
24
|
+
enabled: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'Master switch for incremental capture + join scoping.',
|
|
27
|
+
},
|
|
28
|
+
baseRef: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
minLength: 1,
|
|
31
|
+
description:
|
|
32
|
+
'Git ref the changed-file set is computed against. Omitted falls back to the gate’s own `--ref` (`main`).',
|
|
33
|
+
},
|
|
24
34
|
},
|
|
25
35
|
additionalProperties: false,
|
|
26
36
|
};
|
|
@@ -1,41 +1,86 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
+
import { CRAP_GATE_DEFAULTS } from '../quality.js';
|
|
3
4
|
import { INCREMENTAL_COVERAGE_SCHEMA } from './crap-incremental-coverage.schema.js';
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
+
gateBase,
|
|
6
7
|
LIST_OR_EXTENDER_OF_STRINGS,
|
|
7
8
|
SAFE_STRING,
|
|
8
9
|
} from './shared.js';
|
|
9
10
|
|
|
10
11
|
export const CRAP_GATE = {
|
|
11
12
|
type: 'object',
|
|
13
|
+
description:
|
|
14
|
+
'CRAP (Change Risk Anti-Pattern) ratchet — per-method cyclomatic complexity joined against per-method coverage.',
|
|
12
15
|
properties: {
|
|
13
|
-
...
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
...gateBase({
|
|
17
|
+
enabled: CRAP_GATE_DEFAULTS.enabled,
|
|
18
|
+
baselinePath: CRAP_GATE_DEFAULTS.baselinePath,
|
|
19
|
+
tolerance: CRAP_GATE_DEFAULTS.tolerance,
|
|
20
|
+
floors: CRAP_GATE_DEFAULTS.floors,
|
|
21
|
+
}),
|
|
22
|
+
targetDirs: {
|
|
23
|
+
...LIST_OR_EXTENDER_OF_STRINGS,
|
|
24
|
+
description:
|
|
25
|
+
"Directories whose JS sources the CRAP gate scores. Mandrel ships a `src/`-centric default; projects whose executable code lives elsewhere (e.g. this repo's `.agents/scripts/`) override here. The framework default is intentionally not auto-discovered, so an override is the explicit, auditable signal.",
|
|
26
|
+
default: [...CRAP_GATE_DEFAULTS.targetDirs],
|
|
27
|
+
},
|
|
28
|
+
newMethodCeiling: {
|
|
29
|
+
type: 'integer',
|
|
30
|
+
minimum: 1,
|
|
31
|
+
description:
|
|
32
|
+
'Hard CRAP ceiling applied to a method the diff introduces. A new method above it fails the gate regardless of the baseline.',
|
|
33
|
+
default: CRAP_GATE_DEFAULTS.newMethodCeiling,
|
|
34
|
+
},
|
|
35
|
+
requireCoverage: {
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
description:
|
|
38
|
+
'When true, the gate refuses to score without a coverage artifact rather than silently reporting complexity-only rows.',
|
|
39
|
+
default: CRAP_GATE_DEFAULTS.requireCoverage,
|
|
40
|
+
},
|
|
41
|
+
// Story #4775 — fail-closed floor on the per-method coverage JOIN.
|
|
42
|
+
minMethodResolutionRate: {
|
|
43
|
+
type: 'number',
|
|
44
|
+
minimum: 0,
|
|
45
|
+
maximum: 1,
|
|
46
|
+
description:
|
|
47
|
+
'Fail-closed floor on the per-method coverage JOIN (Story #4775): the fraction of methods that must resolve a coverage entry, counted only over files that HAVE one, before `update-crap-baseline.js` will persist. A broken join is silent by construction — unresolved methods are simply absent — so the updater refuses rather than writing a thin baseline and logging it as success. Not enforced below 25 joinable methods, where a diff-scoped run’s rate is noise. Default 0.75; a healthy repo resolves ~98%.',
|
|
48
|
+
},
|
|
24
49
|
friction: {
|
|
25
50
|
type: 'object',
|
|
26
|
-
|
|
51
|
+
description:
|
|
52
|
+
'Friction-signal wiring for a CRAP baseline regression, so a recurring one can reach the actionable threshold.',
|
|
53
|
+
properties: {
|
|
54
|
+
markerKey: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
minLength: 1,
|
|
57
|
+
description: 'Signal marker key the regression is recorded under.',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
27
60
|
additionalProperties: false,
|
|
61
|
+
default: { ...CRAP_GATE_DEFAULTS.friction },
|
|
62
|
+
},
|
|
63
|
+
refreshTag: {
|
|
64
|
+
...SAFE_STRING,
|
|
65
|
+
minLength: 1,
|
|
66
|
+
description:
|
|
67
|
+
'Commit-subject substring that acknowledges a deliberate CRAP baseline refresh in the compared range. A range commit carrying it that also touches the baseline file demotes head-vs-base regressions; floors stay enforced.',
|
|
68
|
+
default: CRAP_GATE_DEFAULTS.refreshTag,
|
|
69
|
+
},
|
|
70
|
+
refreshTimeoutMs: {
|
|
71
|
+
type: 'integer',
|
|
72
|
+
minimum: 1,
|
|
73
|
+
description:
|
|
74
|
+
'Bounded timeout (ms) for `npm run crap:update` spawned by the baseline-attribution refresh path. Mirrors `coverage.timeoutMs`: a SIGKILL fired at the budget boundary maps to exit 124 so the close orchestrator can flip the Story to `agent::blocked`. Default 60000 (Story #2165).',
|
|
75
|
+
default: CRAP_GATE_DEFAULTS.refreshTimeoutMs,
|
|
76
|
+
},
|
|
77
|
+
ignoreGlobs: {
|
|
78
|
+
type: 'array',
|
|
79
|
+
items: { type: 'string', minLength: 1 },
|
|
80
|
+
description:
|
|
81
|
+
'Minimatch glob patterns matched against the canonicalised repo-relative path of each discovered file. Files matching any pattern are excluded from CRAP discovery before scoring. Orthogonal to `components` (grouping) — a file excluded here never appears in any component bucket. Absent or empty preserves the existing IGNORED_DIRS-only behaviour (Story #3217).',
|
|
82
|
+
default: [...CRAP_GATE_DEFAULTS.ignoreGlobs],
|
|
28
83
|
},
|
|
29
|
-
refreshTag: { ...SAFE_STRING, minLength: 1 },
|
|
30
|
-
// Story #2165 — bounded timeout for `npm run crap:update` spawned by the
|
|
31
|
-
// baseline-attribution refresh path. Mirrors `coverage.timeoutMs` (Story
|
|
32
|
-
// #2142): a SIGKILL fired at the budget boundary maps to exit code 124
|
|
33
|
-
// so the close orchestrator can flip the Story to `agent::blocked`.
|
|
34
|
-
refreshTimeoutMs: { type: 'integer', minimum: 1 },
|
|
35
|
-
// Story #3217 — glob patterns matched against canonicalised repo-relative
|
|
36
|
-
// paths to exclude files from CRAP discovery before scoring. Orthogonal
|
|
37
|
-
// to `components` (grouping). Absent/empty preserves existing behaviour.
|
|
38
|
-
ignoreGlobs: { type: 'array', items: { type: 'string', minLength: 1 } },
|
|
39
84
|
incrementalCoverage: INCREMENTAL_COVERAGE_SCHEMA,
|
|
40
85
|
},
|
|
41
86
|
additionalProperties: false,
|
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { gateBase, LIST_OR_EXTENDER_OF_STRINGS } from './shared.js';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* `delivery.quality.gates.duplication` — code-duplication (DRY) gate
|
|
7
|
-
* (Story #3664). Shares the four-field `GATE_BASE` (enabled, baselinePath,
|
|
8
|
-
* tolerance, floors, components) and adds the scan-scope extras: the
|
|
9
|
-
* `targetDirs` the duplication scanner walks, a bounded refresh timeout
|
|
10
|
-
* mirroring crap/MI, and `ignoreGlobs` to exclude files from the scan.
|
|
11
|
-
*/
|
|
12
5
|
export const DUPLICATION_GATE = {
|
|
13
6
|
type: 'object',
|
|
7
|
+
description:
|
|
8
|
+
'Code-duplication (DRY) gate (Story #3664). Shares the gate base and adds the scan-scope extras: the `targetDirs` the duplication scanner walks, a bounded refresh timeout mirroring crap/MI, and `ignoreGlobs` to exclude files from the scan.',
|
|
14
9
|
properties: {
|
|
15
|
-
...
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
...gateBase({
|
|
11
|
+
enabled: false,
|
|
12
|
+
baselinePath: 'baselines/duplication.json',
|
|
13
|
+
tolerance: { kind: 'absolute', value: 1 },
|
|
14
|
+
floors: { '*': { percentage: 25 } },
|
|
15
|
+
}),
|
|
16
|
+
targetDirs: {
|
|
17
|
+
...LIST_OR_EXTENDER_OF_STRINGS,
|
|
18
|
+
description:
|
|
19
|
+
"Directories whose JS sources the duplication (DRY) gate scans for copy-paste clones. Mandrel ships a `src/`-centric default; projects whose executable code lives elsewhere (e.g. this repo's `.agents/scripts/`) override here. The framework default is intentionally not auto-discovered, so an override is the explicit, auditable signal (Story #3664).",
|
|
20
|
+
default: ['src'],
|
|
21
|
+
},
|
|
22
|
+
refreshTimeoutMs: {
|
|
23
|
+
type: 'integer',
|
|
24
|
+
minimum: 1,
|
|
25
|
+
description:
|
|
26
|
+
'Bounded timeout (ms) for `npm run duplication:update` spawned by the baseline-attribution refresh path. Mirrors `crap.refreshTimeoutMs` / `coverage.timeoutMs`: a SIGKILL fired at the budget boundary maps to exit 124. Default 60000 (Story #3664).',
|
|
27
|
+
default: 60000,
|
|
28
|
+
},
|
|
29
|
+
ignoreGlobs: {
|
|
30
|
+
type: 'array',
|
|
31
|
+
items: { type: 'string', minLength: 1 },
|
|
32
|
+
description:
|
|
33
|
+
'Minimatch glob patterns matched against the canonicalised repo-relative path of each discovered file. Files matching any pattern are excluded from duplication discovery before scanning. Orthogonal to `components` (grouping). Absent or empty preserves the existing behaviour (Story #3664).',
|
|
34
|
+
default: [],
|
|
35
|
+
},
|
|
24
36
|
},
|
|
25
37
|
additionalProperties: false,
|
|
26
38
|
};
|
|
@@ -14,14 +14,17 @@ import { MUTATION_GATE } from './mutation.schema.js';
|
|
|
14
14
|
*
|
|
15
15
|
* Split from the former `lib/config-gates-schema.js` aggregate
|
|
16
16
|
* (Story #2987) into per-gate sub-schema files under
|
|
17
|
-
* `lib/config/gates/`. Shared fragments (`
|
|
17
|
+
* `lib/config/gates/`. Shared fragments (`gateBase()`, `SAFE_STRING`,
|
|
18
18
|
* `TOLERANCE_SCHEMA`, `FLOORS_SCHEMA`, `COMPONENTS_SCHEMA`,
|
|
19
19
|
* `LIST_OR_EXTENDER_OF_STRINGS`, `NULLABLE_NONEMPTY_SAFE_STRING`) live
|
|
20
20
|
* in `./shared.js`. Each per-gate file exports one sub-schema literal
|
|
21
|
-
* with the gate-specific extras layered on top of `
|
|
21
|
+
* with the gate-specific extras layered on top of `gateBase()`, passing
|
|
22
|
+
* that gate's own base-field defaults (Story #5007).
|
|
22
23
|
*/
|
|
23
24
|
export const GATES_SCHEMA = {
|
|
24
25
|
type: 'object',
|
|
26
|
+
description:
|
|
27
|
+
'The eight quality gates, each sharing the `{ enabled, baselinePath, tolerance, floors, components }` base.',
|
|
25
28
|
properties: {
|
|
26
29
|
lint: LINT_GATE,
|
|
27
30
|
coverage: COVERAGE_GATE,
|
|
@@ -1,23 +1,51 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { gateBase, NULLABLE_NONEMPTY_SAFE_STRING } from './shared.js';
|
|
4
4
|
|
|
5
5
|
const LIGHTHOUSE_ROUTE = {
|
|
6
6
|
type: 'object',
|
|
7
|
+
description: 'One route the Lighthouse run scores.',
|
|
7
8
|
required: ['path'],
|
|
8
9
|
properties: {
|
|
9
|
-
path: {
|
|
10
|
-
|
|
10
|
+
path: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
minLength: 1,
|
|
13
|
+
description: 'Route path appended to `baseUrl`.',
|
|
14
|
+
},
|
|
15
|
+
formFactor: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['mobile', 'desktop'],
|
|
18
|
+
description: 'Emulated form factor for this route.',
|
|
19
|
+
},
|
|
11
20
|
},
|
|
12
21
|
additionalProperties: false,
|
|
13
22
|
};
|
|
14
23
|
|
|
15
24
|
export const LIGHTHOUSE_GATE = {
|
|
16
25
|
type: 'object',
|
|
26
|
+
description:
|
|
27
|
+
'Lighthouse category-score ratchet for web targets. Off by default — it needs a running deployment.',
|
|
17
28
|
properties: {
|
|
18
|
-
...
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
...gateBase({
|
|
30
|
+
enabled: false,
|
|
31
|
+
baselinePath: 'baselines/lighthouse.json',
|
|
32
|
+
tolerance: { kind: 'absolute', value: 0 },
|
|
33
|
+
floors: {
|
|
34
|
+
'*': { performance: 0, accessibility: 0, bestPractices: 0, seo: 0 },
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
baseUrl: {
|
|
38
|
+
...NULLABLE_NONEMPTY_SAFE_STRING,
|
|
39
|
+
description:
|
|
40
|
+
'Origin the routes are resolved against. `null` leaves the gate unusable, which is why it ships disabled.',
|
|
41
|
+
default: null,
|
|
42
|
+
},
|
|
43
|
+
routes: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: LIGHTHOUSE_ROUTE,
|
|
46
|
+
description: 'Routes to score on each run.',
|
|
47
|
+
default: [],
|
|
48
|
+
},
|
|
21
49
|
},
|
|
22
50
|
additionalProperties: false,
|
|
23
51
|
};
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { gateBase } from './shared.js';
|
|
4
4
|
|
|
5
5
|
export const LINT_GATE = {
|
|
6
6
|
type: 'object',
|
|
7
|
-
|
|
7
|
+
description:
|
|
8
|
+
'Lint-count ratchet. Floors are absolute error/warning counts; the baseline pins the current count so a regression is visible even while the floor is not yet met.',
|
|
9
|
+
properties: {
|
|
10
|
+
...gateBase({
|
|
11
|
+
enabled: true,
|
|
12
|
+
baselinePath: 'baselines/lint.json',
|
|
13
|
+
tolerance: { kind: 'absolute', value: 0 },
|
|
14
|
+
floors: { '*': { errorCount: 0 } },
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
8
17
|
additionalProperties: false,
|
|
9
18
|
};
|
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
+
import { MAINTAINABILITY_GATE_DEFAULTS } from '../quality.js';
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
+
gateBase,
|
|
5
6
|
LIST_OR_EXTENDER_OF_STRINGS,
|
|
6
7
|
SAFE_STRING,
|
|
7
8
|
} from './shared.js';
|
|
8
9
|
|
|
9
10
|
export const MAINTAINABILITY_GATE = {
|
|
10
11
|
type: 'object',
|
|
12
|
+
description:
|
|
13
|
+
'Maintainability-index ratchet. Scores per file as the average over its methods, so deleting a small high-MI method can legitimately lower a file’s score.',
|
|
11
14
|
properties: {
|
|
12
|
-
...
|
|
13
|
-
|
|
15
|
+
...gateBase({
|
|
16
|
+
enabled: MAINTAINABILITY_GATE_DEFAULTS.enabled,
|
|
17
|
+
baselinePath: MAINTAINABILITY_GATE_DEFAULTS.baselinePath,
|
|
18
|
+
tolerance: MAINTAINABILITY_GATE_DEFAULTS.tolerance,
|
|
19
|
+
floors: MAINTAINABILITY_GATE_DEFAULTS.floors,
|
|
20
|
+
}),
|
|
21
|
+
targetDirs: {
|
|
22
|
+
...LIST_OR_EXTENDER_OF_STRINGS,
|
|
23
|
+
description:
|
|
24
|
+
"Directories whose JS sources the maintainability gate scores. Mandrel ships a `src/`-centric default; projects whose executable code lives elsewhere (e.g. this repo's `.agents/scripts/` plus `tests/`) override here. The framework default is intentionally not auto-discovered, so an override is the explicit, auditable signal.",
|
|
25
|
+
default: [...MAINTAINABILITY_GATE_DEFAULTS.targetDirs],
|
|
26
|
+
},
|
|
14
27
|
// Story #4731 — commit-subject substring that acknowledges a deliberate
|
|
15
|
-
// maintainability baseline refresh in the compared range.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
refreshTimeoutMs: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
// maintainability baseline refresh in the compared range.
|
|
29
|
+
refreshTag: {
|
|
30
|
+
...SAFE_STRING,
|
|
31
|
+
minLength: 1,
|
|
32
|
+
description:
|
|
33
|
+
"Commit-subject substring that acknowledges a deliberate maintainability baseline refresh in the compared range. Mirrors the CRAP gate's `refreshTag`; a range commit carrying it that touches the baseline file demotes head-vs-base regressions (floors still enforced).",
|
|
34
|
+
},
|
|
35
|
+
refreshTimeoutMs: {
|
|
36
|
+
type: 'integer',
|
|
37
|
+
minimum: 1,
|
|
38
|
+
description:
|
|
39
|
+
'Bounded timeout (ms) for `npm run maintainability:update` spawned by the baseline-attribution refresh path. Mirrors `coverage.timeoutMs`: a SIGKILL fired at the budget boundary maps to exit 124 so the close orchestrator can flip the Story to `agent::blocked`. Default 60000 (Story #2165).',
|
|
40
|
+
default: MAINTAINABILITY_GATE_DEFAULTS.refreshTimeoutMs,
|
|
41
|
+
},
|
|
42
|
+
ignoreGlobs: {
|
|
43
|
+
type: 'array',
|
|
44
|
+
items: { type: 'string', minLength: 1 },
|
|
45
|
+
description:
|
|
46
|
+
'Minimatch glob patterns matched against the canonicalised repo-relative path of each discovered file. Files matching any pattern are excluded from MI discovery before scoring. Orthogonal to `components` (grouping) — a file excluded here never appears in any component bucket. Absent or empty preserves the existing IGNORED_DIRS-only behaviour (Story #3217).',
|
|
47
|
+
default: [...MAINTAINABILITY_GATE_DEFAULTS.ignoreGlobs],
|
|
48
|
+
},
|
|
27
49
|
},
|
|
28
50
|
additionalProperties: false,
|
|
29
51
|
};
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
/* node:coverage ignore file -- AJV schema declaration (data-as-code) */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { gateBase, NULLABLE_NONEMPTY_SAFE_STRING } from './shared.js';
|
|
4
4
|
|
|
5
5
|
export const MUTATION_GATE = {
|
|
6
6
|
type: 'object',
|
|
7
|
+
description:
|
|
8
|
+
'Stryker mutation-score ratchet. Off in practice for most consumers — the baseline kind is registered but no framework path runs Stryker.',
|
|
7
9
|
properties: {
|
|
8
|
-
...
|
|
9
|
-
|
|
10
|
+
...gateBase({
|
|
11
|
+
enabled: true,
|
|
12
|
+
baselinePath: 'baselines/mutation.json',
|
|
13
|
+
tolerance: { kind: 'percent', value: 0 },
|
|
14
|
+
floors: { '*': { score: 60 } },
|
|
15
|
+
}),
|
|
16
|
+
strykerConfigPath: {
|
|
17
|
+
...NULLABLE_NONEMPTY_SAFE_STRING,
|
|
18
|
+
description:
|
|
19
|
+
'Repo-relative path to the Stryker config. `null` lets Stryker resolve its own default.',
|
|
20
|
+
default: null,
|
|
21
|
+
},
|
|
10
22
|
},
|
|
11
23
|
additionalProperties: false,
|
|
12
24
|
};
|
|
@@ -48,10 +48,21 @@ export const LIST_OR_EXTENDER_OF_STRINGS = {
|
|
|
48
48
|
/** Object-shaped tolerance: `{ kind: 'absolute' | 'percent', value: number }`. */
|
|
49
49
|
export const TOLERANCE_SCHEMA = {
|
|
50
50
|
type: 'object',
|
|
51
|
+
description:
|
|
52
|
+
'How much a rollup may drift from the committed baseline before the gate reports a regression.',
|
|
51
53
|
required: ['kind', 'value'],
|
|
52
54
|
properties: {
|
|
53
|
-
kind: {
|
|
54
|
-
|
|
55
|
+
kind: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
enum: ['absolute', 'percent'],
|
|
58
|
+
description:
|
|
59
|
+
'Whether `value` is read as raw metric units (`absolute`) or as a percentage of the baseline (`percent`).',
|
|
60
|
+
},
|
|
61
|
+
value: {
|
|
62
|
+
type: 'number',
|
|
63
|
+
minimum: 0,
|
|
64
|
+
description: 'The tolerance magnitude. 0 means no drift is allowed.',
|
|
65
|
+
},
|
|
55
66
|
},
|
|
56
67
|
additionalProperties: false,
|
|
57
68
|
};
|
|
@@ -84,6 +95,8 @@ export const TOLERANCE_SCHEMA = {
|
|
|
84
95
|
*/
|
|
85
96
|
export const FLOORS_SCHEMA = {
|
|
86
97
|
type: 'object',
|
|
98
|
+
description:
|
|
99
|
+
'Workspace-keyed absolute floors: `{ "<workspace>": { "<metric>": number } }`. `"*"` is the project-wide catch-all; the metric keyset is open so per-rollup keys flow through without each gate enumerating them. Floors are absolute — unlike `tolerance`, they are enforced regardless of the baseline.',
|
|
87
100
|
additionalProperties: {
|
|
88
101
|
type: 'object',
|
|
89
102
|
additionalProperties: { type: 'number' },
|
|
@@ -102,16 +115,52 @@ export const FLOORS_SCHEMA = {
|
|
|
102
115
|
*/
|
|
103
116
|
export const COMPONENTS_SCHEMA = {
|
|
104
117
|
type: 'object',
|
|
118
|
+
description:
|
|
119
|
+
'Per-gate component map — component name to the glob list whose files roll up under it. Defaults to `{ "*": ["**"] }` at the resolver layer.',
|
|
105
120
|
additionalProperties: {
|
|
106
121
|
type: 'array',
|
|
107
122
|
items: { type: 'string', minLength: 1 },
|
|
108
123
|
},
|
|
109
124
|
};
|
|
110
125
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Build the shared four-field gate base with per-gate `default` annotations
|
|
128
|
+
* layered on (Story #5007). The base fields are identical in shape across
|
|
129
|
+
* every gate but their defaults are not — each gate ships its own
|
|
130
|
+
* `baselinePath`, tolerance, and floors — so the defaults are supplied by the
|
|
131
|
+
* calling gate module rather than baked in here.
|
|
132
|
+
*
|
|
133
|
+
* @param {{ enabled?: boolean, baselinePath?: string,
|
|
134
|
+
* tolerance?: object, floors?: object }} [defaults]
|
|
135
|
+
* @returns {object} A fresh `properties` fragment; never a shared reference.
|
|
136
|
+
*/
|
|
137
|
+
export function gateBase(defaults = {}) {
|
|
138
|
+
return {
|
|
139
|
+
enabled: {
|
|
140
|
+
type: 'boolean',
|
|
141
|
+
description:
|
|
142
|
+
'When false, the checker exits 0 with a skip line and the gate is reported as `skipped`, never omitted.',
|
|
143
|
+
...(defaults.enabled === undefined ? {} : { default: defaults.enabled }),
|
|
144
|
+
},
|
|
145
|
+
baselinePath: {
|
|
146
|
+
...SAFE_STRING,
|
|
147
|
+
minLength: 1,
|
|
148
|
+
description:
|
|
149
|
+
"Repo-root-relative path to the gate's committed baseline artifact.",
|
|
150
|
+
...(defaults.baselinePath === undefined
|
|
151
|
+
? {}
|
|
152
|
+
: { default: defaults.baselinePath }),
|
|
153
|
+
},
|
|
154
|
+
tolerance: {
|
|
155
|
+
...TOLERANCE_SCHEMA,
|
|
156
|
+
...(defaults.tolerance === undefined
|
|
157
|
+
? {}
|
|
158
|
+
: { default: defaults.tolerance }),
|
|
159
|
+
},
|
|
160
|
+
floors: {
|
|
161
|
+
...FLOORS_SCHEMA,
|
|
162
|
+
...(defaults.floors === undefined ? {} : { default: defaults.floors }),
|
|
163
|
+
},
|
|
164
|
+
components: COMPONENTS_SCHEMA,
|
|
165
|
+
};
|
|
166
|
+
}
|