mandrel 2.56.0 → 2.57.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/agents/plan-critic.md +13 -18
- package/.agents/agents/story-worker.md +25 -34
- package/.agents/docs/agentrc-reference.json +0 -30
- package/.agents/docs/configuration.md +8 -28
- package/.agents/docs/execution-reference.md +5 -5
- package/.agents/docs/quality-gates.md +8 -7
- package/.agents/instructions.md +9 -10
- package/.agents/schemas/agentrc.schema.json +9 -185
- package/.agents/schemas/story-deliver-terminal.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +107 -17
- package/.agents/scripts/ceremony-derive.js +191 -0
- package/.agents/scripts/check-context-budget.js +28 -33
- package/.agents/scripts/check-cyclomatic.js +4 -3
- package/.agents/scripts/deliver-light.js +31 -94
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +15 -2
- package/.agents/scripts/lib/baselines/coverage-updater-cli.js +110 -0
- package/.agents/scripts/lib/baselines/crap-preview-scan.js +25 -0
- package/.agents/scripts/lib/baselines/crap-updater-cli.js +223 -0
- package/.agents/scripts/lib/bdd-scenario-budget.js +21 -3
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -1
- package/.agents/scripts/lib/close-validation/gates.js +52 -1
- package/.agents/scripts/lib/config/acceptance-eval.js +25 -57
- package/.agents/scripts/lib/config/delivery-routing.js +7 -33
- package/.agents/scripts/lib/config/explain.js +0 -19
- package/.agents/scripts/lib/config/limits.js +18 -78
- package/.agents/scripts/lib/config/quality.js +6 -3
- package/.agents/scripts/lib/config/runners.js +3 -2
- package/.agents/scripts/lib/config-settings-schema-delivery.js +15 -68
- package/.agents/scripts/lib/config-settings-schema-quality.js +0 -14
- package/.agents/scripts/lib/config-settings-schema.js +16 -143
- package/.agents/scripts/lib/crap-engine.js +35 -4
- package/.agents/scripts/lib/crap-utils.js +17 -1
- package/.agents/scripts/lib/cyclomatic-ceiling.js +19 -7
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +1 -1
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +5 -4
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +19 -73
- package/.agents/scripts/lib/orchestration/complexity-gate.js +46 -212
- package/.agents/scripts/lib/orchestration/file-assumptions.js +32 -17
- package/.agents/scripts/lib/orchestration/light-escalation.js +3 -3
- package/.agents/scripts/lib/orchestration/light-suitability.js +66 -233
- package/.agents/scripts/lib/orchestration/plan-context.js +181 -387
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +42 -153
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +14 -70
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +300 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +131 -168
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +118 -297
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +55 -0
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +16 -65
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +22 -35
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +30 -139
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +61 -223
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +5 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +46 -16
- package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +213 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +10 -63
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +33 -539
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +21 -414
- package/.agents/scripts/lib/orchestration/ticket-validator.js +54 -118
- package/.agents/scripts/lib/orchestration/verify-credit.js +69 -24
- package/.agents/scripts/lib/story-body/body-format-lints.js +15 -85
- package/.agents/scripts/lib/story-body/story-body.js +17 -237
- package/.agents/scripts/lib/templates/decomposer-prompts.js +84 -121
- package/.agents/scripts/lib/test-isolate/cli-options.js +93 -0
- package/.agents/scripts/lib/test-isolate/progress-log.js +45 -0
- package/.agents/scripts/lib/test-isolate/render-report.js +97 -0
- package/.agents/scripts/lib/test-isolate/run-isolate.js +87 -0
- package/.agents/scripts/lib/test-run-credit.js +266 -0
- package/.agents/scripts/lib/wave-runner/footprint.js +48 -358
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -5
- package/.agents/scripts/lib/workers/crap-worker.js +32 -41
- package/.agents/scripts/plan-context.js +7 -9
- package/.agents/scripts/plan-critics.js +28 -54
- package/.agents/scripts/plan-persist.js +25 -68
- package/.agents/scripts/quality-preview.js +51 -0
- package/.agents/scripts/run-tests.js +12 -0
- package/.agents/scripts/stories-wave-tick.js +23 -45
- package/.agents/scripts/test-isolate.js +13 -180
- package/.agents/scripts/update-coverage-baseline.js +25 -70
- package/.agents/scripts/update-crap-baseline.js +19 -123
- package/.agents/skills/core/scope-triage/SKILL.md +3 -3
- package/.agents/workflows/audit-clean-code.md +4 -3
- package/.agents/workflows/helpers/acceptance-self-eval.md +41 -41
- package/.agents/workflows/helpers/code-quality-guardrails.md +4 -4
- package/.agents/workflows/helpers/code-review.md +2 -3
- package/.agents/workflows/helpers/deliver-digest.md +41 -57
- package/.agents/workflows/helpers/deliver-light.md +40 -105
- package/.agents/workflows/helpers/deliver-reference.md +1 -1
- package/.agents/workflows/helpers/deliver-story-reference.md +37 -58
- package/.agents/workflows/helpers/deliver-story.md +9 -13
- package/.agents/workflows/helpers/plan-reference.md +132 -219
- package/.agents/workflows/mandrel-plan.md +27 -40
- package/.agents/workflows/memory-consolidate.md +9 -13
- package/docs/CHANGELOG.md +23 -0
- package/lib/migrations/index.js +4 -0
- package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +45 -0
- package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +59 -0
- package/package.json +1 -1
- package/.agents/scripts/lib/framework-version.js +0 -39
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +0 -223
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +0 -97
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +0 -26
- package/.agents/scripts/lib/orchestration/spec-budget.js +0 -89
- package/.agents/scripts/lib/orchestration/spec-spill.js +0 -74
- package/.agents/scripts/lib/orchestration/verify-tier-repair.js +0 -107
|
@@ -3,224 +3,187 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Exports:
|
|
5
5
|
* - `resolveBaseBranchRef(config)` — the one place the persist gates learn
|
|
6
|
-
* which
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* which branch name the operator configured.
|
|
7
|
+
*
|
|
8
|
+
* The ref the probes read is resolved per checkout (`resolveProbeRef`): the
|
|
9
|
+
* local branch when it exists, else its `origin/` tracking ref (a PR
|
|
10
|
+
* checkout on CI has no local `main`), else nothing — a shallow checkout
|
|
11
|
+
* with no base at all skips the probes instead of reading every path as
|
|
12
|
+
* absent.
|
|
13
|
+
* - `validateTickets(tickets, config, opts)` — repairs the mechanical
|
|
14
|
+
* `changes[]` formalities against the base branch, then runs the
|
|
15
|
+
* cross-link, freshness, and task-body validators in one pass.
|
|
16
|
+
*
|
|
17
|
+
* Story #5312 deleted the fan-out probe that lived here: the delete
|
|
18
|
+
* blast-radius count never refused a real plan, and the `git grep` it paid
|
|
19
|
+
* for on every persist bought a warning nobody acted on.
|
|
13
20
|
*
|
|
14
21
|
* @module lib/orchestration/plan-persist/persist-helpers
|
|
15
22
|
*/
|
|
16
23
|
|
|
17
|
-
import posix from 'node:path/posix';
|
|
18
24
|
import { gitSpawn } from '../../git-utils.js';
|
|
19
25
|
import { validateTaskBodies } from '../task-body-validator.js';
|
|
20
26
|
import { validateAndNormalizeTickets } from '../ticket-validator.js';
|
|
21
|
-
import {
|
|
22
|
-
import { normalizeVerifyTiers } from '../verify-tier-repair.js';
|
|
27
|
+
import { repairChangeEntries } from './changes-repair.js';
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
30
|
+
* Resolve the ref the persist gates probe against.
|
|
31
|
+
*
|
|
32
|
+
* The canonical resolved config carries the base branch at
|
|
33
|
+
* `project.baseBranch` (`lib/config-resolver.js` defaults it to `main`).
|
|
34
|
+
* This helper used to read `config.baseBranch` — a key the resolver never
|
|
35
|
+
* produces — so every freshness / file-assumption probe silently targeted
|
|
36
|
+
* the literal `main` regardless of configuration. Benign in a repo whose
|
|
37
|
+
* base branch *is* `main`; wrong for any consumer that configured something
|
|
38
|
+
* else (Story #4541).
|
|
39
|
+
*
|
|
40
|
+
* The flat `config.baseBranch` fallback is retained for the legacy
|
|
41
|
+
* `settings`-bag callers that pass `{ baseBranch, paths, planning }`.
|
|
42
|
+
*
|
|
43
|
+
* @param {object} [config] Resolved config, or a legacy settings bag.
|
|
44
|
+
* @returns {string}
|
|
27
45
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/** Every quoted string on a candidate line — the specifier lives in one. */
|
|
31
|
-
const QUOTED_RE = /['"]([^'"\n]+)['"]/g;
|
|
32
|
-
|
|
33
|
-
function escapeRegExp(value) {
|
|
34
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
46
|
+
export function resolveBaseBranchRef(config) {
|
|
47
|
+
return config?.project?.baseBranch ?? config?.baseBranch ?? 'main';
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* This is a *candidate* net only. It is deliberately generous because the
|
|
44
|
-
* resolution pass below re-checks every hit against the real path; a tail
|
|
45
|
-
* that over-matches costs one extra resolve, a tail that under-matches
|
|
46
|
-
* loses a genuine importer.
|
|
51
|
+
* Does `ref` name a commit in the repo at `cwd`?
|
|
52
|
+
*
|
|
53
|
+
* @param {string} ref
|
|
54
|
+
* @param {string} cwd
|
|
55
|
+
* @returns {boolean}
|
|
47
56
|
*/
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (stem === 'index') {
|
|
54
|
-
const dir = posix.basename(posix.dirname(path));
|
|
55
|
-
if (dir && dir !== '.') tails.add(dir);
|
|
56
|
-
}
|
|
57
|
-
return [...tails].filter((t) => t.length > 0);
|
|
57
|
+
function refResolves(ref, cwd) {
|
|
58
|
+
return (
|
|
59
|
+
gitSpawn(cwd, 'rev-parse', '--verify', '--quiet', `${ref}^{commit}`)
|
|
60
|
+
.status === 0
|
|
61
|
+
);
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* `
|
|
65
|
+
* Resolve the configured base branch to a ref the footprint probes can read
|
|
66
|
+
* in this checkout, or `null` when none exists.
|
|
67
|
+
*
|
|
68
|
+
* A developer checkout carries a local `main`; a CI pull-request checkout
|
|
69
|
+
* (`actions/checkout` at the merge ref, detached) carries only
|
|
70
|
+
* `origin/main`; a shallow smoke checkout carries neither. Probing the
|
|
71
|
+
* bare branch name in the last two answers "absent" for every path, which
|
|
72
|
+
* turns each bare-path repair into a `creates` and every declared path into
|
|
73
|
+
* a stale reference. So: the local branch when it resolves, else its
|
|
74
|
+
* `origin/` tracking ref when that does, else `null` — the caller then
|
|
75
|
+
* skips the probes and says so, rather than reporting the tree as missing.
|
|
76
|
+
*
|
|
77
|
+
* @param {{ baseBranch: string, cwd?: string }} opts
|
|
78
|
+
* @returns {string|null}
|
|
65
79
|
*/
|
|
66
|
-
function
|
|
67
|
-
const
|
|
68
|
-
|
|
80
|
+
function resolveProbeRef({ baseBranch, cwd }) {
|
|
81
|
+
const repo = cwd ?? process.cwd();
|
|
82
|
+
const candidates = [baseBranch, `origin/${baseBranch}`];
|
|
83
|
+
return candidates.find((ref) => refResolves(ref, repo)) ?? null;
|
|
69
84
|
}
|
|
70
85
|
|
|
71
86
|
/**
|
|
72
|
-
*
|
|
73
|
-
* path
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* deliberately does not read. Mandrel's own internal imports are all
|
|
80
|
-
* relative. Under-counting is the *quiet* failure direction — it argues for
|
|
81
|
-
* a deletion rather than against one — so if alias-importing consumers
|
|
82
|
-
* appear, this is the place to teach the probe their resolver.
|
|
87
|
+
* Default git probe: returns true when `path` exists at `ref` in the cwd repo.
|
|
88
|
+
* `git cat-file -e <ref>:<path>` is the standard low-cost existence check —
|
|
89
|
+
* the same probe the validator's own gates run, so the repair pass and the
|
|
90
|
+
* gates cannot disagree about what is at base.
|
|
91
|
+
*
|
|
92
|
+
* @param {{ baseBranchRef: string, path: string, cwd?: string }} opts
|
|
93
|
+
* @returns {boolean}
|
|
83
94
|
*/
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
function defaultGitRunner({ baseBranchRef, path, cwd }) {
|
|
96
|
+
const result = gitSpawn(
|
|
97
|
+
cwd ?? process.cwd(),
|
|
98
|
+
'cat-file',
|
|
99
|
+
'-e',
|
|
100
|
+
`${baseBranchRef}:${path}`,
|
|
88
101
|
);
|
|
89
|
-
|
|
90
|
-
if (`${resolved}${ext}` === deletedPath) return true;
|
|
91
|
-
if (ext && `${resolved}/index${ext}` === deletedPath) return true;
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
102
|
+
return result.status === 0;
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* gate's own audit trail would then argue for the deletion it is meant to
|
|
104
|
-
* question (Story #4547).
|
|
106
|
+
* The `existsAtBase` predicate the `changes[]` repair pass probes with. With
|
|
107
|
+
* no base to read, a bare bullet is taken as the in-place edit it almost
|
|
108
|
+
* always is.
|
|
109
|
+
*
|
|
110
|
+
* @param {{ baseBranchRef: string|null, cwd?: string, gitRunner?: Function }} opts
|
|
111
|
+
* @returns {(path: string) => boolean}
|
|
105
112
|
*/
|
|
106
|
-
function
|
|
107
|
-
if (
|
|
108
|
-
|
|
113
|
+
function makeExistsAtBase({ baseBranchRef, cwd, gitRunner }) {
|
|
114
|
+
if (baseBranchRef === null) return () => true;
|
|
115
|
+
const runner = gitRunner ?? defaultGitRunner;
|
|
116
|
+
return (path) => Boolean(runner({ baseBranchRef, path, cwd }));
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
/**
|
|
112
|
-
*
|
|
120
|
+
* The one warning a checkout with no readable base leaves on the dry-run.
|
|
121
|
+
*
|
|
122
|
+
* @param {string} baseBranch
|
|
123
|
+
* @param {string|null} baseBranchRef
|
|
124
|
+
* @returns {string[]}
|
|
113
125
|
*/
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const afterPath = rest.slice(pathEnd + 1);
|
|
122
|
-
const lineEnd = afterPath.indexOf(':');
|
|
123
|
-
if (lineEnd === -1) return null;
|
|
124
|
-
return { path, text: afterPath.slice(lineEnd + 1) };
|
|
126
|
+
function probeSkipWarnings(baseBranch, baseBranchRef) {
|
|
127
|
+
if (baseBranchRef !== null) return [];
|
|
128
|
+
return [
|
|
129
|
+
`base branch ${baseBranch} does not resolve in this checkout (tried ` +
|
|
130
|
+
`${baseBranch} and origin/${baseBranch}) — footprint probes skipped; ` +
|
|
131
|
+
'the plan summary reports its references as ambiguous, not stale.',
|
|
132
|
+
];
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* Two-stage, because accuracy and cost pull in opposite directions:
|
|
133
|
-
*
|
|
134
|
-
* 1. `git grep -n -E` narrows the tree to lines whose quoted import /
|
|
135
|
-
* require specifier could name the module (final-segment match).
|
|
136
|
-
* 2. Each candidate specifier is resolved against its own importer's
|
|
137
|
-
* directory and compared to the deleted path. Only a real resolution
|
|
138
|
-
* counts.
|
|
139
|
-
*
|
|
140
|
-
* The predecessor (Story #2962) grepped the basename stem as a bare word
|
|
141
|
-
* across the whole tree, so a module named `notification` or `options`
|
|
142
|
-
* reported dozens of call sites drawn from prose, schemas, and unrelated
|
|
143
|
-
* modules — and the gate that fired on that number told the operator to
|
|
144
|
-
* split a migration that did not exist. It also returned 0 without probing
|
|
145
|
-
* for any stem under three characters, under-reporting in silence. Both are
|
|
146
|
-
* gone: coupling is measured by resolution, not vocabulary (Story #4547).
|
|
147
|
-
*
|
|
148
|
-
* @returns {(arg: { path: string }) => { count: number, files: string[], probe: string }}
|
|
136
|
+
* Attach non-enumerable bookkeeping to the validated array.
|
|
137
|
+
*
|
|
138
|
+
* @param {object[]} validated
|
|
139
|
+
* @param {Record<string, unknown>} extras
|
|
149
140
|
*/
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (result.status !== 0) return { count: 0, files: [], probe };
|
|
160
|
-
const files = new Set();
|
|
161
|
-
for (const line of result.stdout.split('\n')) {
|
|
162
|
-
if (line.trim().length === 0) continue;
|
|
163
|
-
const hit = parseGrepLine(line, baseBranchRef);
|
|
164
|
-
// The deleted module's own self-references are not call sites.
|
|
165
|
-
if (!hit || hit.path === path) continue;
|
|
166
|
-
for (const match of hit.text.matchAll(QUOTED_RE)) {
|
|
167
|
-
if (specifierResolvesTo(hit.path, match[1], path)) {
|
|
168
|
-
files.add(hit.path);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const sorted = [...files].sort();
|
|
174
|
-
return { count: sorted.length, files: sorted, probe };
|
|
175
|
-
};
|
|
141
|
+
function defineHidden(validated, extras) {
|
|
142
|
+
for (const [key, value] of Object.entries(extras)) {
|
|
143
|
+
Object.defineProperty(validated, key, {
|
|
144
|
+
value,
|
|
145
|
+
enumerable: false,
|
|
146
|
+
configurable: true,
|
|
147
|
+
writable: true,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
176
150
|
}
|
|
177
151
|
|
|
178
152
|
/**
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
* The canonical resolved config carries the base branch at
|
|
182
|
-
* `project.baseBranch` (`lib/config-resolver.js` defaults it to `main`).
|
|
183
|
-
* This helper used to read `config.baseBranch` — a key the resolver never
|
|
184
|
-
* produces — so every freshness / file-assumption / fan-out probe silently
|
|
185
|
-
* targeted the literal `main` regardless of configuration. Benign in a repo
|
|
186
|
-
* whose base branch *is* `main`; wrong for any consumer that configured
|
|
187
|
-
* something else (Story #4541).
|
|
153
|
+
* Repair the mechanical `changes[]` formalities, then validate.
|
|
188
154
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
155
|
+
* Repair before judging (Story #5312, the shape Story #5005 set for the
|
|
156
|
+
* verify tier): a plain-string bullet or a trailing parenthetical is
|
|
157
|
+
* rewritten into `{ path, assumption }` by probing the base branch, and
|
|
158
|
+
* each rewrite is reported on the returned array's `repairs` so the dry-run
|
|
159
|
+
* can print it. An entry nothing path-shaped can be salvaged from survives
|
|
160
|
+
* untouched and still hard-errors in `validateTaskBodies`.
|
|
191
161
|
*
|
|
192
|
-
* @param {object
|
|
193
|
-
* @
|
|
162
|
+
* @param {object[]} tickets Mutated in place.
|
|
163
|
+
* @param {object} config Resolved config.
|
|
164
|
+
* @param {{ cwd?: string, gitRunner?: Function }} [opts]
|
|
165
|
+
* @returns {object[] & { findings: object[], errors: string[], warnings: string[], normalizations: object[], repairs: object[], probeRef: string|null }}
|
|
194
166
|
*/
|
|
195
|
-
export function resolveBaseBranchRef(config) {
|
|
196
|
-
return config?.project?.baseBranch ?? config?.baseBranch ?? 'main';
|
|
197
|
-
}
|
|
198
|
-
|
|
199
167
|
export function validateTickets(tickets, config, opts = {}) {
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
conflictPolicy.fanOutCounter = makeDefaultFanOutCounter({
|
|
168
|
+
const baseBranch = resolveBaseBranchRef(config);
|
|
169
|
+
const baseBranchRef = resolveProbeRef({ baseBranch, cwd: opts.cwd });
|
|
170
|
+
const repairs = repairChangeEntries(tickets, {
|
|
171
|
+
existsAtBase: makeExistsAtBase({
|
|
206
172
|
baseBranchRef,
|
|
207
173
|
cwd: opts.cwd,
|
|
208
|
-
|
|
209
|
-
|
|
174
|
+
gitRunner: opts.gitRunner,
|
|
175
|
+
}),
|
|
176
|
+
});
|
|
210
177
|
const validated = validateAndNormalizeTickets(tickets, {
|
|
211
|
-
baseBranchRef,
|
|
212
|
-
|
|
213
|
-
modelCapacity: opts.modelCapacity,
|
|
178
|
+
baseBranchRef: baseBranchRef ?? undefined,
|
|
179
|
+
gitRunner: opts.gitRunner,
|
|
214
180
|
// Thread the repo cwd into the AC-freshness / file-assumption git
|
|
215
181
|
// probes (#4474 PR7) — without it they silently ran against
|
|
216
182
|
// process.cwd(), which is only the repo root by coincidence.
|
|
217
183
|
cwd: opts.cwd,
|
|
218
184
|
});
|
|
219
|
-
|
|
220
|
-
// validator can already infer is auto-corrected rather than rejected, so a
|
|
221
|
-
// mechanically-fixable formality no longer costs a re-authoring round. An
|
|
222
|
-
// uninferable entry survives untouched and still hard-errors below.
|
|
223
|
-
normalizeVerifyTiers(validated);
|
|
185
|
+
validated.warnings.push(...probeSkipWarnings(baseBranch, baseBranchRef));
|
|
224
186
|
validateTaskBodies(validated);
|
|
187
|
+
defineHidden(validated, { repairs, probeRef: baseBranchRef });
|
|
225
188
|
return validated;
|
|
226
189
|
}
|