@danmoisan/drm-copilot-mcp 1.1.18 → 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 (206) hide show
  1. package/out/mcp-server.js +989 -662
  2. package/package.json +3 -2
  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 +6 -4
  8. package/resources/claude-customizations/.claude/agents/orchestrator.md +5 -4
  9. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +31 -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-mutation-cli.sh +152 -0
  76. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
  77. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
  78. package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
  79. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
  80. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
  81. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
  82. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
  83. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +24 -3
  84. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
  85. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
  86. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
  87. package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
  88. package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
  89. package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
  90. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +37 -4
  91. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
  92. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
  93. package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
  94. package/resources/claude-customizations/.claude/rules/shell.md +10 -8
  95. package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
  96. package/resources/claude-customizations/.claude/settings.json +3 -4
  97. package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  98. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +5 -1
  99. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
  100. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +2 -0
  101. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +2 -0
  102. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +33 -6
  103. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
  104. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  105. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  106. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -3
  107. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +14 -6
  108. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
  109. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
  110. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +79 -16
  111. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
  112. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
  113. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
  114. package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
  115. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +2 -2
  116. package/resources/claude-customizations/pack-manifests/core.json +23 -0
  117. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  118. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
  119. package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
  120. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
  122. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
  123. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
  124. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +8 -0
  125. package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
  126. package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
  127. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  128. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +13 -5
  129. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
  130. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
  131. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +15 -6
  132. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
  133. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
  134. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
  135. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
  136. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
  137. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
  138. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
  139. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
  140. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
  141. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
  142. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
  143. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
  144. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
  145. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
  146. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
  147. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
  148. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
  149. package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
  150. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
  151. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +2 -2
  152. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +2 -2
  153. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +2 -2
  154. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +2 -2
  155. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +2 -2
  156. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +2 -2
  157. package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
  158. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  159. package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
  160. package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
  161. package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
  162. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
  163. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
  164. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
  165. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
  166. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
  167. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
  168. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
  169. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
  170. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
  171. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
  172. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
  173. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
  174. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
  175. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
  176. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
  177. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
  178. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
  179. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
  180. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
  181. package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
  182. package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
  183. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
  184. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
  185. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
  186. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
  187. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
  188. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
  189. package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
  190. package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
  191. package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
  192. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
  193. package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
  194. package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
  195. package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
  196. package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
  197. package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
  198. package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  199. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
  200. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  201. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
  202. package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
  203. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
  204. package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
  205. package/resources/powershell/PoshQC/README.md +8 -2
  206. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -319
@@ -32,6 +32,37 @@ A hardened snapshot from another repository contains a JSON Schema for the orche
32
32
 
33
33
  This prohibition is specific to the disqualified foreign schema identified by the `drmoisan.github.io/mix-calculator/` `$id`. A schema whose `$id` is repo-local and whose required-field set and `additionalProperties` policy match this repository's checkpoint contract is not the disqualified foreign artifact; even so, the repository's enforcement mechanism remains the Python validator prose-and-logic above, not an imported schema file.
34
34
 
35
+ ## Required Top-Level Keys
36
+
37
+ Plain validation requires every key below at the top level of the orchestrator-state checkpoint. The authority is `REQUIRED_STATE_KEYS` in `scripts/dev_tools/validate_orchestrator_state.py`. The TypeScript port in `extensions/drm-copilot/src/lib/validate/orchestrator-state-core.ts` and the PowerShell port in `.claude/lib/orchestrator-state/OrchestratorState.psm1` carry the same keys in the same order.
38
+
39
+ - `objective`
40
+ - `change_budget_estimate`
41
+ - `path_selected`
42
+ - `promotion-type`
43
+ - `short-name`
44
+ - `relativeFile`
45
+ - `long-name`
46
+ - `issue-num`
47
+ - `feature-folder`
48
+ - `work-mode`
49
+ - `plan-path`
50
+ - `completed_steps`
51
+ - `next_step`
52
+ - `last_updated`
53
+ - `step5_status`
54
+ - `step6_status`
55
+ - `step7_status`
56
+ - `step8_status`
57
+ - `step9_status`
58
+ - `step10_status`
59
+ - `delegation_receipts`
60
+ - `blocked_reason`
61
+
62
+ The check is unconditional: it runs with or without `--require-complete`, `--require-pr-creation-ready`, `--require-model-routing`, `--require-codex-model-routing`, and `--require-codex-topology`, and it is skipped only for a `portable_orchestration_handoff` envelope. The check is presence-only: a key whose value is any JSON value, including `null`, satisfies it. Each absent key produces one error line, `Checkpoint missing required key: <key>`. Some keys carry further validation when present, such as the step-status vocabulary for the `step*_status` keys and the Blocked-Reason Vocabulary below for `blocked_reason`.
63
+
64
+ `last_updated` records when the checkpoint was last written. Write it as an ISO-8601 UTC date-time string, for example `2026-10-08T17:28:00Z`. The value is rewritten on every checkpoint write: after every completed step and every state transition, including halts. The validators check presence only and do not parse the value, so a non-UTC, placeholder, or `null` value still passes the required-key check.
65
+
35
66
  ## Scope and Backward Compatibility
36
67
 
37
68
  These invariants apply only when the checkpoint contains a top-level `remediation_loop`; the per-cycle invariants apply when it has a `cycles` array, and the review-outcome and attempt-count invariants apply when their keys are present. A checkpoint with no `remediation_loop` (the existing step-based checkpoint shape) is unaffected: it validates exactly as before and produces no new errors. The invariants are additive.
@@ -170,7 +201,7 @@ The complexity-assessment and model-routing-receipt invariants above are key-gat
170
201
 
171
202
  ## Bare-Module CLI Contract
172
203
 
173
- The validator module runs directly as `python -m scripts.dev_tools.validate_orchestrator_state <path> [--require-complete] [--require-model-routing] [--require-pr-creation-ready] [--require-codex-model-routing] [--require-codex-topology]`. The dispatcher `python -m scripts.dev_tools.validate_orchestration_artifacts orchestrator-state` stays available and accepts the same flags. Exit code 0 means the checkpoint passed and the success line `orchestrator-state validation passed: <path>` is written to stdout. Exit code 1 means validation errors, written one per stderr line. Exit code 2 means the path is missing, unreadable, or not UTF-8, with one stderr diagnostic and no traceback; argparse usage errors also exit 2.
204
+ The validator module runs directly as `python -m scripts.dev_tools.validate_orchestrator_state <path> [--require-complete] [--require-model-routing] [--require-pr-creation-ready] [--require-codex-model-routing] [--require-codex-topology]`. The dispatcher stays available and accepts the same flags in two invocation forms: the module form `python -m scripts.dev_tools.validate_orchestration_artifacts orchestrator-state`, run from the repository root, and the file-path form `python scripts/dev_tools/validate_orchestration_artifacts.py orchestrator-state`. Both forms reach the same `main()`, so their flags, output lines, and exit codes are identical, and a relative artifact path resolves against the working directory in both. The file-path form derives the repository root from the script location and inserts it first in `sys.path` only when the script runs without a package context. The bare-module validator is supported in the module form only. Exit code 0 means the checkpoint passed and the success line `orchestrator-state validation passed: <path>` is written to stdout. Exit code 1 means validation errors, written one per stderr line. Exit code 2 means the path is missing, unreadable, or not UTF-8, with one stderr diagnostic and no traceback; argparse usage errors also exit 2.
174
205
 
175
206
  ## Invariants (require_model_routing mode)
176
207
 
@@ -204,7 +235,7 @@ Enforcement is validator logic plus this prose, never an imported JSON Schema. T
204
235
 
205
236
  These invariants apply only when a checkpoint contains a top-level `standalone_merge_authorizations` array. The key may appear in any of the three checkpoints the epic merge gate reads: `artifacts/orchestration/orchestrator-state.json`, `artifacts/orchestration/epic-orchestrator-state.json`, and `artifacts/orchestration/parallel-orchestrator-state.json`. A checkpoint with no such key (the existing checkpoint shape) is unaffected: it validates exactly as before and produces no new errors. The invariants are additive and key-gated. No JSON Schema file is authored, imported, or read for the block (see the Foreign Schema Warning above); the enforcing surface is the `PreToolUse` merge gate (issue #670).
206
237
 
207
- Each entry records one authorized standalone merge with the shape `{ pr_number, pr_url, issue_num, branch_name, authorized_by, authorized_at, session_id, basis, run_slug? }`. The gate consults the array only for a `gh pr merge --merge` command that names an explicit pull request number, and only after its per-feature, epic, and parallel allow conditions have all declined.
238
+ Each entry records one authorized standalone merge with the shape `{ pr_number, pr_url, issue_num, branch_name, authorized_by, authorized_at, session_id, basis, run_slug? }`. The gate consults the array only for a `gh pr merge --merge` command that names an explicit pull request number, and only after its per-feature, epic, and parallel allow conditions have all declined. For a command that names an explicit pull request number, the gate reads the per-feature checkpoint `artifacts/orchestration/orchestrator-state.json` beneath the one live worktree whose checkpoint records that number in `pr_gate.pr_number` or in a `standalone_merge_authorizations` entry, and it reads no per-feature checkpoint when no live worktree or more than one records it; a bare command reads the checkpoint beneath the session worktree.
208
239
 
209
240
  Honest disclosure: the standalone-merge authorization record is a policy-level, auditable declaration and is
210
241
  not a cryptographic or security control.
@@ -243,7 +274,7 @@ The object has the shape `{ issue_num, issue_url, origin, verified_via, verified
243
274
  | `verified_at` | Present, not `null`, and not a blank string. |
244
275
  | `evidence` | A string with non-whitespace content. |
245
276
  | `waived_tools` | A non-empty list of non-blank tool names that includes `potential_to_issue`. |
246
- | `potential_record` | Required when waiving a promotion-entry tool: a path under `docs/features/potential/` ending in `.md`. |
277
+ | `potential_record` | When waiving a promotion-entry tool: required when `origin` is `epic_decomposition`, optional when `origin` is `transferred` or `filed_before_orchestration`, and validated whenever it is present (a path under `docs/features/potential/` ending in `.md`). |
247
278
 
248
279
  The rules run in this order, and their errors accumulate:
249
280
 
@@ -255,10 +286,12 @@ The rules run in this order, and their errors accumulate:
255
286
  6. `verified_at` must be present: absent, `null`, and blank strings are rejected; any other value passes.
256
287
  7. `evidence` must be a non-empty string.
257
288
  8. `waived_tools` must be a non-empty list of non-blank strings; otherwise no further rule-8 or rule-9 check runs. Each entry, in list order, receives the first applicable error of: listed more than once; not in the closed waivable set; not required by the selected route after promotion-type resolution; already holding a successful MCP receipt. The list must include `potential_to_issue`.
258
- 9. Only when the rule-8 shape check passed: each distinct waived promotion-entry tool (`new_potential_entry` or `new_potential_bug_entry`) requires a valid `potential_record`.
289
+ 9. Only when the rule-8 shape check passed: each distinct waived promotion-entry tool (`new_potential_entry` or `new_potential_bug_entry`) requires a valid `potential_record`, except that rule 9 reports nothing when `origin` is `transferred` or `filed_before_orchestration` and the `potential_record` key is absent. A present `potential_record`, including `null`, is always validated.
259
290
 
260
291
  The closed waivable set is `potential_to_issue`, `new_potential_entry`, and `new_potential_bug_entry`. `new_active_feature_folder`, `collect_pr_context`, `validate_orchestration_artifacts`, and every other tool can never be waived. All comparisons are ordinal and case-sensitive.
261
292
 
293
+ A lifecycle record moved to `docs/features/potential/promoted/` satisfies the `potential_record` path rule, because the rule checks only the `docs/features/potential/` prefix and the `.md` suffix and does not check that the file exists.
294
+
262
295
  Fail-closed behavior: any adoption error waives nothing, so each missing receipt is still reported as `Checkpoint missing successful MCP receipt: <tool>.`. Adoption errors are placed after the receipt-loop errors and before the `local_execution_overrides` errors. The waiver affects only receipt presence: the declared `required_mcp_tools` equality check with the routing matrix is unchanged, so a checkpoint must still declare every route tool it waives.
263
296
 
264
297
  ## Enforcement
@@ -87,13 +87,13 @@ When `require_complete` is not passed, invariants 20 and 21 contribute zero erro
87
87
 
88
88
  ## Invariants (parallel planner checkpoint)
89
89
 
90
- Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_execution=False)` in `scripts/dev_tools/validate_parallel_planner_state.py`. P1 through P4 are enforced unconditionally; P6 through P9 are enforced only under `require_ready_for_execution`.
90
+ Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_execution=False)` in `scripts/dev_tools/validate_parallel_planner_state.py`. P1 through P4 are enforced unconditionally; P6 through P10 are ready-gate invariants, enforced only under `require_ready_for_execution`.
91
91
 
92
92
  - **P1 — Required keys.** The checkpoint must carry `objective`, `parallel_slug`, `parallel_manifest_path`, `mode`, `max_concurrency`, `items`, `cohorts`, `conflict_edges`, `recolor_generation`, `completed_steps`, `next_step`, and `last_updated`. One error is emitted per missing key. `kickoff_prompt_path` is optional outside the ready gate.
93
93
 
94
94
  - **P2 — Route-consistent identity.** `parallel_slug` and `parallel_manifest_path` must be non-empty strings; `mode` and `max_concurrency` satisfy orchestrator invariants 3 and 4.
95
95
 
96
- - **P3 — Item shape.** Each `items[]` entry must carry `issue_num`, `feature_folder`, `kind`, `state`, `blast_radius`, `preparation_status`, `research_path`, `plan_path`, and `preflight_status`. `issue_num` must be a positive integer unique across items; `kind` must be in `{feature, bug}`; `state` must be in the item-state enum; `blast_radius` must satisfy orchestrator invariant 9; `complexity_band`, when present, must be in `{C1, C2, C3, C4}`. The prohibited-key rejections of orchestrator invariants 10 and 11 apply.
96
+ - **P3 — Item shape.** Each `items[]` entry must carry `issue_num`, `feature_folder`, `kind`, `state`, `blast_radius`, `preparation_status`, `research_path`, `plan_path`, and `preflight_status`. `issue_num` must be a positive integer unique across items; `kind` must be in `{feature, bug}`; `state` must be in the item-state enum; `blast_radius` must satisfy orchestrator invariant 9; `complexity_band` is optional outside the ready gate (P10 requires it under `require_ready_for_execution`) and, when present, must be in `{C1, C2, C3, C4}`. The prohibited-key rejections of orchestrator invariants 10 and 11 apply.
97
97
 
98
98
  - **P4 — Cohort and edge shape.** `cohorts[]`, `conflict_edges[]`, and `recolor_generation` satisfy orchestrator invariants 12 through 15.
99
99
 
@@ -107,7 +107,9 @@ Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_exe
107
107
 
108
108
  - **P9 — Ready gate, kickoff path.** Under `require_ready_for_execution`, `kickoff_prompt_path` must be exactly `artifacts/orchestration/parallel-kickoff-<parallel_slug>.md`.
109
109
 
110
- The planner checkpoint carries no `epic_worthiness` analogue and no `NON_EPIC_RECOMMENDED` branch; the parallel surface has no worthiness verdict, and scale assessment happens before parallel planning is invoked. When `require_ready_for_execution` is not passed, P6 through P9 contribute zero errors.
110
+ - **P10 — Ready gate, routing record.** Under `require_ready_for_execution`, each object-shaped item must carry `complexity_band` in `{C1, C2, C3, C4}`; a `complexity_assessment` object `{band, floor, signals_present, rationale, assessed_at}` whose `floor` equals `compute_complexity_floor(signals_present)`, whose `band` is at or above `floor` and equals `complexity_band`, and whose `rationale` and `assessed_at` are non-empty strings; and a Claude `model_routing_receipt` object `{agent, phase, complexity_band, fable_policy, table_model, clamped_from, model}` with `agent == 'orchestrator'`, `complexity_band` equal to the item's band, `fable_policy` in `{disabled, available, preferred}`, and `model` equal to `resolve_delegation_model('orchestrator', complexity_band, fable_policy)['model']`, including the disabled-mode clamp invariants. The checks run per item in this order: (1) the band enum, reported as `None` when absent; (2) the assessment object, skipping checks 3 through 5 when it fails; (3) the assessment entry checks of `_validate_complexity_assessments`, prefix-rewritten to `<item> complexity_assessment`; (4) `assessed_at`; (5) assessment band equals item band; (6) the receipt object, skipping checks 7 through 10 when it fails; (7) the receipt entry checks of `_validate_model_routing_receipts`, prefix-rewritten to `<item> model_routing_receipt`; (8) `agent`; (9) receipt band equals item band; (10) the `fable_policy` enum. Checks 5 and 9 are reported whenever the two values differ, including when check 1 failed. Each item's P10 errors follow that item's P7 errors.
111
+
112
+ The planner checkpoint carries no `epic_worthiness` analogue and no `NON_EPIC_RECOMMENDED` branch; the parallel surface has no worthiness verdict, and scale assessment happens before parallel planning is invoked. When `require_ready_for_execution` is not passed, P6 through P10 contribute zero errors.
111
113
 
112
114
  ## Invariants (parallel run manifest)
113
115
 
@@ -380,6 +382,44 @@ admits.
380
382
  Enforcement of this rejection is prose plus validator logic, exactly as for the three shapes above.
381
383
  No JSON Schema is authored, imported, or read for it, and `config/blast-radius.json` gains no key.
382
384
 
385
+ ### File-shape recognition (issue #797)
386
+
387
+ The classifier accepts a wildcard-free token that carries a separator only when its final component
388
+ names a file. After any `:<line>` suffix is stripped, the final component names a file when either
389
+ condition holds:
390
+
391
+ 1. **Dotted file name.** The component has a non-empty stem before its last dot, and the text after
392
+ that dot, lower-cased, fully matches the pattern
393
+ `[a-z][a-z0-9]*`
394
+ (an ASCII letter followed by ASCII letters or digits).
395
+ 2. **Known file name.** The component is an exact, ordinal member of the closed known-name set:
396
+ `Dockerfile`, `Makefile`, `LICENSE`, `CODEOWNERS`, `NOTICE`, `.gitignore`, `.gitattributes`,
397
+ `.gitkeep`, `.gitmodules`, `.vscodeignore`, `.npmignore`, `.npmrc`, `.nvmrc`, `.editorconfig`,
398
+ `.prettierrc`, `.prettierignore`, `.eslintignore`, `.shellcheckrc`.
399
+
400
+ This rule replaces the former extension allowlist, which dropped files a plan writes with an
401
+ unlisted extension (`.bats`, `.cjs`, `.out`), every dotfile, and every extensionless file name. The
402
+ same predicate decides the wildcard branch: a wildcard token outside the known top-level segments is
403
+ accepted only when its final component names a file by this rule.
404
+
405
+ Directory-shaped tokens remain rejected (issue #489). A final component with no dot, a trailing
406
+ slash, a dot-directory such as `.claude` or `.git` that is not in the known-name set, a digit-led
407
+ tail such as `v1.2.0`, and a trailing dot all fail the predicate.
408
+
409
+ **Accepted residuals (fail-closed direction).** Three token shapes that do not name a file are
410
+ accepted by this rule: a dotted directory cited without a trailing slash, such as the C#-style
411
+ `src/<Product>.Domain`; host-qualified tokens such as `example.com/page.html` or `owner/repo.git`;
412
+ and refs whose final segment has a letter-led dotted tail. Each produces at most an extra contention
413
+ edge, which serializes work. A missed write schedules concurrent edits, which is the unsafe
414
+ direction under this doctrine. In the self-hosted repository W4 removes the host-qualified cases; in
415
+ destinations, where `path_roots` is empty, W2 and W3 bound them.
416
+
417
+ **Parity.** The known-name set and the extension pattern are code constants in both runtimes
418
+ (`scripts/dev_tools/_blast_radius_token_shapes.py` and
419
+ `.claude/lib/blast-radius/BlastRadiusTokenShape.psm1`), not configuration keys, so neither copy of
420
+ `config/blast-radius.json` changes. A Pester test reads the Python source and pins the PowerShell
421
+ known-name set and extension pattern equal to it.
422
+
383
423
  ### Module-map granularity criterion
384
424
 
385
425
  Issue #472 removed the location-bucket modules `docs` and `tests` because a bucket keyed on where a
@@ -525,6 +565,11 @@ Write-intent extraction can drop a genuine write in these cases:
525
565
  5. a new top-level directory not yet in `path_roots` (W4);
526
566
  6. a genuine file whose stem is in the placeholder set (W6).
527
567
 
568
+ The file-shape classifier, which runs before write-intent extraction, drops one further case: a
569
+ genuine file cited only as a separator-free bare file name is not recorded, because only
570
+ repository-relative paths and configured root surfaces are accepted (issue #797). The planner
571
+ cites the repository-relative path or appends it to the declared radius.
572
+
528
573
  Three mitigations bound these cases:
529
574
 
530
575
  1. **The planner remains obliged to enumerate a genuine write explicitly.** When an item's plan will
@@ -635,10 +680,10 @@ shipped surface or a derived module.
635
680
  ## Enforcement
636
681
 
637
682
  - `scripts/dev_tools/validate_parallel_orchestrator_state.py`, with the helper modules `scripts/dev_tools/_parallel_state_common.py`, `scripts/dev_tools/_parallel_state_structures.py`, and `scripts/dev_tools/_parallel_state_records.py`, appends one error per violated orchestrator invariant. The completion-gate invariants 20 and 21 run only when the caller passes `require_complete=True`.
638
- - `scripts/dev_tools/validate_parallel_planner_state.py` appends one error per violated planner invariant. The ready-gate invariants P6 through P9 run only when the caller passes `require_ready_for_execution=True`.
683
+ - `scripts/dev_tools/validate_parallel_planner_state.py`, with the helper module `scripts/dev_tools/_parallel_planner_state_routing.py` for invariant P10, appends one error per violated planner invariant. The ready-gate invariants P6 through P10 run only when the caller passes `require_ready_for_execution=True`.
639
684
  - `scripts/dev_tools/parallel_manifest_contract.py` appends one error per violated manifest invariant and exposes the default-resolving accessors. Manifest validation is a library call, not an MCP artifact type.
640
685
  - `scripts/dev_tools/validate_orchestration_artifacts.py` registers the CLI subparsers `parallel-orchestrator-state` (with `--require-complete`) and `parallel-planner-state` (with `--require-ready-for-execution`). An unknown artifact type continues to fail with `Unsupported artifact type: {type}`.
641
- - The TypeScript parity port at `extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts`, `parallel-state-structures.ts`, `parallel-state-records.ts`, `parallel-orchestrator-state-core.ts`, and `parallel-planner-state-core.ts` reproduces the same invariants and is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for both new `artifact_type` values. Verified scope: 96 of 96 error strings matched across 43 constructed documents, for JSON-representable values that round-trip through both runtimes' native types. Three divergence classes are known outside that verified scope: (1) **`pythonRepr` quote selection** — `parallel-state-shared.ts:112-132` always single-quotes, while Python's `repr` switches to double quotes when the value contains a single quote (recorded repo-wide at `docs/features/potential/2026-08-07-python-repr-quote-selection-divergence.md`); (2) **integral floats** — `JSON.parse` erases Python's `int`/`float` distinction, so an integral float value produces a different Python-side error count than the TypeScript side; (3) **boolean/integer equality** — `parallel-state-structures.ts:228` uses `===`, so a boolean value is not selected the way Python's `True == 1` equality selects it, producing differing error counts.
686
+ - The TypeScript parity port at `extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts`, `parallel-state-structures.ts`, `parallel-state-records.ts`, `parallel-orchestrator-state-core.ts`, and `parallel-planner-state-core.ts` reproduces the same invariants and is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for both new `artifact_type` values. Verified scope: 96 of 96 error strings matched across 43 constructed documents, for JSON-representable values that round-trip through both runtimes' native types. Three divergence classes are known outside that verified scope: (1) **`pythonRepr` quote selection** — `parallel-state-shared.ts:112-132` always single-quotes, while Python's `repr` switches to double quotes when the value contains a single quote (recorded repo-wide at `docs/features/potential/2026-08-07-python-repr-quote-selection-divergence.md`); (2) **integral floats** — `JSON.parse` erases Python's `int`/`float` distinction, so an integral float value produces a different Python-side error count than the TypeScript side; (3) **boolean/integer equality** — `parallel-state-structures.ts:228` uses `===`, so a boolean value is not selected the way Python's `True == 1` equality selects it, producing differing error counts. For ready-gate invariant P10, `extensions/drm-copilot/src/lib/validate/parallel-planner-state-routing.ts` enforces the P10 structural subset (the band enums, the assessment and receipt object checks, `signals_present` shape, `band >= floor` ordering, non-empty `rationale` and `assessed_at`, the band-equality cross-checks, `agent`, and the `fable_policy` enum) with byte-identical error strings; the Python validator is authoritative for floor equality, resolved-model equality, and the disabled clamp, which the TypeScript port does not check.
642
687
  - Enforcement is therefore Python validator logic, plus the TypeScript parity port, plus this prose file. It is NEVER an imported JSON Schema. No schema file is read at validation time.
643
688
  - The `parallel` route entry lives in `config/orchestration-routing.json` with `requires_pr_gate: false` (there is no run-level pull request to gate; each child's own route checkpoint enforces its per-item pull-request gate) and is mirrored byte-for-byte in `extensions/drm-copilot/resources/config/orchestration-routing.json`.
644
689
  - The `PreToolUse` merge gate `.claude/hooks/enforce-epic-merge-gate.ps1` carries a parallel allow-branch that authorizes a per-item `gh pr merge --merge` from the parallel-orchestrator checkpoint when `route_id == "parallel"`, the target item's `merge_status == "ci_green"`, and the command's PR number matches that item's `pr_number`; any other case fails closed with `EPIC_MERGE_GATE_BLOCKED`.
@@ -7,14 +7,14 @@ paths:
7
7
  - "docs/features/**/plan.*.md"
8
8
  - "docs/features/**/remediation-plan.*.md"
9
9
  - ".claude/skills/atomic-plan-contract/SKILL.md"
10
- description: Acceptance-gate rules G1 through G6 applied to the shell commands an atomic plan states as acceptance conditions.
10
+ description: Acceptance-gate rules G1 through G10 for atomic plans. G1 through G9 judge the shell commands a plan states as acceptance conditions; the document-level G10 rule reports a SCRATCH definition that is not namespaced by issue number.
11
11
  ---
12
12
 
13
13
  # Atomic-Plan Acceptance Gates (G1 through G6)
14
14
 
15
- This rule governs the acceptance-gate rules the plan validator applies to the shell commands an atomic plan states as acceptance conditions. It exists because a plan can state an acceptance condition that cannot fail: a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. Such a condition reads as a verification step and gates nothing (issue #486).
15
+ This rule governs the acceptance-gate rules the plan validator applies to an atomic plan: G1 through G9 judge the shell commands the plan states as acceptance conditions, and G10 judges the whole plan document. It exists because a plan can state an acceptance condition that cannot fail: a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. Such a condition reads as a verification step and gates nothing (issue #486).
16
16
 
17
- The rules are enforced by `scripts/dev_tools/plan_gate_discrimination.py` and by the TypeScript parity port at `extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts` with its shared-predicate module `plan-gate-rules.ts`, both fed by the command extractor (`scripts/dev_tools/plan_gate_commands.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts`). Enforcement is validator logic plus this prose file. No JSON Schema is authored, imported, or read.
17
+ The rules are enforced by `scripts/dev_tools/plan_gate_discrimination.py` and by the TypeScript parity port at `extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts` with its shared-predicate module `plan-gate-rules.ts`. G1 through G9 are fed by the command extractor (`scripts/dev_tools/plan_gate_commands.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts`); G10 reads the whole document through `scripts/dev_tools/plan_gate_scratch.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-scratch.ts`. Enforcement is validator logic plus this prose file. No JSON Schema is authored, imported, or read.
18
18
 
19
19
  ## Scope of Invocation — no grandfathering or exemption mechanism
20
20
 
@@ -26,7 +26,7 @@ The consequence is that adding a rule to this set is cheap in migration cost and
26
26
 
27
27
  ## Rule Table
28
28
 
29
- Every finding string begins with the square-bracketed `P#-T#` identifier of the task the command is attributed to, and renders the offending value or literal between backticks.
29
+ Every finding string begins with the square-bracketed `P#-T#` identifier of the task the command is attributed to, and renders the offending value or literal between backticks. The G10 exception: a G10 finding begins with `Line N: ` instead, because a SCRATCH definition sits outside any task window; the prefix matches the structural-error prefix in the same error channel, and the offending logical line is still rendered between backticks.
30
30
 
31
31
  | Rule | Condition | Shipped severity |
32
32
  | --- | --- | --- |
@@ -40,14 +40,15 @@ Every finding string begins with the square-bracketed `P#-T#` identifier of the
40
40
  | **G8** | A `git diff` invocation carrying no non-flag ref operand and neither `--cached` nor `--staged`. It compares the worktree against the index, which is ambient state: the comparison passes vacuously once the change is committed. Exonerated when the attributed task text carries a second `git diff` or a `git status` span. | **Warning** |
41
41
  | **G8b** | A `git diff` invocation carrying a non-flag ref operand together with `--name-only` or `--name-status`, whose attributed task text carries neither a `git add` span nor a `git status --porcelain` span. A name-listing diff enumerates tracked changes only, so a path the plan creates is invisible to it. | **Warning** |
42
42
  | **G9** | A command carrying a `--cov` token, carrying no token beginning `--cov-report=term` and no token beginning `--cov-fail-under`, whose project `addopts` value also carries no `--cov-report=term`. No coverage table is printed, so a coverage number the acceptance condition demands can never be read. | **Warning** |
43
+ | **G10** | An unfenced logical line of the plan document (a physical line plus its indented continuation lines) that matches the SCRATCH definition predicate, and whose text after the first definition match carries neither an `issue-<issue-num>` nor an `issue-<digits>` namespace. One finding per logical line, reported against its first physical line. | **Blocking** |
43
44
 
44
- G1 through G9 are the complete shipped set. G1 through G6 were added by issue #486 and G7 through G9 by issue #519; the parenthetical in this file's title names the original set only.
45
+ G1 through G10 are the complete shipped set. G1 through G6 were added by issue #486, G7 through G9 by issue #519, and G10 by issue #932; the parenthetical in this file's title names the original set only.
45
46
 
46
47
  G1 through G4 form a cascade over each `--cov` value: the value is decided once, so a value G1 rejects is never additionally reported by G2 or G3. G4 is evaluated independently of the cascade because the ambiguous form is a defect whatever the value resolves to. G6 is evaluated before G5, because cross-line presence falsifies G5's tree-absence claim.
47
48
 
48
49
  G8b is a distinct rule from G8 and not a sub-case of it: G8 reports a diff with no ref operand, G8b reports one that has a ref operand but cannot observe an untracked path. A single invocation can satisfy only one of the two, because the presence of a ref operand decides between them.
49
50
 
50
- G1 and G4 are context-free and run on every invocation. G2, G3, G5, and G6 require a repository seam; with no context supplied they do not run, and the Blocking list is byte-identical to the pre-change output for the same text. G7, G8, and G8b are likewise context-free and run on every invocation. G9 requires the repository seam, because it reads the project `addopts` value through it, so with no context supplied G9 does not run. All four of the rules added by issue #519 ship in the Warning channel, so none of them can alter the Blocking list at all.
51
+ G1 and G4 are context-free and run on every invocation. G2, G3, G5, and G6 require a repository seam; with no context supplied they do not run. G7, G8, and G8b are likewise context-free and run on every invocation. G9 requires the repository seam, because it reads the project `addopts` value through it, so with no context supplied G9 does not run. All four of the rules added by issue #519 ship in the Warning channel, so none of them can alter the Blocking list at all. G10 is context-free and document-level: it reads the whole plan text, including the preamble and terms lists the command extractor drops, runs on every invocation, and can add Blocking findings without a context.
51
52
 
52
53
  ### Attribution window
53
54
 
@@ -136,6 +137,43 @@ The remaining 4 findings are true positives, and each is the exact defect the ru
136
137
 
137
138
  Counts, and every one of the 4 false positives named by plan path, task identifier, offending span, and the reason its acceptance condition is falsifiable: `docs/features/completed/2026-08-23-plan-acceptance-gates-miss-unobservable-and-ambient-state-gates-519/evidence/qa-gates/corpus-measurement.2026-08-24T00-00.md`.
138
139
 
140
+ ### G10 — ships as Blocking by operator-approved scope and the pre-declared rule
141
+
142
+ G10 enforces the child-unique scratch location rule introduced by issue #900: a plan that uses scratch files points the `SCRATCH` token at `<session scratchpad>/issue-<issue-num>/`, so concurrent child runs in one session do not collide. Unlike G1 through G9, it judges document prose rather than task-attributed commands, because a SCRATCH definition is written in a plan preamble or terms list that the command extractor drops.
143
+
144
+ The detection contract has two steps, and both patterns use no lookbehind so the Python and JavaScript dialects agree. Step 1 is the definition predicate; step 2 is the namespace that accepts the line when it appears in the text after the first definition match:
145
+
146
+ ```text
147
+ (?:^|[^A-Za-z0-9_<>$/.-])`?SCRATCH`?(?:\*\*)?[ \t]*(?:means\b|:=|=|:|is (?:the|a|an)\b|resolves to\b|abbreviates\b|denotes\b|refers to\b|stands for\b)
148
+ issue-(?:<issue-num>|[0-9]+)
149
+ ```
150
+
151
+ Lines inside fenced code blocks are skipped, and a logical line is reported once however many definition matches it contains.
152
+
153
+ A continuation line is non-blank, begins with whitespace, and is not a fence line, so a heading or task line written at column 0 ends the logical line, and an indented heading or task line is absorbed into it. Both runtimes split the document into physical lines on the CR LF, LF, and CR terminators only; a form feed, a vertical tab, the information separators, NEL, and the Unicode line and paragraph separators do not end a physical line. Both runtimes share one explicit whitespace class for the blank-line test, the continuation test, and whitespace normalization, declared once per runtime as `PLAN_WHITESPACE_CLASS` in the command extractor module, with an identical pattern string in both: tab, line feed, vertical tab, form feed, carriage return, space, the Unicode space separators, and the Unicode line and paragraph separators. NEL, the information separators, and the byte-order mark are outside that class, so in both runtimes a line that begins with one of them ends the logical line, and the character is kept verbatim in the normalized text. G6 uses the same class for its single-line test, its sliding-window join, and the split of the search literal into words, so a tracked file that contains NEL, an information separator, or the byte-order mark produces the same G6 result in both runtimes; the plan-quotation exoneration, which reads the plan text rather than a tracked file, keeps each runtime's native class. The fence test keeps the command extractor's fence pattern, whose leading whitespace is each runtime's native class, so a fence line that begins with NEL, an information separator, or the byte-order mark can be recognized differently by the two runtimes, for G1 through G9 as well as for G10.
154
+
155
+ The severity was fixed by the same two-conjunct decision rule used for G5 through G9, written and committed before the measurement was taken: Blocking if and only if the total G10 finding count is greater than zero **and** the recorded false-positive count is zero; otherwise the measurement indicates Warning. The pre-declared false-positive definition is a flagged logical line that is not a SCRATCH definition, or that defines SCRATCH in the canonical issue-namespaced form.
156
+
157
+ The measurement is recorded in `docs/features/active/2026-10-15-plan-validator-accepts-bare-scratch-paths-932/evidence/qa-gates/g10-corpus-measurement.2026-10-16T01-21.md`. It scanned 493 plan and remediation-plan files under `docs/` at the merge base and produced 17 findings, all 17 true positives and 0 false positives, so both conjuncts hold and the rule yields Blocking.
158
+
159
+ G10 also ships Blocking by operator-approved scope for issue #932. The measurement alone is a weaker basis than the G7 through G9 precedent, because the research for issue #932 observed the committed plan corpus, including the definition forms the predicate targets, before the measurement was taken. The severity is a single constant in each runtime (`G10_SEVERITY`), and a parity test asserts the two constants agree.
160
+
161
+ ### Known false-negative classes — G10
162
+
163
+ G10 does not report the following, and each is a stated limitation rather than a deferred promise:
164
+
165
+ - **Wrong issue number.** A namespaced definition whose issue number differs from the plan's own issue is accepted, because the predicate checks the namespace shape, not its value.
166
+ - **`SCRATCHPAD`-family tokens.** `SCRATCHPAD`, `<SCRATCHPAD>`, and `<SCRATCH>` tokens, and root paths written under them, are excluded by the preceding-character class and the token boundary.
167
+ - **Definition by reference.** A plan that defines SCRATCH by pointing at another plan's definition carries no definition text for the predicate to match.
168
+ - **Fenced definitions.** A definition placed inside a fenced code block is skipped, which is also what lets plans and specifications quote rejected forms as examples.
169
+ - **Any issue token after the definition.** A logical line is accepted when an `issue-<digits>` or `issue-<issue-num>` token appears anywhere in its text after the first definition match, including a cross-reference that is not the scratch location, such as `(see issue-900 for context)`. Step 2 checks the namespace shape anywhere in that text, not inside a path segment.
170
+
171
+ One false-positive class is possible and recorded: the colon connector matches prose in which the word SCRATCH is directly followed by a colon that introduces something other than a definition, as in the line below. The measured corpus contains no instance.
172
+
173
+ ```text
174
+ Each artifact names the token SCRATCH: it never records a host path.
175
+ ```
176
+
139
177
  ## The Write-Mode Register
140
178
 
141
179
  G7 reads a fixed register of six entries. Each entry is an argv predicate plus a set of observation markers matched case-sensitively as substrings of the owning task's attributed text. The register is data, not code, so the same six entries are transcribed into the TypeScript twin without porting behaviour.
@@ -239,7 +277,7 @@ The following are prohibited in gate messages:
239
277
 
240
278
  The reason is byte-identity across the two runtimes. Python's `repr` selects its quote character based on the value's contents, switching to double quotes when the value contains a single quote, while the TypeScript `pythonRepr` helper used elsewhere in this repository always single-quotes. A value carrying an apostrophe would therefore render differently in the two runtimes, and the parity requirement would fail on exactly the class of value a maintainer is most likely to encounter in a path or a prose literal. Backtick delimiting has no content-dependent behaviour and needs no helper.
241
279
 
242
- The prohibition is enforced by tests, not only by prose: a parity test asserts the Python gate module contains neither `!r` nor `repr(`, a companion test asserts no `pythonRepr(` call appears in any of the three TypeScript gate modules, and the parity fixture set includes an apostrophe-bearing `--cov` value and an apostrophe-bearing search literal whose expected strings are asserted identically in both runtimes.
280
+ The prohibition is enforced by tests, not only by prose: a parity test asserts the Python gate module contains neither `!r` nor `repr(`, a companion test asserts no `pythonRepr(` call appears in any of the TypeScript gate modules, and the parity fixture set includes an apostrophe-bearing `--cov` value and an apostrophe-bearing search literal whose expected strings are asserted identically in both runtimes.
243
281
 
244
282
  ## Authoring Guidance for Plan Authors
245
283
 
@@ -251,7 +289,8 @@ The prohibition is enforced by tests, not only by prose: a parity test asserts t
251
289
 
252
290
  ## Enforcement
253
291
 
254
- - `scripts/dev_tools/plan_gate_commands.py` extracts task-attributed command candidates; `scripts/dev_tools/plan_gate_discrimination.py` evaluates G1 through G6 and returns the two severity channels.
292
+ - `scripts/dev_tools/plan_gate_commands.py` extracts task-attributed command candidates; `scripts/dev_tools/plan_gate_discrimination.py` evaluates G1 through G9, calls `scripts/dev_tools/plan_gate_scratch.py` for G10, and returns the two severity channels.
255
293
  - `scripts/dev_tools/validate_orchestration_artifacts.py` routes the existing `plan` artifact type through the two-channel entry point, prints each Warning to stderr prefixed with `PLAN GATE WARNING: `, and derives its exit code from the error channel alone. No new flag, option, or artifact type is added.
256
294
  - The TypeScript parity port is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for the existing `plan` artifact type. The MCP `validate_orchestration_artifacts` input-schema property-key set is unchanged; Warnings surface on an optional `warnings` field that is absent when there are none.
295
+ - `scripts/dev_tools/plan_gate_scratch.py` evaluates G10, the document-level SCRATCH definition rule, and `evaluate_plan_gates` in `scripts/dev_tools/plan_gate_discrimination.py` calls it on every invocation, with or without a context. The TypeScript twin `extensions/drm-copilot/src/lib/validate/plan-gate-scratch.ts` is called the same way from `evaluatePlanGates`. Through the Python CLI a G10 finding is printed as an error and the process exits 1; through the MCP service call it causes the call to throw with the message included.
257
296
  - `.claude/hooks/validate-planner-output.ps1` is not modified by this rule and carries no part of its enforcement.
@@ -6,19 +6,21 @@ description: Module rigor tier system and uniform coverage thresholds.
6
6
 
7
7
  # Module Rigor Tiers
8
8
 
9
- This rule defines the T1–T4 module rigor tier system used by all CI gates in this repository. The tier definitions and gate matrix in this document are the tier system's source of truth; the file `quality-tiers.yml` at the repository root maps every project to a tier. Adding a project without a tier classification fails CI.
9
+ Applicability: this rule applies only when `quality-tiers.yml` exists at the repository root, which indicates that the repository has adopted module rigor tiers. When that file is absent, there is no tier classification requirement, no `tier-classification` CI stage, and no tier-dependent gate (the escape-hatch limits, property-test density, mutation score, contract-bump rule, determinism retry rate, golden tests, and E2E suite scope in the Tier-dependent table below), and the absence of `quality-tiers.yml` is not a defect. The coverage defaults listed under Uniform across all tiers do not depend on tier adoption; their precedence is stated in that section.
10
+
11
+ When `quality-tiers.yml` exists, this rule defines the T1–T4 module rigor tier system used by the repository's CI gates, and the tier definitions and gate matrix in this document are the tier system's source of truth.
10
12
 
11
13
  ## Tiers
12
14
 
13
- - **T1 — Critical.** Behavior bugs cause silent data loss, model drift, or security holes. Examples (No-COM architecture): classifier engines (SpamBayes, Triage), ToDo ID allocator and hierarchy operations, Graph extended-properties adapter, auth/token handling, host-agnostic command bus.
14
- - **T2 — Core.** Bugs cause feature regressions but not data loss. Examples: `TaskMaster.Domain`, `TaskMaster.Application`, mail-item DTOs, settings store abstraction, schema definitions.
15
- - **T3 — Adapters & UI.** Glue around APIs the team does not own. Examples: Outlook task pane UI, Office.js wrappers, Microsoft Graph SDK wrappers, persistence I/O.
15
+ - **T1 — Critical.** Behavior bugs cause silent data loss, model drift, or security holes. Examples: classifier and scoring engines, identifier allocators and hierarchy operations, adapters that write to an external system of record, authentication and token handling, command dispatch.
16
+ - **T2 — Core.** Bugs cause feature regressions but not data loss. Examples: domain and application layers, data-transfer objects, settings store abstractions, schema definitions.
17
+ - **T3 — Adapters & UI.** Glue around APIs the team does not own. Examples: user-interface surfaces, host-platform API wrappers, third-party API and SDK wrappers, persistence I/O.
16
18
  - **T4 — Scaffolding.** Examples: DI wiring, bootstrap, build scripts, dev tooling, generated code, manifests.
17
19
 
18
20
  ## Source of Truth
19
21
 
20
- - `quality-tiers.yml` at repo root maps every project to one tier.
21
- - The CI pipeline's `tier-classification` stage validates that every project entry has a tier and that no unclassified project exists. Adding a project without a tier classification fails CI.
22
+ - When `quality-tiers.yml` exists at the repository root, it maps every project to one tier.
23
+ - In a repository that runs a `tier-classification` CI stage, that stage validates that every project entry has a tier and that no unclassified project exists, and it fails CI for an unclassified project.
22
24
 
23
25
  ## Uniform-vs-Tier-Dependent Gate Matrix
24
26
 
@@ -26,6 +28,8 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
26
28
 
27
29
  ### Uniform across all tiers (T1–T4)
28
30
 
31
+ Threshold precedence: when the repository's root `CLAUDE.md` states line or branch coverage thresholds, those thresholds govern. The 85% line and 75% branch figures are defaults that apply only when the root `CLAUDE.md` states none. This precedence applies to every restatement of these figures in other rule files, agents, and skills. Each metric falls back independently: when the root `CLAUDE.md` states only a line threshold or only a branch threshold, the stated threshold governs that metric and the default governs the other.
32
+
29
33
  - Format check: 100% pass.
30
34
  - Lint errors: 0.
31
35
  - Type errors: 0.
@@ -48,4 +52,4 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
48
52
 
49
53
  ## Rationale (uniform coverage thresholds)
50
54
 
51
- High test coverage is a fundamental quality-control design choice that enables autonomous agentic development and trust in the work product. For that reason, line coverage >= 85% applies uniformly across T1–T4 to every coverage language, and branch coverage >= 75% applies uniformly across T1–T4 to every language whose coverage tooling measures branch coverage; tier-specific lower coverage floors are not used in this repository. The branch threshold is not applied to PowerShell or bash because Pester and kcov do not measure branch coverage. That exemption is a capability limit on an unevaluable threshold, not a licence to exclude files from measurement: PowerShell and bash production files remain in the coverage denominator under the Coverage Exclusion Policy in `.claude/rules/general-unit-test.md`.
55
+ High test coverage is a fundamental quality-control design choice that enables autonomous agentic development and trust in the work product. For that reason, line coverage >= 85% applies uniformly across T1–T4 to every coverage language, and branch coverage >= 75% applies uniformly across T1–T4 to every language whose coverage tooling measures branch coverage; tier-specific lower coverage floors are not used. These figures are defaults under the threshold precedence stated above: a root `CLAUDE.md` that states coverage thresholds overrides them. Each metric falls back independently, so a root `CLAUDE.md` that states only one of the two thresholds overrides only that one. The branch threshold is not applied to PowerShell or bash because Pester and kcov do not measure branch coverage. That exemption is a capability limit on an unevaluable threshold, not a licence to exclude files from measurement: PowerShell and bash production files remain in the coverage denominator under the Coverage Exclusion Policy in `.claude/rules/general-unit-test.md`.
@@ -45,11 +45,12 @@ single pass. Do not substitute the VS Code task wrappers for the native command
45
45
 
46
46
  ## Discovery Contract
47
47
 
48
- - Search roots: `tools/`, `scripts/`, `.claude/lib/bash/`, and `.claude/skills/`, relative to the
49
- current working directory; a missing root is silently skipped. The `.claude/lib/bash/` root carries
50
- the destination-portable bash library published by push-down, and the `.claude/skills/` root carries
51
- scripts bundled inside a skill folder, so those scripts are held to the same format, lint, test, and
52
- coverage standards as `tools/` and `scripts/`.
48
+ - Search roots: `tools/`, `scripts/`, `.claude/lib/bash/`, `.claude/skills/`, and `.codex/`, relative
49
+ to the current working directory; a missing root is silently skipped. The `.claude/lib/bash/` root
50
+ carries the destination-portable bash library published by push-down, the `.claude/skills/` root
51
+ carries scripts bundled inside a skill folder, and the `.codex/` root carries the Codex runtime
52
+ scripts (for example `.codex/codex-web-setup.sh`), so those scripts are held to the same format,
53
+ lint, test, and coverage standards as `tools/` and `scripts/`.
53
54
  - A file is a shell script when its suffix (lowercased) is `.sh` or its first line is a
54
55
  shebang whose resolved interpreter is `bash` or `sh` (including `env` and `env -S`/`-flag`
55
56
  forms; the shebang is lowercased before parsing, so `#!/usr/bin/env BASH` qualifies).
@@ -63,9 +64,10 @@ single pass. Do not substitute the VS Code task wrappers for the native command
63
64
  - Coverage is measured with kcov, which emits a single merged Cobertura report `cov.xml` under
64
65
  `artifacts/pester/kcov` (or `SHELL_QC_KCOV_OUT_DIR`). The run prints
65
66
  `Bash coverage (lines): NN.N%`.
66
- - The kcov include pattern covers all four discovery roots — `tools/`, `scripts/`,
67
- `.claude/lib/bash/`, and `.claude/skills/` — so the Claude bash library and skill-bundled scripts are
68
- measured, not merely discovered. The `tests/` tree remains excluded.
67
+ - The kcov include pattern covers all five discovery roots — `tools/`, `scripts/`,
68
+ `.claude/lib/bash/`, `.claude/skills/`, and `.codex/` — so the Claude bash library, skill-bundled
69
+ scripts, and Codex runtime scripts are measured, not merely discovered. The `tests/` tree remains
70
+ excluded.
69
71
  - kcov reports **line coverage only**. The uniform line-coverage threshold (>= 85% per
70
72
  `.claude/rules/quality-tiers.md`) applies. Branch coverage is not measurable by kcov for
71
73
  bash; there is no bash branch-coverage gate.
@@ -54,7 +54,7 @@ Run the toolchain in order: format → lint → type-check → test. Restart fro
54
54
 
55
55
  ## Architecture Boundaries
56
56
 
57
- Layer rules and the No-COM architecture assertions are defined in `.claude/rules/architecture-boundaries.md`. The TypeScript enforcement tool is `dependency-cruiser` with configuration file `.dependency-cruiser.cjs`.
57
+ Layer rules and the host-neutral architecture assertions are defined in `.claude/rules/architecture-boundaries.md` under the heading "Host-Neutral Architecture Rules (enforceable assertions)". The TypeScript enforcement tool is `dependency-cruiser` with configuration file `.dependency-cruiser.cjs`.
58
58
 
59
59
  ## Property-Based and Mutation Testing
60
60
 
@@ -5,8 +5,11 @@
5
5
  "Bash(git *)",
6
6
  "Bash(poetry run *)",
7
7
  "Bash(pwsh *)",
8
+ "Bash(bash .claude/lib/bash/abandon-parallel-item.sh*)",
8
9
  "Bash(bash .claude/lib/bash/compute-cohorts.sh*)",
9
10
  "Bash(bash .claude/lib/bash/compute-concurrency-batches.sh*)",
11
+ "Bash(bash .claude/lib/bash/mutate-parallel-run.sh*)",
12
+ "Bash(bash .claude/lib/bash/remove-parallel-item.sh*)",
10
13
  "Bash(bash .claude/lib/bash/validate-parallel-manifest.sh*)",
11
14
  "Read",
12
15
  "Edit(docs/**)",
@@ -211,10 +214,6 @@
211
214
  {
212
215
  "matcher": "atomic-planner|atomic-executor|feature-review|task-researcher|prd-feature|staged-review|epic-review|status-updater|python-typed-engineer|powershell-typed-engineer|csharp-typed-engineer|typescript-engineer|orchestrator|epic-orchestrator|epic-planner",
213
216
  "hooks": [
214
- {
215
- "type": "command",
216
- "command": "pwsh -NoProfile -Command \"$input = $env:CLAUDE_HOOK_INPUT | ConvertFrom-Json; $output = $input.output; if (-not ($output -match '(plan-path|research-path|review-artifact|PREFLIGHT|evidence/)')) { Write-Error 'Subagent stopped without required completion artifact path'; exit 1 }; exit 0\""
217
- },
218
217
  {
219
218
  "type": "command",
220
219
  "command": "pwsh -NoProfile -File .claude/hooks/validate-discovery-artifact-gate.ps1"
@@ -88,7 +88,7 @@ During feature review (feature-audit phase):
88
88
 
89
89
  ### When Orchestrators Enforce AC Tracking
90
90
 
91
- Orchestrators do not directly check off AC items. Instead:
91
+ Orchestrators do not directly check off AC items. The one exception is a CI-dependent criterion, which the item's own orchestrator run checks off at S9 as described in `### CI-Dependent Criteria` above. For every other criterion, orchestrators instead:
92
92
 
93
93
  1. Ensure delegated executors and reviewers reference this skill.
94
94
  2. After executor or reviewer completion, verify that AC source files reflect delivered work (spot-check; do not re-execute verification).
@@ -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
 
@@ -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
  #
@@ -348,6 +348,8 @@ cleanup_wt_derive_scan_roots() {
348
348
  p=${paths[i]//\\//}
349
349
  parent=${p%/*}
350
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
351
353
  n=$(normalize_wt_path "$parent")
352
354
  [[ -z $n || -n ${seen[$n]:-} ]] && continue
353
355
  [[ $n == "$main_norm" || $main_norm == "$n"/* ]] && continue
@@ -40,6 +40,8 @@
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.
43
45
  # shellcheck source=.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh
44
46
  # shellcheck disable=SC1091
45
47
  source "$(dirname -- "${BASH_SOURCE[0]}")/cleanup_worktrees_enumerate_lib.sh"
@@ -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
@@ -241,9 +259,15 @@ cross-call/conversation-state visibility.
241
259
  prompt text, reads `artifacts/orchestration/epic-orchestrator-state.json`, looks up that
242
260
  feature's `depends_on`, and denies with reason `EPIC_WAVE_BARRIER_BLOCKED` unless every
243
261
  dependency's `merge_status` is `merged` or `worktree_removed`.
244
- - **Layer 2 — retrospective backstop:** the wave-barrier ordering invariant inside
245
- `validate_epic_orchestrator_state_text`, enforced at `epic-orchestrator` `SubagentStop` time via
246
- the parameterized `validate-orchestrator-output.ps1` hook. It checks only a dependent feature
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
247
271
  that is treated as started: one with a string `worktree_created_at`, or with a `merge_status`
248
272
  other than `not_started` (a missing or non-string `merge_status` counts as started). It appends
249
273
  exactly one error per violated dependency edge. When the dependency's `merge_status` is not
@@ -252,6 +276,9 @@ cross-call/conversation-state visibility.
252
276
  Otherwise, when the dependency's `merge_confirmed_at` is later than the dependent's
253
277
  `worktree_created_at`, the error is
254
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.
255
282
 
256
283
  Both layers are required; neither alone closes the gap. `epic-orchestrator` does not launch wave
257
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