@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.
@@ -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/` when present. Read only matched learning cards or navigation-selected knowledge documents; missing locations are non-blocking and do not create storage.
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
- /** Validate global plan headers and all independently scoped task contracts. */
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 requiredGlobalFields) console.log(`${field}: ${result.missingGlobal.includes(field) ? "missing" : "ok"}`);
386
- console.log(`Global unresolved markers: ${result.globalUnresolved.join(", ") || "none"}`);
387
- console.log(
388
- `File Structure: ${
389
- !result.requiresFileStructure ? "documentation-only exception" : result.fileStructure.ok ? "ok" : "missing or invalid"
390
- }`
391
- );
392
- if (result.requiresFileStructure && !result.fileStructure.ok) {
393
- console.log(`File Structure invalid rows: ${result.fileStructure.invalidRows.join("; ") || "none"}`);
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, mechanics evidence, verification expectations, Read-basis/Live anchors handoff facts, documentation-only exception, external-skill declaration, and plan landing guidance");
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 only the current task's execution spec — `Files`, `Change mechanics`, `Steps`, `Verify` and must reread the current task's named anchors. A current task anchor plus a directly changed neighbor may be reread only when that neighbor is already listed in the task `Files` and its contract could invalidate the edit. An actual edit, anchor mismatch, or verification failure must stop and return `BUILD_BLOCKED` with facts to `devflow-core`: observed mismatch, affected anchor, and smallest replan decision. Do not broadly rediscover, guess, silently repair the plan, or expand scope.
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 required task contract (Task: / Task type: / Files: / Interfaces: / Current behavior: / Target behavior: / Change mechanics: / Call impact: / Steps: / Acceptance: / Verify: / Comments: / Not doing:) defined in `skills/devflow-plan/SKILL.md`.
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. For `Code change`, the dispatched execution spec follows the recorded file symbol/anchor and `Change mechanics`; do not re-decide the implementation mechanism in Build. `Current behavior`, `Target behavior`, and `Call impact` are the plan author's records; bounded current-anchor/neighbor reread is allowed only for drift detection. The verification step must retain its trigger/input, expected result, and command or manual scenario. `Documentation-only` applies only to tasks with no runtime code files and explicit `documentation-only` interfaces. No "add tests" without naming the behavior. No "handle edge cases" without naming the edge case. No "similar to Task N" shortcuts; repeat enough detail for each task to stand alone.
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." | Right: the approved execution spec is edited directly; an actual edit or verification failure returns `BUILD_BLOCKED` to Core. |
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. `.copilot/LEARNING_INDEX.md`, then only cards whose Trigger and Scope match.
39
- 3. `docs/project-knowledge/AI-START-HERE.md` or `index.md`, then only navigation-selected documents.
40
- 4. `graphify-out/GRAPH_REPORT.md` when architecture impact is in scope.
41
- 5. Available environment skills; record a matching specialist skill without widening DevFlow scope. For a matched specialist, record the bounded-work contract:
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 exact affected file responsibilities once in `## File Structure` before writing tasks. Reuse existing modules and name the intended file operation.
20
- 3. Perform bounded real investigation and record it as task-level `Prewalk`: actual `Execution Trace`, Current Handoff Facts, and only the unfinished `Remaining Structured Worklist`.
21
- 4. Split independent deliverables into small, reviewable tasks. Each task should be understandable without referring to another task, and it carries its own complete execution spec(执行规范)— `Files`, `Change mechanics`, `Steps`, and `Verify` so the executor can edit directly while still re-reading the current task anchor. A directly changed neighbor is reread only when it is already listed and its contract could invalidate the edit.
22
- 5. Write the plan using the required header and task contract below.
23
- 6. Self-review Cut Decision fidelity, source coverage, File Structure, Prewalk evidence, file-operation classifications, interface consistency, concrete steps, acceptance proof, and scope exclusions.
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
- Architecture: <smallest design and boundaries>
38
- Tech Stack: <relevant existing stack>
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
- ## Global Constraints
46
- - <applicable boundary>
45
+ ## Tasks
47
46
 
48
- ## File Structure
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
- | File / symbol | Operation | Responsibility | Why here | Not responsible for |
51
- |---|---|---|---|---|
52
- | <path and stable anchor> | Create / Modify / Test | <one responsibility> | <placement rationale> | <explicit boundary> |
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 mechanics`, `Steps`, and `Verify` form the execution basis(执行规范)handed to the executor. The executor must re-read the current task's named anchors. A current task anchor and directly changed neighbor may be reread only when that neighbor is already listed and its contract could invalidate the edit; this is a bounded drift check, not broad repository rediscovery. `Read-basis` / `Live anchors` remain the plan author's evidence record. Do not silently repair stale instructions, redesign outside scope, or expand the touch set.
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> | <test symbol or stable anchor> | <behavior proved> # only when applicable
70
- Interfaces:
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
- Comments: <locations and reasons required by Code Documentation, project convention, or non-obvious boundaries; or "none — trivial change">
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
- `File Structure` is one responsibility map, not a fixed architecture rule. For every non-trivial Code change, every task must carry a `Prewalk`. Each trace row records an action actually performed and its observed result; it cannot describe planned work. `Remaining Structured Worklist` contains only unfinished actions. Each item needs `Anchors`, `Verify`, and `Done when`; cap one task at 12 items. The executor reads the current task's execution spec, must reread named anchors, may reread at most one already-listed neighbor for drift detection, edits, runs `Verify`, appends actual evidence, and returns observed differences as facts to `devflow-core` when an edit or verification fails. Documentation-only tasks retain their existing exception.
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
- Use only `Create`, `Modify`, and `Test` file-operation labels. For a `Code change`, every existing-file row must name a symbol or stable anchor; `Create` rows use `new file`. `Current behavior`, `Target behavior`, `Change mechanics`, and `Call impact` are mandatory. `Change mechanics` must contain the smallest code snippet, pseudocode, or exact replacement rule that removes implementation inference. Interfaces name exact symbols and input/output shape. The verification step and `Verify` field name the trigger/input, expected result, and runnable command or manual scenario.
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
- `Documentation-only` is allowed only when no runtime code changes. Its `Consumes` and `Produces` entries explicitly say `documentation-only`; it cannot label a task that changes a code file. A task does not need a test file unless a test is needed for its stated behavior. Avoid vague work such as generic test additions, unnamed edge cases, cleanup, or cross-task shorthand.
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 static construction checklist. The checker validates static structure; it does not judge architecture or lifecycle state. Plan generation writes the execution spec(执行规范); the zero-view(零 view)execution discipline belongs to `plan-methods.md` and `devflow-build` a Plan Pack must not include execution-phase re-read or pre-edit review instructions.
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
- - [ ] `CUT_PASS` is cited with allowed scope, reuse conclusion, exclusions, and verification constraints.
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
- - [ ] `Spec coverage` maps the source to plan tasks.
139
- - [ ] Header, constraints, File Structure, interfaces, concrete steps, acceptance, verification, context-specific comments, exclusions, and task-level Prewalk records are present.
140
- - [ ] Each trace entry is an observed past action/result; each remaining worklist item is bounded, verified, and fact-complete.
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
- ## File Structure
5
+ ## Touch Set
6
6
 
7
- Write one `## File Structure` table before tasks:
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
- ```text
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
- The table states where approved responsibility belongs. It does not mandate a class count, layer, pattern, or automatic file split. 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 rather than inventing a generic abstraction.
11
+ ## Task Rows
16
12
 
17
- ## Prewalk
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
- Prewalk:
23
-
24
- Execution Trace:
25
- - Read: [actual file/symbol/range] → [observed fact].
26
- - Traced: [actual caller, entry point, collaborator, contract, or test] → [observed path or constraint].
27
- - Ran: [actual command or scenario] → [relevant result].
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
- ### Trace Rules
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
- - Record only work actually performed and what it observed. Do not write future-tense discovery instructions as trace evidence.
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
- ### Worklist Rules
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
- - Include only unfinished work. Completed work belongs in `Execution Trace`.
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
- ## Delegated Execution
40
+ ## Execution Handoff
63
41
 
64
- A delegated executor — the main agent itself, one delegated subagent, or one fan-out subagent — receives only the current task's execution spec (`Files`, exact replacement rules, `Steps`, `Verify`). Before editing, it must re-read the current task's named anchors. A current task anchor and directly changed neighbor may be reread only when that neighbor is already listed and its contract could invalidate the edit; it must not broadly rediscover the repository, re-plan, or expand scope. `Read-basis` and `Live anchors` stay in the plan as the plan author's evidence record. A detected mismatch returns facts to Core instead of silent repair.
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 or a `Verify` fails, or a bounded reread finds changed authorization/contract behavior, the executor returns the observed difference — affected file/anchor, actual behavior, blocked verification, and smallest replan decision — as facts to `devflow-core`; it does not guess past a mismatch. A stale line reference may be corrected only when the symbol, contract, responsibility, and intended outcome are unchanged.
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 execution spec, must reread named anchors and at most one already-listed neighbor, edits its task's `Files`, runs its task's `Verify`, and returns evidence or failure facts. It does not broadly rediscover or redesign. Two tasks may run in parallel only when their `Files` touch disjoint file/symbol sets and neither `Interfaces` consumes a symbol the other `Produces`; tasks sharing a file/symbol or with a consume/produce dependency run in sequence. The orchestrator merges returned results, reconciles cross-task overlap, and enters Prove once with merged evidence.
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 execution spec at a time to one executor subagent, waits for the return, then merges the returned evidence and enters Prove once. The main agent dispatches one task at a time — only that task's execution spec, not the whole plan. The subagent must reread current named anchors and at most one already-listed neighbor for drift, but never broadly rediscover or redesign; it edits, verifies, appends evidence, and returns the task results 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.
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 File Structure row(s) and verdict].
103
- - Prewalk evidence: [Execution Trace, Handoff Facts, remaining-work completion evidence].
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 File Structure, Prewalk evidence, project-convention alignment, local understandability, responsibility boundaries, and any cache benefit/invalidation/consistency claim.
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 Code change Plan Pack requires a concrete `File Structure` row per target and task-level `Prewalk`: actual `Execution Trace`, `Current Handoff Facts`, and bounded `Remaining Structured Worklist`.
417
- - A delegated Build agent reads the latest trace, then re-reads only the current work item's anchors and directly changed neighbor. It does not restart broad discovery or re-decide responsibility by default.
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 responsibility map, actual trace evidence, current handoff facts, bounded work items, or concrete verification. The checker does not approve an architecture pattern.
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: allowed scope / reuse conclusion / exclusions / verification constraints
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; File Structure: ok; trace and remaining worklist: ok; Judgment: PASS
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 `File Structure`, current `Execution Trace`, `Current Handoff Facts`, remaining-work completion evidence, and nearest comparable code.
446
- - The Code Review Report names the reviewed diff, plan boundary, Prewalk evidence, comparable code, Blockers, Warnings, Recommendations, and boundary verdict.
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: File Structure row(s) and verdict
455
- Prewalk evidence: Trace / Handoff Facts / completion evidence
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.5.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": {