@danmoisan/drm-copilot-mcp 1.1.19 → 1.1.21

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 (170) hide show
  1. package/out/mcp-server.js +172 -11
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/atomic-executor.md +17 -6
  4. package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -2
  5. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +5 -0
  6. package/resources/claude-customizations/.claude/agents/orchestrator.md +4 -1
  7. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +4 -0
  8. package/resources/claude-customizations/.claude/agents/task-researcher.md +8 -0
  9. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
  10. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +22 -53
  11. package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +5 -1
  12. package/resources/claude-customizations/.claude/hooks/premortem-section.ps1 +149 -0
  13. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +210 -84
  14. package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +13 -1
  15. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +24 -5
  16. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-MergeConfirmationParser.ps1 +203 -0
  17. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +10 -10
  18. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +46 -10
  19. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +48 -16
  20. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +7 -3
  21. package/resources/claude-customizations/.claude/skills/csharp-change-budget-router/SKILL.md +2 -2
  22. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +12 -3
  23. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +4 -2
  24. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +134 -0
  25. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +22 -9
  26. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +29 -5
  27. package/resources/claude-customizations/.claude/skills/powershell-change-budget-router/SKILL.md +1 -1
  28. package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +1 -1
  29. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +14 -6
  30. package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +6 -0
  31. package/resources/claude-customizations/config/orchestration-routing.json +7 -7
  32. package/resources/claude-customizations/pack-manifests/core.json +4 -0
  33. package/resources/codex-and-agents-customizations/.agents/skills/README.md +1 -0
  34. package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +8 -7
  35. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +39 -4
  36. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +8 -6
  37. package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +6 -6
  38. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +2 -2
  39. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +15 -8
  40. package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +2 -2
  41. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +134 -0
  42. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +16 -6
  43. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
  44. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
  45. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -1
  46. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
  47. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +6 -0
  48. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -7
  49. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -7
  50. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -7
  51. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -7
  52. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -7
  53. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -7
  54. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +6 -3
  55. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +6 -3
  56. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +6 -3
  57. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +6 -3
  58. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +6 -3
  59. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +6 -3
  60. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planning.toml +1 -1
  61. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c1.toml +1 -1
  62. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c2.toml +1 -1
  63. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3-elevated.toml +1 -1
  64. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3.toml +1 -1
  65. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c4.toml +1 -1
  66. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward.toml +1 -1
  67. package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
  68. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
  69. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
  70. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
  71. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
  72. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
  73. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
  74. package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +4 -2
  75. package/resources/codex-and-agents-customizations/.codex/agents/epic-planner.toml +2 -2
  76. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -1
  77. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -1
  78. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -1
  79. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -1
  80. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -1
  81. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -1
  82. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +8 -5
  83. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +8 -5
  84. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +8 -5
  85. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +8 -5
  86. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +8 -5
  87. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +8 -5
  88. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
  89. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
  90. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
  91. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
  92. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
  93. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
  94. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  95. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c1.toml +1 -1
  96. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c2.toml +1 -1
  97. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c3-elevated.toml +1 -1
  98. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c3.toml +1 -1
  99. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c4.toml +1 -1
  100. package/resources/codex-and-agents-customizations/.codex/agents/pr-author.toml +1 -1
  101. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c1.toml +1 -1
  102. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c2.toml +1 -1
  103. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c3-elevated.toml +1 -1
  104. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c3.toml +1 -1
  105. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c4.toml +1 -1
  106. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature.toml +1 -1
  107. package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
  108. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
  109. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
  110. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
  111. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
  112. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
  113. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
  114. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c1.toml +7 -1
  115. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c2.toml +7 -1
  116. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3-elevated.toml +7 -1
  117. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3.toml +7 -1
  118. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c4.toml +7 -1
  119. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +7 -1
  120. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c1.toml +1 -1
  121. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c2.toml +1 -1
  122. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c3-elevated.toml +1 -1
  123. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c3.toml +1 -1
  124. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c4.toml +1 -1
  125. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer.toml +1 -1
  126. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  127. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
  128. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +17 -38
  129. package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +5 -1
  130. package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +82 -70
  131. package/resources/codex-and-agents-customizations/.codex/prompts/feature-review-remediate.md +6 -4
  132. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
  133. package/resources/codex-and-agents-customizations/pack-manifests/core.json +2 -0
  134. package/resources/config/orchestration-routing.json +7 -7
  135. package/resources/customizations/.github/agents/atomic_executor.agent.md +21 -11
  136. package/resources/customizations/.github/agents/atomic_planning.agent.md +8 -3
  137. package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +13 -9
  138. package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
  139. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +2 -2
  140. package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +3 -3
  141. package/resources/customizations/.github/agents/orchestrator.agent.md +8 -5
  142. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +13 -9
  143. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +2 -2
  144. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +2 -2
  145. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +3 -3
  146. package/resources/customizations/.github/agents/python-atomic-executor.agent.md +13 -9
  147. package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
  148. package/resources/customizations/.github/agents/python-orchestrator.agent.md +2 -2
  149. package/resources/customizations/.github/agents/task-researcher.agent.md +6 -0
  150. package/resources/customizations/.github/prompts/generate-atomic-plan.prompt.md +16 -10
  151. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +2 -2
  152. package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +1 -1
  153. package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +1 -1
  154. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +2 -2
  155. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +39 -4
  156. package/resources/customizations/.github/skills/csharp-change-budget-router/SKILL.md +1 -1
  157. package/resources/customizations/.github/skills/execution-environment/SKILL.md +134 -0
  158. package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +1 -1
  159. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
  160. package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +10 -0
  161. package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +11 -0
  162. package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +11 -0
  163. package/resources/lib/codex-routing/CodexDeployment.psm1 +10 -10
  164. package/resources/powershell/PoshQC/PoshQC.CoverageMerge.psm1 +163 -0
  165. package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +296 -0
  166. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +23 -4
  167. package/resources/powershell/PoshQC/PoshQC.psd1 +7 -1
  168. package/resources/powershell/PoshQC/PoshQC.psm1 +17 -5
  169. package/resources/powershell/PoshQC/README.md +13 -1
  170. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +3 -0
@@ -1,11 +1,12 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Pre-tool-use hook that gates gh pr merge --merge behind epic-mode checkpoint state.
3
+ Pre-tool-use hook that gates every pull-request merge or merge-queue enqueue behind checkpoint state.
4
4
 
5
5
  .DESCRIPTION
6
6
  Invoked by the Claude Code PreToolUse hook on the "Bash" matcher before any Bash
7
- command runs. Regex-matches gh pr merge with a --merge flag against
8
- the envelope's tool_input.command and, when matched, allows the merge only when one of four
7
+ command runs. Brings every gh pr merge invocation except a pure --disable-auto, and every gh
8
+ api merge or enqueue mutation, into scope from the envelope's tool_input.command and, when
9
+ matched, allows the action only when one of four
9
10
  checkpoint-only conditions holds:
10
11
 
11
12
  1. Child-feature path: artifacts/orchestration/orchestrator-state.json exists,
@@ -31,7 +32,10 @@
31
32
  non-parallel) run never satisfies conditions 1-3, so its only route to a merge is an
32
33
  explicit, PR-specific, session-bound record under condition 4; a bare command with no
33
34
  PR number never satisfies condition 4, and a blanket flag is rejected rather than read.
34
- Trigger scope: --squash is out of scope for this gate and is allowed on both runtimes.
35
+ Trigger scope (issue #952): every merge method (--merge/-m, --squash/-s, --rebase/-r), --auto,
36
+ --admin, and a bare gh pr merge are gated alike, because under a merge queue each spelling
37
+ enqueues the pull request; only a pure --disable-auto is out of scope. The predicate and the
38
+ PR selector reader live in enforce-epic-merge-gate-command.ps1.
35
39
 
36
40
  Design decision: branches 1-4 trust the on-disk checkpoint and never call gh. Issue #927
37
41
  adds a docs-only branch after branch 4 fails, only for an explicit PR number whose item,
@@ -78,6 +82,8 @@ try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-Ho
78
82
  try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-authorization.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-authorization.ps1' -ErrorRecord $_ }
79
83
  # Checkpoint read seams, the import guard, and run-target resolution (issue #690).
80
84
  try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-resolution.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-resolution.ps1' -ErrorRecord $_ }
85
+ # Merge and enqueue scope predicate and the PR selector reader (issue #952).
86
+ try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-command.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-command.ps1' -ErrorRecord $_ }
81
87
  # Shared docs-only diff classification and the merge-side docs-only exemption (issue #927).
82
88
  try { . (Join-Path $PSScriptRoot 'hook-docs-only-diff.ps1') } catch { Add-HookDependencyFailure -Name 'hook-docs-only-diff.ps1' -ErrorRecord $_ }
83
89
 
@@ -111,21 +117,13 @@ function Get-EpicMergeGateCommandPrNumber {
111
117
  .SYNOPSIS
112
118
  Extract an explicit PR number argument from a gh pr merge command, or $null.
113
119
  .DESCRIPTION
114
- Both spellings are read from the segment that structurally invokes gh pr merge,
115
- never from the whole command line. The positional form ("gh pr merge 410 --merge")
116
- resolves through Get-CommandLineOperand and takes the first all-digit operand; the
117
- flag-led forms ("gh pr merge --merge 410" and "gh pr merge --merge=410") resolve
118
- through Get-CommandLineFlagValue. A bare "gh pr merge --merge" yields $null, which
119
- the parallel branch treats as fail-closed.
120
-
121
- The deleted unanchored branch scanned the WHOLE command text for the first run of
122
- digits once "gh pr merge" appeared anywhere in it, and that failed in both
123
- directions. Fail-closed: a leading "cd <path>" whose path carries a timestamp
124
- component supplied a digit run that was not a pull request number, so an authorized
125
- merge was blocked. False-allow: with authorized item 501 and unauthorized item 777,
126
- "cd /repo/worktrees/501 && gh pr merge --merge 777" extracted 501, matched the
127
- authorized item, and permitted the merge of PR 777. Taking the number from the
128
- matched segment's own operand or flag value closes both directions.
120
+ The number is resolved by Get-EpicMergeGateSelectorPrNumber in
121
+ enforce-epic-merge-gate-command.ps1 (issue #952), from the segment that structurally
122
+ invokes gh pr merge or gh api and never from the whole command line: value flags are
123
+ skipped with their values, an all-digit or /pull/<n> URL selector is accepted, and a
124
+ pulls/<n>/merge path supplies the number for gh api. A command with no resolvable number
125
+ yields $null, which the parallel and standalone branches treat as fail-closed. No
126
+ whole-line digit scan exists, so a cd path component can never supply the number.
129
127
  .PARAMETER CommandText
130
128
  The Bash command text under evaluation.
131
129
  .OUTPUTS
@@ -138,18 +136,7 @@ function Get-EpicMergeGateCommandPrNumber {
138
136
  [string] $CommandText
139
137
  )
140
138
 
141
- foreach ($operand in @(Get-CommandLineOperand -CommandText $CommandText -CommandWord 'gh' -SubcommandPath @('pr', 'merge'))) {
142
- if ($operand -match '^\d+$') {
143
- return [int]$operand
144
- }
145
- }
146
-
147
- $flagValue = Get-CommandLineFlagValue -CommandText $CommandText -CommandWord 'gh' -SubcommandPath @('pr', 'merge') -FlagName '--merge'
148
- if ($null -ne $flagValue -and $flagValue -match '^\d+$') {
149
- return [int]$flagValue
150
- }
151
-
152
- return $null
139
+ return Get-EpicMergeGateSelectorPrNumber -CommandText $CommandText
153
140
  }
154
141
 
155
142
  function Test-ChildCheckpointAllowsEpicMerge {
@@ -341,27 +328,9 @@ function Invoke-EpicMergeGateDecision {
341
328
  return Get-EpicMergeGateAllowDecision
342
329
  }
343
330
 
344
- # Only a gh pr merge invocation carrying --merge is in scope for this gate; every
345
- # other Bash command is unaffected. Both legs are read structurally from the segment
346
- # that invokes the command, so a quoted mention of the phrase and a --merge token
347
- # belonging to some other segment no longer bring a command into scope.
348
- #
349
- # The flag leg needs a raw-scan fallback: a wrapper's quoted argument collapses into ONE
350
- # token, so a flag inside it is never read as a token, and the token-only read took
351
- # bash -c "gh pr merge --merge 688" out of scope. The fallback reads only the segments the
352
- # scanner already scans raw, so a masked mention in a non-wrapper segment stays out.
353
- $isMergeInvocation = Test-CommandLineInvocation -CommandText $commandText -CommandWord 'gh' -SubcommandPath @('pr', 'merge')
354
- $hasMergeFlag = Test-CommandLineFlag -CommandText $commandText -CommandWord 'gh' -SubcommandPath @('pr', 'merge') -FlagName '--merge'
355
- if (-not $hasMergeFlag) {
356
- foreach ($segment in @(Read-CommandLineSegment -CommandText $commandText)) {
357
- if ((Test-CommandLineSegmentRawScan -Segment $segment) -and
358
- $segment.ScanText.IndexOf('--merge', [System.StringComparison]::OrdinalIgnoreCase) -ge 0) {
359
- $hasMergeFlag = $true
360
- break
361
- }
362
- }
363
- }
364
- if (-not $isMergeInvocation -or -not $hasMergeFlag) {
331
+ # Scope (issue #952): every gh pr merge invocation except a pure --disable-auto, and every gh api
332
+ # merge or enqueue mutation, is gated; Test-EpicMergeGateCommandInScope holds the predicate.
333
+ if (-not (Test-EpicMergeGateCommandInScope -CommandText $commandText)) {
365
334
  return Get-EpicMergeGateAllowDecision
366
335
  }
367
336
 
@@ -431,7 +400,7 @@ function Invoke-EpicMergeGateDecision {
431
400
  return Get-EpicMergeGateBlockDecision -Reason ('EPIC_MERGE_GATE_BLOCKED: ' + $prefix + $standalone.ReasonCode + ': ' + $standalone.Message + $docsOnlySuffix)
432
401
  }
433
402
 
434
- return Get-EpicMergeGateBlockDecision -Reason 'EPIC_MERGE_GATE_BLOCKED: gh pr merge --merge requires either a per-feature checkpoint with epic_mode == true and step9_status == "passed", an epic checkpoint with epic_merge_pr.ci_gate.conclusion == "success" and a matching pr_number, or a parallel-orchestrator checkpoint with route_id == "parallel" whose target item (matched by pr_number) has merge_status == "ci_green". No checkpoint satisfied this gate.'
403
+ return Get-EpicMergeGateBlockDecision -Reason 'EPIC_MERGE_GATE_BLOCKED: a pull-request merge or merge-queue enqueue (gh pr merge with any method, --auto, or --admin, or a gh api merge or enqueue mutation) requires either a per-feature checkpoint with epic_mode == true and step9_status == "passed", an epic checkpoint with epic_merge_pr.ci_gate.conclusion == "success" and a matching pr_number, or a parallel-orchestrator checkpoint with route_id == "parallel" whose target item (matched by pr_number) has merge_status == "ci_green". No checkpoint satisfied this gate.'
435
404
  }
436
405
 
437
406
  function Invoke-EpicMergeGateEntryPoint {
@@ -19,7 +19,8 @@
19
19
  is balanced; a structural gh pr merge; no inline
20
20
  VAR= prefix token (GH_REPO=, GH_HOST=); no
21
21
  single-dash token containing R; no --repo or
22
- --repo= token; no --auto token.
22
+ --repo= token; no --auto token; no token
23
+ containing /pull/ (a URL selector).
23
24
  M2 DOCS_ONLY_EXEMPTION_PR_UNRESOLVED - the worktree root is an existing directory.
24
25
  M3 DOCS_ONLY_EXEMPTION_PR_UNRESOLVED - gh pr view <N> --json baseRefName,headRefOid
25
26
  exits 0 and returns a JSON object; headRefOid
@@ -368,6 +369,9 @@ function Get-DocsOnlyMergeShapeViolation {
368
369
  if ($text -eq '--repo' -or $text.StartsWith('--repo=', [System.StringComparison]::OrdinalIgnoreCase)) {
369
370
  return $prefix + "the repository override '$text' is not accepted."
370
371
  }
372
+ if ($text.Contains('/pull/')) {
373
+ return $prefix + "the URL selector '$text' is not accepted."
374
+ }
371
375
  if ($text -eq '--auto' -or $text.StartsWith('--auto=', [System.StringComparison]::OrdinalIgnoreCase)) {
372
376
  return $prefix + 'auto-merge (--auto) is not eligible.'
373
377
  }
@@ -0,0 +1,149 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Shared Pre-Mortem section check for the planner and researcher SubagentStop hooks (issue #964).
4
+
5
+ .DESCRIPTION
6
+ Test-PreMortemSection reads Markdown text and requires a `## Pre-Mortem` heading followed, before
7
+ the next level-one or level-two heading, by one bullet that begins with each of the seven labels:
8
+ Review checklists, Coverage, Mirror parity, File size, Test isolation, CI-only behavior, and
9
+ Evidence. Labels match case-insensitively and may be bold. Each bullet must carry text after its
10
+ label; a bullet whose text is "not applicable" must also state a reason.
11
+
12
+ .NOTES
13
+ Pure functions: they read no file, environment variable, or clock, and keep no script-scope state. The calling hooks dot-source this
14
+ file under the guarded Add-HookDependencyFailure pattern and pass the document text they read
15
+ through their own file seams.
16
+ #>
17
+
18
+ Set-StrictMode -Version Latest
19
+
20
+ function Get-PreMortemLabel {
21
+ <#
22
+ .SYNOPSIS
23
+ Returns the seven required Pre-Mortem labels in their canonical order.
24
+ #>
25
+ [CmdletBinding()]
26
+ [OutputType([string[]])]
27
+ param()
28
+
29
+ return [string[]]@(
30
+ 'Review checklists',
31
+ 'Coverage',
32
+ 'Mirror parity',
33
+ 'File size',
34
+ 'Test isolation',
35
+ 'CI-only behavior',
36
+ 'Evidence'
37
+ )
38
+ }
39
+
40
+ function Get-PreMortemSectionLine {
41
+ <#
42
+ .SYNOPSIS
43
+ Returns the lines of the `## Pre-Mortem` section, or $null when the heading is absent.
44
+ #>
45
+ [CmdletBinding()]
46
+ [OutputType([string[]])]
47
+ param(
48
+ [Parameter(Mandatory = $true)]
49
+ [AllowEmptyString()]
50
+ [string] $Content
51
+ )
52
+
53
+ $lines = @($Content -split "`r?`n")
54
+ $start = -1
55
+ for ($index = 0; $index -lt $lines.Count; $index++) {
56
+ if ($lines[$index] -match '^##[ \t]+Pre-Mortem[ \t]*$') {
57
+ $start = $index
58
+ break
59
+ }
60
+ }
61
+ if ($start -lt 0) {
62
+ return $null
63
+ }
64
+
65
+ $section = [System.Collections.Generic.List[string]]::new()
66
+ for ($index = $start + 1; $index -lt $lines.Count; $index++) {
67
+ if ($lines[$index] -match '^#{1,2}[ \t]') {
68
+ break
69
+ }
70
+ $section.Add($lines[$index])
71
+ }
72
+ return [string[]]@($section)
73
+ }
74
+
75
+ function Test-PreMortemBulletText {
76
+ <#
77
+ .SYNOPSIS
78
+ Returns $true when the text after a label is substantive or is "not applicable" with a reason.
79
+ #>
80
+ [CmdletBinding()]
81
+ [OutputType([bool])]
82
+ param(
83
+ [Parameter(Mandatory = $true)]
84
+ [AllowEmptyString()]
85
+ [string] $Text
86
+ )
87
+
88
+ $body = ($Text -replace '^[\s:*\-\u2013\u2014]+', '').Trim()
89
+ if ($body -notmatch '[A-Za-z0-9]') {
90
+ return $false
91
+ }
92
+ $notApplicable = [regex]::Match($body, '^not applicable\b(?<Reason>.*)$', 'IgnoreCase')
93
+ if (-not $notApplicable.Success) {
94
+ return $true
95
+ }
96
+ return $notApplicable.Groups['Reason'].Value -match '[A-Za-z0-9]'
97
+ }
98
+
99
+ function Test-PreMortemSection {
100
+ <#
101
+ .SYNOPSIS
102
+ Validates the `## Pre-Mortem` section of a plan or research document.
103
+ .OUTPUTS
104
+ Hashtable with Ok (bool), Message (string or $null), and MissingLabels (string[]): the labels
105
+ that have no bullet, or whose bullet has no text or says "not applicable" without a reason.
106
+ #>
107
+ [CmdletBinding()]
108
+ [OutputType([hashtable])]
109
+ param(
110
+ [Parameter(Mandatory = $true)]
111
+ [AllowEmptyString()]
112
+ [string] $Content
113
+ )
114
+
115
+ $labels = Get-PreMortemLabel
116
+ $section = Get-PreMortemSectionLine -Content $Content
117
+ if ($null -eq $section) {
118
+ return @{
119
+ Ok = $false
120
+ Message = 'document has no `## Pre-Mortem` section; add one bullet for each of: ' + ($labels -join ', ') + '.'
121
+ MissingLabels = $labels
122
+ }
123
+ }
124
+
125
+ $missing = [System.Collections.Generic.List[string]]::new()
126
+ foreach ($label in $labels) {
127
+ $pattern = '^\s*[-*+][ \t]+(?:\*\*)?' + [regex]::Escape($label) + '(?![A-Za-z])(?<Rest>.*)$'
128
+ $valid = $false
129
+ foreach ($line in $section) {
130
+ $match = [regex]::Match($line, $pattern, 'IgnoreCase')
131
+ if ($match.Success -and (Test-PreMortemBulletText -Text $match.Groups['Rest'].Value)) {
132
+ $valid = $true
133
+ break
134
+ }
135
+ }
136
+ if (-not $valid) {
137
+ $missing.Add($label)
138
+ }
139
+ }
140
+
141
+ if ($missing.Count -gt 0) {
142
+ return @{
143
+ Ok = $false
144
+ Message = '`## Pre-Mortem` section lacks a bullet with text (or "not applicable" with a reason) for: ' + ($missing -join ', ') + '.'
145
+ MissingLabels = [string[]]@($missing)
146
+ }
147
+ }
148
+ return @{ Ok = $true; Message = $null; MissingLabels = [string[]]@() }
149
+ }