mandrel 2.59.0 → 2.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +11 -9
- package/.agents/agents/acceptance-critic.md +24 -43
- package/.agents/agents/story-worker.md +18 -19
- package/.agents/docs/SDLC.md +6 -6
- package/.agents/docs/agentrc-reference.json +1 -2
- package/.agents/docs/configuration.md +29 -46
- package/.agents/docs/quality-gates.md +8 -4
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +4 -5
- package/.agents/rules/ci-remediation.md +41 -8
- package/.agents/rules/known-tooling-behavior.md +65 -15
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +6 -11
- package/.agents/schemas/story-deliver-terminal.schema.json +3 -3
- package/.agents/scripts/README.md +11 -1
- package/.agents/scripts/acceptance-eval.js +25 -27
- package/.agents/scripts/ceremony-derive.js +15 -10
- package/.agents/scripts/check-context-budget.js +148 -228
- package/.agents/scripts/check-schema-references.js +5 -3
- package/.agents/scripts/check-workflow-citations.js +33 -147
- package/.agents/scripts/coverage-capture.js +7 -4
- package/.agents/scripts/deliver-light.js +41 -100
- package/.agents/scripts/deliver-run.js +631 -0
- package/.agents/scripts/file-ci-gap.js +59 -11
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +6 -2
- package/.agents/scripts/lib/changed-files.js +30 -0
- package/.agents/scripts/lib/config/delivery-routing.js +5 -4
- package/.agents/scripts/lib/config/explain.js +1 -3
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +1 -1
- package/.agents/scripts/lib/config-resolver.js +1 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +28 -21
- package/.agents/scripts/lib/coverage-capture-fullscope.js +10 -2
- package/.agents/scripts/lib/coverage-capture-incremental.js +3 -2
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -1
- package/.agents/scripts/lib/doc-tiers.js +4 -2
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +7 -6
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +7 -5
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/gh-exec.js +160 -0
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +74 -132
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +123 -12
- package/.agents/scripts/lib/orchestration/complexity-gate.js +180 -352
- package/.agents/scripts/lib/orchestration/light-suitability.js +71 -136
- package/.agents/scripts/lib/orchestration/plan-context.js +13 -25
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +8 -6
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +76 -95
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +35 -18
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +11 -11
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +63 -29
- package/.agents/scripts/lib/orchestration/review-depth.js +14 -11
- package/.agents/scripts/lib/orchestration/run-epilogue.js +260 -182
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +63 -99
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +3 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +137 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +105 -18
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -3
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +156 -39
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +71 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -17
- package/.agents/scripts/lib/orchestration/ticket-validator.js +44 -183
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +14 -25
- package/.agents/scripts/lib/story-body/body-format-lints.js +58 -12
- package/.agents/scripts/lib/story-body/story-body.js +83 -29
- package/.agents/scripts/lib/templates/decomposer-prompts.js +7 -15
- package/.agents/scripts/lib/wave-runner/live-probe.js +31 -5
- package/.agents/scripts/merge-baseline.js +4 -5
- package/.agents/scripts/plan-context.js +117 -28
- package/.agents/scripts/plan-persist.js +79 -28
- package/.agents/scripts/plan-run-epilogue.js +11 -8
- package/.agents/scripts/pr-watch-with-update.js +9 -2
- package/.agents/scripts/run-verify.js +13 -6
- package/.agents/scripts/single-story-init.js +7 -57
- package/.agents/scripts/stories-wave-tick.js +160 -26
- package/.agents/skills/core/gates-and-baselines/reference.md +0 -1
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/skills/stack/qa/playwright/SKILL.md +26 -0
- package/.agents/workflows/helpers/acceptance-self-eval.md +84 -157
- package/.agents/workflows/helpers/code-review.md +4 -2
- package/.agents/workflows/helpers/deliver-digest.md +31 -24
- package/.agents/workflows/helpers/deliver-light.md +92 -101
- package/.agents/workflows/helpers/deliver-reference.md +116 -100
- package/.agents/workflows/helpers/deliver-story-reference.md +58 -124
- package/.agents/workflows/helpers/deliver-story.md +17 -18
- package/.agents/workflows/helpers/plan-reference.md +65 -54
- package/.agents/workflows/mandrel-deliver.md +47 -31
- package/.agents/workflows/mandrel-plan.md +22 -21
- package/.agents/workflows/mandrel-update.md +36 -21
- package/docs/CHANGELOG.md +35 -0
- package/lib/cli/update.js +376 -17
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +40 -0
- package/package.json +2 -1
- package/.agents/schemas/model-attribution.schema.json +0 -53
- package/.agents/scripts/lib/orchestration/model-attribution.js +0 -418
- package/.agents/scripts/lib/orchestration/story-plan-state.js +0 -33
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +0 -67
|
@@ -35,7 +35,11 @@ import {
|
|
|
35
35
|
INTAKE_VERDICTS,
|
|
36
36
|
REFUSED_VERDICT,
|
|
37
37
|
} from './lib/orchestration/ci-gap-intake.js';
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
RERUN_ALLOWANCE_VERDICTS,
|
|
40
|
+
readCiDigest,
|
|
41
|
+
recordRerunAllowance,
|
|
42
|
+
} from './lib/orchestration/ci-rerun-guard.js';
|
|
39
43
|
import {
|
|
40
44
|
STATE_LABELS,
|
|
41
45
|
transitionTicketState,
|
|
@@ -55,7 +59,7 @@ const USAGE = {
|
|
|
55
59
|
],
|
|
56
60
|
[
|
|
57
61
|
'--verdict <verdict>',
|
|
58
|
-
`One of ${INTAKE_VERDICTS.join(' | ')}. "${REFUSED_VERDICT}" is refused: it routes to Option 1, fix at source.`,
|
|
62
|
+
`One of ${INTAKE_VERDICTS.join(' | ')}. "${REFUSED_VERDICT}" is refused: it routes to Option 1, fix at source. ${RERUN_ALLOWANCE_VERDICTS.join(' / ')} also record the one-rerun allowance on the CI digest.`,
|
|
59
63
|
],
|
|
60
64
|
[
|
|
61
65
|
'--owner <bucket>',
|
|
@@ -138,7 +142,12 @@ function liveIntakePorts({ provider, searchRepo, cwd, logger }) {
|
|
|
138
142
|
* @param {object} opts
|
|
139
143
|
* @returns {string}
|
|
140
144
|
*/
|
|
141
|
-
export function renderFrictionComment({
|
|
145
|
+
export function renderFrictionComment({
|
|
146
|
+
verdict,
|
|
147
|
+
result,
|
|
148
|
+
digest,
|
|
149
|
+
rerunAllowance = null,
|
|
150
|
+
}) {
|
|
142
151
|
const target = result.issue?.url ?? result.issue?.number ?? '(not filed)';
|
|
143
152
|
const lines = [
|
|
144
153
|
`### CI gap filed — verdict \`${verdict}\``,
|
|
@@ -158,14 +167,31 @@ export function renderFrictionComment({ verdict, result, digest }) {
|
|
|
158
167
|
`- **Routing:** deferred from \`${result.routing.deferredFrom}\` (${result.routing.deferralReason}) — filed locally instead.`,
|
|
159
168
|
);
|
|
160
169
|
}
|
|
161
|
-
lines.push(
|
|
162
|
-
'',
|
|
163
|
-
'This verdict does **not** license a re-run of the failed job. Graduate the',
|
|
164
|
-
'intake issue with `/mandrel-plan <issue number>` to turn it into a Story.',
|
|
165
|
-
);
|
|
170
|
+
lines.push('', renderRerunLine(rerunAllowance), GRADUATE_LINE);
|
|
166
171
|
return lines.join('\n');
|
|
167
172
|
}
|
|
168
173
|
|
|
174
|
+
/** The graduation instruction every filing carries, verdict-independent. */
|
|
175
|
+
const GRADUATE_LINE =
|
|
176
|
+
'Graduate the intake issue with `/mandrel-plan <issue number>` to turn it into a Story.';
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* What this filing says about rerunning the failed job (Story #5343). An
|
|
180
|
+
* allowance is stated with its head SHA and its one-shot bound, because the
|
|
181
|
+
* comment is where an operator reads whether the rerun they are about to do
|
|
182
|
+
* is the sanctioned one.
|
|
183
|
+
*
|
|
184
|
+
* @param {{ headSha: string } | null} rerunAllowance
|
|
185
|
+
* @returns {string}
|
|
186
|
+
*/
|
|
187
|
+
function renderRerunLine(rerunAllowance) {
|
|
188
|
+
return rerunAllowance
|
|
189
|
+
? 'This verdict is environmental and proven, so **one** rerun of the failed ' +
|
|
190
|
+
`job is now admitted on head \`${rerunAllowance.headSha}\` — and one only. ` +
|
|
191
|
+
'A second red after it is real and routes to Option 1.'
|
|
192
|
+
: 'This verdict does **not** license a re-run of the failed job.';
|
|
193
|
+
}
|
|
194
|
+
|
|
169
195
|
/**
|
|
170
196
|
* File the CI-gap intake issue for one Story, post the `friction` comment,
|
|
171
197
|
* and optionally flip the Story to `agent::blocked`.
|
|
@@ -198,7 +224,12 @@ export async function runFileCiGap({
|
|
|
198
224
|
throw new Error('--story <id> is required (a positive issue number).');
|
|
199
225
|
}
|
|
200
226
|
const resolved = config ?? resolveConfig();
|
|
201
|
-
|
|
227
|
+
// The digest's temp root, resolved exactly as `pr-watch-with-update.js`
|
|
228
|
+
// resolves it when it WRITES the digest — the CLI never passed one, so the
|
|
229
|
+
// default read crashed on `undefined` before it could find the file.
|
|
230
|
+
const digestRoot = tempRoot ?? resolved?.project?.paths?.tempRoot ?? 'temp';
|
|
231
|
+
const ciDigest =
|
|
232
|
+
digest ?? readCiDigest({ storyId: sid, tempRoot: digestRoot, cwd });
|
|
202
233
|
if (!ciDigest) {
|
|
203
234
|
throw new Error(
|
|
204
235
|
`no CI digest for Story #${sid}. The digest is written by \`pr-watch-with-update.js --story ${sid}\` on the first red; without it there is no run link or failure signature to file.`,
|
|
@@ -237,9 +268,26 @@ export async function runFileCiGap({
|
|
|
237
268
|
now,
|
|
238
269
|
});
|
|
239
270
|
|
|
271
|
+
// Story #5343 — a proven-environmental verdict earns the one same-SHA
|
|
272
|
+
// rerun the watcher's guard will admit. Recorded on the digest, keyed to
|
|
273
|
+
// the head SHA the red was observed on, and never on a dry run.
|
|
274
|
+
const rerunAllowance = dryRun
|
|
275
|
+
? null
|
|
276
|
+
: recordRerunAllowance({
|
|
277
|
+
storyId: sid,
|
|
278
|
+
verdict,
|
|
279
|
+
tempRoot: digestRoot,
|
|
280
|
+
cwd,
|
|
281
|
+
});
|
|
282
|
+
|
|
240
283
|
const actions = { commented: false, blocked: false };
|
|
241
284
|
if (!dryRun && ticketing) {
|
|
242
|
-
const body = renderFrictionComment({
|
|
285
|
+
const body = renderFrictionComment({
|
|
286
|
+
verdict,
|
|
287
|
+
result,
|
|
288
|
+
digest: ciDigest,
|
|
289
|
+
rerunAllowance,
|
|
290
|
+
});
|
|
243
291
|
try {
|
|
244
292
|
await upsertStructuredComment(ticketing, sid, 'friction', body);
|
|
245
293
|
actions.commented = true;
|
|
@@ -258,7 +306,7 @@ export async function runFileCiGap({
|
|
|
258
306
|
}
|
|
259
307
|
}
|
|
260
308
|
|
|
261
|
-
return { storyId: sid, verdict, ...result, actions };
|
|
309
|
+
return { storyId: sid, verdict, ...result, actions, rerunAllowance };
|
|
262
310
|
}
|
|
263
311
|
|
|
264
312
|
/**
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* so the Story's opt-in wiring lands as new code, not a same-file expansion
|
|
7
7
|
* of the pre-existing preview runner.
|
|
8
8
|
*/
|
|
9
|
-
import { getChangedFiles } from '../changed-files.js';
|
|
9
|
+
import { getChangedFiles, resolveChangedFilesRef } from '../changed-files.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Resolve the `incremental` option `scanAndScore` (`crap-utils.js`) expects,
|
|
@@ -14,6 +14,10 @@ import { getChangedFiles } from '../changed-files.js';
|
|
|
14
14
|
* not be resolved — a resolution failure falls back to full-scope rather
|
|
15
15
|
* than silently relaxing the gate.
|
|
16
16
|
*
|
|
17
|
+
* The join's ref comes from `resolveChangedFilesRef` (Story #5365), the same
|
|
18
|
+
* rule capture applies: the `--changed-since` ref the preview was handed wins
|
|
19
|
+
* over a configured `baseRef`, so one hook invocation cannot resolve two.
|
|
20
|
+
*
|
|
17
21
|
* Gated by `incrementalCoverage.baselineJoin` alone (Story #5173). It MUST
|
|
18
22
|
* NOT consult `skipWhenUnchanged`: the join loosens what the gate demands,
|
|
19
23
|
* while the skip only decides whether a capture runs, so a consumer that took
|
|
@@ -36,7 +40,7 @@ export function resolveCrapPreviewIncremental({
|
|
|
36
40
|
getChangedFilesImpl = getChangedFiles,
|
|
37
41
|
}) {
|
|
38
42
|
if (crap.incrementalCoverage?.baselineJoin !== true) return null;
|
|
39
|
-
const baseRef = crap
|
|
43
|
+
const baseRef = resolveChangedFilesRef({ crap, ref: diffRef });
|
|
40
44
|
try {
|
|
41
45
|
const touchedFiles = new Set(getChangedFilesImpl({ ref: baseRef, cwd }));
|
|
42
46
|
return { touchedFiles, baselineRows };
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { createGitInterface } from './git-utils.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the ONE git ref a step of the pre-push chain computes its
|
|
5
|
+
* changed-file set against — the whole rule, stated once (Story #5365).
|
|
6
|
+
*
|
|
7
|
+
* **A ref the caller named wins; `crap.incrementalCoverage.baseRef` is the
|
|
8
|
+
* default for a caller that named none, and `main` the default for neither.**
|
|
9
|
+
* `.husky/pre-push` captures coverage at `--ref origin/main` and then previews
|
|
10
|
+
* CRAP at `--changed-since origin/main`, and the preview only reads its own
|
|
11
|
+
* tree when the artifact under it was captured over the same change set.
|
|
12
|
+
* Letting the configured value outrank the named ref meant a consumer that set
|
|
13
|
+
* `baseRef` captured one scope while the preview scored another — precisely
|
|
14
|
+
* the stale-artifact read the capture-before-preview ordering (Story #5356)
|
|
15
|
+
* closed. This repository sets no `baseRef`, so that divergence was invisible
|
|
16
|
+
* locally and only a consumer who configured one would have paid for it.
|
|
17
|
+
*
|
|
18
|
+
* Callers that name no ref — the close-validation gate, whose argv carries no
|
|
19
|
+
* `--ref` — still get the configured value, so the key keeps the meaning it
|
|
20
|
+
* was added with.
|
|
21
|
+
*
|
|
22
|
+
* Every step that derives that change set calls this: both `coverage-capture`
|
|
23
|
+
* paths and the preview's CRAP baseline join. A new consumer routes through it
|
|
24
|
+
* rather than reading `baseRef` itself.
|
|
25
|
+
*
|
|
26
|
+
* @param {{ crap: object, ref: string | null | undefined }} opts
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function resolveChangedFilesRef({ crap, ref }) {
|
|
30
|
+
return ref ?? crap?.incrementalCoverage?.baseRef ?? 'main';
|
|
31
|
+
}
|
|
32
|
+
|
|
3
33
|
/**
|
|
4
34
|
* Parse the stdout from `git diff --name-only` into a normalized file list.
|
|
5
35
|
* Trims whitespace, drops blank lines, and converts backslash separators to
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
* Stage 6 dropped `delivery.routing.singleDelivery` (the v1 epic
|
|
6
6
|
* single-vs-fan-out kill-switch). Story #5313 dropped
|
|
7
7
|
* `delivery.routing.freshCriticSampleRate` (the maker-checker sampling
|
|
8
|
-
* floor)
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* floor), and Story #5343 dropped the derived-level routing that replaced
|
|
9
|
+
* it: `minimal` and `standard` resolve the inline self-eval as the Story's
|
|
10
|
+
* verdict owner whatever the diff touches, and `strict` is the one profile
|
|
11
|
+
* that spawns a fresh-context critic. v2 has one Story delivery path;
|
|
12
|
+
* routing here is only about spawn boot context and the ceremony profile.
|
|
12
13
|
*
|
|
13
14
|
* `delivery.routing.roleScopedAgents` is the **kill-switch for the role-scoped
|
|
14
15
|
* boot contexts** (Epic #4478, M7-B). It defaults to `true`: a converted spawn
|
|
@@ -159,11 +159,9 @@ const KEY_MEANINGS = Object.freeze({
|
|
|
159
159
|
'delivery.routing.roleScopedAgents':
|
|
160
160
|
'Whether delivery spawns boot on role-scoped .claude/agents/<role>.md contexts.',
|
|
161
161
|
'delivery.routing.ceremonyProfile':
|
|
162
|
-
'
|
|
162
|
+
'Who authors the Story acceptance verdict: minimal and standard = the inline self-eval, strict = a fresh maker-blind critic.',
|
|
163
163
|
'delivery.routing.closeAndLand':
|
|
164
164
|
'When true, single-story-close lands through merge in one close (opt out with --no-wait-merge).',
|
|
165
|
-
'delivery.feedbackLoop.auditResultsAutoFile':
|
|
166
|
-
'When true, auto-file non-blocking audit findings as follow-up issues.',
|
|
167
165
|
'delivery.feedbackLoop.retroProposals':
|
|
168
166
|
'When true, auto-file actionable retro proposals as follow-up issues.',
|
|
169
167
|
'delivery.quality.formatAutofix.timeoutMs':
|
|
@@ -53,7 +53,7 @@ export const INCREMENTAL_COVERAGE_SCHEMA = {
|
|
|
53
53
|
type: 'string',
|
|
54
54
|
minLength: 1,
|
|
55
55
|
description:
|
|
56
|
-
'
|
|
56
|
+
'Default git ref the changed-file set is computed against, for a caller that passes no `--ref`. A `--ref` the caller named wins over this value, so a caller that anchors another gate on the same ref — `.husky/pre-push`, which passes `--ref origin/main` and then previews `--changed-since origin/main` — resolves ONE scope for both steps (Story #5365). Omitted and unpassed, the gate’s own default `main` applies.',
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
59
|
additionalProperties: false,
|
|
@@ -62,6 +62,7 @@ export { resolveListValue } from './config/shared.js';
|
|
|
62
62
|
export { validateOrchestrationConfig } from './config/validate-orchestration.js';
|
|
63
63
|
export {
|
|
64
64
|
defaultNodeModulesStrategy,
|
|
65
|
+
getWorktreeIsolation,
|
|
65
66
|
WORKTREE_ISOLATION_DEFAULTS,
|
|
66
67
|
} from './config/worktree-isolation.js';
|
|
67
68
|
export { PROJECT_ROOT } from './project-root.js';
|
|
@@ -258,12 +258,12 @@ const MERGE_WATCH_SCHEMA = {
|
|
|
258
258
|
// context; false falls back to `subagent_type: general-purpose` (the instant
|
|
259
259
|
// per-consumer revert + the escape for hosts that ignore `.claude/agents/`).
|
|
260
260
|
// Story #5313 retired `delivery.routing.freshCriticSampleRate` (the
|
|
261
|
-
// maker-checker sampling floor)
|
|
262
|
-
// the
|
|
261
|
+
// maker-checker sampling floor). Story #5343 then retired the derived-level
|
|
262
|
+
// routing it left behind: the profile alone decides the verdict owner.
|
|
263
263
|
const ROUTING_SCHEMA = {
|
|
264
264
|
type: 'object',
|
|
265
265
|
description:
|
|
266
|
-
'v2 delivery-spawn routing: role-scoped boot contexts and the ceremony profile. The v1 singleDelivery epic-route kill-switch was removed in Stage 6; the freshCriticSampleRate sampling floor was retired in Story #5313.',
|
|
266
|
+
'v2 delivery-spawn routing: role-scoped boot contexts and the ceremony profile. The v1 singleDelivery epic-route kill-switch was removed in Stage 6; the freshCriticSampleRate sampling floor was retired in Story #5313 and the derived-level ceremony routing in Story #5343.',
|
|
267
267
|
properties: {
|
|
268
268
|
roleScopedAgents: {
|
|
269
269
|
type: 'boolean',
|
|
@@ -275,7 +275,7 @@ const ROUTING_SCHEMA = {
|
|
|
275
275
|
type: 'string',
|
|
276
276
|
enum: ['minimal', 'standard', 'strict'],
|
|
277
277
|
description:
|
|
278
|
-
'Acceptance-ceremony depth. minimal =
|
|
278
|
+
'Acceptance-ceremony depth — who authors the Story acceptance verdict. minimal and standard (default) = the inline self-eval, whatever the diff touches; strict = a fresh-context maker-blind critic. Review depth is a separate decision and still derives `deep` for any sensitive path (review-depth.js).',
|
|
279
279
|
default: DELIVERY_ROUTING_DEFAULTS.ceremonyProfile,
|
|
280
280
|
},
|
|
281
281
|
closeAndLand: {
|
|
@@ -452,18 +452,31 @@ const REVIEW_SCHEMA = {
|
|
|
452
452
|
};
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
|
-
* `delivery.feedbackLoop` — opt-
|
|
456
|
-
*
|
|
457
|
-
* via `graduator-core.js#makeIsAutoFileEnabled`)
|
|
458
|
-
* (auto-file on); set any to `false` to suppress auto-filing the
|
|
459
|
-
* corresponding non-blocking findings as follow-up issues.
|
|
455
|
+
* `delivery.feedbackLoop` — the **opt-in** toggle consumed by the retro
|
|
456
|
+
* auto-file graduator (`lib/feedback-loop/retro-proposals-graduator.js`, read
|
|
457
|
+
* via `graduator-core.js#makeIsAutoFileEnabled`), plus the friction window.
|
|
460
458
|
*
|
|
461
|
-
* `
|
|
462
|
-
*
|
|
459
|
+
* `auditResultsAutoFile` used to sit beside `retroProposals` here. Its
|
|
460
|
+
* graduator was deleted two releases ago, so by Story #5341 — which flipped
|
|
461
|
+
* its default from `true` to `false` on the measured record of what the
|
|
462
|
+
* channel produced — there was nothing left to switch either way. Story #5366
|
|
463
|
+
* removed the key: a toggle with no runtime reader reads as a live control,
|
|
464
|
+
* and a consumer that set it was configuring nothing. The
|
|
465
|
+
* `2.60.0-retire-audit-results-autofile` migration strips it from both config
|
|
466
|
+
* surfaces, because this block is closed to additional properties and a
|
|
467
|
+
* surviving key is a hard validation failure on upgrade.
|
|
468
|
+
*
|
|
469
|
+
* `retroProposals` (Story #4418) governs the retro auto-filer, and defaults to
|
|
470
|
+
* `false` for the same Story #5341 reasons: Story #5324's roll-up carried 116
|
|
471
|
+
* signals and filed nothing, and issues #4653, #4833, #4834 and #4836 are
|
|
472
|
+
* filings that were false or leaked from test fixtures. An auto-filer whose
|
|
473
|
+
* output is dominated by noise costs triage on every run and buys nothing, so
|
|
474
|
+
* a consumer that wants it now asks for it. When `true` the
|
|
475
|
+
* retro's actionable routed proposals are filed as
|
|
463
476
|
* `meta::<framework-gap|consumer-improvement>` + `friction::<category>`
|
|
464
477
|
* issues via the graduator pre-parsed-findings seam, and the rendered retro
|
|
465
478
|
* sections list the filed issue numbers instead of paste-ready `gh` command
|
|
466
|
-
* stanzas;
|
|
479
|
+
* stanzas; left `false` it renders the command stanzas.
|
|
467
480
|
*
|
|
468
481
|
* `frictionWindowDays` (Story #4850) bounds the run-scope friction recurrence
|
|
469
482
|
* window by row age. The window deliberately spans every surviving signal
|
|
@@ -475,19 +488,13 @@ const REVIEW_SCHEMA = {
|
|
|
475
488
|
const FEEDBACK_LOOP_SCHEMA = {
|
|
476
489
|
type: 'object',
|
|
477
490
|
description:
|
|
478
|
-
'Opt-
|
|
491
|
+
'Opt-in toggle for the close-time retro auto-file graduator, plus the friction recurrence window. Auto-filing defaults to OFF (Story #5341).',
|
|
479
492
|
properties: {
|
|
480
|
-
auditResultsAutoFile: {
|
|
481
|
-
type: 'boolean',
|
|
482
|
-
description:
|
|
483
|
-
'When true (default), the close-time audit-results graduator auto-files non-blocking audit-results findings as follow-up issues routed by source classification. Set to false to suppress auto-filing; findings remain accessible in the structured comments on the Story.',
|
|
484
|
-
default: true,
|
|
485
|
-
},
|
|
486
493
|
retroProposals: {
|
|
487
494
|
type: 'boolean',
|
|
488
495
|
description:
|
|
489
|
-
'When true
|
|
490
|
-
default:
|
|
496
|
+
'When true, the retro auto-files its actionable routed proposals as meta::<framework-gap|consumer-improvement> + friction::<category> issues via the graduator pre-parsed-findings seam, and the rendered retro sections list the filed issue numbers instead of paste-ready gh command stanzas. Defaults to false (Story #5341), which renders the command stanzas instead.',
|
|
497
|
+
default: false,
|
|
491
498
|
},
|
|
492
499
|
frictionWindowDays: {
|
|
493
500
|
type: 'integer',
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* logic; behaviour is byte-for-byte the pre-#4981 body.
|
|
9
9
|
*/
|
|
10
10
|
import path from 'node:path';
|
|
11
|
+
import { resolveChangedFilesRef } from './changed-files.js';
|
|
11
12
|
import {
|
|
12
13
|
anyChangedUnderTargets,
|
|
13
14
|
describeFreshness,
|
|
@@ -19,10 +20,14 @@ import {
|
|
|
19
20
|
* content-digest freshness probe, and — when stale — the full-repo
|
|
20
21
|
* `npm run test:coverage` capture + stamp write.
|
|
21
22
|
*
|
|
23
|
+
* The skip check scores the ref `resolveChangedFilesRef` resolves — the rule,
|
|
24
|
+
* and the same answer, incremental mode applies, so a fall-through from it
|
|
25
|
+
* cannot change scope mid-run (Story #5365).
|
|
26
|
+
*
|
|
22
27
|
* @param {{
|
|
23
28
|
* crap: object,
|
|
24
29
|
* coverage: object,
|
|
25
|
-
* args: { skipWhenNoCrapFiles: boolean, ref: string, cwd: string },
|
|
30
|
+
* args: { skipWhenNoCrapFiles: boolean, ref: string | null, cwd: string },
|
|
26
31
|
* getChangedFilesImpl: Function,
|
|
27
32
|
* isCoverageFreshImpl: Function,
|
|
28
33
|
* runCaptureImpl: Function,
|
|
@@ -46,7 +51,10 @@ export function runFullScopeCapture({
|
|
|
46
51
|
if (args.skipWhenNoCrapFiles) {
|
|
47
52
|
let changed;
|
|
48
53
|
try {
|
|
49
|
-
changed = getChangedFilesImpl({
|
|
54
|
+
changed = getChangedFilesImpl({
|
|
55
|
+
ref: resolveChangedFilesRef({ crap, ref: args.ref }),
|
|
56
|
+
cwd: args.cwd,
|
|
57
|
+
});
|
|
50
58
|
} catch (err) {
|
|
51
59
|
// A bad ref must not silently relax the gate. Fall through to the
|
|
52
60
|
// freshness check so coverage still gets captured if needed.
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* parameter (`.agents/rules/test-seams.md` rules 1-2, 4).
|
|
10
10
|
*/
|
|
11
11
|
import path from 'node:path';
|
|
12
|
+
import { resolveChangedFilesRef } from './changed-files.js';
|
|
12
13
|
import { stampCapturedTree } from './coverage-capture.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -38,7 +39,7 @@ import { stampCapturedTree } from './coverage-capture.js';
|
|
|
38
39
|
* @param {{
|
|
39
40
|
* crap: object,
|
|
40
41
|
* coverage: object,
|
|
41
|
-
* args: { ref: string, cwd: string },
|
|
42
|
+
* args: { ref: string | null, cwd: string },
|
|
42
43
|
* getChangedFilesImpl: Function,
|
|
43
44
|
* filterFilesUnderTargetsImpl: Function,
|
|
44
45
|
* isCoverageFreshImpl: Function,
|
|
@@ -63,7 +64,7 @@ export function tryIncrementalCapture({
|
|
|
63
64
|
}) {
|
|
64
65
|
if (crap.incrementalCoverage?.skipWhenUnchanged !== true) return null;
|
|
65
66
|
|
|
66
|
-
const ref = crap
|
|
67
|
+
const ref = resolveChangedFilesRef({ crap, ref: args.ref });
|
|
67
68
|
let changed = null;
|
|
68
69
|
try {
|
|
69
70
|
changed = getChangedFilesImpl({ ref, cwd: args.cwd });
|
|
@@ -39,7 +39,10 @@ const COVERAGE_CAPTURE_USAGE = {
|
|
|
39
39
|
'--require-credited',
|
|
40
40
|
'Refuse (exit 1) instead of spawning when no credited capture stamp covers this tree. Passed by the close gate when delivery.execution.requireCreditedCapture is set; a bare invocation always runs, so the deposit path stays open.',
|
|
41
41
|
],
|
|
42
|
-
[
|
|
42
|
+
[
|
|
43
|
+
'--ref <git-ref>',
|
|
44
|
+
'Git ref the changed-file set is computed against. Passing it wins over delivery.quality.gates.crap.incrementalCoverage.baseRef, so a caller that anchors another gate on the same ref gets one scope for both.',
|
|
45
|
+
],
|
|
43
46
|
['--cwd <path>', 'Repository root the capture runs in.'],
|
|
44
47
|
],
|
|
45
48
|
};
|
|
@@ -27,8 +27,10 @@
|
|
|
27
27
|
* - `agentBoot` — the role-scoped boot contexts `.agents/agents/*.md`
|
|
28
28
|
* (issue #4478). Each is a standalone system prompt a
|
|
29
29
|
* converted spawn boots on **instead of** the always-loaded
|
|
30
|
-
* closure, so it is
|
|
31
|
-
* ceiling
|
|
30
|
+
* closure, so it is measured independently. Its per-file
|
|
31
|
+
* 8 KB ceiling was deleted by Story #5340;
|
|
32
|
+
* `check-context-budget.js` now reports these sizes and
|
|
33
|
+
* gates nothing on them.
|
|
32
34
|
* - `workflow` / — the `.agents/workflows/**` read-tier (Story #4752),
|
|
33
35
|
* `workflowOnDemand` resolved as each entry point's transitive
|
|
34
36
|
* markdown-link closure by
|
|
@@ -290,18 +290,19 @@ export function runChild({
|
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
292
|
* Build an `isAutoFileEnabled(config)` reader bound to a specific
|
|
293
|
-
* `delivery.feedbackLoop.<key>` toggle. The feature is opt-
|
|
294
|
-
* toggle defaults to `
|
|
293
|
+
* `delivery.feedbackLoop.<key>` toggle. The feature is **opt-in** since Story
|
|
294
|
+
* #5341: the toggle defaults to `false` and only an explicit `true` enables
|
|
295
|
+
* it, because the filings the channel produced unattended were dominated by
|
|
296
|
+
* noise (see `config-settings-schema-delivery.js` for the measured record).
|
|
295
297
|
*
|
|
296
298
|
* @param {string} toggleKey — key under `config.delivery.feedbackLoop`
|
|
297
|
-
* (
|
|
299
|
+
* (today, only "retroProposals" — the factory stays keyed so the next
|
|
300
|
+
* graduator does not have to reinvent the resolution)
|
|
298
301
|
* @returns {(config: object|undefined|null) => boolean}
|
|
299
302
|
*/
|
|
300
303
|
export function makeIsAutoFileEnabled(toggleKey) {
|
|
301
304
|
return function isAutoFileEnabled(config) {
|
|
302
|
-
|
|
303
|
-
if (value === false) return false;
|
|
304
|
-
return true;
|
|
305
|
+
return config?.delivery?.feedbackLoop?.[toggleKey] === true;
|
|
305
306
|
};
|
|
306
307
|
}
|
|
307
308
|
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
* is gone from the whole path, not just from this module. The `meta::<framework-gap|consumer-improvement>` +
|
|
29
29
|
* `friction::<category>` labels are lifted verbatim from the routed item.
|
|
30
30
|
*
|
|
31
|
-
* Behind the `delivery.feedbackLoop.retroProposals` toggle (default
|
|
32
|
-
* per `graduator-core.js#makeIsAutoFileEnabled`). NEVER
|
|
33
|
-
* failure path is captured in `errors[]`.
|
|
31
|
+
* Behind the `delivery.feedbackLoop.retroProposals` toggle (default OFF
|
|
32
|
+
* since Story #5341, per `graduator-core.js#makeIsAutoFileEnabled`). NEVER
|
|
33
|
+
* throws — every failure path is captured in `errors[]`.
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
import {
|
|
@@ -46,8 +46,10 @@ import {
|
|
|
46
46
|
} from './graduator-core.js';
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Resolve the toggle from the resolved agentrc config. Defaults to `
|
|
50
|
-
* — the feature is opt-
|
|
49
|
+
* Resolve the toggle from the resolved agentrc config. Defaults to `false`
|
|
50
|
+
* — the feature is opt-in (Story #5341). It is now the only such toggle: the
|
|
51
|
+
* audit-results sibling was removed by Story #5366, its graduator having been
|
|
52
|
+
* deleted two releases earlier.
|
|
51
53
|
*
|
|
52
54
|
* @param {object|undefined|null} config
|
|
53
55
|
* @returns {boolean}
|