devflow-kit 3.9.0 → 3.11.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/README.md +1 -1
  3. package/dist/agents/code.md +6 -6
  4. package/dist/agents/fix.md +6 -6
  5. package/dist/agents/harden.md +7 -6
  6. package/dist/agents/refactor.md +6 -6
  7. package/dist/cli/commands/ambient.js +10 -2
  8. package/dist/cli/commands/backup-session.js +131 -0
  9. package/dist/cli/commands/compliance-prompts.js +9 -4
  10. package/dist/cli/commands/compliance.js +184 -24
  11. package/dist/cli/commands/curation.js +23 -10
  12. package/dist/cli/commands/gate-level-prompts.js +39 -25
  13. package/dist/cli/commands/gates.js +5 -7
  14. package/dist/cli/commands/init.js +169 -184
  15. package/dist/cli/commands/install-report.js +129 -0
  16. package/dist/cli/commands/legacy-sweep.js +159 -0
  17. package/dist/cli/commands/proxy.js +6 -1
  18. package/dist/cli/commands/rules.js +75 -21
  19. package/dist/cli/commands/skills.js +42 -9
  20. package/dist/cli/commands/tracker.js +9 -3
  21. package/dist/cli/commands/uninstall.js +339 -75
  22. package/dist/commands/bug-analysis.md +69 -120
  23. package/dist/commands/dynamic-build.md +23 -23
  24. package/dist/commands/implement.md +46 -32
  25. package/dist/commands/release.md +1 -1
  26. package/dist/commands/resolve.md +35 -31
  27. package/dist/commands/self-review.md +8 -7
  28. package/dist/compliance-off/agents/git.md +120 -0
  29. package/dist/compliance-off/agents/triage.md +180 -0
  30. package/dist/compliance-off/commands/bug-analysis.md +398 -0
  31. package/dist/compliance-off/commands/code-review.md +520 -0
  32. package/dist/compliance-off/commands/dynamic-build.md +1251 -0
  33. package/dist/compliance-off/commands/dynamic-tickets.md +676 -0
  34. package/dist/compliance-off/commands/implement.md +736 -0
  35. package/dist/compliance-off/commands/plan.md +671 -0
  36. package/dist/compliance-off/commands/release.md +309 -0
  37. package/dist/compliance-off/commands/resolve.md +742 -0
  38. package/dist/compliance-off/skills/git/references/decision-markers.md +17 -0
  39. package/dist/compliance-off/skills/git/references/learn-conventions.md +80 -0
  40. package/dist/compliance-off/skills/git/references/pr/check-ci-status.md +33 -0
  41. package/dist/compliance-off/skills/git/references/pr/check-merge-readiness.md +49 -0
  42. package/dist/compliance-off/skills/git/references/pr/fetch-review-threads.md +52 -0
  43. package/dist/compliance-off/skills/git/references/pr/validate-branch.md +47 -0
  44. package/dist/compliance-off/skills/git/references/tracker/_contract.md +33 -0
  45. package/dist/compliance-off/skills/git/references/tracker/_mcp.md +153 -0
  46. package/dist/compliance-off/skills/git/references/tracker/github/create-release.md +35 -0
  47. package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +100 -0
  48. package/dist/compliance-off/skills/git/references/tracker/github/ensure-traceable-issue.md +74 -0
  49. package/dist/compliance-off/skills/git/references/tracker/github/fetch-issue.md +69 -0
  50. package/dist/compliance-off/skills/git/references/tracker/github/fetch-issues-batch.md +65 -0
  51. package/dist/compliance-off/skills/git/references/tracker/github/gather-release-evidence.md +48 -0
  52. package/dist/compliance-off/skills/git/references/tracker/github/setup-task.md +77 -0
  53. package/dist/compliance-off/skills/git/references/tracker/jira/create-release.md +35 -0
  54. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +100 -0
  55. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-traceable-issue.md +61 -0
  56. package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issue.md +51 -0
  57. package/dist/compliance-off/skills/git/references/tracker/jira/fetch-issues-batch.md +63 -0
  58. package/dist/compliance-off/skills/git/references/tracker/jira/gather-release-evidence.md +47 -0
  59. package/dist/compliance-off/skills/git/references/tracker/jira/setup-task.md +82 -0
  60. package/dist/compliance-off/skills/git/references/tracker/linear/create-release.md +35 -0
  61. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +100 -0
  62. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-traceable-issue.md +61 -0
  63. package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issue.md +51 -0
  64. package/dist/compliance-off/skills/git/references/tracker/linear/fetch-issues-batch.md +63 -0
  65. package/dist/compliance-off/skills/git/references/tracker/linear/gather-release-evidence.md +47 -0
  66. package/dist/compliance-off/skills/git/references/tracker/linear/setup-task.md +83 -0
  67. package/dist/compliance-off/skills/git/references/trust-rule.md +7 -0
  68. package/dist/core/agent-models.js +19 -4
  69. package/dist/core/assets.js +126 -17
  70. package/dist/core/compliance-off-files.js +27 -0
  71. package/dist/core/compliance.js +14 -0
  72. package/dist/core/curation-variants.js +460 -112
  73. package/dist/core/flags.js +2 -2
  74. package/dist/core/fs-atomic.js +5 -1
  75. package/dist/core/installed-variants.js +63 -0
  76. package/dist/core/manifest.js +48 -5
  77. package/dist/core/mds-variants.js +700 -3
  78. package/dist/core/orphan-sweep.js +29 -2
  79. package/dist/core/path-set.js +15 -0
  80. package/dist/core/plugins.js +68 -10
  81. package/dist/core/reference-sweep.js +42 -25
  82. package/dist/core/retired-shipped-names.js +278 -0
  83. package/dist/curation-compliance-off/agents/triage.md +176 -0
  84. package/dist/curation-compliance-off/commands/bug-analysis.md +349 -0
  85. package/dist/curation-compliance-off/commands/code-review.md +481 -0
  86. package/dist/curation-compliance-off/commands/dynamic-build.md +1211 -0
  87. package/dist/curation-compliance-off/commands/dynamic-tickets.md +634 -0
  88. package/dist/curation-compliance-off/commands/implement.md +689 -0
  89. package/dist/curation-compliance-off/commands/plan.md +631 -0
  90. package/dist/curation-compliance-off/commands/release.md +279 -0
  91. package/dist/curation-compliance-off/commands/resolve.md +692 -0
  92. package/dist/curation-off/agents/code.md +6 -6
  93. package/dist/curation-off/agents/fix.md +6 -6
  94. package/dist/curation-off/agents/harden.md +7 -6
  95. package/dist/curation-off/agents/refactor.md +6 -6
  96. package/dist/curation-off/commands/bug-analysis.md +69 -119
  97. package/dist/curation-off/commands/dynamic-build.md +23 -23
  98. package/dist/curation-off/commands/implement.md +46 -32
  99. package/dist/curation-off/commands/release.md +1 -1
  100. package/dist/curation-off/commands/resolve.md +35 -31
  101. package/dist/curation-off/commands/self-review.md +8 -7
  102. package/dist/skills/git/references/pr/resolve-review-threads.md +1 -1
  103. package/dist/targets/claude-code/behavior-install.js +23 -9
  104. package/dist/targets/claude-code/charter-render.js +374 -0
  105. package/dist/targets/claude-code/compliance-install.js +62 -17
  106. package/dist/targets/claude-code/compliance-off-files.js +249 -0
  107. package/dist/targets/claude-code/curation-install.js +632 -117
  108. package/dist/targets/claude-code/folder-swap.js +142 -0
  109. package/dist/targets/claude-code/install-backup.js +780 -0
  110. package/dist/targets/claude-code/installer.js +795 -199
  111. package/dist/targets/claude-code/language-stamp.js +6 -0
  112. package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
  113. package/dist/targets/claude-code/linked-folder.js +176 -0
  114. package/dist/targets/claude-code/reference-converge.js +131 -0
  115. package/dist/targets/claude-code/rules-folder.js +34 -0
  116. package/dist/targets/claude-code/shipped-set.js +160 -0
  117. package/dist/targets/claude-code/tracker-install.js +21 -8
  118. package/dist/targets/claude-code/tracker-servers.js +20 -6
  119. package/dist/targets/claude-code/workflow-folder-install.js +251 -0
  120. package/dist/variant-axes.json +109 -0
  121. package/package.json +1 -1
  122. package/src/assets/agents/_partials/_code.mds +6 -6
  123. package/src/assets/agents/evaluate.md +1 -1
  124. package/src/assets/agents/git.mds +32 -0
  125. package/src/assets/agents/harden.mds +7 -6
  126. package/src/assets/agents/test.md +21 -12
  127. package/src/assets/agents/triage.mds +2 -0
  128. package/src/assets/agents/validate.md +10 -10
  129. package/src/assets/commands/_partials/_compliance.mds +5 -3
  130. package/src/assets/commands/_partials/_engine.mds +9 -8
  131. package/src/assets/commands/_partials/_publication.mds +10 -1
  132. package/src/assets/commands/bug-analysis.mds +80 -126
  133. package/src/assets/commands/code-review.mds +43 -0
  134. package/src/assets/commands/dynamic-build.mds +109 -15
  135. package/src/assets/commands/dynamic-tickets.mds +13 -0
  136. package/src/assets/commands/implement.mds +145 -33
  137. package/src/assets/commands/plan.mds +19 -0
  138. package/src/assets/commands/release.mds +50 -1
  139. package/src/assets/commands/resolve.mds +217 -32
  140. package/src/assets/commands/self-review.mds +8 -7
  141. package/src/assets/mds/git/_ops.mds +23 -0
  142. package/src/assets/mds/git/_ops_steps.mds +17 -0
  143. package/src/assets/mds/git/_pr.mds +1 -1
  144. package/src/assets/mds/git/_references.mds +6 -0
  145. package/src/assets/mds/tracker/_common.mds +4 -0
  146. package/src/assets/mds/tracker/_github.mds +42 -0
  147. package/src/assets/mds/tracker/_jira.mds +43 -0
  148. package/src/assets/mds/tracker/_linear.mds +43 -0
  149. package/src/assets/rules/quality.md +2 -0
  150. package/src/assets/scripts/ci-wait.cjs +204 -126
  151. package/src/assets/scripts/hooks/assets/implement-installed +1 -0
  152. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +13 -11
  153. package/src/assets/scripts/hooks/preamble +18 -8
  154. package/src/assets/scripts/hooks/session-start-orchestrator +4 -2
  155. package/src/assets/scripts/pr-evidence.cjs +41 -2
  156. package/src/assets/scripts/verify-evidence.cjs +408 -56
  157. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +3 -3
  158. package/src/assets/skills/agent-references/references/commands/plan-levels.md +1 -1
  159. package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +6 -2
  160. package/src/assets/skills/agent-references/references/validate/passed-alone.md +7 -7
  161. package/src/assets/skills/docs-framework/SKILL.md +5 -2
  162. package/src/assets/skills/git/SKILL.md +3 -3
  163. package/src/assets/skills/git/references/github-api.md +2 -139
  164. package/src/assets/skills/git/references/github-posting.md +158 -0
  165. package/src/assets/skills/review-methodology/SKILL.md +1 -1
  166. package/src/assets/skills/review-methodology/references/patterns.md +1 -1
  167. package/src/assets/skills/review-methodology/references/report-template.md +1 -2
  168. package/src/assets/skills/testing/SKILL.md +2 -4
@@ -3,7 +3,7 @@ description: Execute a single task through implementation, quality gates, and PR
3
3
  ---
4
4
  # Implement Command
5
5
 
6
- Orchestrate a single task through implementation by spawning specialized agents.
6
+ Orchestrate a single task by spawning agents.
7
7
 
8
8
  ## Usage
9
9
 
@@ -77,7 +77,7 @@ If `PR_DESCRIPTION_GUIDANCE` was not set above (non-plan paths: issue input or t
77
77
 
78
78
  **Empty input.** When `COMMAND_INPUT` is empty — a plan handoff arrives this way, with the plan already in the conversation — there is no argument to name the branch from, and the Git agent sees none of this conversation. Write the description yourself: one line, taken from the plan's title or, with no plan, from the conversation. Send it as the setup-task `TASK_DESCRIPTION` below.
79
79
 
80
- Spawn Git agent to set up the task:
80
+ Spawn Git agent:
81
81
 
82
82
  ```
83
83
  Agent(subagent_type="Git"):
@@ -261,7 +261,7 @@ FEATURE_KNOWLEDGE: {feature_knowledge}
261
261
 
262
262
  **SEQUENTIAL_CODE_AGENTS**:
263
263
 
264
- Spawn Code agents one at a time. Each appends its own phase section to the handoff file, and the next reads only the section before it:
264
+ Spawn Code agents one at a time:
265
265
 
266
266
  **Phase 1 Code agent:**
267
267
  ```
@@ -338,7 +338,7 @@ FEATURE_KNOWLEDGE: {feature_knowledge}
338
338
  - If the Read fails, or the file has no `## Phases` heading with the `| Phase | standard | lean |` header, or a row breaks its grammar, apply no row, keep `GATE_LEVEL` and say `level reference unreadable: no level rows applied`.
339
339
  - Validate, the CI gate, the evidence claims and the compliance directive run at every level. An enabled compliance lens keeps Harden.
340
340
 
341
- After the Code agent completes, spawn Polish agent to polish the code. The Phase 6 Validate covers its commits. `{branch_diff}` is the output of `git diff --name-only --diff-filter=d {BASE_REF}...HEAD`, run again at each spawn; a non-zero exit stops, and an empty list counts only on exit 0.
341
+ After the Code agent completes, spawn Polish agent. `{branch_diff}` is the output of `git diff --name-only --diff-filter=d {BASE_REF}...HEAD`, run again at each spawn; a non-zero exit stops, and an empty list counts only on exit 0.
342
342
 
343
343
  ```
344
344
  Agent(subagent_type="Polish"):
@@ -354,7 +354,7 @@ Commit any improvements with a conventional-commit message."
354
354
  **Produces:** HARDEN_OUTPUT
355
355
  **Requires:** BASE_REF
356
356
 
357
- After Phase 3, spawn Harden agent as the quality gate:
357
+ After Phase 3, spawn Harden agent:
358
358
 
359
359
  ```
360
360
  Agent(subagent_type="Harden"):
@@ -366,12 +366,14 @@ Evaluate 9 pillars, fix P0/P1 issues, report status"
366
366
 
367
367
  Harden agent reports `### Status: PASS | FIXED | BLOCKED`. **If BLOCKED:** report to user and halt. **If PASS or FIXED:** continue to Phase 5. A FIXED status commits fixes and starts no Validate of its own: the Phase 6 run covers them.
368
368
 
369
+ Harden never reviews a deleted file or the old path of a rename; an empty list is no review, and Harden reports `no files reviewed`.
370
+
369
371
  ### Phase 5: Alignment Check
370
372
 
371
373
  **Produces:** ALIGNMENT_RESULT
372
374
  **Requires:** BASE_REF, EXECUTION_PLAN
373
375
 
374
- After Harden agent passes, spawn Evaluate agent to validate alignment. Evaluate agent receives `FEATURE_KNOWLEDGE_RULES` as acceptance context only; pattern and anti-pattern judgments belong to Harden agent:
376
+ After Harden agent passes, spawn Evaluate agent:
375
377
 
376
378
  ```
377
379
  Agent(subagent_type="Evaluate"):
@@ -389,7 +391,7 @@ Validate alignment with request and plan. Report ALIGNED or MISALIGNED with deta
389
391
  1. Extract misalignment details from Evaluate agent output
390
392
  2. Increment `alignment_fix_count`
391
393
  3. If `alignment_fix_count <= 2`:
392
- - Spawn Fix agent to fix misalignments:
394
+ - Spawn Fix agent:
393
395
  ```
394
396
  Agent(subagent_type="Fix"):
395
397
  "OPERATION: alignment-fix
@@ -407,7 +409,9 @@ Validate alignment with request and plan. Report ALIGNED or MISALIGNED with deta
407
409
  **Produces:** VALIDATION_RESULT, VALIDATED_HEAD
408
410
  **Requires:** BASE_REF, GATE_LEVEL
409
411
 
410
- Validate takes the one full-suite slot, after every commit it must cover: Code, Polish, Harden and the alignment fixes. After Evaluate agent passes, spawn Validate agent. `FILES_CHANGED` is the branch diff:
412
+ Alignment-fix commits get no self-review: Phase 6 Validate and `/code-review` check them.
413
+
414
+ After Evaluate agent passes, spawn Validate agent:
411
415
 
412
416
  ```
413
417
  Agent(subagent_type="Validate"):
@@ -419,10 +423,9 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
419
423
  ```
420
424
 
421
425
  **If FAIL:**
422
- 1. Extract failure details from Validate agent output
423
- 2. Increment `validation_retry_count`
424
- 3. If `validation_retry_count <= 2`:
425
- - Spawn Fix agent with fix context:
426
+ 1. Increment `validation_retry_count`
427
+ 2. If `validation_retry_count <= 2`:
428
+ - Spawn Fix agent:
426
429
  ```
427
430
  Agent(subagent_type="Fix"):
428
431
  "OPERATION: validation-fix
@@ -433,10 +436,14 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
433
436
  {COMPLIANCE_DIRECTIVE}"
434
437
  ```
435
438
  - Loop back to Phase 6 (re-validate at the new HEAD, full scope)
436
- 4. If `validation_retry_count > 2`: Report failures to user and halt
439
+ 3. Else report failures to user and halt
440
+
441
+ **If BLOCKED:** report its cause and log path, then halt.
437
442
 
438
443
  **If PASS:** append a `gate:validate` claim, run `git rev-parse HEAD` and record the result as `VALIDATED_HEAD`, then continue to Phase 7.
439
444
 
445
+ Any other or missing Status: report and halt; never PASS.
446
+
440
447
  **Evidence claims** are lines appended to the `## Claims` section of `EVIDENCE_FILE` — the file's last section, created when absent. Append only: never edit or remove a claim; the last valid one per target wins. Each line takes exactly one of these shapes, where `<head>` is the 40-hex `HEAD:` the agent's report shows:
441
448
 
442
449
  ```
@@ -453,7 +460,7 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
453
460
  **Produces:** QA_RESULT
454
461
  **Requires:** BASE_REF, EXECUTION_PLAN, TEST_PLAN, VALIDATED_HEAD
455
462
 
456
- After Phase 6 passes, spawn Test agent for scenario-based acceptance testing:
463
+ After Phase 6 passes, spawn Test agent:
457
464
 
458
465
  ```
459
466
  Agent(subagent_type="Test"):
@@ -462,18 +469,17 @@ EXECUTION_PLAN: {execution plan from Phase 1}
462
469
  FILES_CHANGED: {branch_diff}
463
470
  ACCEPTANCE_CRITERIA: {extracted criteria if available}
464
471
  TEST_PLAN: {the TP lines of the evidence file's ## Test Plan section, or (none)}
465
- Design and execute scenario-based acceptance tests. Report PASS or FAIL with evidence."
472
+ Design and execute scenario-based acceptance tests. Report your Status with evidence."
466
473
  ```
467
474
 
468
- After every Test agent run — PASS or FAIL, first run or retry — append its TP claims (Phase 6's **Evidence claims**).
475
+ After every Test agent run — whatever its Status, first run or retry — append its TP claims (Phase 6's **Evidence claims**).
469
476
 
470
- **If PASS:** Continue to Phase 8
477
+ **If PASS** (first word of the Status): Continue to Phase 8
471
478
 
472
479
  **If FAIL:**
473
- 1. Extract failure details from Test agent output
474
- 2. Increment `qa_retry_count`
475
- 3. If `qa_retry_count <= 2`:
476
- - Spawn Fix agent to fix QA failures:
480
+ 1. Increment `qa_retry_count`
481
+ 2. If `qa_retry_count <= 2`:
482
+ - Spawn Fix agent:
477
483
  ```
478
484
  Agent(subagent_type="Fix"):
479
485
  "OPERATION: qa-fix
@@ -483,15 +489,17 @@ After every Test agent run — PASS or FAIL, first run or retry — append its T
483
489
  SCOPE: Fix only the listed failures, no other changes
484
490
  {COMPLIANCE_DIRECTIVE}"
485
491
  ```
486
- - Loop back to Phase 7 (re-run Test agent). The fix is not validated here: Phase 8 covers it.
487
- 4. If `qa_retry_count > 2`: Report QA failures to user for decision. The run stops at the report (Phase 12), so Phases 8 to 11 do not run.
492
+ - Loop back to Phase 7.
493
+ 3. If `qa_retry_count > 2`: Report QA failures to user for decision. The run stops at the report (Phase 12), so Phases 8 to 11 do not run.
494
+
495
+ **If BLOCKED, or any other or missing Status:** report its cause and log path, and stop as in step 3; no Fix agent.
488
496
 
489
497
  ### Phase 8: Re-Validate (only if a qa-fix committed)
490
498
 
491
499
  **Produces:** REVALIDATION_RESULT
492
- **Requires:** QA_RESULT, VALIDATED_HEAD
500
+ **Requires:** QA_RESULT, VALIDATED_HEAD, BASE_REF, GATE_LEVEL
493
501
 
494
- Run this phase only if a qa-fix committed (`git rev-parse HEAD` differs from `VALIDATED_HEAD`); otherwise skip it and continue to Phase 9. Spawn Validate agent over what changed since the Phase 6 run:
502
+ Run this phase only if a qa-fix committed (`git rev-parse HEAD` differs from `VALIDATED_HEAD`); else skip to Phase 9. Spawn Validate agent:
495
503
 
496
504
  ```
497
505
  Agent(subagent_type="Validate"):
@@ -500,10 +508,16 @@ VALIDATION_SCOPE: changed-only
500
508
  Verify the qa-fix commits did not break anything."
501
509
  ```
502
510
 
511
+ At `lean`, open the prompt with Phase 6's `GATE_LEVEL` and `BASE_SHA` lines; its `Lint pack:` line, or `Lint pack: UNVERIFIED` if it prints none, replaces Phase 6's in VALIDATION_RESULT.
512
+
503
513
  **If FAIL:** Report the failures to user and halt.
504
514
 
515
+ **If BLOCKED:** as in Phase 6.
516
+
505
517
  **If PASS:** append a `gate:validate` claim (Phase 6's **Evidence claims**), then continue to Phase 9.
506
518
 
519
+ Any other or missing Status: report and halt; never PASS.
520
+
507
521
  ### Phase 9: Open PR
508
522
 
509
523
  **Produces:** PR_NUMBER
@@ -546,13 +560,13 @@ git push origin HEAD; echo "exit=$?"
546
560
  `exit=0` continues to the gate. Any other result, a rejected non-fast-forward push included, records `TRACEABILITY: DEGRADED (ci push failed)` for the Phase 12 report, reports "CI status unknown — verify manually before merging" and proceeds to Phase 11 without waiting.
547
561
 
548
562
  <!-- PATTERN: ci-status-gate -->
549
- 1. Wait: run `cd {worktree} && HEAD_SHA=$(git rev-parse HEAD) && node "$HOME/.devflow/scripts/ci-wait.cjs" --pr {PR_NUMBER} --head "$HEAD_SHA"` through the Bash tool with `timeout: 600000`. Each run is one wait of at most 570 seconds and prints one line, `CI <STATUS> pr=… head=… failing=… pending=… waited=…` (INDETERMINATE adds `reason=…`). A missing or unparseable line, a status outside the six below, or a non-zero exit is INDETERMINATE.
563
+ 1. Wait: run `cd {worktree} && HEAD_SHA=$(git rev-parse HEAD) && node "$HOME/.devflow/scripts/ci-wait.cjs" --pr {PR_NUMBER} --head "$HEAD_SHA"` through the Bash tool with `timeout: 600000`. Each run waits at most 570 seconds and prints one line, `CI <STATUS> pr=… head=… failing=… pending=… waited=…` (INDETERMINATE adds `reason=…`). A missing or unparseable line, an unknown status or a non-zero exit is INDETERMINATE.
550
564
  2. **If PASSING** → proceed to Phase 11.
551
565
  3. **If NO_PR or NO_CI** → skip: "No PR/CI configured, skipping CI validation." Proceed to Phase 11.
552
- 4. **If PENDING** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI still running — verify manually before merging" and proceed.
553
- 5. **If INDETERMINATE** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI status unknown — verify manually before merging" and proceed.
566
+ 4. **If PENDING** and fewer than 3 waits have run → wait again. Otherwise → report "CI still running — verify manually before merging" and proceed.
567
+ 5. **If INDETERMINATE** and fewer than 3 waits have run → wait again, unless `waited=570` with `reason=head-mismatch` or `no-workflow-check`. Otherwise → report "CI status unknown — verify manually before merging" and proceed.
554
568
  6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Fix")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_DIRECTIVE` (when it is not empty), `CI_FAILURES` and `PUSH: false`; `CI_FAILURES` holds the failing-check names from the line and nothing else, because the Fix agent fetches the full names and reads the logs itself and this command reads none. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
555
- 7. **Budget**: at most 3 waits and 2 fixes in all. When one is spent, report the current status and proceed.
569
+ 7. **Budget**: at most 3 waits and 2 fixes in all. When one is spent, report the status and proceed.
556
570
  <!-- /PATTERN: ci-status-gate -->
557
571
 
558
572
  ### Phase 11: Evidence
@@ -582,7 +596,7 @@ Drop the `--evidence` pair when that file does not exist or its path does not ma
582
596
 
583
597
  **Requires:** VALIDATION_RESULT, ALIGNMENT_RESULT, QA_RESULT, PR_NUMBER, EVIDENCE_RESULT, GATE_LEVEL
584
598
 
585
- Display completion summary with phase status, `Gate level: {GATE_LEVEL}` with any level note, Validate's `Lint pack:` line if any, PR info, and next steps.
599
+ Display completion summary with phase status, `Gate level: {GATE_LEVEL}` with any level note, Harden's `no files reviewed` line if any, Validate's `Lint pack:` line if any, PR info, and next steps.
586
600
 
587
601
  Show the test plan's evidence from Phase 11: `Test plan: {VERIFIED-CI + ATTESTED-LOCAL}/{total} verified (VERIFIED-CI {n}, ATTESTED-LOCAL {n})`, read from the `EVIDENCE` line and never inferred, then its `**Body**:` / `**Comment**:` line verbatim. Without an `EVIDENCE` line, show `Test plan: evidence unavailable`; with no test plan, `Test plan: missing`.
588
602
 
@@ -647,9 +661,9 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
647
661
  ├─ Phase 6: Validate (the one full-suite slot)
648
662
  ├─ Phase 7: QA Testing
649
663
  ├─ Phase 8: Re-Validate (only if a qa-fix committed)
650
- ├─ Phase 9: Open PR (every strategy, outside the strategy branches)
664
+ ├─ Phase 9: Open PR (every strategy)
651
665
  ├─ Phase 10: CI Status Gate (every strategy)
652
- ├─ Phase 11: Evidence (every strategy)
666
+ ├─ Phase 11: Evidence
653
667
  ├─ Phase 12: Report
654
668
  │
655
669
  └─ Feature Knowledge Write-Back (Conditional)
@@ -304,7 +304,7 @@ On completion:
304
304
 
305
305
  ## Error Handling
306
306
 
307
- - Validate agent fails (build/test): halt, report failures, do not proceed
307
+ - Validate agent reports no PASS: halt, report failures, do not proceed
308
308
  - User declines release plan: halt gracefully
309
309
  - User halts at the traceability question: stop — nothing has been committed, tagged or published
310
310
  - Git agent reports DEGRADED while gathering, back-linking or associating: warn and continue — never halt the release
@@ -29,7 +29,7 @@ Process issues from code review reports: triage every issue through the blast-ra
29
29
  - Additional filter: must have unresolved reviews (latest review directory has no `resolution-summary.md`)
30
30
  2. **If `--path` flag provided:** use only that worktree, skip discovery
31
31
  **`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
32
- 3. **If only 1 resolvable worktree** (the common case): proceed as single-worktree flow — zero behavior change
32
+ 3. **If only 1 resolvable worktree:** proceed as single-worktree flow
33
33
  4. **If multiple resolvable worktrees:** report "Found N worktrees with unresolved reviews: {list}" and proceed with multi-worktree flow
34
34
 
35
35
  #### Step 0b: Per-Worktree Pre-Flight (Git Agent)
@@ -59,7 +59,7 @@ PR_DESCRIPTION=$(gh pr view {pr_number} --json body --jq '.body' 2>/dev/null ||
59
59
  ```
60
60
  If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
61
61
 
62
- **DIFF_FILES** is extracted from the `### Diff Scope` block in the Git agent validate-branch output. Set to empty string `""` if the block is absent (bug-analysis mode edge case).
62
+ **DIFF_FILES** is the `### Diff Scope` block of the validate-branch output, or `""` when the block is absent.
63
63
 
64
64
  #### Step 0c: Target Review Directory
65
65
 
@@ -70,13 +70,13 @@ For each worktree:
70
70
 
71
71
  1. List directories in `{worktree}/.devflow/docs/reviews/{branch-slug}/`
72
72
  2. **If `--review {timestamp}` provided:** use that specific directory (not supported in multi-worktree mode)
73
- 3. **Otherwise:** sort directories by name descending (timestamps are naturally sortable), scan the 10 most recent directories only. Select the first that contains `review-summary.md` (complete review)
73
+ 3. **Otherwise:** sort directories by name descending, scan the 10 most recent directories only. Select the first that contains `review-summary.md` (complete review)
74
74
  4. **If latest directory already has `resolution-summary.md`:** the review is resolved — check bug-analysis fallback (step 5b).
75
75
  5. **Legacy fallback:** if no timestamped subdirectories exist but flat `*.md` files do in `{worktree}/.devflow/docs/reviews/{branch-slug}/`, read them directly.
76
76
 
77
77
  **5b. Bug analysis fallback** — if no qualifying review directory found (no reviews exist, or all resolved):
78
78
  - List directories in `{worktree}/.devflow/docs/bug-analysis/{branch-slug}/`
79
- - Sort by name descending (timestamps are naturally sortable), scan the 10 most recent directories only. Select the latest that:
79
+ - Sort by name descending, scan the 10 most recent directories only. Select the latest that:
80
80
  - Contains at least one focus report (`security.md`, `functional.md`, `integration.md`, or `usability.md`)
81
81
  - Does NOT contain a `resolution-summary.md`
82
82
  - If found: set `TARGET_DIR` to that path. Reviews take priority — bug analysis is only used when no qualifying review exists.
@@ -196,9 +196,9 @@ Read review reports from `{TARGET_DIR}/*.md` and extract:
196
196
 
197
197
  **Exclude from issue extraction:**
198
198
  - `review-summary.md` (Synthesize agent output, not individual findings)
199
- - `resolution-summary.md` (if it exists from a previous partial run)
199
+ - `resolution-summary.md` (from a previous partial run)
200
200
  - `bug-analysis-summary.md` (Synthesize agent output for bug-analysis runs)
201
- - `static-findings.md` (raw static analysis tool output, not individual findings)
201
+ - `static-findings.md` (raw tool output, not individual findings)
202
202
 
203
203
  **Include:** ALL issues from all categories and severities, including Suggestions.
204
204
 
@@ -252,7 +252,7 @@ Triage every issue: collapse duplicates first, then apply the blast-radius dispo
252
252
  Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE."
253
253
  ```
254
254
 
255
- Wait for Triage agent to complete before proceeding. Parse verdict ledger from Triage agent output:
255
+ When the Triage agent completes, parse its verdict ledger:
256
256
  - **ESCALATED**: Security issues requiring human escalation
257
257
  - **FIX_NOW**: Valid issues assigned to Code agents (with risk tier: Standard | Careful | `Standard, prose only: edit text alone; agent instructions count as logic; if this issue needs a logic change, leave it unedited and name it`; any other value counts as Careful). SCOPE gives one `{id}: {tier}` line per issue.
258
258
  - **FALSE_POSITIVE**: Issues the Review agent got wrong (with cited evidence)
@@ -278,7 +278,7 @@ A ledger `### Summary` line `- Tiers: not applied (…)` is the level note.
278
278
 
279
279
  If FIX_NOW list is empty: skip to Phase 5, then run Phases 9, 9b, 9c and 10.
280
280
 
281
- Otherwise, batch FIX_NOW issues for Code agent execution. **DUPLICATE issues are never dispatched** — they inherit the primary's outcome:
281
+ Otherwise, batch FIX_NOW issues. **DUPLICATE issues are never dispatched** — they inherit the primary's outcome:
282
282
  - **Same-file issues** → one batch (one Code agent per file)
283
283
  - **Distinct-file issues** → parallel Code agents
284
284
  - **Max 5 issues per batch** — chunk large sets
@@ -317,7 +317,7 @@ Collect from each Code agent:
317
317
  **Produces:** RESOLUTION_FILE (early write for compaction safety)
318
318
  **Requires:** TRIAGE_RESULTS, CODE_AGENT_RESULTS, TARGET_DIR, TARGET_DIR_REL, BRANCH_INFO, RESOLUTION_TS, GATE_LEVEL
319
319
 
320
- **Immediately write `resolution-summary.md`** to `{TARGET_DIR}` using the Write tool.
320
+ **Immediately write `resolution-summary.md`** to `{TARGET_DIR}`.
321
321
 
322
322
  Set `Tracked` for FIX_SEPARATE and TECH_DEBT items to `(pending)` — to be backfilled after Phase 9 manage-debt (or `TRACEABILITY: DEGRADED ({reason})` if manage-debt degrades).
323
323
 
@@ -332,7 +332,7 @@ Use the template from the Output Artifact section below. Put text not for public
332
332
  **Produces:** POLISH_RESULT
333
333
  **Requires:** CODE_AGENT_RESULTS, GATE_LEVEL
334
334
 
335
- If any fixes were made, spawn Polish agent to refine the changed code:
335
+ If any fixes were made, spawn Polish agent:
336
336
 
337
337
  ```
338
338
  Agent(subagent_type="Polish", run_in_background=false):
@@ -345,7 +345,7 @@ Commit any improvements with a conventional-commit message."
345
345
 
346
346
  ### Phase 7: Verification Gate
347
347
 
348
- **Produces:** VERIFICATION_STATUS
348
+ **Produces:** VERIFICATION_STATUS, VERIFICATION_BLOCKER
349
349
  **Requires:** CODE_AGENT_RESULTS, BRANCH_INFO
350
350
 
351
351
  If no fixes were made (CODE_AGENT_RESULTS contains 0 commits) → set VERIFICATION_STATUS = SKIPPED, skip: "No fixes applied — skipping Verification Gate."
@@ -362,10 +362,9 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
362
362
  `validation_retry_count = 0`
363
363
 
364
364
  **If FAIL:**
365
- 1. Extract failure details from Validate agent output
366
- 2. Increment `validation_retry_count`
367
- 3. If `validation_retry_count <= 2`:
368
- - Spawn Fix agent with fix context:
365
+ 1. Increment `validation_retry_count`
366
+ 2. If `validation_retry_count <= 2`:
367
+ - Spawn Fix agent:
369
368
  ```
370
369
  Agent(subagent_type="Fix"):
371
370
  "OPERATION: validation-fix
@@ -377,12 +376,16 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
377
376
  {COMPLIANCE_DIRECTIVE}"
378
377
  ```
379
378
  - Loop back to re-validate
380
- 4. If `validation_retry_count > 2`: set VERIFICATION_STATUS = FAILED and exit the validation loop — record a blocking callout in the `## Verification` section (never a silent pass).
379
+ 3. If `validation_retry_count > 2`: set VERIFICATION_STATUS = FAILED, Final gate `FAILED after N attempts`; exit the validation loop.
381
380
 
382
- **If PASS:** set VERIFICATION_STATUS = PASS and exit the validation loop.
381
+ **If BLOCKED:** FAILED, Final gate `FAILED (Validate blocked)`, no Fix agent, exit the loop; VERIFICATION_BLOCKER = its cause and log path, for the Phase 10 report only, never resolution-summary.md.
382
+
383
+ **If PASS:** set VERIFICATION_STATUS = PASS, Final gate `PASS`; exit the validation loop.
384
+
385
+ Any other or missing Status: FAILED, Final gate `FAILED (no Validate status)`, exit the loop; never PASS.
383
386
 
384
387
  Record `## Verification` outcome in resolution-summary.md (runs unconditionally after the validation loop exits):
385
- - Rewrite the `## Verification` section with | Command | Result | table + `Final gate: PASS | FAILED after N attempts`
388
+ - Rewrite the `## Verification` section with | Command | Result | table + `Final gate: {value above}`; a FAILED gate gets a blocking callout (never a silent pass)
386
389
 
387
390
  Push all commits to remote once (Code and Fix agents ran with PUSH: false — runs whether the gate PASSED or FAILED, so the branch is always visible before Phase 9 or CI runs):
388
391
  ```bash
@@ -398,9 +401,7 @@ git -C {worktree} push
398
401
  **Produces:** CI_STATUS
399
402
  **Requires:** CODE_AGENT_RESULTS, VERIFICATION_STATUS, BRANCH_INFO
400
403
 
401
- If no issues were fixed (CODE_AGENT_RESULTS contains 0 fixes) → skip: "No fixes applied — skipping CI validation."
402
-
403
- If Verification Gate FAILED → skip CI gate (validation failures already reported).
404
+ If VERIFICATION_STATUS is not PASS → skip CI gate.
404
405
 
405
406
  If `fork_no_push` is set → skip: "Cannot push to fork — skipping CI validation."
406
407
 
@@ -414,16 +415,16 @@ Otherwise, for each worktree with fixes:
414
415
  git -C {worktree} push; echo "exit=$?"
415
416
  ```
416
417
 
417
- Phase 7 has pushed already, so this is a no-op unless the head moved since. `exit=0` continues to the gate. Any other result records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and skips the wait for this worktree. Pass `WORKTREE_PATH: {worktree_path}` on the fix spawn below.
418
+ `exit=0` continues to the gate. Any other result records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and skips the wait for this worktree. Pass `WORKTREE_PATH: {worktree_path}` on the fix spawn below.
418
419
 
419
420
  <!-- PATTERN: ci-status-gate -->
420
- 1. Wait: run `cd {worktree} && HEAD_SHA=$(git rev-parse HEAD) && node "$HOME/.devflow/scripts/ci-wait.cjs" --pr {PR_NUMBER} --head "$HEAD_SHA"` through the Bash tool with `timeout: 600000`. Each run is one wait of at most 570 seconds and prints one line, `CI <STATUS> pr=… head=… failing=… pending=… waited=…` (INDETERMINATE adds `reason=…`). A missing or unparseable line, a status outside the six below, or a non-zero exit is INDETERMINATE.
421
+ 1. Wait: run `cd {worktree} && HEAD_SHA=$(git rev-parse HEAD) && node "$HOME/.devflow/scripts/ci-wait.cjs" --pr {PR_NUMBER} --head "$HEAD_SHA"` through the Bash tool with `timeout: 600000`. Each run waits at most 570 seconds and prints one line, `CI <STATUS> pr=… head=… failing=… pending=… waited=…` (INDETERMINATE adds `reason=…`). A missing or unparseable line, an unknown status or a non-zero exit is INDETERMINATE.
421
422
  2. **If PASSING** → proceed to next phase.
422
423
  3. **If NO_PR or NO_CI** → skip: "No PR/CI configured, skipping CI validation." Proceed to next phase.
423
- 4. **If PENDING** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI still running — verify manually before merging" and proceed.
424
- 5. **If INDETERMINATE** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI status unknown — verify manually before merging" and proceed.
425
- 6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Fix")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_DIRECTIVE` (when it is not empty), `CI_FAILURES` and `PUSH: false`; `CI_FAILURES` holds the failing-check names from the line and nothing else, because the Fix agent fetches the full names and reads the logs itself and this command reads none. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
426
- 7. **Budget**: at most 3 waits and 2 fixes in all, per worktree. When one is spent, report the current status and proceed.
424
+ 4. **If PENDING** and fewer than 3 waits have run → wait again. Otherwise → report "CI still running — verify manually before merging" and proceed.
425
+ 5. **If INDETERMINATE** and fewer than 3 waits have run → wait again, unless `waited=570` with `reason=head-mismatch` or `no-workflow-check`. Otherwise → report "CI status unknown — verify manually before merging" and proceed.
426
+ 6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Fix")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_DIRECTIVE` (when it is not empty), `CI_FAILURES` and `PUSH: false`; `CI_FAILURES` holds only the failing-check names from the line: the Fix agent fetches the full names and reads the logs itself. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
427
+ 7. **Budget**: at most 3 waits and 2 fixes in all, per worktree. When one is spent, report the status and proceed.
427
428
  <!-- /PATTERN: ci-status-gate -->
428
429
 
429
430
  ### Phase 9: Manage Debt (Sequential)
@@ -482,6 +483,8 @@ Append one claim per `### Test Plan Evidence` row whose TP is in the stale file
482
483
 
483
484
  The line ends at `by:test` when the row's Exit is not a number from 0 to 255; append nothing when the report's `HEAD:` is not one 40-hex SHA. Record `Test plan: {n} stale, {m} re-verified` under `## Verification` in resolution-summary.md now, before 9b-2 posts it, and set `STALE_REVERIFICATION` to that line.
484
485
 
486
+ A Test Status whose first word is not PASS or FAIL still gets its claims, but `Test plan: DEGRADED (Test run blocked)` replaces that line. `{m}` counts PASS rows only.
487
+
485
488
  **Step 9b-1: Resolve external threads**
486
489
 
487
490
  Run this step only when `EVIDENCE_POLICY` is `required` and THREAD_MAP is non-empty; otherwise skip it and record `THREAD_RESOLUTION_RESULT` as `SKIPPED ({reason})`.
@@ -561,7 +564,7 @@ If the script prints a `TRACEABILITY: DEGRADED` line: warn, proceed to Phase 10.
561
564
 
562
565
  ### Phase 10: Report
563
566
 
564
- **Requires:** BRANCH_INFO, TARGET_DIR, PR_COMMENT, THREAD_RESOLUTION_RESULT, GATE_LEVEL
567
+ **Requires:** BRANCH_INFO, TARGET_DIR, PR_COMMENT, THREAD_RESOLUTION_RESULT, GATE_LEVEL, VERIFICATION_BLOCKER
565
568
 
566
569
  The resolution summary was already written to `{TARGET_DIR}/resolution-summary.md` in Phase 5 (updated by Phase 7, Phase 9 and Phase 9b-1). Display results to the user:
567
570
 
@@ -585,7 +588,8 @@ The resolution summary was already written to `{TARGET_DIR}/resolution-summary.m
585
588
  | Duplicates Collapsed | {n} |
586
589
 
587
590
  ### Verification
588
- Final gate: {PASS | FAILED after N attempts}
591
+ Final gate: {the value Phase 7 recorded}
592
+ {VERIFICATION_BLOCKER, if any}
589
593
 
590
594
  ### Commits Created
591
595
  - {sha} {message}
@@ -707,7 +711,7 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
707
711
 
708
712
  ## Output Artifact
709
713
 
710
- Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
714
+ Written in Phase 5 to `{TARGET_DIR}/resolution-summary.md`:
711
715
 
712
716
  ```markdown
713
717
  # Resolution Summary
@@ -739,7 +743,7 @@ _(Note: `Deferred` = `## Fix Separately` count + `## Deferred to Tech Debt` coun
739
743
 
740
744
  Regression tests added: {n}
741
745
 
742
- Final gate: PASS | FAILED after {n} attempts
746
+ Final gate: {the value Phase 7 recorded}
743
747
 
744
748
  ## Fixed Issues
745
749
  | Issue | File:Line | Commit |
@@ -131,7 +131,7 @@ Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE. Skip if (none)."
131
131
 
132
132
  If STATUS is BLOCKED, skip this phase: the report (Phase 4) names the blocker.
133
133
 
134
- Run this phase only if HEAD moved — `git rev-parse HEAD` differs from `HEAD_BEFORE`, meaning Polish or Harden committed (Polish alone counts, whatever Harden's STATUS is). Otherwise skip it. Its scope is changed-only over what the two agents changed:
134
+ Run this phase only if HEAD moved — `git rev-parse HEAD` differs from `HEAD_BEFORE`, meaning Polish or Harden committed (Polish alone counts, whatever Harden's STATUS is). Otherwise skip it.
135
135
 
136
136
  Agent(subagent_type="Validate", run_in_background=false):
137
137
  "FILES_CHANGED: {output of `git diff --name-only HEAD_BEFORE..HEAD`}
@@ -140,6 +140,7 @@ Run build, typecheck, lint, test on modified files"
140
140
 
141
141
  **If FAIL:** Report validation failures to user and halt
142
142
  **If PASS:** Continue to report
143
+ **Any other or missing Status** (BLOCKED included): report the status or "none", its cause and log path if any, then halt.
143
144
 
144
145
  ### Phase 4: Report
145
146
 
@@ -230,7 +231,7 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
230
231
  │ └─ 9-pillar quality gate (may fix and commit)
231
232
  │
232
233
  ├─ Phase 3: Validate agent (conditional)
233
- │ └─ If HEAD moved since HEAD_BEFORE (Polish or Harden committed), changed-only Validate over HEAD_BEFORE..HEAD
234
+ │ └─ If HEAD moved: changed-only over HEAD_BEFORE..HEAD
234
235
  │
235
236
  └─ Phase 4: Report
236
237
  └─ Display summary with pillar status
@@ -242,13 +243,13 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
242
243
  | No changes | Report "No changes to review" and exit |
243
244
  | Polish agent finds nothing | Normal, continue to Harden agent |
244
245
  | Harden agent BLOCKED | Report blocking issue, halt workflow |
245
- | Validation fails | Report failures, halt (don't create broken state) |
246
+ | Validation fails | Report failures, halt |
247
+ | Validate not PASS or FAIL | Report status and cause, halt |
246
248
  | Not in git repo | Report error, suggest running in git repo |
247
249
 
248
250
  ## Principles
249
251
 
250
252
  1. **Orchestration only** - Command spawns agents, doesn't do the work
251
- 2. **Sequential execution** - Polish agent must complete before Harden agent
252
- 3. **Validation gate** - If Polish agent or Harden agent committed, the changes must pass validation
253
- 4. **Honest reporting** - Display actual agent outputs
254
- 5. **Fail fast** - Stop on BLOCKED or validation failure
253
+ 2. **Validation gate** - If Polish agent or Harden agent committed, the changes must pass validation
254
+ 3. **Honest reporting** - Display actual agent outputs
255
+ 4. **Fail fast** - Stop on BLOCKED or a Validate status other than PASS
@@ -41,7 +41,7 @@ Each `THREAD_MAP` entry carries one verdict:
41
41
 
42
42
  ### Process
43
43
 
44
- Rate limits: this op fans out, so read the remaining-budget rungs in `references/github-api.md` before the first iteration.
44
+ Rate limits: this op fans out, so read the remaining-budget rungs in `references/github-api.md` before the first iteration. The thread-reply and `resolveReviewThread` recipes are in `references/github-posting.md`.
45
45
 
46
46
  For each `ext-{N}` in THREAD_MAP (sequentially, ≤50, 1s between operations). `fetch-review-threads`
47
47
  returns up to 100 threads, so a busy PR can exceed this bound: process the first 50 in THREAD_MAP
@@ -22,6 +22,7 @@
22
22
  import { promises as fs } from 'fs';
23
23
  import * as path from 'path';
24
24
  import { installRuleFile } from './installer.js';
25
+ import { newLinkReport, refuseUnrealFolder, warnLinkReport } from './linked-folder.js';
25
26
  // ── Types ──────────────────────────────────────────────────────────────────
26
27
  export const BEHAVIOR_RULE_NAME = 'behavior';
27
28
  // ── Path helpers ───────────────────────────────────────────────────────────
@@ -47,46 +48,59 @@ async function pathExists(p) {
47
48
  * enabled + !rulesEnabled → rule file removed
48
49
  * !enabled → rule file removed
49
50
  *
51
+ * `rules/devflow` that is a link, or not a folder, is refused: the rule is neither written nor
52
+ * removed there, and the folder is named in `refusedFolders` and in a warning. A rule file that is a
53
+ * link is replaced by a real file, or unlinked on removal, and never written through.
54
+ *
50
55
  * Never throws. A relative `claudeDir` is refused with a warning rather than resolved
51
56
  * against the working directory, because the removal arm deletes a path.
52
57
  */
53
58
  export async function convergeBehaviorRule(opts) {
54
59
  const { claudeDir, devflowDir, enabled, rulesEnabled, warn } = opts;
60
+ const links = newLinkReport();
61
+ const finish = (state) => {
62
+ warnLinkReport(links, warn);
63
+ return { ...state, replacedLinks: links.replacedLinks, refusedFolders: links.refusedFolders };
64
+ };
55
65
  if (!path.isAbsolute(claudeDir)) {
56
66
  warn(`behavior: claudeDir is not an absolute path ("${claudeDir}") — skipping convergence`);
57
- return { installed: false, removed: false, converged: false };
67
+ return finish({ installed: false, removed: false, converged: false });
58
68
  }
59
69
  const target = behaviorRulePath(claudeDir);
70
+ // A link at the folder sends the write and the removal into another place, so the folder is proven first.
71
+ if (await refuseUnrealFolder(links, path.dirname(target))) {
72
+ return finish({ installed: await pathExists(target), removed: false, converged: false });
73
+ }
60
74
  if (enabled && rulesEnabled) {
61
75
  try {
62
76
  await fs.mkdir(path.dirname(target), { recursive: true });
63
- const outcome = await installRuleFile(BEHAVIOR_RULE_NAME, devflowDir, path.dirname(target));
77
+ const outcome = await installRuleFile(BEHAVIOR_RULE_NAME, devflowDir, path.dirname(target), links);
64
78
  if (outcome === 'skipped') {
65
79
  warn('behavior: rule install failed — the file could not be copied');
66
- return { installed: false, removed: false, converged: false };
80
+ return finish({ installed: false, removed: false, converged: false });
67
81
  }
68
82
  if (outcome === 'source-invalid-shadow:empty-shadow-file' || outcome === 'source-invalid-shadow:not-a-file') {
69
83
  warn("behavior: the shadow is invalid — Devflow's version was installed");
70
- return { installed: true, removed: false, converged: false };
84
+ return finish({ installed: true, removed: false, converged: false });
71
85
  }
72
- return { installed: true, removed: false, converged: true };
86
+ return finish({ installed: true, removed: false, converged: true });
73
87
  }
74
88
  catch (err) {
75
89
  warn(`behavior: rule install failed — ${String(err)}`);
76
- return { installed: false, removed: false, converged: false };
90
+ return finish({ installed: false, removed: false, converged: false });
77
91
  }
78
92
  }
79
93
  // Off, or rules off: no rule. Probe first so the caller can report a removal;
80
94
  // absence is already the desired end state.
81
95
  if (!(await pathExists(target)))
82
- return { installed: false, removed: false, converged: true };
96
+ return finish({ installed: false, removed: false, converged: true });
83
97
  try {
84
98
  await fs.rm(target, { force: true });
85
- return { installed: false, removed: true, converged: true };
99
+ return finish({ installed: false, removed: true, converged: true });
86
100
  }
87
101
  catch (err) {
88
102
  warn(`behavior: failed to remove rule — ${String(err)}`);
89
- return { installed: true, removed: false, converged: false };
103
+ return finish({ installed: true, removed: false, converged: false });
90
104
  }
91
105
  }
92
106
  // ── Manifest-slice wrapper ─────────────────────────────────────────────────