intentdna 1.6.3 → 1.6.4
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.
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "intentdna",
|
|
11
11
|
"description": "Declarative policy layer for AI agent behavior with plugin-managed hook runtime for Claude Code.",
|
|
12
|
-
"version": "1.6.
|
|
12
|
+
"version": "1.6.4",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Samuel"
|
|
15
15
|
},
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
]
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
|
-
"version": "1.6.
|
|
28
|
+
"version": "1.6.4"
|
|
29
29
|
}
|
|
@@ -12,7 +12,7 @@ import { toKebabCase } from "./agent-md.js";
|
|
|
12
12
|
const SENTINEL = "<!-- intentdna:managed — do not edit manually -->";
|
|
13
13
|
// ── Compile Controller → Skill ─────────────────────────────
|
|
14
14
|
export function compileControllerToSkill(controllerKey, controller, variables, workflows) {
|
|
15
|
-
if (controller.kind !== "flutter_rewrite_fix_loop") {
|
|
15
|
+
if (controller.kind !== "fix_loop" && controller.kind !== "flutter_rewrite_fix_loop") {
|
|
16
16
|
throw new Error(`Unsupported controller kind: ${controller.kind}`);
|
|
17
17
|
}
|
|
18
18
|
const skillName = `dna-${toKebabCase(controllerKey)}`;
|
|
@@ -29,6 +29,7 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
29
29
|
const reviewChangesStep = requireStepByRole(fixWorkflow, controller.roles.fix_reviewer, controller.fix_workflow);
|
|
30
30
|
const verifyReportStep = requireStepByRole(fixWorkflow, controller.roles.test_runner, controller.fix_workflow);
|
|
31
31
|
const stepPrompt = (step) => step.prompt || step.description || "";
|
|
32
|
+
const policy = normalizeControllerPolicy(controller);
|
|
32
33
|
const lines = [];
|
|
33
34
|
lines.push("---");
|
|
34
35
|
lines.push(`name: ${skillName}`);
|
|
@@ -49,7 +50,7 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
49
50
|
lines.push("</Purpose>");
|
|
50
51
|
lines.push("");
|
|
51
52
|
lines.push("<Controller>");
|
|
52
|
-
lines.push(
|
|
53
|
+
lines.push(`kind: ${controller.kind}`);
|
|
53
54
|
lines.push(`max_rounds: ${controller.max_rounds}`);
|
|
54
55
|
lines.push(`diagnosis_workflow: ${controller.diagnosis_workflow}`);
|
|
55
56
|
lines.push(`fix_workflow: ${controller.fix_workflow}`);
|
|
@@ -59,7 +60,7 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
59
60
|
lines.push("<Steps>");
|
|
60
61
|
lines.push("0. Validate the module argument before using it in any artifact path.");
|
|
61
62
|
lines.push(" - The module argument must match /^[A-Za-z0-9_-]+$/.");
|
|
62
|
-
lines.push(" - If it contains '/', '.', '..', spaces, braces, glob characters, or path separators, stop with the
|
|
63
|
+
lines.push(" - If it contains '/', '.', '..', spaces, braces, glob characters, or path separators, stop with the configured stop report.");
|
|
63
64
|
lines.push(" - Do not read or write controller artifacts until the module argument is safe.");
|
|
64
65
|
lines.push("1. Check diagnosis artifact freshness before any fix round.");
|
|
65
66
|
lines.push(` - Diagnosis artifact: ${controller.diagnosis_artifact_path}`);
|
|
@@ -68,12 +69,9 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
68
69
|
lines.push(" - Reuse the same controller_run_id in every child Agent prompt and in every progress validation.");
|
|
69
70
|
lines.push(" - Do not regenerate controller_run_id inside fix rounds.");
|
|
70
71
|
lines.push("3. Reuse diagnosis only when all diagnosis reuse criteria pass:");
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
lines.push(" - baseline artifact is not newer than diagnosis spec");
|
|
75
|
-
lines.push(" - user did not explicitly pass reanalyze or scope changed");
|
|
76
|
-
lines.push(" - progress JSON does not say diagnosis_invalid");
|
|
72
|
+
for (const criterion of policy.diagnosis_reuse_criteria) {
|
|
73
|
+
lines.push(` - ${criterion}`);
|
|
74
|
+
}
|
|
77
75
|
lines.push(`4. If diagnosis is missing, invalid, stale, or scope-changed, run diagnosis once with fresh context and sequential gates:`);
|
|
78
76
|
lines.push(" a. Spawn fresh analyzer agent with controller_run_id, then wait for completion.");
|
|
79
77
|
lines.push(" ```");
|
|
@@ -91,7 +89,7 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
91
89
|
lines.push(" )");
|
|
92
90
|
lines.push(" ```");
|
|
93
91
|
lines.push(` d. Diagnosis review JSON gate: read ${controller.diagnosis_review_artifact_path}; require existing valid JSON with verdict APPROVE before fix rounds.`);
|
|
94
|
-
lines.push(" If the review JSON is missing, invalid, or verdict is not APPROVE, stop immediately with the
|
|
92
|
+
lines.push(" If the review JSON is missing, invalid, or verdict is not APPROVE, stop immediately with the configured stop report; do NOT enter fix rounds.");
|
|
95
93
|
lines.push(`5. For round 1..${controller.max_rounds}, set current_round to the loop number and run one fresh context fix round with sequential gates:`);
|
|
96
94
|
lines.push(" a. Spawn fresh surgeon agent with controller_run_id and current_round, then wait for completion.");
|
|
97
95
|
lines.push(" ```");
|
|
@@ -118,43 +116,33 @@ export function compileControllerToSkill(controllerKey, controller, variables, w
|
|
|
118
116
|
lines.push(" ```");
|
|
119
117
|
lines.push(` f. Progress JSON read/provenance validation: read ${controller.progress_artifact_path}. The controller must read this JSON sidecar, not Markdown prose.`);
|
|
120
118
|
lines.push(" g. Verify progress JSON provenance before branching:");
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
lines.push(` -
|
|
125
|
-
lines.push(` - review_artifact equals ${controller.review_artifact_path}`);
|
|
126
|
-
lines.push(" - git_head or last_fix_commit references the current round's fix commit when available");
|
|
127
|
-
lines.push(" - updated_at is not earlier than the current round start time");
|
|
128
|
-
lines.push(" - if provenance is missing, stale, or mismatched, stop with Verdict BLOCKED and failure_reason PROGRESS_PROVENANCE_MISMATCH");
|
|
119
|
+
for (const check of policy.progress_provenance_checks) {
|
|
120
|
+
lines.push(` - ${check}`);
|
|
121
|
+
}
|
|
122
|
+
lines.push(` - ${policy.progress_provenance_failure}`);
|
|
129
123
|
lines.push(" h. Branch only from the JSON verdict:");
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
lines.push(
|
|
134
|
-
lines.push(`6. If max ${controller.max_rounds} rounds is reached, stop with Chinese report.`);
|
|
124
|
+
for (const branch of policy.verdict_branches) {
|
|
125
|
+
lines.push(` - ${branch}`);
|
|
126
|
+
}
|
|
127
|
+
lines.push(`6. If max ${controller.max_rounds} rounds is reached, stop with the configured stop report.`);
|
|
135
128
|
lines.push("</Steps>");
|
|
136
129
|
lines.push("");
|
|
137
130
|
lines.push("<Verdict_Mapping>");
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
lines.push("- REQUEST_CHANGES: stop, report reviewer/verifier requested changes");
|
|
142
|
-
lines.push("- BLOCKED: stop, report blocker");
|
|
143
|
-
lines.push("- MAX_ROUNDS: stop, report max rounds reached and next focus");
|
|
131
|
+
for (const line of policy.verdict_mapping) {
|
|
132
|
+
lines.push(line);
|
|
133
|
+
}
|
|
144
134
|
lines.push("</Verdict_Mapping>");
|
|
145
135
|
lines.push("");
|
|
146
136
|
lines.push("<Stop_Report>");
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
lines.push("下一步:...");
|
|
137
|
+
for (const line of policy.stop_report) {
|
|
138
|
+
lines.push(line);
|
|
139
|
+
}
|
|
151
140
|
lines.push("</Stop_Report>");
|
|
152
141
|
lines.push("");
|
|
153
142
|
lines.push("<Constraints>");
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
lines.push("- Do not use the generic workflow policy block; branch only from the progress JSON verdict.");
|
|
143
|
+
for (const constraint of policy.constraints) {
|
|
144
|
+
lines.push(`- ${constraint}`);
|
|
145
|
+
}
|
|
158
146
|
lines.push("</Constraints>");
|
|
159
147
|
lines.push("");
|
|
160
148
|
let content = lines.join("\n") + "\n";
|
|
@@ -174,6 +162,84 @@ function requireStepByRole(workflow, role, workflowName) {
|
|
|
174
162
|
}
|
|
175
163
|
return step;
|
|
176
164
|
}
|
|
165
|
+
function normalizeControllerPolicy(controller) {
|
|
166
|
+
const defaults = defaultControllerPolicy(controller);
|
|
167
|
+
const policy = {
|
|
168
|
+
diagnosis_reuse_criteria: controller.policy?.diagnosis_reuse_criteria ?? defaults.diagnosis_reuse_criteria,
|
|
169
|
+
progress_provenance_checks: controller.policy?.progress_provenance_checks ?? defaults.progress_provenance_checks,
|
|
170
|
+
progress_provenance_failure: controller.policy?.progress_provenance_failure ?? defaults.progress_provenance_failure,
|
|
171
|
+
verdict_branches: controller.policy?.verdict_branches ?? defaults.verdict_branches,
|
|
172
|
+
verdict_mapping: controller.policy?.verdict_mapping ?? defaults.verdict_mapping,
|
|
173
|
+
stop_report: controller.policy?.stop_report ?? defaults.stop_report,
|
|
174
|
+
constraints: controller.policy?.constraints ?? defaults.constraints,
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
diagnosis_reuse_criteria: renderControllerPolicyLines(policy.diagnosis_reuse_criteria, controller),
|
|
178
|
+
progress_provenance_checks: renderControllerPolicyLines(policy.progress_provenance_checks, controller),
|
|
179
|
+
progress_provenance_failure: renderControllerPolicyText(policy.progress_provenance_failure, controller),
|
|
180
|
+
verdict_branches: renderControllerPolicyLines(policy.verdict_branches, controller),
|
|
181
|
+
verdict_mapping: renderControllerPolicyLines(policy.verdict_mapping, controller),
|
|
182
|
+
stop_report: renderControllerPolicyLines(policy.stop_report, controller),
|
|
183
|
+
constraints: renderControllerPolicyLines(policy.constraints, controller),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function renderControllerPolicyLines(lines, controller) {
|
|
187
|
+
return lines.map((line) => renderControllerPolicyText(line, controller));
|
|
188
|
+
}
|
|
189
|
+
function renderControllerPolicyText(text, controller) {
|
|
190
|
+
const replacements = {
|
|
191
|
+
"$progress_artifact_path": controller.progress_artifact_path,
|
|
192
|
+
"$diagnosis_artifact_path": controller.diagnosis_artifact_path,
|
|
193
|
+
"$diagnosis_review_artifact_path": controller.diagnosis_review_artifact_path,
|
|
194
|
+
"$review_artifact_path": controller.review_artifact_path,
|
|
195
|
+
};
|
|
196
|
+
let rendered = text;
|
|
197
|
+
for (const [token, value] of Object.entries(replacements)) {
|
|
198
|
+
rendered = rendered.replaceAll(token, value);
|
|
199
|
+
}
|
|
200
|
+
return rendered;
|
|
201
|
+
}
|
|
202
|
+
function defaultControllerPolicy(controller) {
|
|
203
|
+
return {
|
|
204
|
+
diagnosis_reuse_criteria: [
|
|
205
|
+
`${controller.diagnosis_artifact_path} exists`,
|
|
206
|
+
`${controller.diagnosis_review_artifact_path} exists and verdict is APPROVE`,
|
|
207
|
+
"the user did not explicitly request reanalysis",
|
|
208
|
+
"progress JSON does not invalidate the diagnosis",
|
|
209
|
+
],
|
|
210
|
+
progress_provenance_checks: [
|
|
211
|
+
"module equals the safe module argument",
|
|
212
|
+
"round equals the provided current_round",
|
|
213
|
+
"run_id equals the provided controller_run_id",
|
|
214
|
+
`diagnosis_artifact equals ${controller.diagnosis_artifact_path}`,
|
|
215
|
+
`review_artifact equals ${controller.review_artifact_path}`,
|
|
216
|
+
"git_head or last_fix_commit references the current round's fix commit when available",
|
|
217
|
+
"updated_at is not earlier than the current round start time",
|
|
218
|
+
],
|
|
219
|
+
progress_provenance_failure: "if provenance is missing, stale, or mismatched, stop with Verdict BLOCKED and failure_reason PROGRESS_PROVENANCE_MISMATCH",
|
|
220
|
+
verdict_branches: [
|
|
221
|
+
"PASS -> success stop",
|
|
222
|
+
"CONTINUE -> next fresh context fix round",
|
|
223
|
+
"REQUEST_CHANGES -> stop with the configured stop report",
|
|
224
|
+
"BLOCKED -> stop with the configured stop report",
|
|
225
|
+
],
|
|
226
|
+
verdict_mapping: [
|
|
227
|
+
"PASS / CONTINUE / REQUEST_CHANGES / BLOCKED mapping:",
|
|
228
|
+
"- PASS: success stop",
|
|
229
|
+
"- CONTINUE: start the next fresh context round",
|
|
230
|
+
"- REQUEST_CHANGES: stop and report the requested changes",
|
|
231
|
+
"- BLOCKED: stop and report the blocker",
|
|
232
|
+
"- MAX_ROUNDS: stop and report max rounds reached",
|
|
233
|
+
],
|
|
234
|
+
stop_report: [
|
|
235
|
+
"On REQUEST_CHANGES, BLOCKED, or MAX_ROUNDS, explain the stop reason, the evidence, and the next action.",
|
|
236
|
+
],
|
|
237
|
+
constraints: [
|
|
238
|
+
`The controller must schedule only from ${controller.progress_artifact_path}.`,
|
|
239
|
+
"Branch only from the progress JSON verdict.",
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
177
243
|
// ── Compile Workflow → Skill ───────────────────────────────
|
|
178
244
|
/**
|
|
179
245
|
* Compile a WorkflowPlan + roles + IR into a SKILL.md file.
|
package/dist/schema/types.d.ts
CHANGED
|
@@ -200,7 +200,16 @@ export interface WorkflowDef {
|
|
|
200
200
|
default_isolation?: "none" | "worktree" | "auto";
|
|
201
201
|
merge_strategy?: "escalate";
|
|
202
202
|
}
|
|
203
|
-
export type ControllerKind = "flutter_rewrite_fix_loop";
|
|
203
|
+
export type ControllerKind = "fix_loop" | "flutter_rewrite_fix_loop";
|
|
204
|
+
export interface ControllerPolicyDef {
|
|
205
|
+
diagnosis_reuse_criteria?: string[];
|
|
206
|
+
progress_provenance_checks?: string[];
|
|
207
|
+
progress_provenance_failure?: string;
|
|
208
|
+
verdict_branches?: string[];
|
|
209
|
+
verdict_mapping?: string[];
|
|
210
|
+
stop_report?: string[];
|
|
211
|
+
constraints?: string[];
|
|
212
|
+
}
|
|
204
213
|
export interface ControllerDef {
|
|
205
214
|
name: string;
|
|
206
215
|
description?: string;
|
|
@@ -219,7 +228,8 @@ export interface ControllerDef {
|
|
|
219
228
|
fix_reviewer: string;
|
|
220
229
|
test_runner: string;
|
|
221
230
|
};
|
|
222
|
-
stop_format: "zh_three_part";
|
|
231
|
+
stop_format: "configured_stop_report" | "zh_three_part";
|
|
232
|
+
policy?: ControllerPolicyDef;
|
|
223
233
|
}
|
|
224
234
|
/** Parallel block syntax sugar — expanded by compiler into steps with depends_on */
|
|
225
235
|
export interface ParallelBlockDef {
|
package/dist/schema/validate.js
CHANGED
|
@@ -308,12 +308,52 @@ function isSafeControllerArtifactPath(path) {
|
|
|
308
308
|
!path.includes("}}") &&
|
|
309
309
|
path.includes("$ARGUMENTS");
|
|
310
310
|
}
|
|
311
|
+
function validateStringList(value, path, errors) {
|
|
312
|
+
if (!Array.isArray(value)) {
|
|
313
|
+
errors.push({ path, message: "must be an array of non-empty strings" });
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
value.forEach((item, index) => {
|
|
317
|
+
if (typeof item !== "string" || item.trim() === "") {
|
|
318
|
+
errors.push({ path: `${path}.${index}`, message: "must be a non-empty string" });
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
function validateControllerPolicy(policy, path, errors) {
|
|
323
|
+
if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
|
|
324
|
+
errors.push({ path, message: "policy must be an object" });
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const record = policy;
|
|
328
|
+
const listFields = [
|
|
329
|
+
"diagnosis_reuse_criteria",
|
|
330
|
+
"progress_provenance_checks",
|
|
331
|
+
"verdict_branches",
|
|
332
|
+
"verdict_mapping",
|
|
333
|
+
"stop_report",
|
|
334
|
+
"constraints",
|
|
335
|
+
];
|
|
336
|
+
const allowedFields = new Set([...listFields, "progress_provenance_failure"]);
|
|
337
|
+
for (const field of Object.keys(record)) {
|
|
338
|
+
if (!allowedFields.has(field)) {
|
|
339
|
+
errors.push({ path: `${path}.${field}`, message: "unknown controller policy field" });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
for (const field of listFields) {
|
|
343
|
+
if (record[field] !== undefined)
|
|
344
|
+
validateStringList(record[field], `${path}.${field}`, errors);
|
|
345
|
+
}
|
|
346
|
+
if (record.progress_provenance_failure !== undefined &&
|
|
347
|
+
(typeof record.progress_provenance_failure !== "string" || record.progress_provenance_failure.trim() === "")) {
|
|
348
|
+
errors.push({ path: `${path}.progress_provenance_failure`, message: "must be a non-empty string" });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
311
351
|
function validateController(controller, roleNames, workflows, path) {
|
|
312
352
|
const errors = [];
|
|
313
353
|
if (!controller.name) {
|
|
314
354
|
errors.push({ path: `${path}.name`, message: "controller requires 'name'" });
|
|
315
355
|
}
|
|
316
|
-
if (controller.kind !== "flutter_rewrite_fix_loop") {
|
|
356
|
+
if (controller.kind !== "fix_loop" && controller.kind !== "flutter_rewrite_fix_loop") {
|
|
317
357
|
errors.push({ path: `${path}.kind`, message: "unsupported controller kind" });
|
|
318
358
|
}
|
|
319
359
|
if (!Number.isInteger(controller.max_rounds) || controller.max_rounds < 1 || controller.max_rounds > 20) {
|
|
@@ -371,8 +411,11 @@ function validateController(controller, roleNames, workflows, path) {
|
|
|
371
411
|
validateControllerWorkflowRoles(diagnosisWorkflow, ["analyzer", "analysis_reviewer"], roleMap, `${path}.diagnosis_workflow`, errors);
|
|
372
412
|
validateControllerWorkflowRoles(fixWorkflow, ["surgeon", "fix_reviewer", "test_runner"], roleMap, `${path}.fix_workflow`, errors);
|
|
373
413
|
}
|
|
374
|
-
if (controller.stop_format !== "zh_three_part") {
|
|
375
|
-
errors.push({ path: `${path}.stop_format`, message: "stop_format must be 'zh_three_part'" });
|
|
414
|
+
if (controller.stop_format !== "configured_stop_report" && controller.stop_format !== "zh_three_part") {
|
|
415
|
+
errors.push({ path: `${path}.stop_format`, message: "stop_format must be 'configured_stop_report' or legacy 'zh_three_part'" });
|
|
416
|
+
}
|
|
417
|
+
if (controller.policy !== undefined) {
|
|
418
|
+
validateControllerPolicy(controller.policy, `${path}.policy`, errors);
|
|
376
419
|
}
|
|
377
420
|
return errors;
|
|
378
421
|
}
|
|
@@ -289,7 +289,7 @@ controllers:
|
|
|
289
289
|
fix-loop:
|
|
290
290
|
name: Fix Loop
|
|
291
291
|
description: "Run diagnosis once if needed, then loop fix/review/verify until PASS or stop condition"
|
|
292
|
-
kind:
|
|
292
|
+
kind: fix_loop
|
|
293
293
|
max_rounds: 10
|
|
294
294
|
progress_artifact_path: ".dna/fix-progress/$ARGUMENTS.json"
|
|
295
295
|
diagnosis_workflow: diagnosis
|
|
@@ -303,7 +303,47 @@ controllers:
|
|
|
303
303
|
surgeon: surgeon
|
|
304
304
|
fix_reviewer: fix_reviewer
|
|
305
305
|
test_runner: test_runner
|
|
306
|
-
stop_format:
|
|
306
|
+
stop_format: configured_stop_report
|
|
307
|
+
policy:
|
|
308
|
+
diagnosis_reuse_criteria:
|
|
309
|
+
- "$diagnosis_artifact_path exists"
|
|
310
|
+
- "$diagnosis_review_artifact_path exists and verdict is APPROVE"
|
|
311
|
+
- "behavior doc is not newer than diagnosis spec"
|
|
312
|
+
- "baseline artifact is not newer than diagnosis spec"
|
|
313
|
+
- "user did not explicitly pass reanalyze or scope changed"
|
|
314
|
+
- "progress JSON does not say diagnosis_invalid"
|
|
315
|
+
progress_provenance_checks:
|
|
316
|
+
- "module equals the safe module argument"
|
|
317
|
+
- "round equals the provided current_round"
|
|
318
|
+
- "run_id equals the provided controller_run_id"
|
|
319
|
+
- "diagnosis_artifact equals $diagnosis_artifact_path"
|
|
320
|
+
- "review_artifact equals $review_artifact_path"
|
|
321
|
+
- "git_head or last_fix_commit references the current round's fix commit when available"
|
|
322
|
+
- "updated_at is not earlier than the current round start time"
|
|
323
|
+
progress_provenance_failure: "if provenance is missing, stale, or mismatched, stop with Verdict BLOCKED and failure_reason PROGRESS_PROVENANCE_MISMATCH"
|
|
324
|
+
verdict_branches:
|
|
325
|
+
- "PASS -> success stop"
|
|
326
|
+
- "CONTINUE -> next fresh context fix round"
|
|
327
|
+
- "REQUEST_CHANGES -> stop with the configured stop report"
|
|
328
|
+
- "BLOCKED -> stop with the configured stop report"
|
|
329
|
+
verdict_mapping:
|
|
330
|
+
- "PASS / CONTINUE / REQUEST_CHANGES / BLOCKED mapping:"
|
|
331
|
+
- "- PASS: success stop"
|
|
332
|
+
- "- CONTINUE: start the next fresh context round"
|
|
333
|
+
- "- REQUEST_CHANGES: stop, report reviewer/verifier requested changes"
|
|
334
|
+
- "- BLOCKED: stop, report blocker"
|
|
335
|
+
- "- MAX_ROUNDS: stop, report max rounds reached and next focus"
|
|
336
|
+
stop_report:
|
|
337
|
+
- "On REQUEST_CHANGES, BLOCKED, or MAX_ROUNDS, output exactly these Chinese sections:"
|
|
338
|
+
- "结论:state the direct stop trigger, current round, and current commit if one exists."
|
|
339
|
+
- "为什么停止:explain the workflow principle in plain language; if this is a current-round new red, explain that continuing would build on a bad baseline."
|
|
340
|
+
- "是否回滚:say whether rollback/revert is recommended. If the commit direction looks wrong or the blast radius is unclear, recommend revert; if the failure is narrow and fixable, recommend fix-forward."
|
|
341
|
+
- "下一步:give one concrete next action. If recommending fix-forward, include a copy-paste single-fix prompt with current commit, exact failure, allowed scope, forbidden actions, verification command, commit expectation, and stop conditions."
|
|
342
|
+
constraints:
|
|
343
|
+
- "Do not infer module completion from raw test output."
|
|
344
|
+
- "The controller must schedule only from $progress_artifact_path."
|
|
345
|
+
- "Manual /dna-frw-diagnosis and /dna-frw-fix flows remain separate and available."
|
|
346
|
+
- "Do not use the generic workflow policy block; branch only from the progress JSON verdict."
|
|
307
347
|
|
|
308
348
|
workflows:
|
|
309
349
|
behavior-lock:
|
|
@@ -494,7 +534,11 @@ workflows:
|
|
|
494
534
|
|
|
495
535
|
Continue within the round while changes are coherent and reviewable. If the remaining work is large, stop at a natural boundary and leave the rest for the next fix round.
|
|
496
536
|
|
|
497
|
-
|
|
537
|
+
Shared boundary rule:
|
|
538
|
+
- If this round changes an interface, abstract class, provider, initializer, repository contract, constructor, public model/DTO, fake/mock, or test helper, search for affected fake/mock/helper implementations and update them in the same round.
|
|
539
|
+
- In that case, run the targeted test plus the affected module behavior suite once when practical; do not wait for final verification to discover compile/load failures caused by stale test fakes.
|
|
540
|
+
|
|
541
|
+
After each fix: run tests ONCE for that specific file unless the shared boundary rule requires the affected module behavior suite.
|
|
498
542
|
Commit only the round's coherent changes, with message including what changed, why, and which tests were targeted.
|
|
499
543
|
handoff:
|
|
500
544
|
consumes:
|
|
@@ -520,7 +564,8 @@ workflows:
|
|
|
520
564
|
2. Is REMOVED handling absent unless explicitly approved by user?
|
|
521
565
|
3. Does implementation preserve v1 behavior and follow v2 architecture?
|
|
522
566
|
4. Are test infra changes honest, not fake mocks?
|
|
523
|
-
5.
|
|
567
|
+
5. If shared interfaces/providers/initializers/contracts/constructors/models or test helpers changed, were affected fake/mock/helper implementations searched and synchronized?
|
|
568
|
+
6. Is there unrelated refactor or scope creep?
|
|
524
569
|
|
|
525
570
|
Output exactly one structured verdict block:
|
|
526
571
|
```json
|
|
@@ -614,6 +659,8 @@ workflows:
|
|
|
614
659
|
- Remaining UNIMPLEMENTED skipped: U diagnosis-backed skipped tests still remaining
|
|
615
660
|
- Failure reason: why progress stopped, if any
|
|
616
661
|
- Next round focus: the priority/classification/test file to continue with, if verdict is CONTINUE or REQUEST_CHANGES
|
|
662
|
+
- Rollback decision: say whether the current round commit should be reverted or fixed forward, with one plain-language reason
|
|
663
|
+
- Single-fix prompt: required when rollback decision recommends fix-forward; include current commit, exact failure, allowed scope, forbidden actions, verification command, commit expectation, and stop conditions
|
|
617
664
|
|
|
618
665
|
Always write or update .dna/fix-progress/$ARGUMENTS.md before finishing, even when review blocks verification. Include these sections:
|
|
619
666
|
- Current verdict: Verdict, Review, Module complete, Last fix commit, Updated at
|
|
@@ -622,6 +669,8 @@ workflows:
|
|
|
622
669
|
- Review Issues To Address First: reviewer issues when Review is REQUEST_CHANGES
|
|
623
670
|
- Failed approaches / Do not repeat: approaches that failed or caused regressions
|
|
624
671
|
- Evidence: commands run and relevant paths
|
|
672
|
+
- Rollback Decision: required when Verdict is REQUEST_CHANGES or BLOCKED after a current-round commit exists; say revert or fix-forward with one reason
|
|
673
|
+
- Single-Fix Prompt: required when Rollback Decision recommends fix-forward; make it copy-pasteable and narrow
|
|
625
674
|
|
|
626
675
|
Always write or update .dna/fix-progress/$ARGUMENTS.json before finishing, even when review blocks verification. The JSON must match this contract exactly:
|
|
627
676
|
```json
|