@danmoisan/drm-copilot-mcp 1.0.24 → 1.0.27
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.
- package/out/mcp-server.js +1045 -214
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/feature-review.md +5 -3
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +11 -4
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +5 -2
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +28 -8
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +28 -8
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +117 -46
- package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +115 -3
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +312 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +392 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +500 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +58 -67
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCheckpointValue.psm1 +383 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexModelReceipts.psm1 +297 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexTopologyReceipts.psm1 +298 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +232 -43
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +416 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateModelReceipts.psm1 +366 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +408 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +428 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingMatrix.psm1 +377 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateUnconditional.psm1 +166 -0
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +1 -1
- package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +88 -3
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
- package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +3 -3
- package/resources/claude-customizations/.claude/settings.json +5 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +10 -5
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +116 -41
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +95 -13
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +7 -3
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +1 -1
- package/resources/claude-customizations/config/blast-radius.json +9 -3
- package/resources/claude-customizations/pack-manifests/core.json +31 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +37 -1
package/package.json
CHANGED
|
@@ -109,12 +109,14 @@ Coverage metrics are mandatory for every language that has changed files in the
|
|
|
109
109
|
|
|
110
110
|
Coverage thresholds follow the uniform tier rule (Authoritative Decision #2) defined in `.claude/rules/quality-tiers.md`:
|
|
111
111
|
|
|
112
|
-
- **New code files** (files added in this feature, not previously existing): line coverage >= 85%, branch coverage >= 75
|
|
113
|
-
- **Modified files** (files that existed before and were changed): line coverage >= 85%, branch coverage >= 75
|
|
114
|
-
- **Repo-wide per language**: line coverage >= 85%, branch coverage >= 75
|
|
112
|
+
- **New code files** (files added in this feature, not previously existing): line coverage >= 85%, branch coverage >= 75% for branch-capable languages.
|
|
113
|
+
- **Modified files** (files that existed before and were changed): line coverage >= 85%, branch coverage >= 75% for branch-capable languages, and no regression on changed lines relative to baseline.
|
|
114
|
+
- **Repo-wide per language**: line coverage >= 85%, branch coverage >= 75% for branch-capable languages.
|
|
115
115
|
|
|
116
116
|
Tier-specific lower thresholds are not used.
|
|
117
117
|
|
|
118
|
+
The branch threshold applies only to branch-capable languages — TypeScript, Python, and C#. PowerShell is a coverage language and is fully subject to the line threshold and the no-regression requirement, but Pester measures command (instruction) coverage and line coverage only, so no branch percentage exists to evaluate and no branch threshold applies to it (see `.claude/rules/powershell.md`). Do not record FAIL for an absent PowerShell branch figure.
|
|
119
|
+
|
|
118
120
|
### Verification Procedure
|
|
119
121
|
|
|
120
122
|
For each language that has changed files in the feature branch:
|
|
@@ -187,10 +187,17 @@ Read `cohorts[] { index, generation, item_keys[] }` and schedule from it exactly
|
|
|
187
187
|
|
|
188
188
|
Two scheduling rules govern every launch:
|
|
189
189
|
|
|
190
|
-
1. **Cohort barrier.**
|
|
191
|
-
`
|
|
192
|
-
`
|
|
193
|
-
|
|
190
|
+
1. **Cohort barrier (per-edge).** An item may start only when every conflicting neighbour
|
|
191
|
+
(`conflict_edges[]`) that sits in a strictly prior current-generation cohort has `merge_status`
|
|
192
|
+
of `merged` or `worktree_removed`. `ci_green` does not satisfy the barrier. Same-cohort and
|
|
193
|
+
later-cohort neighbours do not hold an item back, and an item with no conflicting prior-cohort
|
|
194
|
+
neighbour may start regardless of other cohorts' progress. Evaluate the predicate only against
|
|
195
|
+
durable state confirmed by `git` and `gh` commands, never from in-memory notifications. A
|
|
196
|
+
blocked item is neither `merged` nor `worktree_removed`, so it holds only its own conflicting
|
|
197
|
+
later-cohort neighbours and, transitively, the tail of its own conflict component; unrelated
|
|
198
|
+
lanes keep advancing. `current_cohort` is a PROGRESS INDICATOR — the lowest current-generation
|
|
199
|
+
cohort index still holding a non-terminal, non-withdrawn item, updated only on the same durable
|
|
200
|
+
confirmation — and gates nothing.
|
|
194
201
|
2. **`max_concurrency` slot filling.** `max_concurrency` caps the number of simultaneously in-flight
|
|
195
202
|
items independently of cohort size. Fill slots in ascending item-key (`issue_num`) order, and
|
|
196
203
|
refill each freed slot with the next unstarted item of the current cohort in the same ascending
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: parallel-planner
|
|
3
3
|
model: opus
|
|
4
|
-
description: Planning half of the parallel orchestration surface. It performs item intake over issue numbers and potential-entry paths, drives per-item preparation (promotion, research, spec/user-story, atomic plan, preflight clearance) through
|
|
4
|
+
description: Planning half of the parallel orchestration surface. It performs item intake over issue numbers and potential-entry paths, drives per-item preparation (promotion, research, spec/user-story, atomic plan, preflight clearance) through preparation-mode Agent(orchestrator) delegations launched in bounded waves of at most max_concurrency, computes and validates each item's blast radius, seeds the generation-0 cohort table, writes the parallel run manifest and the planner checkpoint, and emits the parallel-orchestrator kickoff prompt artifact. Performs no atomic execution, PR authoring, or CI monitoring.
|
|
5
5
|
tools:
|
|
6
6
|
- "Agent(orchestrator)"
|
|
7
7
|
- Read
|
|
@@ -90,7 +90,10 @@ On every invocation:
|
|
|
90
90
|
## Delegation Model
|
|
91
91
|
|
|
92
92
|
You delegate exclusively through `Agent(orchestrator)`, one delegation per item, each carrying the
|
|
93
|
-
preparation-mode kickoff line defined in the `parallel-plan` skill.
|
|
93
|
+
preparation-mode kickoff line defined in the `parallel-plan` skill. Delegations are launched in
|
|
94
|
+
BOUNDED WAVES of at most `max_concurrency`, computed with
|
|
95
|
+
`bash .claude/lib/bash/compute-concurrency-batches.sh`, with wave *k+1* launched only after every
|
|
96
|
+
child of wave *k* has terminated. Never launch every item's preparation at once. Each child `orchestrator` runs
|
|
94
97
|
promotion, research, feature documents, atomic planning, and preflight clearance under
|
|
95
98
|
`route_id: preparation`, commits and pushes its own branch, then stops before any execution. You do
|
|
96
99
|
not delegate directly to `atomic-planner`, `atomic-executor`, `task-researcher`, or `prd-feature`;
|
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
interprets the CLI's exit code and captured output.
|
|
26
26
|
|
|
27
27
|
.NOTES
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Requires PowerShell 7.4+ (the shared validation module uses
|
|
29
|
+
`Test-Json -SchemaFile` Draft 2020-12 support). Read-only validation gate that
|
|
30
|
+
invokes NO external process: validation runs in-process through
|
|
31
|
+
`.claude/lib/discovery-validation/DiscoveryValidation.psm1` (issue #475).
|
|
30
32
|
#>
|
|
31
33
|
[CmdletBinding()]
|
|
32
34
|
param()
|
|
@@ -34,11 +36,23 @@ param()
|
|
|
34
36
|
function Invoke-DiscoveryValidatorExe {
|
|
35
37
|
<#
|
|
36
38
|
.SYNOPSIS
|
|
37
|
-
Wrapper around the discovery-artifact validator
|
|
39
|
+
Wrapper around the discovery-artifact validator. Mockable seam.
|
|
38
40
|
.DESCRIPTION
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
Delegates to the portable PowerShell implementation in
|
|
42
|
+
`.claude/lib/discovery-validation/DiscoveryValidation.psm1`, keeping this
|
|
43
|
+
function's name, its `-ValidatorArgs <string[]>` parameter, and its
|
|
44
|
+
`@{ ExitCode; Output }` return shape unchanged so existing mocks and
|
|
45
|
+
`Should -Invoke` assertions continue to bind.
|
|
46
|
+
|
|
47
|
+
This no longer invokes a Python interpreter (issue #475). The `.claude/**`
|
|
48
|
+
payload ships to destinations with no guaranteed Python, Poetry, or
|
|
49
|
+
`scripts/dev_tools`, where the previous `python -m ...` call failed
|
|
50
|
+
obscurely or blocked every operation.
|
|
51
|
+
|
|
52
|
+
Success is SILENT by contract: a passing validation returns `ExitCode = 0`
|
|
53
|
+
with an EMPTY `Output`. The caller denies on a non-zero exit code OR on
|
|
54
|
+
non-empty output, so any success chatter here would deny a passing
|
|
55
|
+
validation (defect D-2).
|
|
42
56
|
#>
|
|
43
57
|
[CmdletBinding()]
|
|
44
58
|
[OutputType([hashtable])]
|
|
@@ -47,8 +61,14 @@ function Invoke-DiscoveryValidatorExe {
|
|
|
47
61
|
[string[]] $ValidatorArgs
|
|
48
62
|
)
|
|
49
63
|
|
|
50
|
-
$
|
|
51
|
-
|
|
64
|
+
$modulePath = Join-Path -Path $PSScriptRoot `
|
|
65
|
+
-ChildPath '../lib/discovery-validation/DiscoveryValidation.psm1'
|
|
66
|
+
if (-not (Test-Path -LiteralPath $modulePath -PathType Leaf)) {
|
|
67
|
+
return @{ ExitCode = 1; Output = "Discovery-validation module not found: $modulePath" }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Import-Module -Name $modulePath -Force -ErrorAction Stop
|
|
71
|
+
return Invoke-DiscoveryArtifactValidation -ValidatorArgs $ValidatorArgs
|
|
52
72
|
}
|
|
53
73
|
|
|
54
74
|
function Get-DiscoveryArtifactType {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
.DESCRIPTION
|
|
6
6
|
Invoked by the Claude Code PreToolUse hook on the "Bash" matcher before any Bash
|
|
7
7
|
command runs. Regex-matches gh pr merge with a --merge flag against
|
|
8
|
-
CLAUDE_TOOL_INPUT.command and, when matched, allows the merge only when one of
|
|
8
|
+
CLAUDE_TOOL_INPUT.command and, when matched, allows the merge only when one of three
|
|
9
9
|
checkpoint-only conditions holds:
|
|
10
10
|
|
|
11
11
|
1. Child-feature path: artifacts/orchestration/orchestrator-state.json exists,
|
|
@@ -14,11 +14,17 @@
|
|
|
14
14
|
2. Epic-integration path: artifacts/orchestration/epic-orchestrator-state.json exists,
|
|
15
15
|
epic_merge_pr.ci_gate.conclusion == "success", and, when the command names an
|
|
16
16
|
explicit PR number, that number matches epic_merge_pr.pr_number.
|
|
17
|
+
3. Parallel path: artifacts/orchestration/parallel-orchestrator-state.json exists,
|
|
18
|
+
route_id == "parallel", and the command's explicit PR number matches an items[]
|
|
19
|
+
entry whose merge_status == "ci_green". A parallel run always names an explicit PR
|
|
20
|
+
number (each item merges from its own isolated worktree), so a bare command with no
|
|
21
|
+
PR number cannot satisfy this branch.
|
|
17
22
|
|
|
18
23
|
Otherwise the command is denied with reason EPIC_MERGE_GATE_BLOCKED. A missing or
|
|
19
|
-
unreadable checkpoint in
|
|
20
|
-
orchestration never sets epic_mode
|
|
21
|
-
|
|
24
|
+
unreadable checkpoint in any branch fails closed (denies); standalone (non-epic,
|
|
25
|
+
non-parallel) orchestration never sets epic_mode, populates epic_merge_pr, or writes a
|
|
26
|
+
parallel checkpoint with route_id == "parallel", so it is structurally prevented from
|
|
27
|
+
invoking gh pr merge --merge at all.
|
|
22
28
|
|
|
23
29
|
Design decision: this gate trusts the on-disk checkpoint rather than shelling out live
|
|
24
30
|
to gh pr view for a real-time head-SHA check, matching the same non-adversarial,
|
|
@@ -35,6 +41,7 @@ param()
|
|
|
35
41
|
|
|
36
42
|
$script:ChildCheckpointPath = 'artifacts/orchestration/orchestrator-state.json'
|
|
37
43
|
$script:EpicCheckpointPath = 'artifacts/orchestration/epic-orchestrator-state.json'
|
|
44
|
+
$script:ParallelCheckpointPath = 'artifacts/orchestration/parallel-orchestrator-state.json'
|
|
38
45
|
|
|
39
46
|
function Get-ChildOrchestratorCheckpointContent {
|
|
40
47
|
<#
|
|
@@ -72,6 +79,24 @@ function Get-EpicOrchestratorCheckpointContent {
|
|
|
72
79
|
return (Get-Content -LiteralPath $script:EpicCheckpointPath -Raw)
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
function Get-ParallelOrchestratorCheckpointContent {
|
|
83
|
+
<#
|
|
84
|
+
.SYNOPSIS
|
|
85
|
+
Read the raw JSON text of the parallel-orchestrator checkpoint. Tests mock
|
|
86
|
+
this function (read seam).
|
|
87
|
+
.OUTPUTS
|
|
88
|
+
System.String or $null
|
|
89
|
+
#>
|
|
90
|
+
[CmdletBinding()]
|
|
91
|
+
[OutputType([string])]
|
|
92
|
+
param()
|
|
93
|
+
|
|
94
|
+
if (-not (Test-Path -LiteralPath $script:ParallelCheckpointPath -PathType Leaf)) {
|
|
95
|
+
return $null
|
|
96
|
+
}
|
|
97
|
+
return (Get-Content -LiteralPath $script:ParallelCheckpointPath -Raw)
|
|
98
|
+
}
|
|
99
|
+
|
|
75
100
|
function ConvertFrom-EpicMergeGateJson {
|
|
76
101
|
<#
|
|
77
102
|
.SYNOPSIS
|
|
@@ -113,9 +138,20 @@ function Get-EpicMergeGateCommandPrNumber {
|
|
|
113
138
|
[string] $CommandText
|
|
114
139
|
)
|
|
115
140
|
|
|
141
|
+
# Original form: the PR number appears immediately after "merge"
|
|
142
|
+
# (e.g. "gh pr merge 410 --merge"). Preserved verbatim so epic-path outcomes
|
|
143
|
+
# for the forms the epic path uses are unchanged.
|
|
116
144
|
if ($CommandText -match '(?i)\bgh\s+pr\s+merge\s+(\d+)\b') {
|
|
117
145
|
return [int]$Matches[1]
|
|
118
146
|
}
|
|
147
|
+
# Broadened, additive form: the parallel command places the flag before the
|
|
148
|
+
# number (e.g. "gh pr merge --merge 410"). Once "gh pr merge" is confirmed,
|
|
149
|
+
# capture the first standalone run of digits that is not preceded by "-" or a
|
|
150
|
+
# word character, so a flag token such as "--merge" is not treated as a number
|
|
151
|
+
# and a bare "gh pr merge --merge" still yields $null.
|
|
152
|
+
if ($CommandText -match '(?i)\bgh\s+pr\s+merge\b' -and $CommandText -match '(?<![-\w])(\d+)\b') {
|
|
153
|
+
return [int]$Matches[1]
|
|
154
|
+
}
|
|
119
155
|
return $null
|
|
120
156
|
}
|
|
121
157
|
|
|
@@ -206,6 +242,69 @@ function Test-EpicCheckpointAllowsMerge {
|
|
|
206
242
|
return $true
|
|
207
243
|
}
|
|
208
244
|
|
|
245
|
+
function Test-ParallelCheckpointAllowsMerge {
|
|
246
|
+
<#
|
|
247
|
+
.SYNOPSIS
|
|
248
|
+
Decision logic for the parallel-orchestrator checkpoint path (branch 3).
|
|
249
|
+
.PARAMETER Checkpoint
|
|
250
|
+
Parsed parallel-orchestrator checkpoint, or $null when absent/unreadable.
|
|
251
|
+
.PARAMETER CommandPrNumber
|
|
252
|
+
The explicit PR number parsed from the command, or $null when the command
|
|
253
|
+
does not name one. A parallel run always names an explicit PR number because
|
|
254
|
+
each item merges from its own isolated worktree, so a $null value denies.
|
|
255
|
+
.OUTPUTS
|
|
256
|
+
System.Boolean
|
|
257
|
+
#>
|
|
258
|
+
[CmdletBinding()]
|
|
259
|
+
[OutputType([bool])]
|
|
260
|
+
param(
|
|
261
|
+
[AllowNull()]
|
|
262
|
+
$Checkpoint,
|
|
263
|
+
|
|
264
|
+
[AllowNull()]
|
|
265
|
+
[Nullable[int]] $CommandPrNumber
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if ($null -eq $Checkpoint) {
|
|
269
|
+
return $false
|
|
270
|
+
}
|
|
271
|
+
$props = @($Checkpoint.PSObject.Properties.Name)
|
|
272
|
+
if ($props -notcontains 'route_id' -or ([string]$Checkpoint.route_id) -ne 'parallel') {
|
|
273
|
+
return $false
|
|
274
|
+
}
|
|
275
|
+
# A parallel merge always names an explicit PR number; without one the target
|
|
276
|
+
# item cannot be identified, so fail closed.
|
|
277
|
+
if ($null -eq $CommandPrNumber) {
|
|
278
|
+
return $false
|
|
279
|
+
}
|
|
280
|
+
if ($props -notcontains 'items' -or $null -eq $Checkpoint.items) {
|
|
281
|
+
return $false
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
foreach ($item in @($Checkpoint.items)) {
|
|
285
|
+
if ($null -eq $item) {
|
|
286
|
+
continue
|
|
287
|
+
}
|
|
288
|
+
$itemProps = @($item.PSObject.Properties.Name)
|
|
289
|
+
if ($itemProps -notcontains 'pr_number') {
|
|
290
|
+
continue
|
|
291
|
+
}
|
|
292
|
+
$itemPrNumber = 0
|
|
293
|
+
if (-not [int]::TryParse([string]$item.pr_number, [ref] $itemPrNumber)) {
|
|
294
|
+
continue
|
|
295
|
+
}
|
|
296
|
+
if ($itemPrNumber -ne $CommandPrNumber) {
|
|
297
|
+
continue
|
|
298
|
+
}
|
|
299
|
+
if ($itemProps -notcontains 'merge_status') {
|
|
300
|
+
return $false
|
|
301
|
+
}
|
|
302
|
+
return ([string]$item.merge_status) -eq 'ci_green'
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return $false
|
|
306
|
+
}
|
|
307
|
+
|
|
209
308
|
function Get-EpicMergeGateAllowDecision {
|
|
210
309
|
[CmdletBinding()]
|
|
211
310
|
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
@@ -284,7 +383,12 @@ function Invoke-EpicMergeGateDecision {
|
|
|
284
383
|
return Get-EpicMergeGateAllowDecision
|
|
285
384
|
}
|
|
286
385
|
|
|
287
|
-
|
|
386
|
+
$parallelCheckpoint = ConvertFrom-EpicMergeGateJson -Raw (Get-ParallelOrchestratorCheckpointContent)
|
|
387
|
+
if (Test-ParallelCheckpointAllowsMerge -Checkpoint $parallelCheckpoint -CommandPrNumber $commandPrNumber) {
|
|
388
|
+
return Get-EpicMergeGateAllowDecision
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
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.'
|
|
288
392
|
}
|
|
289
393
|
|
|
290
394
|
# Guard allows dot-sourcing in tests without executing the entrypoint.
|