@devflow-core/dsh-devflow 0.5.0 → 0.6.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/assets/commands/devflow.toml +1 -1
- package/assets/scripts/devflow-plan.js +488 -15
- package/assets/skills/devflow-brainstorm/SKILL.md +2 -0
- package/assets/skills/devflow-build/SKILL.md +6 -4
- package/assets/skills/devflow-build/references/build-methods.md +4 -0
- package/assets/skills/devflow-core/SKILL.md +4 -1
- package/assets/skills/devflow-core/references/core-methods.md +5 -4
- package/assets/skills/devflow-cut/SKILL.md +10 -1
- package/assets/skills/devflow-cut/references/cut-methods.md +3 -0
- package/assets/skills/devflow-docs-followup/SKILL.md +1 -1
- package/assets/skills/devflow-learn/SKILL.md +13 -2
- package/assets/skills/devflow-plan/SKILL.md +41 -65
- package/assets/skills/devflow-plan/references/plan-methods.md +28 -50
- package/assets/skills/devflow-prove/SKILL.md +4 -2
- package/assets/skills/devflow-prove/references/flow-self-test.md +13 -11
- package/assets/skills/devflow-spec/SKILL.md +1 -0
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ Use Fast for pure Q&A, fact lookup, verification, or an already approved trivial
|
|
|
12
12
|
Use Design-lite when the risk gate skips Brainstorm for a small unapproved change to an existing feature with all low-risk conditions holding. Design-lite states goal, acceptance, and exclusions, records Depth C, and selects Cut then Build. It does not wait for Brainstorm. Not for new requirements.
|
|
13
13
|
If the boundary is unclear after Brainstorm, have Core select the smallest compatible route instead of guessing.
|
|
14
14
|
Run Sense first by reading or citing relevant project facts.
|
|
15
|
-
At Sense, probe `.copilot/LEARNING_INDEX.md` and `docs/project-knowledge
|
|
15
|
+
At Sense, match the task keywords against `docs/features/INDEX.md` and `docs/plans/INDEX.md` when present and open only the matched row's entry file or ledger section (an index over 40 rows is filtered with `node scripts/devflow-plan.js --index --query 关键词`); do not bulk-read capability documents. Then probe `.copilot/LEARNING_INDEX.md` (global preference cards first) and `docs/project-knowledge/`, reading only matched learning cards or navigation-selected knowledge documents and applying known developer preferences; missing locations are non-blocking and do not create storage.
|
|
16
16
|
The direct success map is Skip-Brainstorm Design-lite: Cut -> Build -> Prove, A: Brainstorm -> Spec -> Cut -> Plan -> Build -> Prove, B: Brainstorm -> Cut -> Plan -> Build -> Prove, C: Brainstorm -> Cut -> Build -> Prove. An approved A Spec directly starts Cut; A/B `CUT_PASS` directly starts Plan; C `CUT_PASS` and a skip-path `CUT_PASS` directly start Build; an approved A/B Plan directly starts Build; a completed Build directly starts Prove.
|
|
17
17
|
Before implementation, run Cut with Required Gates: Reuse, Native, Overbuild, Diff, and Scope checks. Core keeps non-unique selection: `CUT_REDUCE`/`CUT_REUSE` STOP for user confirmation, then return facts to Core; `CUT_BLOCKED`, Plan scope drift, `BUILD_BLOCKED`, Proof `FAIL`/`BLOCKED`, changed intent, and PUA recovery return facts so Core chooses the next owner.
|
|
18
18
|
For bug fixes, include Root-Cause Check: searched callers/references; shared vs narrow fix; reason.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
2
3
|
|
|
3
4
|
const requiredGlobalFields = ["Goal", "Architecture", "Tech Stack", "Source", "Spec coverage", "External Skills"];
|
|
4
5
|
const requiredTaskFields = ["Task", "Task type", "Files", "Interfaces", "Steps", "Acceptance", "Verify", "Comments", "Not doing"];
|
|
@@ -38,10 +39,32 @@ const worklistItemPattern = /^\s*-\s*\[ \]\s+(.+)$/gim;
|
|
|
38
39
|
const worklistDetailNames = ["Anchors", "Verify", "Done when"];
|
|
39
40
|
const maximumWorklistItems = 12;
|
|
40
41
|
|
|
42
|
+
// v2 契约(2026-09-10 可用性重构):计划只保留排序与验收字段;实现改法归 Build。
|
|
43
|
+
// 判定:含 `## Progress` 且不含 `Prewalk` 视为 v2;否则走 legacy 分支,旧计划无需迁移。
|
|
44
|
+
const v2GlobalFields = ["Goal", "Not doing", "Cut"];
|
|
45
|
+
const v2TaskFields = ["Task", "Files", "Change", "Acceptance", "Verify", "Not doing"];
|
|
46
|
+
const v2AllFields = [...v2GlobalFields, ...v2TaskFields];
|
|
47
|
+
const v2FieldPatterns = Object.fromEntries(
|
|
48
|
+
v2AllFields.map((field) => [field, new RegExp(`^(?:\\*\\*)?${field}(?:\\*\\*)?\\s*:`, "im")])
|
|
49
|
+
);
|
|
50
|
+
const progressHeadingPattern = /^##\s+Progress\s*$/im;
|
|
51
|
+
const progressRowPattern = /^\s*\|\s*(\d+)\s*\|\s*([^|]*)\|\s*(todo|doing|done)\s*\|\s*([^|]*)\|/gim;
|
|
52
|
+
const indexStatuses = ["active", "planned", "legacy", "retired"];
|
|
53
|
+
const indexPaths = { plans: "docs/plans/INDEX.md", features: "docs/features/INDEX.md" };
|
|
54
|
+
// 需求台账:一条需求从确认到落地的唯一记录;opt-out 表示用户显式跳过文档(仍必须有验证证据与原因)。
|
|
55
|
+
const requirementPath = "docs/requirements.md";
|
|
56
|
+
const requirementStatuses = ["open", "designed", "planned", "built", "landed", "opt-out", "dropped"];
|
|
57
|
+
const terminalRequirementStatuses = ["landed", "opt-out", "dropped"];
|
|
58
|
+
const promotionConfidence = 0.7;
|
|
59
|
+
|
|
41
60
|
/** Print the checker command contract and default plan landing. */
|
|
42
61
|
function usage() {
|
|
43
|
-
console.log("Usage: node scripts/devflow-plan.js [plan-file] [--self-test] [--json]");
|
|
62
|
+
console.log("Usage: node scripts/devflow-plan.js [plan-file] [--index] [--self-test] [--json]");
|
|
44
63
|
console.log("Checks whether a DevFlow Plan Pack has an executable header, task contracts, and plan landing.");
|
|
64
|
+
console.log("v2 plans carry a slim header, per-task Files/Change/Acceptance/Verify/Not doing, and a ## Progress table; legacy plans keep the old contract.");
|
|
65
|
+
console.log("--index checks docs/plans/INDEX.md and docs/features/INDEX.md against the filesystem.");
|
|
66
|
+
console.log("--index --query <keyword> prints only matching index rows for progressive loading; an empty result still exits 0.");
|
|
67
|
+
console.log("--loop prints a read-only loop report: requirement status counts, plan landing rate, feature rows, and promotion candidates.");
|
|
45
68
|
console.log("Default plan landing is docs/plans/YYYY-MM-DD-<short-kebab-name>.md unless the project documents another plan path.");
|
|
46
69
|
console.log("--json prints a single-line machine-readable summary; optional Status header values: " + validStatuses.join(" | "));
|
|
47
70
|
}
|
|
@@ -311,8 +334,369 @@ function checkTask(task, fileStructure) {
|
|
|
311
334
|
};
|
|
312
335
|
}
|
|
313
336
|
|
|
314
|
-
/**
|
|
337
|
+
/** v2 计划判定:新格式带 Progress 表且不含 Prewalk;旧格式继续走 legacy 校验。 */
|
|
338
|
+
function detectV2(body) {
|
|
339
|
+
return progressHeadingPattern.test(body) && !/^\s*Prewalk\s*:\s*$/im.test(body);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Extract one v2 field block; ends at the next v1 or v2 field line. */
|
|
343
|
+
function v2FieldBlock(body, field) {
|
|
344
|
+
const lines = body.split(/\r?\n/);
|
|
345
|
+
const start = lines.findIndex((line) => v2FieldPatterns[field].test(line));
|
|
346
|
+
if (start < 0) return "";
|
|
347
|
+
|
|
348
|
+
const value = lines[start].replace(v2FieldPatterns[field], "").trim();
|
|
349
|
+
const end = lines.findIndex(
|
|
350
|
+
(line, index) =>
|
|
351
|
+
index > start && (v2AllFields.some((name) => v2FieldPatterns[name].test(line)) || /^#{1,6}\s+\S/.test(line))
|
|
352
|
+
);
|
|
353
|
+
return [value, ...lines.slice(start + 1, end < 0 ? lines.length : end)].join("\n").trim();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Split a v2 plan at Task fields; the Progress table is not part of any task body. */
|
|
357
|
+
function splitTasksV2(body) {
|
|
358
|
+
const lines = body.split(/\r?\n/);
|
|
359
|
+
const progressIndex = lines.findIndex((line) => progressHeadingPattern.test(line));
|
|
360
|
+
const limit = progressIndex < 0 ? lines.length : progressIndex;
|
|
361
|
+
const taskStarts = [];
|
|
362
|
+
lines.forEach((line, index) => {
|
|
363
|
+
if (index < limit && v2FieldPatterns.Task.test(line)) taskStarts.push(index);
|
|
364
|
+
});
|
|
365
|
+
return taskStarts.map((start, index) => {
|
|
366
|
+
const end = taskStarts[index + 1] ?? limit;
|
|
367
|
+
return { number: index + 1, body: lines.slice(start, end).join("\n") };
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Validate one v2 task: files, change intent, acceptance, proof, and exclusion. */
|
|
372
|
+
function checkTaskV2(task) {
|
|
373
|
+
const missing = v2TaskFields.filter((field) => !v2FieldPatterns[field].test(task.body));
|
|
374
|
+
const files = v2FieldBlock(task.body, "Files");
|
|
375
|
+
const change = v2FieldBlock(task.body, "Change");
|
|
376
|
+
const verify = v2FieldBlock(task.body, "Verify");
|
|
377
|
+
const notDoing = v2FieldBlock(task.body, "Not doing");
|
|
378
|
+
const fileEntries = parseFileEntries(files);
|
|
379
|
+
const invalidFiles = fileEntries.filter(({ match }) => !match).map(({ line }) => line);
|
|
380
|
+
const unlocatedCodeFiles = findUnlocatedCodeFiles(fileEntries);
|
|
381
|
+
const unresolved = findMatches(task.body, unresolvedPatterns);
|
|
382
|
+
const vague = findMatches([change, v2FieldBlock(task.body, "Acceptance"), verify].join("\n"), vaguePatterns);
|
|
383
|
+
// v2 不强制精确改法;只要求 Change 说出可执行意图,具体实现归 Build。
|
|
384
|
+
const missingChange = !implementationVerbPattern.test(change) || genericMechanicsPattern.test(change);
|
|
385
|
+
const incompleteVerification = !hasVerificationExpectation(verify);
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
number: task.number,
|
|
389
|
+
missing,
|
|
390
|
+
unresolved,
|
|
391
|
+
vague,
|
|
392
|
+
invalidFiles,
|
|
393
|
+
unlocatedCodeFiles,
|
|
394
|
+
missingChange,
|
|
395
|
+
incompleteVerification,
|
|
396
|
+
missingNotDoing: !notDoing,
|
|
397
|
+
ok:
|
|
398
|
+
missing.length === 0 &&
|
|
399
|
+
unresolved.length === 0 &&
|
|
400
|
+
vague.length === 0 &&
|
|
401
|
+
invalidFiles.length === 0 &&
|
|
402
|
+
unlocatedCodeFiles.length === 0 &&
|
|
403
|
+
!missingChange &&
|
|
404
|
+
!incompleteVerification &&
|
|
405
|
+
Boolean(notDoing)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** Validate the v2 plan contract: slim header, task rows, Progress table, and Cut subtraction. */
|
|
410
|
+
function checkPlanV2(body) {
|
|
411
|
+
const tasks = splitTasksV2(body);
|
|
412
|
+
const taskResults = tasks.map(checkTaskV2);
|
|
413
|
+
const missingGlobal = v2GlobalFields.filter((field) => !v2FieldPatterns[field].test(body));
|
|
414
|
+
const cutBlock = v2FieldBlock(body, "Cut");
|
|
415
|
+
const missingRejected = !/Rejected\s*:\s*\S/im.test(cutBlock);
|
|
416
|
+
const statusMatch = body.match(statusPattern);
|
|
417
|
+
const status = statusMatch ? statusMatch[1].trim() : "legacy";
|
|
418
|
+
const invalidStatus = statusMatch ? !validStatuses.includes(status) : false;
|
|
419
|
+
const progress = [...body.matchAll(progressRowPattern)].map((match) => ({
|
|
420
|
+
number: Number(match[1]),
|
|
421
|
+
state: match[3],
|
|
422
|
+
evidence: match[4].trim()
|
|
423
|
+
}));
|
|
424
|
+
const missingEvidence = progress.filter((row) => row.state === "done" && (!row.evidence || row.evidence === "-"));
|
|
425
|
+
const progressMismatch = progress.length !== tasks.length;
|
|
426
|
+
const doneStatusNeedsAllDone = status === "done" && progress.some((row) => row.state !== "done");
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
v2: true,
|
|
430
|
+
status,
|
|
431
|
+
invalidStatus,
|
|
432
|
+
missingGlobal,
|
|
433
|
+
cut: { missingRejected },
|
|
434
|
+
tasks: taskResults,
|
|
435
|
+
progress: { count: progress.length, mismatch: progressMismatch, missingEvidence },
|
|
436
|
+
doneStatusNeedsAllDone,
|
|
437
|
+
ok:
|
|
438
|
+
missingGlobal.length === 0 &&
|
|
439
|
+
!missingRejected &&
|
|
440
|
+
!invalidStatus &&
|
|
441
|
+
tasks.length > 0 &&
|
|
442
|
+
taskResults.every((task) => task.ok) &&
|
|
443
|
+
!progressMismatch &&
|
|
444
|
+
missingEvidence.length === 0 &&
|
|
445
|
+
!doneStatusNeedsAllDone
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** Read every markdown table in a file as header cells plus data rows, skipping separator rows. */
|
|
450
|
+
function readMarkdownTables(filePath) {
|
|
451
|
+
const lines = fs.readFileSync(filePath, "utf8").split(/\r?\n/);
|
|
452
|
+
const tables = [];
|
|
453
|
+
let current = [];
|
|
454
|
+
for (const line of lines) {
|
|
455
|
+
if (/^\s*\|/.test(line)) {
|
|
456
|
+
current.push(line.split("|").slice(1, -1).map((cell) => cell.trim()));
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (current.length) {
|
|
460
|
+
tables.push(current);
|
|
461
|
+
current = [];
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (current.length) tables.push(current);
|
|
465
|
+
return tables
|
|
466
|
+
.map((cells) => cells.filter((row) => !row.every((cell) => /^:?-{2,}:?$/.test(cell))))
|
|
467
|
+
.filter((cells) => cells.length > 1)
|
|
468
|
+
.map((cells) => ({ header: cells[0], rows: cells.slice(1) }));
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** Read the first markdown table into its header cells and data rows. */
|
|
472
|
+
function readMarkdownTable(filePath) {
|
|
473
|
+
return readMarkdownTables(filePath)[0] || { header: [], rows: [] };
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** Resolve named column positions from the table header so a new column cannot shift the checks. */
|
|
477
|
+
function columnIndexes(header, names) {
|
|
478
|
+
return Object.fromEntries(names.map((name) => [name, header.findIndex((cell) => cell.includes(name))]));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/** Read one index file's data rows, returning an empty list when the index does not exist yet. */
|
|
482
|
+
function readIndexRows(root, kind) {
|
|
483
|
+
const filePath = path.join(root, ...indexPaths[kind].split("/"));
|
|
484
|
+
return fs.existsSync(filePath) ? readMarkdownTable(filePath).rows : [];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** Return index rows whose text contains the query, for progressive index loading. */
|
|
488
|
+
function matchIndexRows(rows, query) {
|
|
489
|
+
const needle = String(query || "").trim().toLowerCase();
|
|
490
|
+
if (!needle) return [];
|
|
491
|
+
return rows.filter((cells) => cells.join(" ").toLowerCase().includes(needle));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/** Read the value after a flag, or an empty string when it is absent or looks like another flag. */
|
|
495
|
+
function argValue(args, flag) {
|
|
496
|
+
const index = args.indexOf(flag);
|
|
497
|
+
return index >= 0 && args[index + 1] && !args[index + 1].startsWith("-") ? args[index + 1] : "";
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/** Check docs/plans/INDEX.md and docs/features/INDEX.md against the filesystem. */
|
|
501
|
+
function checkIndexes(root) {
|
|
502
|
+
const problems = [];
|
|
503
|
+
const plansDir = path.join(root, "docs", "plans");
|
|
504
|
+
const featuresDir = path.join(root, "docs", "features");
|
|
505
|
+
const plansIndex = path.join(root, ...indexPaths.plans.split("/"));
|
|
506
|
+
const featuresIndex = path.join(root, ...indexPaths.features.split("/"));
|
|
507
|
+
const planFiles = fs.existsSync(plansDir)
|
|
508
|
+
? fs.readdirSync(plansDir).filter((name) => name.endsWith(".md") && name !== "INDEX.md")
|
|
509
|
+
: [];
|
|
510
|
+
const planRows = readIndexRows(root, "plans");
|
|
511
|
+
const featureRows = readIndexRows(root, "features");
|
|
512
|
+
const plansTable = fs.existsSync(plansIndex) ? readMarkdownTable(plansIndex) : { header: [] };
|
|
513
|
+
const featuresTable = fs.existsSync(featuresIndex) ? readMarkdownTable(featuresIndex) : { header: [] };
|
|
514
|
+
const planCols = columnIndexes(plansTable.header, ["计划", "Status", "落地证据", "功能条目"]);
|
|
515
|
+
const featureCols = columnIndexes(featuresTable.header, ["功能", "Status", "关键文件", "来源计划"]);
|
|
516
|
+
|
|
517
|
+
if (planFiles.length > 0 && !fs.existsSync(plansIndex)) {
|
|
518
|
+
problems.push("docs/plans/INDEX.md missing while plan files exist");
|
|
519
|
+
}
|
|
520
|
+
for (const file of planFiles) {
|
|
521
|
+
const rows = planRows.filter((cells) => cells.some((cell) => cell.includes(file)));
|
|
522
|
+
if (rows.length === 0) problems.push(`plan not listed in docs/plans/INDEX.md: ${file}`);
|
|
523
|
+
if (rows.length > 1) problems.push(`plan listed more than once in docs/plans/INDEX.md: ${file}`);
|
|
524
|
+
}
|
|
525
|
+
for (const cells of planRows) {
|
|
526
|
+
const link = cells.find((cell) => cell.includes(".md"));
|
|
527
|
+
const file = link ? (link.match(/([^()/]+\.md)/) || [])[1] : null;
|
|
528
|
+
if (!file) continue;
|
|
529
|
+
if (!planFiles.includes(file)) problems.push(`docs/plans/INDEX.md lists unknown plan: ${file}`);
|
|
530
|
+
const filePath = path.join(plansDir, file);
|
|
531
|
+
if (!fs.existsSync(filePath)) continue;
|
|
532
|
+
const body = fs.readFileSync(filePath, "utf8");
|
|
533
|
+
const statusMatch = body.match(statusPattern);
|
|
534
|
+
const expected = statusMatch ? statusMatch[1].trim() : "legacy";
|
|
535
|
+
const rowStatus = (cells[planCols.Status] || "").trim();
|
|
536
|
+
if (rowStatus && rowStatus !== expected) {
|
|
537
|
+
problems.push(`status mismatch for ${file}: index ${rowStatus} vs file ${expected}`);
|
|
538
|
+
}
|
|
539
|
+
const evidence = (cells[planCols["落地证据"]] || "").trim();
|
|
540
|
+
if (rowStatus === "done" && (!evidence || evidence === "-")) {
|
|
541
|
+
problems.push(`done plan needs landing evidence in docs/plans/INDEX.md: ${file}`);
|
|
542
|
+
}
|
|
543
|
+
const featureCell = (cells[planCols["功能条目"]] || "").trim();
|
|
544
|
+
if (featureCell && featureCell !== "-" && !featureRows.some((row) => (row[featureCols["功能"]] || "").includes(featureCell))) {
|
|
545
|
+
problems.push(`feature entry not found in docs/features/INDEX.md: ${featureCell}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (const cells of featureRows) {
|
|
549
|
+
const status = (cells[featureCols.Status] || "").trim();
|
|
550
|
+
if (status && !indexStatuses.includes(status)) {
|
|
551
|
+
problems.push(`invalid feature status in docs/features/INDEX.md: ${status}`);
|
|
552
|
+
}
|
|
553
|
+
const files = (cells[featureCols["关键文件"]] || "").split(",").map((value) => value.replaceAll("`", "").trim()).filter((value) => value && value !== "-");
|
|
554
|
+
for (const rel of files) {
|
|
555
|
+
if (!fs.existsSync(path.join(root, rel))) problems.push(`feature file missing: ${rel}`);
|
|
556
|
+
}
|
|
557
|
+
const plan = (cells[featureCols["来源计划"]] || "").replaceAll("`", "").trim();
|
|
558
|
+
if (plan && plan !== "-" && !fs.existsSync(path.join(root, "docs", "plans", plan))) {
|
|
559
|
+
problems.push(`feature source plan missing: ${plan}`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const requirementTable = readRequirementTable(root);
|
|
563
|
+
problems.push(
|
|
564
|
+
...checkRequirementTable(requirementTable.header, requirementTable.rows, (rel) => fs.existsSync(path.join(root, rel)))
|
|
565
|
+
);
|
|
566
|
+
return problems;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Run the plan and feature index consistency check, or answer a single query. */
|
|
570
|
+
function runIndexCheck(json, query) {
|
|
571
|
+
const root = path.resolve(__dirname, "..");
|
|
572
|
+
if (query) {
|
|
573
|
+
const featureMatches = matchIndexRows(readIndexRows(root, "features"), query);
|
|
574
|
+
const planMatches = matchIndexRows(readIndexRows(root, "plans"), query);
|
|
575
|
+
if (json) {
|
|
576
|
+
console.log(JSON.stringify({ checker: "plan-index-query", query, features: featureMatches, plans: planMatches, judgment: "PASS" }));
|
|
577
|
+
} else {
|
|
578
|
+
console.log(`DevFlow index query: ${query}`);
|
|
579
|
+
for (const cells of featureMatches) console.log(`功能行: ${cells.join(" | ")}`);
|
|
580
|
+
for (const cells of planMatches) console.log(`计划行: ${cells.join(" | ")}`);
|
|
581
|
+
console.log(`Matches: ${featureMatches.length + planMatches.length}`);
|
|
582
|
+
}
|
|
583
|
+
return 0;
|
|
584
|
+
}
|
|
585
|
+
const problems = checkIndexes(root);
|
|
586
|
+
if (json) {
|
|
587
|
+
console.log(JSON.stringify({ checker: "plan-index", problems, judgment: problems.length === 0 ? "PASS" : "FAIL" }));
|
|
588
|
+
} else {
|
|
589
|
+
console.log("DevFlow plan and feature index report");
|
|
590
|
+
console.log(`Index files: ${indexPaths.plans} | ${indexPaths.features}`);
|
|
591
|
+
if (problems.length === 0) console.log("Problems: none");
|
|
592
|
+
for (const problem of problems) console.log(`Problem: ${problem}`);
|
|
593
|
+
console.log(`Judgment: ${problems.length === 0 ? "PASS" : "FAIL"}`);
|
|
594
|
+
}
|
|
595
|
+
return problems.length === 0 ? 0 : 1;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** Validate the requirement ledger table: status whitelist, terminal evidence, opt-out reason, artifact paths. */
|
|
599
|
+
function checkRequirementTable(header, rows, exists) {
|
|
600
|
+
const problems = [];
|
|
601
|
+
const cols = columnIndexes(header, ["需求", "日期", "落地物", "状态", "证据或跳过"]);
|
|
602
|
+
if (cols["状态"] < 0 || cols["证据或跳过"] < 0) {
|
|
603
|
+
problems.push("docs/requirements.md header must contain 状态 and 证据或跳过 columns");
|
|
604
|
+
return problems;
|
|
605
|
+
}
|
|
606
|
+
for (const cells of rows) {
|
|
607
|
+
const requirement = (cells[cols["需求"]] || "").trim();
|
|
608
|
+
const date = cols["日期"] >= 0 ? (cells[cols["日期"]] || "").trim() : "";
|
|
609
|
+
const status = (cells[cols["状态"]] || "").trim();
|
|
610
|
+
const evidence = (cells[cols["证据或跳过"]] || "").trim();
|
|
611
|
+
if (!requirement) problems.push("requirement row missing 需求 text");
|
|
612
|
+
if (!date) problems.push(`requirement row missing 日期: ${requirement}`);
|
|
613
|
+
if (!requirementStatuses.includes(status)) problems.push(`invalid requirement status: ${status}`);
|
|
614
|
+
if (terminalRequirementStatuses.includes(status) && (!evidence || evidence === "-")) {
|
|
615
|
+
problems.push(`terminal requirement needs evidence: ${requirement}`);
|
|
616
|
+
}
|
|
617
|
+
if (status === "opt-out" && !/原因|reason|skip/i.test(evidence)) {
|
|
618
|
+
problems.push(`opt-out needs a recorded reason: ${requirement}`);
|
|
619
|
+
}
|
|
620
|
+
const artifacts = (cells[cols["落地物"]] || "")
|
|
621
|
+
.split(",")
|
|
622
|
+
.map((value) => value.replaceAll("`", "").trim())
|
|
623
|
+
.filter((value) => value && value !== "-");
|
|
624
|
+
for (const rel of artifacts) {
|
|
625
|
+
if (!exists(rel)) problems.push(`requirement artifact missing: ${rel}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return problems;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/** Read the requirement ledger table, selecting the table that carries the ledger columns. */
|
|
632
|
+
function readRequirementTable(root) {
|
|
633
|
+
const filePath = path.join(root, ...requirementPath.split("/"));
|
|
634
|
+
if (!fs.existsSync(filePath)) return { header: [], rows: [] };
|
|
635
|
+
const tables = readMarkdownTables(filePath);
|
|
636
|
+
const ledger = tables.find(
|
|
637
|
+
(table) => table.header.some((cell) => cell.includes("状态")) && table.header.some((cell) => cell.includes("证据或跳过"))
|
|
638
|
+
);
|
|
639
|
+
return ledger || tables[0] || { header: [], rows: [] };
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/** Count requirement statuses and promotion candidates for the read-only loop report. */
|
|
643
|
+
function summarizeLoop(root) {
|
|
644
|
+
const { header, rows } = readRequirementTable(root);
|
|
645
|
+
const cols = columnIndexes(header, ["状态", "需求"]);
|
|
646
|
+
const counts = Object.fromEntries(requirementStatuses.map((status) => [status, 0]));
|
|
647
|
+
for (const cells of rows) {
|
|
648
|
+
const status = cols["状态"] >= 0 ? (cells[cols["状态"]] || "").trim() : "";
|
|
649
|
+
if (Object.prototype.hasOwnProperty.call(counts, status)) counts[status] += 1;
|
|
650
|
+
}
|
|
651
|
+
const planRows = readIndexRows(root, "plans");
|
|
652
|
+
const plansWithStatus = planRows.filter((cells) => validStatuses.includes((cells[2] || "").trim()));
|
|
653
|
+
const plansDone = plansWithStatus.filter((cells) => (cells[2] || "").trim() === "done");
|
|
654
|
+
const learningIndex = path.join(root, ".copilot", "LEARNING_INDEX.md");
|
|
655
|
+
const learningTable = fs.existsSync(learningIndex) ? readMarkdownTable(learningIndex) : { header: [], rows: [] };
|
|
656
|
+
const cardCols = columnIndexes(learningTable.header, ["Card", "Confidence"]);
|
|
657
|
+
const candidates = learningTable.rows
|
|
658
|
+
.map((cells) => ({
|
|
659
|
+
name: ((cells[cardCols.Card] || "").match(/\[([^\]]+)\]/) || [])[1] || "",
|
|
660
|
+
confidence: Number((cells[cardCols.Confidence] || "").trim())
|
|
661
|
+
}))
|
|
662
|
+
.filter((card) => card.name && Number.isFinite(card.confidence) && card.confidence >= promotionConfidence);
|
|
663
|
+
|
|
664
|
+
return {
|
|
665
|
+
requirements: { total: rows.length, counts },
|
|
666
|
+
plans: { withStatus: plansWithStatus.length, done: plansDone.length },
|
|
667
|
+
features: readIndexRows(root, "features").length,
|
|
668
|
+
candidates
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/** Run the read-only loop report: requirement counts, plan landing rate, feature rows, promotion candidates. */
|
|
673
|
+
function runLoopReport(json) {
|
|
674
|
+
const summary = summarizeLoop(path.resolve(__dirname, ".."));
|
|
675
|
+
const counts = summary.requirements.counts;
|
|
676
|
+
const landingRate = summary.plans.withStatus
|
|
677
|
+
? Math.round((summary.plans.done / summary.plans.withStatus) * 100)
|
|
678
|
+
: 0;
|
|
679
|
+
if (json) {
|
|
680
|
+
console.log(JSON.stringify({ checker: "devflow-loop", ...summary, landingRate, judgment: "PASS" }));
|
|
681
|
+
return 0;
|
|
682
|
+
}
|
|
683
|
+
console.log("DevFlow loop report");
|
|
684
|
+
console.log(`Requirements: total ${summary.requirements.total} | ${requirementStatuses.map((status) => `${status} ${counts[status]}`).join(" | ")}`);
|
|
685
|
+
console.log(`Plan landing: ${summary.plans.done}/${summary.plans.withStatus} with status (${landingRate}%)`);
|
|
686
|
+
console.log(`Feature rows: ${summary.features}`);
|
|
687
|
+
console.log(`Promotion candidates (confidence >= ${promotionConfidence}): ${summary.candidates.length}`);
|
|
688
|
+
for (const card of summary.candidates) console.log(` - ${card.name} (${card.confidence})`);
|
|
689
|
+
console.log("Judgment: PASS");
|
|
690
|
+
return 0;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** Dispatch the v2 and legacy plan contracts so old plans keep validating. */
|
|
315
694
|
function checkPlan(body) {
|
|
695
|
+
return detectV2(body) ? checkPlanV2(body) : checkPlanLegacy(body);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/** Validate global plan headers and all independently scoped task contracts. */
|
|
699
|
+
function checkPlanLegacy(body) {
|
|
316
700
|
const fileStructure = checkFileStructure(body);
|
|
317
701
|
const tasks = splitTasks(body);
|
|
318
702
|
const requiresFileStructure = tasks.some((task) => fieldBlock(task.body, "Task type") === "Code change");
|
|
@@ -366,12 +750,21 @@ function report(body, filePath, json) {
|
|
|
366
750
|
console.log(
|
|
367
751
|
JSON.stringify({
|
|
368
752
|
checker: "plan",
|
|
753
|
+
format: result.v2 ? "v2" : "legacy",
|
|
369
754
|
landing: landing.message,
|
|
370
755
|
status: result.status,
|
|
371
756
|
invalidStatus: result.invalidStatus,
|
|
372
757
|
missingGlobal: result.missingGlobal,
|
|
373
|
-
globalUnresolved: result.globalUnresolved,
|
|
374
|
-
fileStructure: result.fileStructure.ok ? "ok" : "missing or invalid",
|
|
758
|
+
globalUnresolved: result.globalUnresolved || [],
|
|
759
|
+
fileStructure: result.v2 ? "v2" : result.fileStructure.ok ? "ok" : "missing or invalid",
|
|
760
|
+
cut: result.v2 ? { missingRejected: result.cut.missingRejected } : null,
|
|
761
|
+
progress: result.v2
|
|
762
|
+
? {
|
|
763
|
+
count: result.progress.count,
|
|
764
|
+
mismatch: result.progress.mismatch,
|
|
765
|
+
missingEvidence: result.progress.missingEvidence.length
|
|
766
|
+
}
|
|
767
|
+
: null,
|
|
375
768
|
tasks: result.tasks.map((task) => ({ number: task.number, ok: task.ok })),
|
|
376
769
|
judgment
|
|
377
770
|
})
|
|
@@ -381,22 +774,43 @@ function report(body, filePath, json) {
|
|
|
381
774
|
|
|
382
775
|
console.log("DevFlow plan pack report");
|
|
383
776
|
console.log(landing.message);
|
|
777
|
+
console.log(`Format: ${result.v2 ? "v2" : "legacy"}`);
|
|
384
778
|
console.log(`Status: ${result.invalidStatus ? "invalid" : result.status}`);
|
|
385
|
-
for (const field of
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}`
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
779
|
+
for (const field of result.v2 ? v2GlobalFields : requiredGlobalFields) {
|
|
780
|
+
console.log(`${field}: ${result.missingGlobal.includes(field) ? "missing" : "ok"}`);
|
|
781
|
+
}
|
|
782
|
+
if (result.v2) {
|
|
783
|
+
console.log(`Cut Rejected: ${result.cut.missingRejected ? "missing" : "ok"}`);
|
|
784
|
+
console.log(`Progress rows: ${result.progress.count} (tasks ${result.tasks.length})${result.progress.mismatch ? " mismatch" : ""}`);
|
|
785
|
+
for (const row of result.progress.missingEvidence) console.log(`Progress row ${row.number} is done without evidence`);
|
|
786
|
+
if (result.doneStatusNeedsAllDone) console.log("Status done requires every Progress row done");
|
|
787
|
+
} else {
|
|
788
|
+
console.log(`Global unresolved markers: ${result.globalUnresolved.join(", ") || "none"}`);
|
|
789
|
+
console.log(
|
|
790
|
+
`File Structure: ${
|
|
791
|
+
!result.requiresFileStructure ? "documentation-only exception" : result.fileStructure.ok ? "ok" : "missing or invalid"
|
|
792
|
+
}`
|
|
793
|
+
);
|
|
794
|
+
if (result.requiresFileStructure && !result.fileStructure.ok) {
|
|
795
|
+
console.log(`File Structure invalid rows: ${result.fileStructure.invalidRows.join("; ") || "none"}`);
|
|
796
|
+
}
|
|
394
797
|
}
|
|
395
798
|
console.log(`Tasks: ${result.tasks.length}`);
|
|
396
799
|
if (result.tasks.length === 0) console.log("Missing: at least one Task field");
|
|
397
800
|
|
|
398
801
|
for (const task of result.tasks) {
|
|
399
|
-
const issues =
|
|
802
|
+
const issues = result.v2
|
|
803
|
+
? [
|
|
804
|
+
...task.missing.map((field) => `missing ${field}`),
|
|
805
|
+
...task.unresolved.map((match) => `unresolved ${match}`),
|
|
806
|
+
...task.vague.map((match) => `vague ${match}`),
|
|
807
|
+
...task.invalidFiles.map((line) => `unclassified file ${line}`),
|
|
808
|
+
...task.unlocatedCodeFiles.map((line) => `missing file symbol/anchor ${line}`),
|
|
809
|
+
...(task.missingChange ? ["Change needs an executable intent verb"] : []),
|
|
810
|
+
...(task.missingNotDoing ? ["missing Not doing exclusion"] : []),
|
|
811
|
+
...(task.incompleteVerification ? ["Verify needs command/scenario and expected result"] : [])
|
|
812
|
+
]
|
|
813
|
+
: [
|
|
400
814
|
...task.missing.map((field) => `missing ${field}`),
|
|
401
815
|
...task.unresolved.map((match) => `unresolved ${match}`),
|
|
402
816
|
...task.vague.map((match) => `vague ${match}`),
|
|
@@ -621,8 +1035,61 @@ function selfTest() {
|
|
|
621
1035
|
if (!checkPlanLanding("docs/plans/2026-07-14-add-plan-scanner.md").ok) throw new Error("Self-test expected docs/plans landing to pass");
|
|
622
1036
|
if (checkPlanLanding("docs/features/add-plan-scanner.md").ok) throw new Error("Self-test expected docs/features plan landing to fail");
|
|
623
1037
|
|
|
1038
|
+
const validV2Plan = [
|
|
1039
|
+
"Status: approved",
|
|
1040
|
+
"Goal: validate the slim v2 plan contract",
|
|
1041
|
+
"Not doing: architecture review",
|
|
1042
|
+
"Cut: 做 checker | 不做 迁移旧计划 | 复用 既有 self-test | 验证 node scripts/devflow-plan.js | Rejected: 新增独立脚本 — 复用既有 checker",
|
|
1043
|
+
"## Tasks",
|
|
1044
|
+
"",
|
|
1045
|
+
"Task: Add v2 validation",
|
|
1046
|
+
"Files:",
|
|
1047
|
+
"- Modify: scripts/devflow-plan.js | symbol: `checkPlanV2` | validate the slim contract",
|
|
1048
|
+
"Change: add v2 field validation and dispatch",
|
|
1049
|
+
"Acceptance: v2 plans pass and legacy plans keep passing",
|
|
1050
|
+
"Verify: run `node scripts/devflow-plan.js --self-test` expect exit 0",
|
|
1051
|
+
"Not doing: changing legacy validation",
|
|
1052
|
+
"",
|
|
1053
|
+
"## Progress",
|
|
1054
|
+
"",
|
|
1055
|
+
"| # | Task | Status | Evidence |",
|
|
1056
|
+
"|---|---|---|---|",
|
|
1057
|
+
"| 1 | Add v2 validation | todo | - |"
|
|
1058
|
+
].join("\n");
|
|
1059
|
+
if (!detectV2(validV2Plan)) throw new Error("Self-test expected v2 detection to pass");
|
|
1060
|
+
if (!checkPlan(validV2Plan).ok) throw new Error("Self-test expected valid v2 plan to pass");
|
|
1061
|
+
if (checkPlan(validV2Plan.replace(/Rejected:[^\n]*/, "Rejected:")).ok) throw new Error("Self-test expected missing Rejected to fail");
|
|
1062
|
+
if (checkPlan(validV2Plan.replace("| 1 | Add v2 validation | todo | - |", "| 1 | Add v2 validation | done | - |")).ok) {
|
|
1063
|
+
throw new Error("Self-test expected a done Progress row without evidence to fail");
|
|
1064
|
+
}
|
|
1065
|
+
if (checkPlan(validV2Plan.replace("| 1 | Add v2 validation | todo | - |", "")).ok) {
|
|
1066
|
+
throw new Error("Self-test expected a Progress/task count mismatch to fail");
|
|
1067
|
+
}
|
|
1068
|
+
if (typeof checkIndexes !== "function") throw new Error("Self-test expected the index checker to exist");
|
|
1069
|
+
if (matchIndexRows([["功能A", "计划相关", "x"]], "计划").length !== 1) throw new Error("Self-test expected index query to match a row");
|
|
1070
|
+
if (matchIndexRows([["功能A", "计划相关", "x"]], "不存在").length !== 0) throw new Error("Self-test expected index query to miss");
|
|
1071
|
+
if (matchIndexRows([["功能A"]], "").length !== 0) throw new Error("Self-test expected an empty index query to match nothing");
|
|
1072
|
+
if (argValue(["--index", "--query", "计划"], "--query") !== "计划") throw new Error("Self-test expected --query to read its value");
|
|
1073
|
+
if (argValue(["--index", "--query", "--json"], "--query") !== "") throw new Error("Self-test expected --query to reject a flag as its value");
|
|
1074
|
+
|
|
1075
|
+
const requirementHeader = ["日期", "需求", "来源", "深度", "落地物", "状态", "证据或跳过", "更新日"];
|
|
1076
|
+
const requirementRows = [
|
|
1077
|
+
["2026-09-10", "已落地需求", "用户请求", "A", "docs/specs/x.md", "landed", "npm test 通过", "2026-09-10"],
|
|
1078
|
+
["2026-09-10", "跳过文档需求", "用户请求", "C", "-", "opt-out", "原因:用户显式跳过", "2026-09-10"]
|
|
1079
|
+
];
|
|
1080
|
+
const requirementProblems = checkRequirementTable(requirementHeader, requirementRows, () => true);
|
|
1081
|
+
if (requirementProblems.length !== 0) throw new Error(`Self-test expected a valid requirement table to pass: ${requirementProblems.join("; ")}`);
|
|
1082
|
+
const badStatus = checkRequirementTable(requirementHeader, [["2026-09-10", "状态非法", "用户请求", "A", "-", "shipped", "证据", "2026-09-10"]], () => true);
|
|
1083
|
+
if (badStatus.length === 0) throw new Error("Self-test expected an invalid requirement status to fail");
|
|
1084
|
+
const missingEvidence = checkRequirementTable(requirementHeader, [["2026-09-10", "终态无证据", "用户请求", "A", "-", "landed", "-", "2026-09-10"]], () => true);
|
|
1085
|
+
if (missingEvidence.length === 0) throw new Error("Self-test expected a terminal requirement without evidence to fail");
|
|
1086
|
+
const missingReason = checkRequirementTable(requirementHeader, [["2026-09-10", "跳过无原因", "用户请求", "C", "-", "opt-out", "验证通过", "2026-09-10"]], () => true);
|
|
1087
|
+
if (missingReason.length === 0) throw new Error("Self-test expected an opt-out without a reason to fail");
|
|
1088
|
+
const missingArtifact = checkRequirementTable(requirementHeader, [["2026-09-10", "落地物不存在", "用户请求", "A", "docs/specs/nope.md", "planned", "-", "2026-09-10"]], () => false);
|
|
1089
|
+
if (missingArtifact.length === 0) throw new Error("Self-test expected a missing requirement artifact to fail");
|
|
1090
|
+
|
|
624
1091
|
console.log("DevFlow plan self-test passed");
|
|
625
|
-
console.log("Checked code-level fields, precise file locations,
|
|
1092
|
+
console.log("Checked v2 and legacy plan contracts, Progress evidence, Cut Rejected, code-level fields, precise file locations, verification expectations, documentation-only exception, external-skill declaration, and plan landing guidance");
|
|
626
1093
|
}
|
|
627
1094
|
|
|
628
1095
|
const args = process.argv.slice(2);
|
|
@@ -634,5 +1101,11 @@ if (args.includes("--self-test")) {
|
|
|
634
1101
|
selfTest();
|
|
635
1102
|
process.exit(0);
|
|
636
1103
|
}
|
|
1104
|
+
if (args.includes("--loop")) {
|
|
1105
|
+
process.exit(runLoopReport(args.includes("--json")));
|
|
1106
|
+
}
|
|
1107
|
+
if (args.includes("--index")) {
|
|
1108
|
+
process.exit(runIndexCheck(args.includes("--json"), argValue(args, "--query")));
|
|
1109
|
+
}
|
|
637
1110
|
const targetArg = args.find((arg) => !arg.startsWith("-"));
|
|
638
1111
|
process.exitCode = report(readInput(args), targetArg, args.includes("--json"));
|
|
@@ -122,6 +122,8 @@ Confirmed request:
|
|
|
122
122
|
|
|
123
123
|
The summary records the agreed request and the exploration findings only. It must not contain an implementation plan, solution-space design, lifecycle route, or handoff instruction. It is the factual basis that downstream skills — starting with `devflow-spec` — build on, so record findings faithfully rather than trimming them away.
|
|
124
124
|
|
|
125
|
+
On `Status: clarified`, create or update the requirement row in `docs/requirements.md` with status `open`; depth is recorded when the lifecycle path is chosen. Pure Q&A, lookup, and read-only verification create no row.
|
|
126
|
+
|
|
125
127
|
## A/B/C Gate
|
|
126
128
|
|
|
127
129
|
After the fixed summary, present these choices and wait for one explicit user selection:
|
|
@@ -19,7 +19,7 @@ When no plan file exists, the approved design and Cut Decision form the Build Co
|
|
|
19
19
|
|
|
20
20
|
Load `skills/devflow-build/references/build-methods.md` after this section and before implementation slices. It owns the detailed minimal-change and slice discipline.
|
|
21
21
|
|
|
22
|
-
There is no broad pre-edit plan review. The executor reads
|
|
22
|
+
There is no broad pre-edit plan review. The executor reads the current task's `Files`, `Change`, `Acceptance`, `Verify`, and `Not doing`, and may read the task's named anchors plus one directly changed neighbor to choose the smallest implementation. Build owns how inside the task boundary; it must not broadly rediscover the repository, redesign outside the task boundary, silently repair the plan, or expand scope. An anchor mismatch or verification failure must stop and return `BUILD_BLOCKED` with facts to `devflow-core`: observed mismatch, affected anchor, and smallest replan decision.
|
|
23
23
|
|
|
24
24
|
Every skill declared in `External Skills` (Cut Decision or plan header) must actually be loaded through the platform's skill mechanism, or the reason it does not apply recorded; loading alone is not completion — Build requires the specialist's returned result, not-applicable, or failure facts. A specialist result implying structure outside the approved scope returns scope-drift facts to `devflow-core`, not silent adoption. Skill loading is not a pre-edit view and remains mandatory.
|
|
25
25
|
|
|
@@ -44,9 +44,11 @@ If work touches more than one file or one logical step, create Implementation Sl
|
|
|
44
44
|
|
|
45
45
|
When saving a plan file, use `docs/plans/YYYY-MM-DD-<short-kebab-name>.md`, resolved from the current target project's root, unless that project already documents another plan/spec path. Do not save implementation plans under `docs/features/`; that directory is for feature ledgers.
|
|
46
46
|
|
|
47
|
-
For multi-step work, tasks must cite the approved source, be small and verifiable, and follow the
|
|
47
|
+
For multi-step work, tasks must cite the approved source, be small and verifiable, and follow the six-field contract (`Task` / `Files` / `Change` / `Acceptance` / `Verify` / `Not doing`) in `skills/devflow-plan/SKILL.md`. Legacy plans with `Change mechanics` and `Prewalk` stay executable under their own contract.
|
|
48
48
|
|
|
49
|
-
No unresolved markers.
|
|
49
|
+
No unresolved markers. `Change` states the executable intent and boundary; add exact mechanics only when the change crosses a module contract, is irreversible, or touches security or data boundaries. Otherwise Build chooses the smallest implementation and records it as Progress evidence. The verification step keeps its trigger/input, expected result, and command or manual scenario. A task whose files are all documentation paths is documentation-only. No "add tests" without naming the behavior, no "handle edge cases" without naming the edge case, no "similar to Task N" shortcuts.
|
|
50
|
+
|
|
51
|
+
Close each task by writing back its `## Progress` row: `doing` when starting, `done` with the command and key result when its `Verify` passes. A `done` row without evidence fails the checker. On a legacy plan without a Progress table, report the same evidence in the completion message. When every task is `done`, advance the requirement row in `docs/requirements.md` to `built`.
|
|
50
52
|
|
|
51
53
|
Before Build, run `node scripts/devflow-plan.js <plan-file>` when a plan is saved to a file. If not found at `scripts/devflow-plan.js` (project-level), try `~/.codex/scripts/devflow-plan.js` or `~/.claude/scripts/devflow-plan.js` (user-level). Do NOT look under `skills/scripts/`. See `core-methods.md` Script Path Resolution.
|
|
52
54
|
|
|
@@ -191,7 +193,7 @@ If any file has no goal link, remove that change.
|
|
|
191
193
|
| "We'll verify everything at the end." | Verify slices when focused checks exist. |
|
|
192
194
|
| "Docs changes do not need proof." | Docs/rules/skills need validation just like code. |
|
|
193
195
|
| "The issue only mentions one caller." | Check sibling callers before choosing the fix location. |
|
|
194
|
-
| "The plan is approved, so I just execute." |
|
|
196
|
+
| "The plan is approved, so I just execute." | The plan fixes the boundary and proof; Build still chooses the smallest implementation inside that boundary. A real edit or verification failure returns `BUILD_BLOCKED` to Core. |
|
|
195
197
|
| "I'll infer the missing step." | Guessing past a gap is forbidden; unclear instructions return `BUILD_BLOCKED` facts. |
|
|
196
198
|
| "The code is self-explanatory." | That does not waive a comment required by the approved contract, project convention, or a non-obvious boundary. |
|
|
197
199
|
| "Comments will get stale." | Keep a required comment accurate or remove a stale one; a stale explanation is not a reason to skip a needed decision record. |
|
|
@@ -19,6 +19,10 @@ Verification:
|
|
|
19
19
|
|
|
20
20
|
Split multi-step work into one to five testable slices. Each slice names files, user-visible or contract behavior, verification, and comment requirements. Verify a slice before moving on whenever a focused check exists.
|
|
21
21
|
|
|
22
|
+
Build owns how. A v2 plan task gives `Files`, `Change`, `Acceptance`, `Verify`, and `Not doing`; the executor reads the named anchors plus one directly changed neighbor, chooses the smallest implementation inside that boundary, and records the choice in the task's `## Progress` evidence. It does not wait for Plan to pre-decide the edit, and it does not widen the boundary. Legacy plans that prescribe `Change mechanics` are followed as written.
|
|
23
|
+
|
|
24
|
+
After a slice passes its verification, write back the plan's `## Progress` row: `doing` while in flight, `done` with the command and key result when verified. On a legacy plan without a Progress table, report the same evidence in the completion message.
|
|
25
|
+
|
|
22
26
|
## Readability Outcome Check
|
|
23
27
|
|
|
24
28
|
Before handoff, review changed code from the perspective of a maintainer familiar with the project but not this change. Use names, structure, extraction, comments, and tests as appropriate; do not apply any technique mechanically.
|
|
@@ -15,6 +15,7 @@ Trigger: <user words or task shape>
|
|
|
15
15
|
Route: Problem / Fast / Design-lite / Design / Build / Recovery
|
|
16
16
|
Brainstorm required: yes/no
|
|
17
17
|
Depth hint: skip / compact / standard / deep / none
|
|
18
|
+
Preferences applied: <count of global preference cards matched this turn>
|
|
18
19
|
Next skill: <skill name or none>
|
|
19
20
|
Status: [DevFlow: <node> -> <next> | awaiting approval / in progress]
|
|
20
21
|
```
|
|
@@ -25,7 +26,7 @@ While a DevFlow lifecycle node is active, end each user-facing message with one
|
|
|
25
26
|
|
|
26
27
|
Read `skills/devflow-core/references/core-methods.md` before route selection. It supplies Method 0, shared route rules, and the owner map. Do not load all lifecycle references by default.
|
|
27
28
|
|
|
28
|
-
Read the narrowest relevant project facts, then progressively recall learning and project knowledge. Scan available skills and record a matching external specialist skill; a specialist may perform bounded specialist work inside the current node while DevFlow retains route and node ownership.
|
|
29
|
+
Read the narrowest relevant project facts, then match the task keywords against `docs/features/INDEX.md` and `docs/plans/INDEX.md` when present and open only the matched row's entry file or ledger section; an index over 40 rows is filtered with `node scripts/devflow-plan.js --index --query 关键词`. Do not bulk-read capability documents. Then progressively recall learning and project knowledge. Scan available skills and record a matching external specialist skill; a specialist may perform bounded specialist work inside the current node while DevFlow retains route and node ownership.
|
|
29
30
|
|
|
30
31
|
Before a route-specific decision, load only the selected owner reference:
|
|
31
32
|
|
|
@@ -61,6 +62,8 @@ Brainstorm is required when any material risk or decision-impact uncertainty exi
|
|
|
61
62
|
| Build | User asks to implement, fix, build, or land an approved change. | Select Cut, then Plan when construction needs several steps, then Build and Prove. |
|
|
62
63
|
| Recovery | Same target remains wrong after correction or proof failure. | Select PUA, consume recovery facts, then choose a different path. |
|
|
63
64
|
|
|
65
|
+
Every creative or problem-directed change creates or updates one row in `docs/requirements.md`: Brainstorm writes `open` after `Confirmed request`, and Design-lite writes `open` with depth `C` when Brainstorm is skipped. Pure Q&A, lookup, read-only verification, and explicit independent reviews create no row.
|
|
66
|
+
|
|
64
67
|
## Core Flow Map
|
|
65
68
|
|
|
66
69
|
```text
|
|
@@ -35,10 +35,11 @@ Apply these principles to every route:
|
|
|
35
35
|
Read the narrowest useful facts:
|
|
36
36
|
|
|
37
37
|
1. Project rules and relevant source, tests, commands, and current docs.
|
|
38
|
-
2.
|
|
39
|
-
3.
|
|
40
|
-
4. `
|
|
41
|
-
5.
|
|
38
|
+
2. `docs/features/INDEX.md` and `docs/plans/INDEX.md` when present: match the task keywords against the index rows and read only the matched row's entry file or ledger section; an index over 40 rows is filtered with `node scripts/devflow-plan.js --index --query 关键词`. Do not bulk-read capability documents. Missing indexes are non-blocking.
|
|
39
|
+
3. `.copilot/LEARNING_INDEX.md`: match `Scope: global` preference cards first (few, cross-project), then `project` cards whose Trigger and Scope match. Apply known preferences and report the count in Activation Evidence.
|
|
40
|
+
4. `docs/project-knowledge/AI-START-HERE.md` or `index.md`, then only navigation-selected documents.
|
|
41
|
+
5. `graphify-out/GRAPH_REPORT.md` when architecture impact is in scope.
|
|
42
|
+
6. Available environment skills; record a matching specialist skill without widening DevFlow scope. For a matched specialist, record the bounded-work contract:
|
|
42
43
|
|
|
43
44
|
```text
|
|
44
45
|
Owner: current DevFlow node
|
|
@@ -167,6 +167,14 @@ CUT_REUSE: existing capability can be reused; do not write new implementation
|
|
|
167
167
|
CUT_BLOCKED: missing facts or risk too high; return the blocking facts to `devflow-core`
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
+
Every result also records a four-line decision plus a mandatory subtraction record:
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
Cut: 做 <what is included> | 不做 <what is excluded> | 复用 <reused capability> | 验证 <verification> | Rejected: <at least one candidate scope, dependency, abstraction, or config that was cut, or none plus evidence why nothing could be cut>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`Rejected` is what separates a real Cut from a rubber stamp. A Cut that removes nothing writes `Rejected: none` and names the evidence that ruled each candidate out; a Cut that removes something names it. Without this line, a plan can pass every gate while quietly carrying avoidable work.
|
|
177
|
+
|
|
170
178
|
When `CUT_REDUCE` or `CUT_REUSE` occurs, **STOP — present the reduction or reuse finding to the user**. Explain what was cut, what existing capability replaces it, and why the smaller option is sufficient. After confirmation, return the confirmed result to `devflow-core`.
|
|
171
179
|
|
|
172
180
|
When `CUT_BLOCKED` occurs, return the blocking facts to `devflow-core`. Core decides whether it must restart `devflow-brainstorm` to re-explore the goal and constraints.
|
|
@@ -195,7 +203,7 @@ When `CUT_BLOCKED` occurs, return the blocking facts to `devflow-core`. Core dec
|
|
|
195
203
|
|
|
196
204
|
## Handoff
|
|
197
205
|
|
|
198
|
-
After `CUT_PASS`, record a Cut Decision containing the allowed scope, reuse conclusion, exclusions, required verification, `External Skills`, and `Depth`. A recorded specialist role performs bounded work only; Cut retains reuse and scope authority, and `CUT_PASS` is never delegated. A/B directly enter `devflow-plan`; C directly enters `devflow-build`. `CUT_REDUCE`, `CUT_REUSE`, and `CUT_BLOCKED` return facts to `devflow-core`; `CUT_REDUCE` and `CUT_REUSE` remain stopped until user confirmation. A Plan Pack that broadens scope returns affected-gate facts to Core before any later selection.
|
|
206
|
+
After `CUT_PASS`, record a Cut Decision containing the four-line decision, the `Rejected` subtraction record, allowed scope, reuse conclusion, exclusions, required verification, `External Skills`, and `Depth`. When a plan file is produced, the four lines and `Rejected` go into the plan header; at depth C they stay in the Build Contract message. A recorded specialist role performs bounded work only; Cut retains reuse and scope authority, and `CUT_PASS` is never delegated. A/B directly enter `devflow-plan`; C directly enters `devflow-build`. `CUT_REDUCE`, `CUT_REUSE`, and `CUT_BLOCKED` return facts to `devflow-core`; `CUT_REDUCE` and `CUT_REUSE` remain stopped until user confirmation. A Plan Pack that broadens scope returns affected-gate facts to Core before any later selection.
|
|
199
207
|
|
|
200
208
|
## Verification
|
|
201
209
|
|
|
@@ -204,5 +212,6 @@ Before leaving this skill, confirm:
|
|
|
204
212
|
- [ ] Reuse, Root-Cause when relevant, Native, Overbuild, Diff, and Scope checks were answered.
|
|
205
213
|
- [ ] Any new structure has a current need.
|
|
206
214
|
- [ ] Removed scope is explicitly named.
|
|
215
|
+
- [ ] The four-line `Cut` decision is recorded, with a non-empty `Rejected` or `none` plus evidence.
|
|
207
216
|
- [ ] Intentional simplifications have `devflow:` ceiling and revisit trigger markers.
|
|
208
217
|
- [ ] Cut result is one of the four allowed statuses.
|
|
@@ -40,8 +40,11 @@ Reuse Check: what existing capability was checked first?
|
|
|
40
40
|
Trace Check: what accepted request does each key change trace to?
|
|
41
41
|
Scope Check: what tempting but unrequested feature was removed?
|
|
42
42
|
Diff Check: which user goal does each changed file serve?
|
|
43
|
+
Rejected: what candidate scope, dependency, abstraction, or config was cut — or none plus the evidence that ruled each candidate out?
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
`Rejected` is not optional. A gate that answers only "what is included" cannot show whether any subtraction happened, which is how a Cut degrades into a stamp. Name the cut candidate, or name the evidence that closed each candidate out.
|
|
47
|
+
|
|
45
48
|
## Method 8A: Contextual Design Quality Check
|
|
46
49
|
|
|
47
50
|
For changes that introduce or relocate code, alter module responsibilities, or add performance behavior, inspect the nearest comparable project code before selecting a shape. Record the decision without requiring a fixed layer, class count, interface, or cache:
|
|
@@ -34,7 +34,7 @@ Rules:
|
|
|
34
34
|
|
|
35
35
|
- Treat only an explicit selection as approval to create that document type.
|
|
36
36
|
- Treat silence, an ambiguous reply, or an unselected item as not approved.
|
|
37
|
-
- Treat `none` as a completed follow-up with no files written.
|
|
37
|
+
- Treat `none` as a completed follow-up with no files written; record it as `opt-out` in `docs/requirements.md` with the skip reason and the verification evidence. Silence or an ambiguous reply never becomes `opt-out`; the default requirement record still applies.
|
|
38
38
|
- If the user selects more than one type, create only those selected types.
|
|
39
39
|
|
|
40
40
|
## Evidence And Landing
|
|
@@ -19,15 +19,21 @@ Extract only knowledge that can help a future task:
|
|
|
19
19
|
- a non-obvious repository convention or invariant
|
|
20
20
|
- a costly, counterintuitive, repeated, or project-wide lesson
|
|
21
21
|
- a confirmed project-business fact that may require knowledge-package maintenance
|
|
22
|
+
- a user-visible capability or interface-contract change that must appear in `docs/features/INDEX.md`
|
|
23
|
+
- a developer preference about how to work — language, documentation depth, design-first, verify-command habits, review style — confirmed by a repeated correction
|
|
22
24
|
|
|
23
25
|
`PASS` requires the review, not a new record. If no useful reusable knowledge remains after classification, report that result and create nothing.
|
|
24
26
|
|
|
25
27
|
| Review result | Action | Store |
|
|
26
28
|
|---|---|---|
|
|
27
29
|
| Reusable execution experience or proven work pattern | Create or update one focused card | `.copilot/cards/` |
|
|
30
|
+
| User-visible capability or interface contract changed | Add or update one row: what it does, its trigger words, its entry point, its verify command, and its source plan | `docs/features/INDEX.md` |
|
|
31
|
+
| The same how-to preference was corrected twice | Create or update one `Scope: global` preference card | `.copilot/cards/` |
|
|
28
32
|
| Confirmed business fact changed | Report a project-knowledge candidate and wait for user confirmation | `docs/project-knowledge/` after confirmation via `devflow-project-knowledge` |
|
|
29
33
|
| Ordinary detail, one-off fact, already-covered lesson, or pure refactor without insight | Report no useful record | none |
|
|
30
34
|
|
|
35
|
+
The capability row is a mechanical duty, not a documentation inquiry: a verified change that alters what a user can do, or an interface contract others depend on, must be findable from one index on the next session. Writing a longer document still needs explicit user confirmation through `devflow-docs-followup`.
|
|
36
|
+
|
|
31
37
|
Project-knowledge candidates include changed domain semantics, rules, boundaries, entity/DTO/enum meaning, API or table boundaries, module responsibility, job behavior, and task entry points. `devflow-learn` must not update the package itself or infer business facts without evidence.
|
|
32
38
|
|
|
33
39
|
## Process
|
|
@@ -39,6 +45,7 @@ Project-knowledge candidates include changed domain semantics, rules, boundaries
|
|
|
39
45
|
4. Extract a candidate from the task's implementation, decisions, proof, and business impact.
|
|
40
46
|
5. Decide whether to record:
|
|
41
47
|
- record if the candidate is cross-task reusable and proven useful, costly if missed, counterintuitive, non-obvious, repeated, or project-wide
|
|
48
|
+
- add or update one capability row in `docs/features/INDEX.md` with trigger words if the verified change altered user-visible behavior or an interface contract; report `no-change` otherwise
|
|
42
49
|
- report a project-knowledge candidate if code-backed business semantics changed; wait for user confirmation before calling `devflow-project-knowledge`
|
|
43
50
|
- skip if it is ordinary narration, a one-off fact, already covered, or too context-specific
|
|
44
51
|
6. Create `.copilot/LEARNING_INDEX.md`, `.copilot/cards/`, and one focused card only when the result belongs in project learning; do not create empty learning storage after a no-record review.
|
|
@@ -96,9 +103,10 @@ Learning storage is lazily created only by this skill after a qualifying reusabl
|
|
|
96
103
|
|---|---|---|
|
|
97
104
|
| `graphify-out/` | Structural code graph, communities, and dependency relationships | Execution lessons or curated business guidance |
|
|
98
105
|
| `.copilot/cards/` | Execution experience, intercept rules, and proven work patterns | Business reference documentation |
|
|
106
|
+
| `docs/features/INDEX.md` | The capability routing index: what a feature does, its trigger words, its entry point, its verify command, and its source plan | Execution lessons, business reference docs, version history, feature bodies |
|
|
99
107
|
| `docs/project-knowledge/` | Curated, code-backed business facts, boundaries, and task entry points | Agent mistakes or raw implementation history |
|
|
100
108
|
|
|
101
|
-
Handoff: `devflow-prove PASS` -> `devflow-learn` review -> project-knowledge candidate -> user confirmation -> `devflow-project-knowledge` lazy maintenance of `docs/project-knowledge/`. Only after a verified feature implementation with an actual source-behavior or interface-contract change may `devflow-learn` hand off to `devflow-docs-followup` for an optional documentation inquiry. Do not automatically hand off validation-only, documentation-only, rule-only, skill-only, or no-diff `PASS` results.
|
|
109
|
+
Handoff: `devflow-prove PASS` -> `devflow-learn` review -> capability row in `docs/features/INDEX.md` and/or a project-knowledge candidate -> user confirmation -> `devflow-project-knowledge` lazy maintenance of `docs/project-knowledge/`. Only after a verified feature implementation with an actual source-behavior or interface-contract change may `devflow-learn` hand off to `devflow-docs-followup` for an optional documentation inquiry. Do not automatically hand off validation-only, documentation-only, rule-only, skill-only, or no-diff `PASS` results.
|
|
102
110
|
|
|
103
111
|
## Card Format
|
|
104
112
|
|
|
@@ -133,6 +141,7 @@ Read this index first. Only read a card when its trigger matches the current tas
|
|
|
133
141
|
| 1 | Create/update card, confidence 0.3-0.5 |
|
|
134
142
|
| 2 | Raise confidence and force recall before acting |
|
|
135
143
|
| 3 | Propose `AGENTS.md` or platform rule update |
|
|
144
|
+
| Card confidence reaches 0.7 | Propose the rule or skill change and create one `docs/requirements.md` row for the proposal, so learning returns to the requirement loop |
|
|
136
145
|
| 4+ | Propose skill or command automation |
|
|
137
146
|
| User explicitly says remember/learn/沉淀 | Promote immediately if scope is clear |
|
|
138
147
|
|
|
@@ -145,7 +154,8 @@ Learning closure:
|
|
|
145
154
|
- Learning signal: PASS review/correction/pitfall/none
|
|
146
155
|
- Recall record: none/index/card
|
|
147
156
|
- Knowledge recall: none/learning index + matched card/project knowledge candidate
|
|
148
|
-
- Review result: learning card/project-knowledge candidate/no useful record
|
|
157
|
+
- Review result: learning card/capability row/project-knowledge candidate/no useful record
|
|
158
|
+
- Capability entry: added/updated/no-change
|
|
149
159
|
- New sediment: none/learning card/rule/skill
|
|
150
160
|
- Next intercept: next time <X>, first do <Y>, do not do <Z>
|
|
151
161
|
```
|
|
@@ -172,5 +182,6 @@ Before leaving this skill, confirm:
|
|
|
172
182
|
- [ ] Only matched cards were read.
|
|
173
183
|
- [ ] Repeated user corrections, repeated user challenges, and misplaced content were recorded or explicitly classified as already covered.
|
|
174
184
|
- [ ] New or updated card has trigger, lesson, next action, scope, related files, evidence, and invalidation condition.
|
|
185
|
+
- [ ] A user-visible capability or interface-contract change added or updated one `docs/features/INDEX.md` row with trigger words, or was reported as `no-change`.
|
|
175
186
|
- [ ] Business-semantic changes were reported as candidates and await user confirmation before knowledge-package maintenance.
|
|
176
187
|
- [ ] Completion output includes learning closure.
|
|
@@ -16,13 +16,14 @@ Turn an A/B `CUT_PASS`-bounded approved design or confirmed Spec into one review
|
|
|
16
16
|
## Authoring Process
|
|
17
17
|
|
|
18
18
|
1. Read only source material, code, tests, and conventions relevant to the approved scope. Load `skills/devflow-spec/references/spec-plan-methods.md` and `skills/devflow-plan/references/plan-methods.md` before applying Plan Pack mechanics.
|
|
19
|
-
2. Map
|
|
20
|
-
3.
|
|
21
|
-
4. Split independent deliverables into small, reviewable tasks. Each task
|
|
22
|
-
5. Write the plan using the required header
|
|
23
|
-
6. Self-review Cut
|
|
19
|
+
2. Map the intended touch set once: list the files and the responsibility each one carries. Reuse existing modules and name the intended file operation.
|
|
20
|
+
3. Do the bounded investigation needed to write correct tasks. Keep that evidence in the conversation or in a learning card; it is not a plan field.
|
|
21
|
+
4. Split independent deliverables into small, reviewable tasks. Each task carries `Files`, `Change`, `Acceptance`, `Verify`, and `Not doing` so an executor can act on it without reading another task.
|
|
22
|
+
5. Write the plan using the required header, task contract, and `## Progress` table below.
|
|
23
|
+
6. Self-review Cut fidelity, touch-set coverage, acceptance proof, scope exclusions, and Progress row count against the task count.
|
|
24
24
|
7. Run `node scripts/devflow-plan.js <plan-file>` when the project-level checker exists. Otherwise resolve the user-level checker according to `core-methods.md` Script Path Resolution.
|
|
25
25
|
8. **STOP — request user review.** On DSH, request review with the structured `ask_user_question` tool (single-select: approve / request changes). Revise and revalidate when requested. On approval, ask execution mode (single-select: `sequential` — the Build agent runs tasks in dependency order / `single-subagent` — the main agent only schedules: one subagent runs tasks one per round in dependency order / `fan-out` — independent tasks run as parallel subagents) and record it as the plan's optional `Execution mode` header. Then perform only a lightweight Cut-consistency review. An approved A/B Plan directly enters `devflow-build`; scope-drift facts return to `devflow-core`.
|
|
26
|
+
9. On approval, advance the requirement row in `docs/requirements.md` to `planned` and fill the plan path in its artifact column.
|
|
26
27
|
|
|
27
28
|
Default landing is `docs/plans/YYYY-MM-DD-<short-kebab-name>.md`, resolved from the target project root. Do not place implementation plans in `docs/features/` or `docs/specs/`.
|
|
28
29
|
|
|
@@ -33,88 +34,64 @@ Structural headers remain English so the checker can parse them; content uses th
|
|
|
33
34
|
```text
|
|
34
35
|
# <Plan title>
|
|
35
36
|
|
|
37
|
+
Status: draft | approved | in-progress | done | abandoned
|
|
36
38
|
Goal: <outcome>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Source: <approved design or docs/specs/YYYY-MM-DD-<short-kebab-name>.md>
|
|
40
|
-
Spec coverage: <requirements mapped to tasks, or design-only>
|
|
41
|
-
Cut Decision: <CUT_PASS allowed scope, reuse conclusion, exclusions, verification constraints>
|
|
42
|
-
External Skills: <skill-name>; role: <bounded specialist work>; expected evidence: <result needed by that node>; return facts: <result / not-applicable / failure> / none
|
|
39
|
+
Not doing: <scope excluded>
|
|
40
|
+
Cut: 做 <included> | 不做 <excluded> | 复用 <reused capability> | 验证 <verification> | Rejected: <at least one cut candidate, or none plus evidence why nothing could be cut>
|
|
41
|
+
Source: <approved design or docs/specs/YYYY-MM-DD-<short-kebab-name>.md> (optional)
|
|
43
42
|
Execution mode: sequential | single-subagent | fan-out (optional; ask and record at approval)
|
|
43
|
+
Landed: <date and fresh evidence> (completion only)
|
|
44
44
|
|
|
45
|
-
##
|
|
46
|
-
- <applicable boundary>
|
|
45
|
+
## Tasks
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
Task: <short, independently understandable title>
|
|
48
|
+
Files:
|
|
49
|
+
- Create: <path> | new file | <responsibility>
|
|
50
|
+
- Modify: <path> | <symbol or stable anchor> | <responsibility>
|
|
51
|
+
- Test: <path> | <symbol or stable anchor> | <behavior proved> # only when applicable
|
|
52
|
+
Change: <what changes and its boundary; add the smallest mechanics only when the change crosses a module contract, is irreversible, or touches security or data boundaries>
|
|
53
|
+
Acceptance: <specific observable condition>
|
|
54
|
+
Verify: <exact command or manual scenario, trigger/input, and expected result>
|
|
55
|
+
Not doing: <scope excluded by this task>
|
|
56
|
+
|
|
57
|
+
## Progress
|
|
49
58
|
|
|
50
|
-
|
|
|
51
|
-
|
|
52
|
-
|
|
|
59
|
+
| # | Task | Status | Evidence |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| 1 | <task title> | todo | - |
|
|
53
62
|
```
|
|
54
63
|
|
|
64
|
+
The v2 header is deliberately slim: the Plan owns ordering and acceptance, while Cut owns the subtraction and Build owns how the change is implemented. `Cut` is one line and must carry a non-empty `Rejected` (or `none` plus evidence), so a plan without a real subtraction is visible instead of silently passing. `## Progress` is the resume and landing record: Build flips one row to `doing` or `done` and fills its evidence, and Prove writes `Landed` on `PASS`. A plan without `## Progress` and with a `Prewalk` block is a legacy plan; `scripts/devflow-plan.js` keeps validating it with the old rules, so existing plans never need migration.
|
|
65
|
+
|
|
55
66
|
Inherit `External Skills` from the Cut Decision unchanged; the Plan Pack carries the specialist role, expected evidence, and return facts into Build and Prove. When a specialist skill is declared, merge its core quality checks into the affected tasks' `Acceptance` and `Verify` fields — the Plan Pack is the only channel that carries external-skill quality requirements into Build and Prove. A declared skill never widens the Cut scope; if its recommendation exceeds the Cut Decision, return the scope-drift facts to `devflow-core`.
|
|
56
67
|
|
|
57
68
|
`Execution mode` is not part of Cut scope and does not change the checker. It is asked at approval and recorded so Build knows how to run tasks: sequentially as the Build agent itself, through one delegated subagent while the main agent only schedules, or fan out independent tasks to parallel subagents.
|
|
58
69
|
|
|
59
|
-
Each task's `Files`, `Change
|
|
70
|
+
Each task's `Files`, `Change`, `Acceptance`, `Verify`, and `Not doing` form the execution basis(执行规范)handed to the executor. Build may read the current task's named anchors and a directly changed neighbor to choose the smallest implementation; it must not broadly rediscover the repository, redesign outside the task boundary, silently repair the plan, or expand the touch set. A real anchor mismatch or verification failure returns `BUILD_BLOCKED` facts to `devflow-core` instead of a guessed edit.
|
|
60
71
|
|
|
61
72
|
## Required Task Contract
|
|
62
73
|
|
|
63
74
|
```text
|
|
64
75
|
Task: <short, independently understandable title>
|
|
65
|
-
Task type: Code change | Documentation-only
|
|
66
76
|
Files:
|
|
67
77
|
- Create: <path> | new file | <responsibility>
|
|
68
78
|
- Modify: <path> | <symbol or stable anchor> | <responsibility>
|
|
69
|
-
- Test: <path> | <
|
|
70
|
-
|
|
71
|
-
- Consumes: <exact symbol/API input and type/shape, or documentation-only exception>
|
|
72
|
-
- Produces: <exact symbol/API output and type/shape, or documentation-only exception>
|
|
73
|
-
Current behavior: <observable current state> # Code change only
|
|
74
|
-
Target behavior: <observable outcome> # Code change only
|
|
75
|
-
Change mechanics: <minimal code snippet, pseudocode, or exact replacement rule> # Code change only
|
|
76
|
-
Call impact: <known callers/downstream effect, or no runtime impact> # Code change only
|
|
77
|
-
Steps:
|
|
78
|
-
- [ ] <one file + symbol/anchor + executable action; include the relevant snippet, pseudocode, or exact replacement for code logic>
|
|
79
|
-
- [ ] <one verification action with trigger/input, expected result, and command or manual scenario>
|
|
79
|
+
- Test: <path> | <symbol or stable anchor> | <behavior proved> # only when applicable
|
|
80
|
+
Change: <what changes and its boundary; exact mechanics only when the change crosses a module contract, is irreversible, or touches security or data boundaries>
|
|
80
81
|
Acceptance: <specific observable condition>
|
|
81
82
|
Verify: <exact command or manual scenario, trigger/input, and expected result>
|
|
82
|
-
|
|
83
|
-
Not doing: <scope excluded>
|
|
84
|
-
|
|
85
|
-
Prewalk:
|
|
86
|
-
|
|
87
|
-
Execution Trace:
|
|
88
|
-
- Read: <actual file/symbol/range> → <observed fact relevant to this task>.
|
|
89
|
-
- Traced: <actual caller, entry point, collaborator, contract, or test> → <observed path or constraint>.
|
|
90
|
-
- Ran: <actual command or scenario> → <relevant result, including a failure when applicable>.
|
|
91
|
-
- Edited: <actual file/symbol and change> → <reason; or "none yet">.
|
|
92
|
-
- Verified: <actual check> → <observed result; or "none yet">.
|
|
93
|
-
|
|
94
|
-
Current Handoff Facts:
|
|
95
|
-
- Target anchors: <current file, symbol, or range the plan author verified (evidence record, not executor re-read instruction)>.
|
|
96
|
-
- Nearby convention: <comparable inspected code and observed convention; or "no comparable code found">.
|
|
97
|
-
- Direct path: <traced callers, collaborators, boundaries, affected tests; or "none">.
|
|
98
|
-
- Current constraints: <observed contract, ordering, errors, compatibility; or "none">.
|
|
99
|
-
- Planned touch set: <remaining expected files/symbols and reason>.
|
|
100
|
-
- Risks / stop conditions: <facts requiring Core replan; or "none beyond ordinary Plan drift">.
|
|
101
|
-
|
|
102
|
-
Remaining Structured Worklist:
|
|
103
|
-
- [ ] <one independently completable remaining action with file/symbol and expected outcome>.
|
|
104
|
-
Anchors: <minimum current anchors>.
|
|
105
|
-
Verify: <command, test, call-path check, or observable result>.
|
|
106
|
-
Done when: <fact proving this action is complete>.
|
|
83
|
+
Not doing: <scope excluded by this task>
|
|
107
84
|
```
|
|
108
85
|
|
|
109
|
-
`
|
|
86
|
+
Use only `Create`, `Modify`, and `Test` file-operation labels. `Create` rows use `new file`; every other row names a symbol or stable anchor. `Change` states the executable intent and its boundary in one or two lines; it does not restate current behavior, target behavior, call impact, or interfaces unless the task changes a cross-module contract. The Plan no longer classifies tasks by `Task type`: a task whose files are all documentation paths is documentation-only, and the checker treats it that way.
|
|
110
87
|
|
|
111
|
-
|
|
88
|
+
Six fields per task is the whole contract: ordering, the touch set, the intent, the acceptance condition, the proof command, and the exclusion. Investigation traces, handoff facts, per-task worklists, architecture, tech stack, spec coverage, and comment locations are owned by other nodes or stay in the conversation. `Prewalk`, `File Structure`, `Interfaces`, `Current behavior`, `Target behavior`, `Change mechanics`, `Call impact`, and `Comments` are not part of the v2 contract; a plan that still carries them is treated as legacy.
|
|
112
89
|
|
|
113
|
-
|
|
90
|
+
Keep one task understandable on its own. Do not use cross-task shorthand, generic test additions, unnamed edge cases, or cleanup entries. Name a test file only when the stated behavior needs one.
|
|
114
91
|
|
|
115
92
|
## Boundaries
|
|
116
93
|
|
|
117
|
-
Plan generation does not repeat Cut, perform Build or Prove, prescribe independent review, test-first workflow, version-control task steps, or execute automatically. It converts `CUT_PASS` into a
|
|
94
|
+
Plan generation does not repeat Cut, perform Build or Prove, prescribe independent review, test-first workflow, version-control task steps, or execute automatically. It converts `CUT_PASS` into a slim construction checklist plus a Progress record. The checker validates static structure; it does not judge architecture or lifecycle state. The v2 contract applies to new plans only; legacy plans keep the old validation rules and are never migrated or rewritten.
|
|
118
95
|
|
|
119
96
|
## Anti-Rationalization
|
|
120
97
|
|
|
@@ -131,14 +108,13 @@ Plan generation does not repeat Cut, perform Build or Prove, prescribe independe
|
|
|
131
108
|
|
|
132
109
|
Before leaving this skill, confirm:
|
|
133
110
|
|
|
134
|
-
- [ ] `
|
|
111
|
+
- [ ] `Cut` is one line with 做 / 不做 / 复用 / 验证 and a non-empty `Rejected`.
|
|
135
112
|
- [ ] `External Skills` is inherited from the Cut Decision; declared skills' quality checks are merged into task `Acceptance`/`Verify`.
|
|
136
113
|
- [ ] Execution mode was asked at approval and recorded as the optional `Execution mode` header.
|
|
137
|
-
- [ ] Approved design or saved spec is cited as `Source`.
|
|
138
|
-
- [ ]
|
|
139
|
-
- [ ]
|
|
140
|
-
- [ ]
|
|
141
|
-
- [ ] Every task is independently understandable, requires named-anchor rereads and at most one already-listed neighbor, and has no unresolved or vague placeholder.
|
|
114
|
+
- [ ] Approved design or saved spec is cited as optional `Source`.
|
|
115
|
+
- [ ] Header, tasks, and `## Progress` match the v2 contract; each task has six fields and no legacy field.
|
|
116
|
+
- [ ] Every task is independently understandable and has no unresolved or vague placeholder.
|
|
117
|
+
- [ ] Progress row count equals task count; every `done` row carries evidence.
|
|
142
118
|
- [ ] The checker passed when available.
|
|
143
119
|
- [ ] The user reviewed the written plan.
|
|
144
120
|
- [ ] An approved A/B Plan entered `devflow-build`; any scope-drift facts returned to `devflow-core`.
|
|
@@ -2,73 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference after `skills/devflow-spec/references/spec-plan-methods.md` and before writing a Plan Pack. It defines the smallest handoff that lets another executor continue approved work without repeating broad repository discovery.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Touch Set
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
State the intended touch set once, before tasks: the files and the responsibility each one carries. Reuse the nearest owner when it already has the responsibility. If no target can hold the responsibility without a materially different concern, return the fact to Core instead of inventing a generic abstraction.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
| File / symbol | Operation | Responsibility | Why here | Not responsible for |
|
|
11
|
-
|---|---|---|---|---|
|
|
12
|
-
| [path and stable anchor] | Create / Modify / Test | [one responsibility] | [placement rationale] | [explicit boundary] |
|
|
13
|
-
```
|
|
9
|
+
The v2 Plan Pack has no `File Structure` table. The per-task `Files` rows are the touch set; a global table would only restate them.
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
## Task Rows
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Every non-trivial Code change task ends with `Prewalk`. It is an append-only handoff with three parts:
|
|
13
|
+
Each task carries exactly six fields:
|
|
20
14
|
|
|
21
15
|
```text
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- Edited: [actual file/symbol and change] → [reason; or "none yet"].
|
|
29
|
-
- Verified: [actual check] → [observed result; or "none yet"].
|
|
30
|
-
|
|
31
|
-
Current Handoff Facts:
|
|
32
|
-
- Target anchors: [current file/symbol/range the plan author verified; evidence record, not executor re-read instruction].
|
|
33
|
-
- Nearby convention: [inspected comparable code and observed convention; or "no comparable code found"].
|
|
34
|
-
- Direct path: [traced callers, collaborators, boundaries, affected tests; or "none"].
|
|
35
|
-
- Current constraints: [observed contract, ordering, error behavior, compatibility; or "none"].
|
|
36
|
-
- Planned touch set: [remaining expected files/symbols and reason].
|
|
37
|
-
- Risks / stop conditions: [facts that require Core replan; or "none beyond ordinary Plan drift"].
|
|
38
|
-
- Read-basis: [已读文件清单——计划作者的证据簿记,执行者不重读].
|
|
39
|
-
- Live anchors: [计划作者已确认的锚点——执行者不重读,仅作失败回报时的定位].
|
|
40
|
-
|
|
41
|
-
Remaining Structured Worklist:
|
|
42
|
-
- [ ] [one independently completable remaining action with file/symbol and expected outcome].
|
|
43
|
-
Anchors: [minimum current anchors].
|
|
44
|
-
Verify: [command, test, call-path check, or observable result].
|
|
45
|
-
Done when: [fact proving completion].
|
|
16
|
+
Task: <short, independently understandable title>
|
|
17
|
+
Files: <Create / Modify / Test rows with path and symbol or stable anchor>
|
|
18
|
+
Change: <what changes and its boundary>
|
|
19
|
+
Acceptance: <specific observable condition>
|
|
20
|
+
Verify: <command or manual scenario with trigger, input, and expected result>
|
|
21
|
+
Not doing: <scope excluded by this task>
|
|
46
22
|
```
|
|
47
23
|
|
|
48
|
-
|
|
24
|
+
`Change` states the executable intent. Add exact mechanics only when the change crosses a module contract, is irreversible, or touches security or data boundaries. Otherwise the executor chooses the smallest implementation inside the task boundary. This is the deliberate trade: the plan stops pre-deciding every edit, and Build regains bounded implementation authority. That trade is the fix for the bloated-plan problem, not a relaxation of proof.
|
|
25
|
+
|
|
26
|
+
Investigation evidence does not belong in the plan. Keep it in the conversation, or in a `.copilot/cards/` learning card when it is reusable across tasks.
|
|
49
27
|
|
|
50
|
-
|
|
51
|
-
- `Read`, `Traced`, `Ran`, `Edited`, and `Verified` may say `none yet` only where that action truly has not happened. At least one actual read or trace result is required for a Code change handoff.
|
|
52
|
-
- A failed command is valid evidence when its relevant failure is recorded. Do not rewrite it as success.
|
|
53
|
-
- The executor appends real evidence after completing each remaining work item; it does not erase prior trace facts.
|
|
28
|
+
## Progress Table
|
|
54
29
|
|
|
55
|
-
|
|
30
|
+
Close the plan with one row per task:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
| # | Task | Status | Evidence |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| 1 | <task title> | todo | - |
|
|
36
|
+
```
|
|
56
37
|
|
|
57
|
-
|
|
58
|
-
- Order work by dependency. Keep every item independently verifiable.
|
|
59
|
-
- Require `Anchors`, `Verify`, and `Done when` for each item. Generic phrases such as “check the code” do not prove completion.
|
|
60
|
-
- Limit one task to 12 remaining items. Group mechanical substeps under one verified result or return a scope-splitting fact to Core.
|
|
38
|
+
Status values are `todo`, `doing`, and `done`. Build flips the row it is working on and fills the evidence with the command and key result. Prove writes `Status: done` and `Landed:` on `PASS`. A `done` row without evidence fails the checker, and a plan whose header `Status` is `done` requires every row to be `done`. The table is why an interrupted session can resume: the next reader sees exactly what landed and what did not.
|
|
61
39
|
|
|
62
|
-
##
|
|
40
|
+
## Execution Handoff
|
|
63
41
|
|
|
64
|
-
|
|
42
|
+
An executor — the main agent itself, one delegated subagent, or one fan-out subagent — receives the current task's six fields. It may read the task's named anchors and one directly changed neighbor to choose the smallest implementation; it must not broadly rediscover the repository, redesign outside the task boundary, silently repair the plan, or expand the touch set.
|
|
65
43
|
|
|
66
|
-
When an edit cannot be applied
|
|
44
|
+
When an edit cannot be applied, a `Verify` fails, or a bounded read finds changed contract behavior, the executor returns the observed difference — affected file/anchor, actual behavior, blocked verification, and the smallest replan decision — as facts to `devflow-core`. It never guesses past a mismatch.
|
|
67
45
|
|
|
68
46
|
### Fan-out
|
|
69
47
|
|
|
70
|
-
When the plan's `Execution mode` is `fan-out`, one Build orchestrator partitions tasks into parallel groups and dispatches each task to a subagent. Every subagent receives only its own task's
|
|
48
|
+
When the plan's `Execution mode` is `fan-out`, one Build orchestrator partitions tasks into parallel groups and dispatches each task to a subagent. Every subagent receives only its own task's six fields, reads its anchors, edits its task's `Files`, runs its task's `Verify`, flips its Progress row, and returns evidence or failure facts. Two tasks may run in parallel only when their `Files` touch disjoint file/symbol sets and neither task's `Change` consumes what the other produces; tasks sharing a file/symbol or with a dependency run in sequence. The orchestrator merges returned results, reconciles cross-task overlap, and enters Prove once with merged evidence.
|
|
71
49
|
|
|
72
50
|
### Single-subagent
|
|
73
51
|
|
|
74
|
-
When the plan's `Execution mode` is `single-subagent`, the main agent only schedules: it dispatches one task's
|
|
52
|
+
When the plan's `Execution mode` is `single-subagent`, the main agent only schedules: it dispatches one task's six fields at a time to one executor subagent, waits for the return, then merges the returned evidence and enters Prove once. The subagent reads its anchors, edits, verifies, flips its Progress row, and returns the task result and evidence or `BUILD_BLOCKED` facts. The next task continues the same subagent conversation through `send_message`. On DeepSeek Harness (DSH), subagent turns are time-bounded, so one task per round is the norm; a timeout or truncated return retries that one task once with a narrower instruction. Nothing runs in parallel; prefer this mode for small to medium plans or plans whose tasks are strongly dependent, and keep `fan-out` for large parallel plans.
|
|
@@ -92,6 +92,8 @@ Coverage: <what was verified>
|
|
|
92
92
|
Not covered: <none or explicit gap>
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
On `PASS` with a plan file, write back before reporting: header `Status: done` plus `Landed: <date> · <evidence>`; every `## Progress` row must already be `done` with evidence. `PASS` also requires the `docs/requirements.md` row to be terminal — write `landed` with the evidence, or return the missing-row facts to Core. On `FAIL` or `BLOCKED`, leave `Status` unchanged and report facts to Core.
|
|
96
|
+
|
|
95
97
|
## Code Review Report
|
|
96
98
|
|
|
97
99
|
For code changes, after running the Code Quality Review (General Engineering Review + Language-Specific Checklist), generate this report before claiming PASS or FAIL. Review the actual diff before relying on test results. A Blocker or unresolved Warning returns `FAIL` facts to Core; Recommendations remain visible but do not independently prevent PASS.
|
|
@@ -99,8 +101,8 @@ For code changes, after running the Code Quality Review (General Engineering Rev
|
|
|
99
101
|
```text
|
|
100
102
|
Code Review Report:
|
|
101
103
|
- Diff reviewed: [actual changed files/ranges].
|
|
102
|
-
- Plan boundary: [approved
|
|
103
|
-
-
|
|
104
|
+
- Plan boundary: [approved task `Files` rows and verdict; legacy plans may cite `File Structure` rows].
|
|
105
|
+
- Progress evidence: [Progress rows with their Status and recorded command/result; legacy plans may cite Prewalk evidence].
|
|
104
106
|
- Comparable code: [nearest inspected file/symbol and observed convention].
|
|
105
107
|
- Blockers: [count].
|
|
106
108
|
1. [Blocker] [file:line] — [changed-code evidence and concrete risk] → [smallest correction].
|
|
@@ -383,7 +383,7 @@ Expected behavior:
|
|
|
383
383
|
- Cut compares nearest order-history patterns and records convention, responsibility, performance, and readability checks.
|
|
384
384
|
- It must not require a Service split, interface, cache, or fixed function length without current evidence.
|
|
385
385
|
- Build makes business intent, key rules, failure paths, and side effects locally understandable, then records a Readability Check.
|
|
386
|
-
- Prove reviews the actual diff against
|
|
386
|
+
- Prove reviews the actual diff against the plan task boundary, Progress evidence, project-convention alignment, local understandability, responsibility boundaries, and any cache benefit/invalidation/consistency claim.
|
|
387
387
|
- A coherent orchestration change passes when its responsibility, side effects, and direct contracts remain evidenced in the diff.
|
|
388
388
|
- A changed responsibility or unrecorded side effect is a Blocker or Warning only when the diff shows concrete risk; a justified local convention deviation remains non-blocking.
|
|
389
389
|
|
|
@@ -413,20 +413,22 @@ Expected behavior:
|
|
|
413
413
|
- Brainstorm presents A/B/C after the confirmed request. User-selected A starts Spec directly; Core routes only missing-depth, changed-intent, or non-success facts.
|
|
414
414
|
- Spec must compare real no-change/reuse, direct, and relevant existing-pattern options; it writes the design contract/saved spec, waits for user approval, then an approved A Spec directly enters Cut.
|
|
415
415
|
- A/B `CUT_PASS` directly enters Plan; only `CUT_REDUCE`, `CUT_REUSE`, `CUT_BLOCKED`, or other non-success facts return to Core.
|
|
416
|
-
- A
|
|
417
|
-
-
|
|
416
|
+
- A v2 Plan Pack carries a slim header, one six-field task per deliverable, a mandatory `Cut` line with a non-empty `Rejected`, and a `## Progress` table.
|
|
417
|
+
- Build may read the current task's anchors and one directly changed neighbor to choose the smallest implementation, flips the task's Progress row, and records the command and result as evidence.
|
|
418
|
+
- Prove writes `Status: done` and `Landed:` on `PASS`; a `done` Progress row without evidence is not `PASS`.
|
|
419
|
+
- A legacy plan that still carries `File Structure` and `Prewalk` remains valid under the legacy rules.
|
|
418
420
|
- A user-approved Plan Pack receives a lightweight Cut-consistency review; an approved A/B Plan directly enters Build, while scope-drift facts return to Core.
|
|
419
421
|
- Saved plan files default to `docs/plans/YYYY-MM-DD-<short-kebab-name>.md`.
|
|
420
422
|
- Must not save implementation plans under `docs/features/`; that directory is for feature ledgers.
|
|
421
423
|
- Must run `node scripts/devflow-plan.js <plan-file>` when the plan is saved to a file. If not found at `scripts/devflow-plan.js` (project-level), try `~/.codex/scripts/devflow-plan.js` or `~/.claude/scripts/devflow-plan.js` (user-level). Do NOT look under `skills/scripts/`.
|
|
422
|
-
- Must fail or revise a plan missing a
|
|
424
|
+
- Must fail or revise a v2 plan missing `Rejected`, a six-field task, a Progress row matching the task count, evidence on a `done` row, or a runnable `Verify`. The checker does not approve an architecture pattern.
|
|
423
425
|
|
|
424
426
|
Pass check:
|
|
425
427
|
|
|
426
428
|
```text
|
|
427
|
-
CUT_PASS:
|
|
429
|
+
CUT_PASS: 做 / 不做 / 复用 / 验证 plus Rejected
|
|
428
430
|
Command: node scripts/devflow-plan.js docs/plans/YYYY-MM-DD-<short-kebab-name>.md
|
|
429
|
-
Result: DevFlow plan pack report;
|
|
431
|
+
Result: DevFlow plan pack report; Format: v2; Cut Rejected: ok; Progress rows match tasks; Judgment: PASS
|
|
430
432
|
Next: lightweight Cut-consistency review -> confirmed Plan and scope-drift facts -> devflow-core
|
|
431
433
|
Judgment: PASS / FAIL / BLOCKED
|
|
432
434
|
```
|
|
@@ -442,8 +444,8 @@ The approved export plan is implemented. Verify it and mark it ready.
|
|
|
442
444
|
Expected behavior:
|
|
443
445
|
|
|
444
446
|
- Route: Prove.
|
|
445
|
-
- Prove reads the actual diff before interpreting test output, and compares it with the approved
|
|
446
|
-
- The Code Review Report names the reviewed diff, plan boundary,
|
|
447
|
+
- Prove reads the actual diff before interpreting test output, and compares it with the approved task boundary, Progress evidence, and nearest comparable code.
|
|
448
|
+
- The Code Review Report names the reviewed diff, plan boundary, Progress evidence, comparable code, Blockers, Warnings, Recommendations, and boundary verdict.
|
|
447
449
|
- An unresolved evidence-backed Blocker or Warning returns `FAIL` facts to Core; Recommendations alone do not prevent PASS.
|
|
448
450
|
- A function size, class name, dependency count, cache preference, or fixed architecture shape without changed-code evidence and concrete risk is not a blocking finding.
|
|
449
451
|
|
|
@@ -451,8 +453,8 @@ Pass check:
|
|
|
451
453
|
|
|
452
454
|
```text
|
|
453
455
|
Diff reviewed: actual changed files/ranges
|
|
454
|
-
Plan boundary:
|
|
455
|
-
|
|
456
|
+
Plan boundary: approved task Files rows and verdict
|
|
457
|
+
Progress evidence: row Status plus recorded command/result
|
|
456
458
|
Blockers: 0
|
|
457
459
|
Warnings: 0
|
|
458
460
|
Recommendations: 0 or documented
|
|
@@ -686,7 +688,7 @@ Judgment: FAIL
|
|
|
686
688
|
Input:
|
|
687
689
|
|
|
688
690
|
```text
|
|
689
|
-
A Build subagent receives an approved Plan whose latest Prewalk trace records `OrderHistoryQuery`, its API handler, and current authorization behavior. The first remaining work item anchors the query and handler. A minimal anchor reread discovers a new authorization policy that changes denial behavior and the requested rule's placement.
|
|
691
|
+
A Build subagent receives an approved legacy Plan whose latest Prewalk trace records `OrderHistoryQuery`, its API handler, and current authorization behavior. The first remaining work item anchors the query and handler. A minimal anchor reread discovers a new authorization policy that changes denial behavior and the requested rule's placement.
|
|
690
692
|
```
|
|
691
693
|
|
|
692
694
|
Expected behavior:
|
|
@@ -52,6 +52,7 @@ Do not force a spec for Design-lite work where a short design contract and quick
|
|
|
52
52
|
- Design: the comparison names the real alternatives and the selected approach has an explicit trade-off.
|
|
53
53
|
6. Run `node scripts/devflow-spec.js <spec-file>` when the script exists. If not found at `scripts/devflow-spec.js` (project-level), try `~/.codex/scripts/devflow-spec.js` or `~/.claude/scripts/devflow-spec.js` (user-level). Do NOT look under `skills/scripts/`. See `core-methods.md` Script Path Resolution.
|
|
54
54
|
7. **STOP — Wait for user approval of the design contract and spec.** On DSH, request approval with the structured `ask_user_question` tool (single-select: approve / request changes). Tell the user the spec path and review result. If they request changes, revise the comparison/design contract and re-run self-review. An approved A-branch Spec directly enters `devflow-cut`; any non-success state returns facts to `devflow-core`.
|
|
55
|
+
8. On approval, advance the requirement row in `docs/requirements.md` to `designed` and fill the spec path in its artifact column.
|
|
55
56
|
|
|
56
57
|
## Output
|
|
57
58
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devflow-core/dsh-devflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "DevFlow for DeepSeek Harness: devflow-2 agent preset + skills + commands + verification scripts, synced into ~/.dsh on host startup.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|