@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.19

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 (225) hide show
  1. package/out/mcp-server.js +1405 -684
  2. package/package.json +6 -4
  3. package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
  4. package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
  5. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
  6. package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
  7. package/resources/claude-customizations/.claude/agents/feature-review.md +16 -5
  8. package/resources/claude-customizations/.claude/agents/orchestrator.md +21 -7
  9. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +37 -13
  10. package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
  11. package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
  12. package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
  13. package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
  14. package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
  15. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
  16. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
  17. package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
  18. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
  19. package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
  20. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
  21. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
  22. package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
  23. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
  24. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
  25. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
  26. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
  27. package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
  28. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
  29. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
  30. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
  31. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
  32. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
  33. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
  34. package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
  35. package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
  36. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
  37. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
  38. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
  39. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
  40. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
  41. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
  42. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
  43. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
  44. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
  45. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
  46. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
  47. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
  48. package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
  49. package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
  50. package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
  51. package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
  52. package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
  53. package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
  54. package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
  55. package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
  56. package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
  57. package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
  58. package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
  59. package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
  60. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
  61. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
  62. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
  63. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
  64. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
  65. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
  66. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
  67. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
  68. package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
  69. package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
  70. package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
  71. package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
  72. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
  73. package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
  74. package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
  75. package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
  76. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
  77. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
  78. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
  79. package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
  80. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
  81. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
  82. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
  83. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
  84. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
  85. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +396 -0
  86. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
  87. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
  88. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
  89. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
  90. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
  91. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
  92. package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
  93. package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
  94. package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
  95. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +153 -4
  96. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
  97. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
  98. package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
  99. package/resources/claude-customizations/.claude/rules/shell.md +10 -8
  100. package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
  101. package/resources/claude-customizations/.claude/settings.json +3 -4
  102. package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +9 -1
  103. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +7 -1
  104. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
  105. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
  106. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
  107. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +171 -5
  108. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
  109. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
  110. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +6 -15
  111. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -11
  112. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
  113. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  114. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
  115. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +7 -4
  116. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -16
  117. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
  118. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
  119. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +97 -19
  120. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
  121. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
  122. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
  123. package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
  124. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
  125. package/resources/claude-customizations/pack-manifests/core.json +25 -0
  126. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +9 -1
  127. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
  128. package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
  129. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
  130. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
  131. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
  132. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
  133. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +13 -3
  134. package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
  135. package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
  136. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  137. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  138. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
  139. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +16 -6
  140. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
  141. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
  142. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +43 -11
  143. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
  144. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +19 -4
  145. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
  146. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
  147. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
  148. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
  149. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
  150. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
  151. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
  152. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
  153. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
  154. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
  155. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
  156. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
  157. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
  158. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
  159. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
  160. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
  161. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
  162. package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
  163. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
  164. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
  165. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
  166. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
  167. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
  168. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
  169. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
  170. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +3 -3
  171. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +3 -3
  172. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +3 -3
  173. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +3 -3
  174. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +3 -3
  175. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +3 -3
  176. package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
  177. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  178. package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
  179. package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
  180. package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
  181. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
  182. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
  183. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
  184. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
  185. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
  186. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
  187. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
  188. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
  189. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
  190. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
  191. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
  192. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
  193. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
  194. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
  195. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
  196. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
  197. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
  198. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
  199. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
  200. package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
  201. package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
  202. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
  203. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
  204. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
  205. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
  206. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
  207. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
  208. package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
  209. package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
  210. package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
  211. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
  212. package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
  213. package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
  214. package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
  215. package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
  216. package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
  217. package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +9 -1
  218. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
  219. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  220. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
  221. package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
  222. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
  223. package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
  224. package/resources/powershell/PoshQC/README.md +8 -2
  225. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -315
@@ -104,6 +104,10 @@ For short-path/minimal-audit plans, Phase 0 evidence is incomplete unless both a
104
104
 
105
105
  `Output Summary:` is mandatory for each command-step artifact and must concisely summarize the essential result signal (for example: pass/fail status, key counts, coverage headline, or primary diagnostic).
106
106
 
107
+ ## Evidence Filename Timestamps in Plans
108
+
109
+ Plans name evidence artifacts `<name>.<timestamp>.md` and never fix a plan-time stamp in an evidence filename. An acceptance condition identifies a consumed evidence artifact by the derivation in `evidence-and-timestamp-conventions` (`### Evidence Filename Timestamp`): the lexicographically greatest file matching `<name>.*.md`, not a pre-stamped literal path. This section governs artifact paths only: asserted search tokens remain concrete.
110
+
107
111
  ## Coverage Evidence Contract (Mandatory when policy requires coverage)
108
112
 
109
113
  For any language in scope where repository policy requires coverage validation:
@@ -191,7 +195,7 @@ Before a plan can be treated as approved:
191
195
 
192
196
  The same validator call also applies the acceptance-gate rules G1 through G6 defined in `.claude/rules/plan-acceptance-gates.md`. Those rules report acceptance conditions that cannot fail — a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. They run automatically on the existing `plan` route with no additional flag. Blocking findings appear in the validator's error output and fail the gate; Warnings are surfaced without failing it, prefixed with `PLAN GATE WARNING: ` on the CLI and carried on the optional `warnings` field of the MCP result. Read that rule file before authoring acceptance conditions.
193
197
 
194
- The same call additionally applies the rules G7, G8, G8b, and G9, which report a write-mode command observed only by its exit code, an unanchored `git diff`, a name-listing diff with no companion span, and a coverage command that prints no table. All four ship in the Warning channel, so they surface without failing the gate. The complete shipped set is therefore G1 through G9.
198
+ The same call additionally applies the rules G7, G8, G8b, and G9, which report a write-mode command observed only by its exit code, an unanchored `git diff`, a name-listing diff with no companion span, and a coverage command that prints no table. All four ship in the Warning channel, so they surface without failing the gate. The same call also applies G10, a document-level rule that reports a SCRATCH definition not namespaced by issue number. G10 ships in the Blocking channel and reports each finding with a `Line N: ` prefix rather than a task identifier, because the definition sits outside any task window. The complete shipped set is therefore G1 through G10.
195
199
 
196
200
  ## Wrap-Tolerant Assertion Authoring (Mandatory)
197
201
 
@@ -212,6 +216,8 @@ Rules:
212
216
  - **Observe a command's success-case output before asserting over that output (mandatory).** Run the command, or read a recorded run of it, and confirm the value you intend to assert is actually printed on a *successful* run. Do not infer it from the tool's documentation, from the plan, or from what the tool prints on failure. This requirement exists because the class of defect it prevents is not detectable by reading: an assertion on a line the tool prints only when it changed something is unsatisfiable on a clean run; a demand for a zero-diagnostic count from a tool that returns only an ok flag names a value with no source; a demand for separate line and branch percentages from a coverage run that prints one combined column reads two numbers that are never printed. G7 and G9 cover two decidable slices of this class. The remainder is covered by this requirement and by nothing else, so a reviewer cannot rely on the gate to catch it.
213
217
  - **Fix the evidence in the plan; never leave the executor to select it.** An executor free to choose the evidence it is judged against cannot fail. Do not write an acceptance condition that asks the executor to identify "the known-genuine pair", to choose a survivor list, or to pick any suitable instance. Name the instances, or state the mechanical derivation that produces them, so a third party re-running it obtains the same set. This is authoring guidance and not a rule: a validator rule that scanned acceptance text for selection vocabulary was proposed and rejected, because that vocabulary is ordinary plan prose used in roles carrying no selection semantics and a keyword scan over prose is not statically decidable for the property it would claim to detect. The judgment is the author's, and it is not automated. `.claude/rules/plan-acceptance-gates.md` records the rejection and the reason for it.
214
218
  - **Check that the task-ordering does not make the condition unsatisfiable.** No rule covers this. A gate that runs a test path containing deliberately-failing cases added by an earlier task, before the later task that makes them pass, cannot exit 0. A baseline captured after a write-mode formatter has already repaired pre-existing drift becomes either a blanket waiver or makes a later gate unsatisfiable. Read each acceptance condition against the state the plan will actually be in when its task runs.
219
+ - **Name the runner and job for a Pester acceptance criterion.** CI runs Pester in two jobs of `.github/workflows/_poshqc.yml`: `poshqc / PowerShell QC` runs every suite with coverage on `windows-latest`, and `poshqc / PowerShell hook suites (Linux)` runs only `tests/scripts/claude-hooks` and `tests/scripts/codex-hooks` on `ubuntu-latest`, with coverage disabled. A Pester acceptance criterion may cite `ubuntu-latest` only for suites under `tests/scripts/claude-hooks` or `tests/scripts/codex-hooks`, never for coverage, and must name the job it relies on (`poshqc / PowerShell QC` or `poshqc / PowerShell hook suites (Linux)`).
220
+ - **Do not assert a fixed-string search literal that contains a backslash.** Git for Windows grep 3.0 reads a doubled backslash in a `grep -F` pattern as one backslash, so the same check returns a different count locally than on a CI runner and cannot pass in both places. Assert a backslash-free substring of the literal, a named test, or a hash or byte-identity check instead.
215
221
 
216
222
  ## Plan-Path Continuity Contract (Mandatory)
217
223
 
@@ -128,9 +128,17 @@ The script emits pipe-delimited, `LC_ALL=C`-ordered records, one per line:
128
128
  per-file outcome is reported by the companion `ACTION|preserve-stage|...` record.
129
129
  - `ORPHAN_DIR|<path>|<size>` — a directory under a worktree-tracking root that carries
130
130
  no `.git` pointer file and no `git worktree list` entry. `<size>` is best-effort and
131
- may be the literal `unknown`. The record is advisory: it reports the directory, and
132
- nothing in apply mode acts on it. For the disposition, see the Dirty Worktree Triage
133
- Procedure's step 7, which governs how an orphaned directory is handled.
131
+ may be the literal `unknown`. The scanned roots are the default pair
132
+ `<main>/.claude/worktrees` and `<main>-wt`, or the `CLEANUP_WT_ORPHAN_ROOTS` entries
133
+ when that variable is set (the override replaces the default pair), plus the parent
134
+ directory of every non-main registered worktree, which is always added. A derived
135
+ parent is skipped when it is the main worktree or one of its ancestors, or is equal to
136
+ or inside a registered worktree. `CLEANUP_WT_ORPHAN_ROOTS` entries are separated by a
137
+ semicolon, a newline, or a colon; a colon that follows a single drive letter and
138
+ precedes `/` or `\` is part of the path, and empty or relative entries are dropped.
139
+ The record is advisory: it reports the directory, and nothing in apply mode acts on
140
+ it. For the disposition, see the Dirty Worktree Triage Procedure's step 7, which
141
+ governs how an orphaned directory is handled.
134
142
  - `STALE_REF|<refname>` — a `refs/remotes/<name>/*` ref whose `<name>` is not a
135
143
  configured remote, named in full ref form. Advisory only; no ref is ever pruned by
136
144
  this tool.
@@ -139,8 +139,17 @@ Environment overrides:
139
139
  nonexistent value is treated as missing (falls back to
140
140
  the bundled cleanup_worktrees_scan_helper.sh). This is
141
141
  the filesystem-scan test-stub seam.
142
- CLEANUP_WT_ORPHAN_ROOTS Colon-separated override for the worktree-tracking roots
143
- scanned for ORPHAN_DIR and WARN|registration-lost.
142
+ CLEANUP_WT_ORPHAN_ROOTS Worktree-tracking roots scanned for ORPHAN_DIR and
143
+ WARN|registration-lost. Entries are separated by a
144
+ semicolon, a newline, or a colon; a colon that follows
145
+ a single drive letter and precedes / or \ is part of
146
+ the path (C:/x). Empty and relative entries are
147
+ dropped. When set, it replaces the default pair
148
+ <main>/.claude/worktrees and <main>-wt. The parent of
149
+ every non-main registered worktree is always added,
150
+ except a parent that is the main worktree or its
151
+ ancestor, or is equal to or inside a registered
152
+ worktree.
144
153
  CLEANUP_WT_STUB_SCENARIO Scenario directory consumed by the checked-in git and
145
154
  scan stubs (tests only).
146
155
  CLEANUP_WT_CONSOLIDATION_PATH Override the derived consolidation worktree path
@@ -43,7 +43,7 @@ is_detached_candidate() {
43
43
  #
44
44
  # The predicate is the porcelain FLAG, not the branch field: emit_record writes the
45
45
  # literal DETACHED into the branch field whenever the branch accumulator is empty
46
- # (.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh:115-116), which is also true of a
46
+ # (emit_record, nested in parse_worktree_list in cleanup_worktrees_enumerate_lib.sh), which is also true of a
47
47
  # bare-repository stanza, and a local branch literally named DETACHED would produce
48
48
  # the same branch field with no `detached` flag.
49
49
  #
@@ -4,16 +4,19 @@
4
4
  # every file within the 500-line cap. Provides the git-binary test seam
5
5
  # (cleanup_wt_git), branch/worktree enumeration (enumerate_branches,
6
6
  # parse_worktree_list), path normalization (normalize_wt_path), the
7
- # current-worktree/branch and base-branch protection set (compute_protected), and
8
- # the main-freshness warning (check_main_freshness). The classification ladder,
9
- # consolidation, deletion, and the CLI live in sibling files (cleanup_worktrees_lib.sh,
10
- # cleanup_worktrees_actions_lib.sh, cleanup-worktrees.sh).
7
+ # current-worktree/branch and base-branch protection set (compute_protected), the
8
+ # main-freshness warning (check_main_freshness), the shared absolute-path predicate
9
+ # (cleanup_wt_is_absolute_path), and the worktree-tracking scan roots
10
+ # (cleanup_wt_split_roots, cleanup_wt_derive_scan_roots, cleanup_wt_scan_roots). The
11
+ # classification ladder, consolidation, deletion, and the CLI live in sibling files
12
+ # (cleanup_worktrees_lib.sh, cleanup_worktrees_actions_lib.sh, cleanup-worktrees.sh).
11
13
  #
12
14
  # Sourcing contract: defines functions and the single constant CLEANUP_WT_BASE_BRANCH
13
15
  # and runs no other work at source time, so wrapper and bats suites source it safely.
14
16
  # It MUST be sourced before cleanup_worktrees_lib.sh, whose classification functions
15
17
  # call cleanup_wt_git, parse_worktree_list, compute_protected, and normalize_wt_path
16
- # defined here.
18
+ # defined here. The filesystem-scan helper cleanup_worktrees_scan_helper.sh runs as a
19
+ # separate process and sources this library directly for cleanup_wt_is_absolute_path.
17
20
  #
18
21
  # All git commands go through cleanup_wt_git so tests can stub the git binary via
19
22
  # CLEANUP_WT_GIT_BIN. Git exit-code capture rule: the `git worktree list --porcelain`
@@ -250,3 +253,166 @@ check_main_freshness() {
250
253
  fi
251
254
  return 0
252
255
  }
256
+
257
+ cleanup_wt_is_absolute_path() {
258
+ # Return 0 when <path> is absolute, else 1. Pure: no filesystem access.
259
+ #
260
+ # Absolute forms are a leading `/` (POSIX paths, MSYS `/c/...` paths, and `//server`
261
+ # UNC paths) and a drive letter followed by `/` or `\` (`C:/...`, `c:/...`,
262
+ # `C:\...`), which is the form Git for Windows writes into a worktree's `.git`
263
+ # pointer file (issue #706). A drive letter with no separator (`C:rel`) is
264
+ # drive-relative and is not absolute; an empty path is not absolute. This is the one
265
+ # absolute-path predicate of the skill: the preserve library and the filesystem-scan
266
+ # helper both call it.
267
+ #
268
+ # Args: $1 = path. Returns 0 (absolute) or 1 (not absolute).
269
+ local path=${1:-}
270
+ [[ $path == /* || $path == [A-Za-z]:[/\\]* ]]
271
+ }
272
+
273
+ cleanup_wt_split_roots() {
274
+ # Split a CLEANUP_WT_ORPHAN_ROOTS value into absolute roots, one per line.
275
+ #
276
+ # Entries are separated by `;`, by a newline, or by `:`. A `:` is part of the path
277
+ # instead when the text before it in the current entry is exactly one ASCII letter
278
+ # and the character after it is `/` or `\` (a drive letter, as in `C:/x`). Empty
279
+ # entries are dropped. An entry that is not absolute (cleanup_wt_is_absolute_path) is
280
+ # dropped with a one-line stderr diagnostic naming it, because a relative root would
281
+ # be resolved against the process's current working directory.
282
+ #
283
+ # The value is walked one character at a time with parameter expansion and never
284
+ # word-split, so no pathname expansion occurs and a `*` is emitted literally.
285
+ #
286
+ # Args: $1 = the override value. Always returns 0.
287
+ local value=${1:-}
288
+ local -a entries=()
289
+ local entry="" ch next i
290
+ for ((i = 0; i < ${#value}; i++)); do
291
+ ch=${value:i:1}
292
+ if [[ $ch == ';' || $ch == $'\n' ]]; then
293
+ entries+=("$entry")
294
+ entry=""
295
+ elif [[ $ch == ':' ]]; then
296
+ next=${value:i+1:1}
297
+ if [[ ${#entry} -eq 1 && $entry == [A-Za-z] && $next == [/\\] ]]; then
298
+ entry+=$ch
299
+ else
300
+ entries+=("$entry")
301
+ entry=""
302
+ fi
303
+ else
304
+ entry+=$ch
305
+ fi
306
+ done
307
+ entries+=("$entry")
308
+ for entry in "${entries[@]}"; do
309
+ [[ -z $entry ]] && continue
310
+ if ! cleanup_wt_is_absolute_path "$entry"; then
311
+ printf 'cleanup-worktrees: CLEANUP_WT_ORPHAN_ROOTS entry is not absolute, dropped: %s\n' "$entry" >&2
312
+ continue
313
+ fi
314
+ printf '%s\n' "$entry"
315
+ done
316
+ return 0
317
+ }
318
+
319
+ cleanup_wt_derive_scan_roots() {
320
+ # Echo the registration-derived scan roots, one per line.
321
+ #
322
+ # Input is parse_worktree_list output; its first record is the main worktree. The
323
+ # candidate for every later record is the parent directory of its path (backslashes
324
+ # converted to `/`). A candidate is kept only when its normalize_wt_path value N:
325
+ # - is not the main worktree's normalized path and is not one of its ancestors
326
+ # (scanning an ancestor would list the main worktree's siblings), and
327
+ # - is not equal to, and not inside, any registered worktree, main included
328
+ # (its subdirectories are that worktree's own content, not worktrees).
329
+ # Kept candidates are emitted in LC_ALL=C order of N, once per N, using the first
330
+ # spelling seen in record order.
331
+ #
332
+ # Args: $1 = parse_worktree_list output. Always returns 0.
333
+ local records=${1:-}
334
+ local -a paths=() norms=()
335
+ local record path
336
+ while IFS= read -r record; do
337
+ [[ -z $record ]] && continue
338
+ path=${record%%|*}
339
+ paths+=("$path")
340
+ norms+=("$(normalize_wt_path "$path")")
341
+ done <<<"$records"
342
+ ((${#paths[@]} < 2)) && return 0
343
+ local main_norm=${norms[0]}
344
+ local -A seen=()
345
+ local -a kept=()
346
+ local i p parent n w inside
347
+ for ((i = 1; i < ${#paths[@]}; i++)); do
348
+ p=${paths[i]//\\//}
349
+ parent=${p%/*}
350
+ [[ -z $parent || $parent == "$p" ]] && continue
351
+ # A drive-relative parent (a registration directly under a drive root, such as D:/wt) is not an absolute root and is dropped.
352
+ cleanup_wt_is_absolute_path "$parent" || continue
353
+ n=$(normalize_wt_path "$parent")
354
+ [[ -z $n || -n ${seen[$n]:-} ]] && continue
355
+ [[ $n == "$main_norm" || $main_norm == "$n"/* ]] && continue
356
+ inside=0
357
+ for w in "${norms[@]}"; do
358
+ [[ -z $w ]] && continue
359
+ if [[ $n == "$w" || $n == "$w"/* ]]; then
360
+ inside=1
361
+ break
362
+ fi
363
+ done
364
+ ((inside == 1)) && continue
365
+ seen[$n]=1
366
+ kept+=("$n|$parent")
367
+ done
368
+ ((${#kept[@]} == 0)) && return 0
369
+ local line
370
+ while IFS= read -r line; do
371
+ printf '%s\n' "${line#*|}"
372
+ done < <(printf '%s\n' "${kept[@]}" | LC_ALL=C sort -t '|' -k1,1)
373
+ return 0
374
+ }
375
+
376
+ cleanup_wt_scan_roots() {
377
+ # Echo the worktree-tracking roots to scan, one per line.
378
+ #
379
+ # Configured roots come first: the CLEANUP_WT_ORPHAN_ROOTS entries
380
+ # (cleanup_wt_split_roots) when that variable is set, otherwise the default pair
381
+ # derived from the main worktree path (the first `git worktree list --porcelain`
382
+ # stanza, the same derivation consolidation_worktree_path uses in
383
+ # cleanup_worktrees_actions_lib.sh): `<main>/.claude/worktrees` then `<main>-wt`.
384
+ # Registration-derived roots (cleanup_wt_derive_scan_roots) are always appended.
385
+ # The combined list is deduplicated by normalize_wt_path, keeping the first spelling.
386
+ #
387
+ # The listing is read once (`out=$(...) || rc=$?`). On a parse_worktree_list hard
388
+ # failure nothing is derived from it: with no override no root is emitted at all,
389
+ # rather than a bare relative path resolved against the current working directory,
390
+ # and with an override exactly the override roots are emitted.
391
+ # cleanup_wt_scan_records returns 0 with no record for an empty root list, so the
392
+ # advisory records degrade to silence rather than to a misleading scan.
393
+ # Always returns 0.
394
+ local out rc=0 first_record main_wt="" configured="" derived=""
395
+ out=$(parse_worktree_list) || rc=$?
396
+ if ((rc == 0)); then
397
+ first_record=${out%%$'\n'*}
398
+ main_wt=${first_record%%|*}
399
+ derived=$(cleanup_wt_derive_scan_roots "$out")
400
+ fi
401
+ if [[ -n ${CLEANUP_WT_ORPHAN_ROOTS:-} ]]; then
402
+ configured=$(cleanup_wt_split_roots "$CLEANUP_WT_ORPHAN_ROOTS")
403
+ elif [[ -n $main_wt ]]; then
404
+ configured="${main_wt}/.claude/worktrees"$'\n'"${main_wt}-wt"
405
+ fi
406
+ local -A seen=()
407
+ local root n
408
+ while IFS= read -r root; do
409
+ [[ -z $root ]] && continue
410
+ n=$(normalize_wt_path "$root")
411
+ # A root of `/` normalizes to empty, which is not a valid array key.
412
+ [[ -z $n ]] && n=/
413
+ [[ -n ${seen[$n]:-} ]] && continue
414
+ seen[$n]=1
415
+ printf '%s\n' "$root"
416
+ done <<<"${configured}"$'\n'"${derived}"
417
+ return 0
418
+ }
@@ -158,7 +158,7 @@ preserve_relative_path_reason() {
158
158
  local name=${1-} val=${2-}
159
159
  if [[ -z $val ]]; then
160
160
  printf '%s is empty' "$name"
161
- elif [[ $val == /* || $val == [A-Za-z]:[\\/]* ]]; then
161
+ elif cleanup_wt_is_absolute_path "$val"; then
162
162
  printf '%s is absolute: %s' "$name" "$val"
163
163
  elif [[ $val == ".." || $val == "../"* || $val == *"/../"* || $val == *"/.." ]]; then
164
164
  printf '%s contains a .. segment: %s' "$name" "$val"
@@ -6,10 +6,10 @@
6
6
  # whose gitdir pointer no longer resolves, and the ancestor relationship between two
7
7
  # branches that both resolve NOT_MERGED. The enumeration/protection seam
8
8
  # (cleanup_wt_git, enumerate_branches, parse_worktree_list, normalize_wt_path,
9
- # compute_protected, check_main_freshness) lives in cleanup_worktrees_enumerate_lib.sh
10
- # and the classification ladder (classify_branch) lives in cleanup_worktrees_lib.sh;
11
- # both MUST be sourced before this file. Keeping these records in a sibling file keeps
12
- # every file within the 500-line cap.
9
+ # compute_protected, check_main_freshness, cleanup_wt_scan_roots) lives in
10
+ # cleanup_worktrees_enumerate_lib.sh and the classification ladder (classify_branch)
11
+ # lives in cleanup_worktrees_lib.sh; both MUST be sourced before this file. Keeping
12
+ # these records in a sibling file keeps every file within the 500-line cap.
13
13
  #
14
14
  # Sourcing contract: this library defines functions only; it never runs work at source
15
15
  # time, so the wrapper and the bats suites can source it without side effects.
@@ -111,47 +111,10 @@ scan_stale_refs() {
111
111
  return 0
112
112
  }
113
113
 
114
- cleanup_wt_scan_roots() {
115
- # Echo the worktree-tracking roots to scan, one per line.
116
- #
117
- # CLEANUP_WT_ORPHAN_ROOTS overrides the derivation with a colon-separated list.
118
- # Otherwise BOTH roots derive from the main worktree path — the first
119
- # `git worktree list --porcelain` stanza, the same derivation
120
- # consolidation_worktree_path uses in cleanup_worktrees_actions_lib.sh. They are
121
- # `<main-worktree-path>` joined with `.claude/worktrees` (the agent worktree folder)
122
- # and `<main-worktree-path>-wt` (the sibling worktree folder), in that order.
123
- #
124
- # Deriving both from one read means a parse_worktree_list hard failure emits no root
125
- # at all, rather than a bare relative path that would be resolved against whatever
126
- # the process's current working directory happened to be. cleanup_wt_scan_records
127
- # returns 0 with no record for an empty root list, so the advisory records degrade to
128
- # silence rather than to a misleading scan. Always returns 0.
129
- local override=${CLEANUP_WT_ORPHAN_ROOTS:-}
130
- if [[ -n $override ]]; then
131
- local IFS=:
132
- local part
133
- for part in $override; do
134
- [[ -n $part ]] && printf '%s\n' "$part"
135
- done
136
- return 0
137
- fi
138
- local out rc=0 first_record main_wt=""
139
- out=$(parse_worktree_list) || rc=$?
140
- if ((rc != 0)); then
141
- return 0
142
- fi
143
- first_record=${out%%$'\n'*}
144
- main_wt=${first_record%%|*}
145
- if [[ -n $main_wt ]]; then
146
- printf '%s\n' "${main_wt}/.claude/worktrees"
147
- printf '%s\n' "${main_wt}-wt"
148
- fi
149
- return 0
150
- }
151
-
152
114
  cleanup_wt_scan_records() {
153
115
  # Echo the raw `<path>|<has_gitfile>|<gitdir_target_exists>|<size>` records for every
154
- # candidate directory under the resolved scan roots, one per line.
116
+ # candidate directory under the resolved scan roots, one per line. The roots come
117
+ # from cleanup_wt_scan_roots in cleanup_worktrees_enumerate_lib.sh.
155
118
  #
156
119
  # Every filesystem read goes through the CLEANUP_WT_SCAN_BIN seam, so the bats suites
157
120
  # replay canned records instead of touching the real filesystem. The scan output is
@@ -40,6 +40,11 @@
40
40
  # the SHELL_QC_<TOOL>_BIN seams substitute a checked-in stand-in for a real dependency.
41
41
  # An empty value is treated as missing and falls back to `.git`.
42
42
  set -euo pipefail
43
+ # The library path is computed at runtime from BASH_SOURCE, so shellcheck (run without
44
+ # -x) cannot follow it; SC1091 is the expected, benign result.
45
+ # shellcheck source=.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh
46
+ # shellcheck disable=SC1091
47
+ source "$(dirname -- "${BASH_SOURCE[0]}")/cleanup_worktrees_enumerate_lib.sh"
43
48
 
44
49
  scan_helper_dir_size() {
45
50
  # Echo the best-effort human-readable size of a directory, or `unknown`.
@@ -70,20 +75,6 @@ scan_helper_gitfile_name() {
70
75
  printf '%s\n' ".git"
71
76
  }
72
77
 
73
- scan_helper_is_absolute_path() {
74
- # Return 0 when <path> is absolute, else 1. Pure: no filesystem access.
75
- #
76
- # Absolute forms are a leading `/` (POSIX paths, MSYS `/c/...` paths, and `//server`
77
- # UNC paths) and a drive letter followed by `/` or `\` (`C:/...`, `c:/...`,
78
- # `C:\...`), which is the form Git for Windows writes into a worktree's `.git`
79
- # pointer file (issue #706). A drive letter with no separator (`C:rel`) is
80
- # drive-relative and is not absolute; an empty path is not absolute.
81
- #
82
- # Args: $1 = path. Returns 0 (absolute) or 1 (not absolute).
83
- local path=${1:-}
84
- [[ $path == /* || $path == [A-Za-z]:[/\\]* ]]
85
- }
86
-
87
78
  scan_helper_target_present() {
88
79
  # Return 0 when <path> exists, else non-zero. This is the helper's single
89
80
  # filesystem existence check, kept in its own function as a test seam: bats tests
@@ -113,7 +104,7 @@ scan_helper_gitdir_target_exists() {
113
104
  printf '0\n'
114
105
  return 0
115
106
  fi
116
- if ! scan_helper_is_absolute_path "$target"; then
107
+ if ! cleanup_wt_is_absolute_path "$target"; then
117
108
  target="$dir/$target"
118
109
  fi
119
110
  if scan_helper_target_present "$target"; then
@@ -95,14 +95,32 @@ function of the DAG.
95
95
  2. Before starting each wave, `epic-orchestrator` runs
96
96
  `git fetch origin epic/<epic-slug>-integration` so the wave's child worktrees branch off the
97
97
  current remote tip, not a stale local ref.
98
- 3. Each child feature's worktree/branch (created via
98
+ 3. Before each wave launches (wave 0 included), `epic-orchestrator` runs
99
+ `git fetch origin main` and then
100
+ `git rev-list --count origin/epic/<epic-slug>-integration..origin/main`. A zero count
101
+ proceeds directly to the wave. A non-zero count means `origin/main` has commits the
102
+ integration branch lacks, and the main-sync runs as a dedicated chore child item before the
103
+ wave launches, following the `epic-852-main-sync` / PR #882 pattern. Before delegating it,
104
+ `epic-orchestrator` writes the sync child's `features[]` row (with `depends_on: []`) and its
105
+ own `waves[]` entry to the epic checkpoint, because `enforce-epic-wave-barrier.ps1` denies a
106
+ delegation whose feature record is absent. The sync child must not reuse a manifest child's
107
+ issue number; it uses the epic issue number or a dedicated chore issue. Its branch is created
108
+ from the integration branch, merges `origin/main` with a merge commit
109
+ (`git merge --no-ff origin/main`; no rebase, no force-push), resolves any conflict inside its
110
+ own remediation loop, and opens a PR into the integration branch. The wave does not launch
111
+ until that PR has merged into the integration branch and the sync entry's `merge_status` is
112
+ `merged`. At most one main-sync child runs per wave: after it merges, `epic-orchestrator`
113
+ re-runs step 2 and launches the wave without repeating the count, and commits that reach
114
+ `origin/main` afterwards are picked up by the next wave's check or by the final integration
115
+ PR in step 6.
116
+ 4. Each child feature's worktree/branch (created via
99
117
  `Agent(orchestrator, isolation: "worktree", run_in_background: true)`) is branched from
100
118
  `origin/<integration_branch>`, not `origin/main`. The child's own `orchestrator` instance
101
119
  honors this via the epic-mode kickoff line below.
102
- 4. Each child feature's PR base branch is the integration branch, not `main` — an explicit
120
+ 5. Each child feature's PR base branch is the integration branch, not `main` — an explicit
103
121
  epic-mode override recorded in the checkpoint, not a reliance on `pr-base-branch-merge-base`'s
104
122
  ancestry heuristic. Non-epic (standalone) orchestration is unchanged.
105
- 5. At epic completion (every feature in the final wave has `merge_status: "merged"`),
123
+ 6. At epic completion (every feature in the final wave has `merge_status: "merged"`),
106
124
  `epic-orchestrator` drives a final PR merging `epic/<epic-slug>-integration` into `main`,
107
125
  delegating PR authoring to `Agent(pr-author)` and refreshing context via
108
126
  `mcp__drm-copilot__collect_pr_context`. `epic-orchestrator` runs the same S9 CI-green
@@ -221,9 +239,10 @@ Procedure, triggered by S9 step 6's merge failure:
221
239
  3. The existing R1–R5 loop processes this finding exactly as a local blocking finding:
222
240
  `atomic-planner` (R1) plans the resolution, `atomic-executor` performs preflight (R2) then
223
241
  resolves the conflict markers, stages, and commits (R3), `feature-review` re-audits (R4).
224
- 4. The child's own `remediation_pass` counter is shared with local-finding and CI-failure passes
225
- (cap 3), unmodified.
226
- 5. On the third conflict pass without resolution, the child's `orchestrator` records
242
+ 4. Conflict cycles share the child's own `remediation_loop.completed_attempts` count with
243
+ local-finding and CI-failure cycles. The active cycle number is `completed_attempts + 1`, and a
244
+ cycle without an applied candidate consumes no number.
245
+ 5. After three completed attempts without resolution, the child's `orchestrator` records
227
246
  `step9_status: "blocked_conflict_loop_limit"` (parallel to `blocked_ci_loop_limit`), does not
228
247
  write DONE, and halts. It reports this status to `epic-orchestrator`, which mirrors it into
229
248
  the epic checkpoint's per-feature `merge_status: "blocked_conflict_loop_limit"` field.
@@ -240,11 +259,26 @@ cross-call/conversation-state visibility.
240
259
  prompt text, reads `artifacts/orchestration/epic-orchestrator-state.json`, looks up that
241
260
  feature's `depends_on`, and denies with reason `EPIC_WAVE_BARRIER_BLOCKED` unless every
242
261
  dependency's `merge_status` is `merged` or `worktree_removed`.
243
- - **Layer 2 — retrospective backstop:** the wave-barrier ordering invariant inside
244
- `validate_epic_orchestrator_state_text`, enforced at `epic-orchestrator` `SubagentStop` time via
245
- the parameterized `validate-orchestrator-output.ps1` hook. It appends
246
- `EPIC_WAVE_BARRIER_VIOLATION: <f> started before dependency <d> merged` when a dependency edge's
247
- timing invariant is violated.
262
+ - **Layer 2 — retrospective backstop:** the wave-barrier ordering invariant of
263
+ `validate_epic_orchestrator_state_text`, enforced at `epic-orchestrator` `SubagentStop` time by a
264
+ PowerShell port, `Get-OrchestratorStateEpicWaveBarrierError` in
265
+ `.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1`, which the parameterized
266
+ `validate-orchestrator-output.ps1` hook invokes for `epic-orchestrator-state` after resolving the
267
+ epic checkpoint through `WorktreeRunResolution.psm1`. The hook starts no Python process. Parity
268
+ with `validate_epic_orchestrator_state_text` is pinned by the shared fixtures under
269
+ `tests/fixtures/epic_wave_barrier/`, and the Python validator remains the authority used through
270
+ the `mcp__drm-copilot__validate_orchestration_artifacts` call. It checks only a dependent feature
271
+ that is treated as started: one with a string `worktree_created_at`, or with a `merge_status`
272
+ other than `not_started` (a missing or non-string `merge_status` counts as started). It appends
273
+ exactly one error per violated dependency edge. When the dependency's `merge_status` is not
274
+ `merged` or `worktree_removed`, the error is
275
+ `EPIC_WAVE_BARRIER_VIOLATION: <f> is treated as started while dependency <d> is not merged`.
276
+ Otherwise, when the dependency's `merge_confirmed_at` is later than the dependent's
277
+ `worktree_created_at`, the error is
278
+ `EPIC_WAVE_BARRIER_VIOLATION: <f> worktree_created_at precedes dependency <d> merge_confirmed_at`.
279
+ A violation blocks with an instruction to report it to the operator and halt. The `SubagentStop`
280
+ transport and exit-code defect that this check previously depended on was resolved by epic #904
281
+ and issue #928: a violation blocks the stop with exit 2 and a stderr reason.
248
282
 
249
283
  Both layers are required; neither alone closes the gap. `epic-orchestrator` does not launch wave
250
284
  N+1 until every wave-N feature's dependency edges are durably confirmed merged, verified against
@@ -211,7 +211,7 @@ With no ready feature checkpoint, the exemption admits two attribution-trailer f
211
211
  - The trailer option: `git commit -m 'docs: plan' --trailer 'Co-Authored-By: Name <email>' --trailer 'Claude-Session: <url>' -- <exempt paths>`. The separate-value form and the `--trailer=<value>` form are both admitted, any number of times, on `git commit` only; `git add --trailer` and a trailer option with no value are denied. Git writes every trailer value into one trailer block.
212
212
  - The one-paragraph multi-message form: the subject in the first `-m` and every trailer in one single-quoted second `-m` value, separated by a literal newline. Each `-m` value becomes its own paragraph and git parses only the last paragraph as the trailer block, so trailers split across separate `-m` values do not form one trailer block.
213
213
 
214
- Quoting rules: `$` and backtick are literal and admitted inside single quotes, and denied outside quotes and inside double quotes, where the shell expands them. `<` and `>` are admitted inside single or double quotes and denied outside quotes. An unquoted `#` is denied anywhere, because it starts a shell comment that the exemption does not model; a `#` inside quotes is admitted. A typographic quote character (U+2018 to U+201E) anywhere in the command line is denied, because a PowerShell host reads it as a quote.
214
+ Quoting rules: `$` and backtick are literal and admitted inside single quotes, and denied outside quotes and inside double quotes, where the shell expands them. `<` and `>` are admitted inside single or double quotes and denied outside quotes. An unquoted `#` is denied anywhere, because it starts a shell comment that the exemption does not model; a `#` inside quotes is admitted. A typographic quote character (U+2018 to U+201E) anywhere in the command line is denied, because a PowerShell host reads it as a quote. Because the executing shell is undetermined (issue #735), a shape whose meaning differs between a POSIX shell and PowerShell is denied: a backslash anywhere in the command line is denied, and `{`, `}`, `,`, `(`, `)`, and `@` are denied outside quotes. Every staging operand must be a plain forward-slash repository-relative path that uses only the characters `A-Z a-z 0-9 . _ / -`.
215
215
 
216
216
  Not admitted: heredoc-fed messages, including `git commit -m "$(cat <<'EOF' ... EOF)"` and `git commit -F - <<'EOF'`, and message files supplied through `-F <file>` or `--file=<file>`. Use one of the two forms above instead.
217
217
 
@@ -46,6 +46,17 @@ Use this skill when:
46
46
  Use `yyyy-MM-ddTHH-mm` for all audit, remediation, and evidence artifacts.
47
47
  Example: `2026-02-06T14-30`.
48
48
 
49
+ The `Timestamp` value is UTC read from the host system clock when the recorded command runs (for example `Get-Date -AsUTC -Format yyyy-MM-ddTHH-mm` in PowerShell 7, `(Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH-mm')` in Windows PowerShell 5.1, or `date -u +%Y-%m-%dT%H-%M` in a POSIX shell); the agent never composes or estimates it. The value is written without a zone suffix.
50
+
51
+ ### Evidence Filename Timestamp
52
+
53
+ The stamp in the filename of every artifact under `<FEATURE>/evidence/<kind>/` is the UTC time at which that file is written, read from the host system clock immediately before the write, in the same `yyyy-MM-ddTHH-mm` shape with no zone suffix. It is never a plan-time stamp, a plan-cycle identifier, or any other value fixed before the write.
54
+
55
+ - Plans name such an artifact `<name>.<timestamp>.md`, and the executor substitutes the write time. A later loop pass writes a new file with a new stamp.
56
+ - A task that consumes an evidence artifact selects the lexicographically greatest file matching `<name>.*.md`. The fixed-width UTC shape sorts in chronological order, so that file is the most recently written one.
57
+ - Plan files (`plan.<timestamp>.md`, stamped by the feature-folder tooling in America/New_York) and the review artifact set (`policy-audit`, `code-review`, `feature-audit`, `remediation-inputs`, which share one stamp) are outside this rule.
58
+ - Existing evidence files whose names carry a plan-time stamp are not renamed.
59
+
49
60
  ## Canonical Evidence Locations
50
61
 
51
62
  - Baseline evidence: `evidence/baseline/`
@@ -110,6 +121,8 @@ When evidence artifacts are used for automated checking or plan reconciliation,
110
121
  - `Command: <exact command>`
111
122
  - `EXIT_CODE: <int>`
112
123
 
124
+ The first occurrence of `Timestamp`, `Command`, `EXIT_CODE`, and `ExpectedExitCode` forms the record in both the Python and the TypeScript parser; later occurrences, including empty later values, are ignored. An artifact that records several gates therefore reports its first gate.
125
+
113
126
  One optional field may also be declared:
114
127
  - `ExpectedExitCode: <int>` — the exit code the gate is expected to produce.
115
128
 
@@ -40,6 +40,16 @@ Each `delegation_receipts.promotion.*` field stores the raw MCP receipt payload
40
40
 
41
41
  Note: VS Code command-palette commands may exist for interactive extension use, but this note is non-authoritative for agent sessions.
42
42
 
43
+ ## Pre-Existing Issue Path
44
+
45
+ When the GitHub issue already exists (it was transferred, filed before orchestration, or created by epic decomposition), do not call `potential_to_issue`: that tool creates a new issue and would duplicate the existing one. Instead:
46
+
47
+ 1. Verify the issue read-only with `gh issue view`, a `gh api` GET request, or a GitHub MCP issue read, and use its number as `${issue-num}`.
48
+ 2. Record a top-level `issue_adoption` object in the orchestrator checkpoint (`issue_num`, `issue_url`, `origin`, `verified_via`, `verified_at`, `evidence`, `waived_tools`, and, when a promotion-entry tool is waived, `potential_record`). For that waiver `potential_record` is required when `origin` is `epic_decomposition`, optional when `origin` is `transferred` or `filed_before_orchestration`, and validated whenever it is present. A valid record waives the `potential_to_issue` receipt requirement at completion.
49
+ 3. `delegation_receipts.promotion.issue` may be omitted, because no promotion receipt exists for an adopted issue.
50
+
51
+ The field rules, the closed set of waivable tools, and the fail-closed behavior are defined in `.claude/rules/orchestrator-state.md` under `## Invariants (issue_adoption object)`.
52
+
43
53
  ## Canonical Variables
44
54
 
45
55
  - `${promotion-type}`: `feature` or `bug`
@@ -70,9 +70,9 @@ Always apply:
70
70
  If the branch diff modifies any path matching `.github/workflows/**`, `scripts/benchmarks/**`, or `.github/actions/**`, the policy audit emits a Blocking finding unless evidence of a green workflow run against the branch head is present in the remediation inputs.
71
71
 
72
72
  - The rule provides a second, independent line of defense for CI-gate-modifying features, separate from and prior to the orchestrator's S9 CI green gate.
73
- - "Green workflow run against the branch head" means a workflow run whose head SHA matches the current branch head and whose conclusion is success for the affected workflow.
73
+ - "Green workflow run against the branch head" means a run of the affected workflow whose conclusion is success and which satisfies either (a) or (b): (a) its head SHA equals the current branch head; or (b) all three predecessor-head conditions hold: (1) the run's head SHA is an ancestor of, or equal to, the current branch head and contains the latest commit that changes any path outside the active feature folder (`git merge-base --is-ancestor <commit> <run-sha>`); (2) every commit after the run's head SHA changes only paths inside the active feature folder (`git log <run-sha>..HEAD -- . ":!<feature-folder>"` returns no commits); (3) the policy audit states that the orchestrator's S9 CI green gate remains responsible for `ci_gate.conclusion == "success"` with `ci_gate.head_sha` equal to the final PR head before DONE. Condition (b) exists because an in-repo evidence artifact cannot name the SHA of the commit that contains it.
74
74
  - A green `workflow_dispatch` run against the branch head also satisfies the rule, not only a PR-context run. This mitigates the chicken-and-egg case where a feature must land its CI gate before the gate can run in PR context (see spec.md Risks & Mitigations).
75
- - When the rule fires and no qualifying green-run evidence is present, record a Blocking finding and route it through the standard remediation handoff. The supporting validator `scripts/feature-review/Test-ModifiedWorkflowNeedsGreenRun.ps1` implements the trigger-path and evidence-presence logic.
75
+ - When the rule fires and no qualifying green-run evidence is present, record a Blocking finding classified `awaiting_ci` (the remediation inputs carry `Remediability: awaiting_ci` and a `Remediability-Evidence:` line naming the awaited workflow) and route it to the wait path (`AWAITING_CI` when no other class is present) instead of the remediation handoff.
76
76
 
77
77
  ## Ordered Procedure
78
78
 
@@ -108,12 +108,13 @@ If the branch diff modifies any path matching `.github/workflows/**`, `scripts/b
108
108
  - Python: `poetry run pytest --cov` → artifact: `artifacts/python/lcov.info`
109
109
  - PowerShell: `mcp__drm-copilot__run_poshqc_test` → artifact: `artifacts/pester/powershell-coverage.xml`
110
110
  - C#: `dotnet test --collect:"XPlat Code Coverage"` → artifact: `artifacts/csharp/coverage.xml`
111
- - Coverage thresholds (uniform tier rule per quality-tiers.md). The branch threshold applies only to branch-capable languages — TypeScript, Python, and C#. PowerShell is a coverage language and is fully subject to the line threshold and the no-regression requirement, but Pester measures command (instruction) coverage and line coverage only, so no branch percentage exists to evaluate and no branch threshold applies to it (see `.claude/rules/powershell.md`). Do not flag a missing PowerShell branch figure as FAIL:
111
+ - Coverage thresholds (threshold precedence per `.claude/rules/quality-tiers.md` and `.claude/rules/general-unit-test.md`: when the repository's root `CLAUDE.md` states line or branch coverage thresholds, those thresholds govern; otherwise the default thresholds below govern; each metric falls back independently, so a root `CLAUDE.md` that states only one of the two thresholds governs only that metric). The branch threshold applies only to branch-capable languages — TypeScript, Python, and C#. PowerShell is a coverage language and is fully subject to the line threshold and the no-regression requirement, but Pester measures command (instruction) coverage and line coverage only, so no branch percentage exists to evaluate and no branch threshold applies to it (see `.claude/rules/powershell.md`). Do not flag a missing PowerShell branch figure as FAIL:
112
112
  - New code files (added in this feature): line coverage >= 85%, and branch coverage >= 75% for branch-capable languages. Flag as FAIL otherwise.
113
113
  - Modified files (changed but previously existing): line coverage >= 85%, branch coverage >= 75% for branch-capable languages, and no regression on changed lines relative to baseline. Flag as FAIL otherwise.
114
114
  - Repo-wide per language: line coverage >= 85%, and branch coverage >= 75% for branch-capable languages. Flag as FAIL otherwise.
115
115
  - If coverage artifacts already exist from the executor run, inspect them instead of re-running.
116
116
  - If no coverage artifact exists for a language that has changed files, flag as FAIL — coverage verification is mandatory for all languages with changed files.
117
+ - Tier classification findings: report a missing or incomplete `quality-tiers.yml` only when the repository has adopted tiers, that is, when `quality-tiers.yml` exists at the repository root on the resolved base branch or the repository's CI runs a tier-classification check. Otherwise record tier classification as not applicable; it is not a finding.
117
118
  - Run the smallest relevant subset first when the repo policy permits it.
118
119
  - If a tool cannot run in the environment, mark the affected section unverified or partial with a concrete reason.
119
120
 
@@ -145,8 +146,10 @@ If the branch diff modifies any path matching `.github/workflows/**`, `scripts/b
145
146
  - toolchain checks fail
146
147
  - the code review contains blockers
147
148
  - required acceptance criteria are FAIL or PARTIAL
148
- - coverage regression below policy threshold (< 80% repo-wide per language, < 80% or regression for modified files, or < 90% for new files)
149
+ - coverage below the governing thresholds defined in step 5 (repo-wide per language, modified files including any regression on changed lines, or new files)
149
150
  - coverage artifact absent for any language that has changed files
151
+ - Classify each blocking finding before triggering remediation: each receives one remediability class (`autonomous`, `external_dependency`, `policy_hold`, `awaiting_ci`, or `human_decision_required`; `autonomous` when no class is stated). A published MCP runtime that lags the repository contract is classified `external_dependency`.
152
+ - Trigger the remediation handoff only when at least one blocking finding is `autonomous`. When every blocking finding is non-remediable, write the remediation inputs with the `HALT_NON_REMEDIABLE` or `AWAITING_CI` verdict and create no remediation plan target.
150
153
  - Create `remediation-inputs.<timestamp>.md` first.
151
154
  - Create the target remediation plan file from the canonical plan template.
152
155
  - Hand off plan creation through `remediation-handoff-atomic-planner`.