@danmoisan/drm-copilot-mcp 1.0.24 → 1.0.26
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 +504 -174
- 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/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/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/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/parallel-orchestration.md +28 -3
- 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/skills/feature-review-workflow/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +10 -5
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +108 -34
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +71 -9
- 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 +1 -3
- package/resources/claude-customizations/pack-manifests/core.json +12 -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/powershell/PoshQC/settings/pester.runsettings.psd1 +21 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Portable completion-gate checks C1, C2, C3, C4, C5, and C7.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Destination-runtime PowerShell port of the `--require-complete` checks the
|
|
7
|
+
authoritative Python validator performs, excluding the routing contract (C6),
|
|
8
|
+
which lives in the sibling `OrchestratorStateRoutingContract.psm1`. The rows
|
|
9
|
+
ported here are:
|
|
10
|
+
|
|
11
|
+
C1.1 completion-blocking step statuses, full five-value blocking set
|
|
12
|
+
C2.1 blocked_reason must be absent, null, or the literal `none`
|
|
13
|
+
C3.1 pr_gate must be an object (route-gated)
|
|
14
|
+
C3.2 pr_gate missing required fields (route-gated)
|
|
15
|
+
C4.1 ci_gate must be an object (route-gated)
|
|
16
|
+
C4.2 ci_gate missing required fields (route-gated)
|
|
17
|
+
C4.3 ci_gate.conclusion must be success (route-gated)
|
|
18
|
+
C4.4 ci_gate.head_sha must match pr_gate.head_sha (route-gated)
|
|
19
|
+
C5.1 mandatory route phases, from a static map
|
|
20
|
+
C7.1 preparation terminal next_step (value-gated, repr rendering)
|
|
21
|
+
C7.2 preparation terminal step statuses (value-gated, repr rendering)
|
|
22
|
+
|
|
23
|
+
Route gating for C3 and C4 is resolved through
|
|
24
|
+
`OrchestratorStateRoutingMatrix.psm1`, implementing deviation PD-1: the gate
|
|
25
|
+
decision reads pinned constants and never opens
|
|
26
|
+
`config/orchestration-routing.json`. The gates are deliberately asymmetric,
|
|
27
|
+
matching the Python reference: the PR gate applies only when a route sets
|
|
28
|
+
`requires_pr_gate: true`, while the CI gate applies unless a route explicitly
|
|
29
|
+
sets `requires_ci_gate: false`.
|
|
30
|
+
|
|
31
|
+
C5's mandatory-phase map is static in the Python reference too, so it needs no
|
|
32
|
+
matrix lookup. C7 renders both sides with Python `repr()` semantics.
|
|
33
|
+
|
|
34
|
+
Every function is pure: it reads no file, starts no process, and never mutates
|
|
35
|
+
its input.
|
|
36
|
+
#>
|
|
37
|
+
|
|
38
|
+
Set-StrictMode -Version Latest
|
|
39
|
+
|
|
40
|
+
# Import the shared checkpoint-value primitives and the pinned routing matrix,
|
|
41
|
+
# resolved relative to this module's directory so both imports travel with the
|
|
42
|
+
# pushed-down pack regardless of the working directory.
|
|
43
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force
|
|
44
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateRoutingMatrix.psm1') -Force
|
|
45
|
+
|
|
46
|
+
# The six step-status keys, in report order.
|
|
47
|
+
$script:STEP_STATUS_KEYS = @(
|
|
48
|
+
'step5_status',
|
|
49
|
+
'step6_status',
|
|
50
|
+
'step7_status',
|
|
51
|
+
'step8_status',
|
|
52
|
+
'step9_status',
|
|
53
|
+
'step10_status'
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Step statuses that must never appear in a checkpoint written as DONE. The
|
|
57
|
+
# documented S9 success value `passed` is deliberately absent: it records CI green
|
|
58
|
+
# and must not block completion. Pinned to COMPLETION_BLOCKING_STEP_STATUS in
|
|
59
|
+
# scripts/dev_tools/_orchestrator_state_step_status.py.
|
|
60
|
+
$script:COMPLETION_BLOCKING_STEP_STATUS = @(
|
|
61
|
+
'pending',
|
|
62
|
+
'blocked',
|
|
63
|
+
'failed_remediation_required',
|
|
64
|
+
'blocked_ci_loop_limit',
|
|
65
|
+
'blocked_remediation_loop_limit'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# The gate object key sets, in the order the error messages join them.
|
|
69
|
+
$script:PR_GATE_KEYS = @('pr_number', 'pr_url', 'head_branch', 'head_sha')
|
|
70
|
+
$script:CI_GATE_KEYS = @('conclusion', 'head_sha', 'verified_at')
|
|
71
|
+
|
|
72
|
+
# The mandatory canonical phases per route. Static in the Python reference, so no
|
|
73
|
+
# matrix lookup is involved; a route absent from this map imposes no requirement.
|
|
74
|
+
$script:MANDATORY_ROUTE_PHASES = @{
|
|
75
|
+
small = @('S3_promotion', 'S4_atomic_planning')
|
|
76
|
+
preparation = @('S3_promotion', 'S4_atomic_planning')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# The preparation-route terminal contract: the exact required next_step and the
|
|
80
|
+
# six step keys that must read not-applicable.
|
|
81
|
+
$script:PREPARATION_ROUTE_ID = 'preparation'
|
|
82
|
+
$script:PREPARATION_EXPECTED_NEXT_STEP = 'S5_atomic_execution'
|
|
83
|
+
$script:PREPARATION_NOT_APPLICABLE = 'not-applicable'
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
function Get-MissingGateKey {
|
|
87
|
+
<#
|
|
88
|
+
.SYNOPSIS
|
|
89
|
+
Return the gate keys absent or blank in a gate object.
|
|
90
|
+
.DESCRIPTION
|
|
91
|
+
Private helper mirroring _missing_pr_gate_keys / _missing_object_keys. A
|
|
92
|
+
non-object value reports every key as missing; a present key holding null
|
|
93
|
+
or a blank string is also missing, so a placeholder cannot satisfy a gate.
|
|
94
|
+
.PARAMETER Value
|
|
95
|
+
The candidate gate value from the checkpoint. May be $null.
|
|
96
|
+
.PARAMETER GateKey
|
|
97
|
+
The required key names, in message order.
|
|
98
|
+
.OUTPUTS
|
|
99
|
+
System.String[] - the missing key names, in the given order.
|
|
100
|
+
#>
|
|
101
|
+
[CmdletBinding()]
|
|
102
|
+
[OutputType([string[]])]
|
|
103
|
+
param(
|
|
104
|
+
[Parameter(Mandatory = $true)]
|
|
105
|
+
[AllowNull()]
|
|
106
|
+
[object] $Value,
|
|
107
|
+
|
|
108
|
+
[Parameter(Mandatory = $true)]
|
|
109
|
+
[string[]] $GateKey
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if (-not (Test-CheckpointObjectValue -Value $Value)) { return [string[]]@($GateKey) }
|
|
113
|
+
|
|
114
|
+
$missing = [System.Collections.Generic.List[string]]::new()
|
|
115
|
+
foreach ($key in $GateKey) {
|
|
116
|
+
$item = (Get-CheckpointObjectMember -Owner $Value -Name $key).Value
|
|
117
|
+
if ($null -eq $item -or (($item -is [string]) -and [string]::IsNullOrWhiteSpace([string]$item))) {
|
|
118
|
+
$missing.Add($key)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return $missing.ToArray()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function Get-OrchestratorStateCompletionStepStatusError {
|
|
125
|
+
<#
|
|
126
|
+
.SYNOPSIS
|
|
127
|
+
Return the completion-blocking step-status errors (inventory row C1.1).
|
|
128
|
+
.DESCRIPTION
|
|
129
|
+
Mirrors collect_completion_blocking_step_errors. One error per step key
|
|
130
|
+
whose recorded value is in the five-value blocking set, in step-key order.
|
|
131
|
+
The check is applied across all six step keys because the failure values
|
|
132
|
+
are per-key-valid only.
|
|
133
|
+
.PARAMETER State
|
|
134
|
+
The parsed checkpoint object.
|
|
135
|
+
.OUTPUTS
|
|
136
|
+
System.String[] - zero or more error strings.
|
|
137
|
+
#>
|
|
138
|
+
[CmdletBinding()]
|
|
139
|
+
[OutputType([string[]])]
|
|
140
|
+
param(
|
|
141
|
+
[Parameter(Mandatory = $true)]
|
|
142
|
+
[psobject] $State
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
146
|
+
|
|
147
|
+
# Report in step-key order so the operator reads failures in pipeline order.
|
|
148
|
+
foreach ($key in $script:STEP_STATUS_KEYS) {
|
|
149
|
+
$value = (Get-CheckpointObjectMember -Owner $State -Name $key).Value
|
|
150
|
+
if (($value -is [string]) -and ($script:COMPLETION_BLOCKING_STEP_STATUS -ccontains [string]$value)) {
|
|
151
|
+
$errors.Add("Checkpoint completion validation failed: $key is $value.")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return $errors.ToArray()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function Get-OrchestratorStateCompletionBlockedReasonError {
|
|
159
|
+
<#
|
|
160
|
+
.SYNOPSIS
|
|
161
|
+
Return the completion blocked_reason error (inventory row C2.1).
|
|
162
|
+
.DESCRIPTION
|
|
163
|
+
Mirrors the `state.get("blocked_reason") not in {None, "none"}` guard.
|
|
164
|
+
Absent, null, and the literal `none` all satisfy the gate; every other
|
|
165
|
+
recorded reason blocks completion. The message quotes `none` with
|
|
166
|
+
backticks, exactly as the Python reference does.
|
|
167
|
+
.PARAMETER State
|
|
168
|
+
The parsed checkpoint object.
|
|
169
|
+
.OUTPUTS
|
|
170
|
+
System.String[] - zero or one error string.
|
|
171
|
+
#>
|
|
172
|
+
[CmdletBinding()]
|
|
173
|
+
[OutputType([string[]])]
|
|
174
|
+
param(
|
|
175
|
+
[Parameter(Mandatory = $true)]
|
|
176
|
+
[psobject] $State
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
180
|
+
|
|
181
|
+
$value = (Get-CheckpointObjectMember -Owner $State -Name 'blocked_reason').Value
|
|
182
|
+
if ($null -ne $value -and -not (($value -is [string]) -and ([string]$value -ceq 'none'))) {
|
|
183
|
+
$errors.Add('Checkpoint completion validation failed: blocked_reason is not `none`.')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return $errors.ToArray()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function Get-OrchestratorStateCompletionPrGateError {
|
|
190
|
+
<#
|
|
191
|
+
.SYNOPSIS
|
|
192
|
+
Return the completion PR-gate errors (inventory rows C3.1-C3.2).
|
|
193
|
+
.DESCRIPTION
|
|
194
|
+
Mirrors validate_completion_pr_gate. The gate applies only to routes whose
|
|
195
|
+
pinned `requires_pr_gate` is true; every other route contributes no
|
|
196
|
+
pr_gate errors. A non-object pr_gate reports the object-shape error alone,
|
|
197
|
+
and an object with absent or blank required fields names them.
|
|
198
|
+
.PARAMETER State
|
|
199
|
+
The parsed checkpoint object.
|
|
200
|
+
.PARAMETER RoutingMatrix
|
|
201
|
+
Optional matrix override forwarded to the route lookup.
|
|
202
|
+
.OUTPUTS
|
|
203
|
+
System.String[] - zero or one error string.
|
|
204
|
+
#>
|
|
205
|
+
[CmdletBinding()]
|
|
206
|
+
[OutputType([string[]])]
|
|
207
|
+
param(
|
|
208
|
+
[Parameter(Mandatory = $true)]
|
|
209
|
+
[psobject] $State,
|
|
210
|
+
|
|
211
|
+
[Parameter(Mandatory = $false)]
|
|
212
|
+
[AllowNull()]
|
|
213
|
+
[hashtable] $RoutingMatrix = $null
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
217
|
+
|
|
218
|
+
$routeId = Get-OrchestratorStateSelectedRouteId -State $State
|
|
219
|
+
if (-not (Test-OrchestratorStateRouteRequiresPrGate -RouteId $routeId -RoutingMatrix $RoutingMatrix)) {
|
|
220
|
+
return $errors.ToArray()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
$prGate = (Get-CheckpointObjectMember -Owner $State -Name 'pr_gate').Value
|
|
224
|
+
$missing = @(Get-MissingGateKey -Value $prGate -GateKey $script:PR_GATE_KEYS)
|
|
225
|
+
|
|
226
|
+
# A non-object pr_gate reports only the shape error; the field list would be
|
|
227
|
+
# every key and adds nothing.
|
|
228
|
+
if (-not (Test-CheckpointObjectValue -Value $prGate)) {
|
|
229
|
+
$errors.Add("Checkpoint completion validation failed: pr_gate must be an object with keys: $($script:PR_GATE_KEYS -join ', ').")
|
|
230
|
+
return $errors.ToArray()
|
|
231
|
+
}
|
|
232
|
+
if ($missing.Count -gt 0) {
|
|
233
|
+
$errors.Add("Checkpoint completion validation failed: pr_gate missing required fields: $($missing -join ', ').")
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return $errors.ToArray()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function Get-OrchestratorStateCompletionCiGateError {
|
|
240
|
+
<#
|
|
241
|
+
.SYNOPSIS
|
|
242
|
+
Return the completion CI-gate errors (inventory rows C4.1-C4.4).
|
|
243
|
+
.DESCRIPTION
|
|
244
|
+
Mirrors _validate_completion_ci_gate plus its route gate. The gate applies
|
|
245
|
+
unless the route's pinned `requires_ci_gate` is exactly false, so an
|
|
246
|
+
absent flag keeps the gate on. A non-object ci_gate reports the shape
|
|
247
|
+
error alone; otherwise the missing-field, success-conclusion, and
|
|
248
|
+
head_sha-match rules each contribute independently.
|
|
249
|
+
.PARAMETER State
|
|
250
|
+
The parsed checkpoint object.
|
|
251
|
+
.PARAMETER RoutingMatrix
|
|
252
|
+
Optional matrix override forwarded to the route lookup.
|
|
253
|
+
.OUTPUTS
|
|
254
|
+
System.String[] - zero or more error strings.
|
|
255
|
+
#>
|
|
256
|
+
[CmdletBinding()]
|
|
257
|
+
[OutputType([string[]])]
|
|
258
|
+
param(
|
|
259
|
+
[Parameter(Mandatory = $true)]
|
|
260
|
+
[psobject] $State,
|
|
261
|
+
|
|
262
|
+
[Parameter(Mandatory = $false)]
|
|
263
|
+
[AllowNull()]
|
|
264
|
+
[hashtable] $RoutingMatrix = $null
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
268
|
+
|
|
269
|
+
$routeId = Get-OrchestratorStateSelectedRouteId -State $State
|
|
270
|
+
if (-not (Test-OrchestratorStateRouteRequiresCiGate -RouteId $routeId -RoutingMatrix $RoutingMatrix)) {
|
|
271
|
+
return $errors.ToArray()
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
$ciGate = (Get-CheckpointObjectMember -Owner $State -Name 'ci_gate').Value
|
|
275
|
+
$missing = @(Get-MissingGateKey -Value $ciGate -GateKey $script:CI_GATE_KEYS)
|
|
276
|
+
|
|
277
|
+
if (-not (Test-CheckpointObjectValue -Value $ciGate)) {
|
|
278
|
+
$errors.Add("Checkpoint completion validation failed: ci_gate must be an object with keys: $($script:CI_GATE_KEYS -join ', ').")
|
|
279
|
+
return $errors.ToArray()
|
|
280
|
+
}
|
|
281
|
+
if ($missing.Count -gt 0) {
|
|
282
|
+
$errors.Add("Checkpoint completion validation failed: ci_gate missing required fields: $($missing -join ', ').")
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
$conclusion = (Get-CheckpointObjectMember -Owner $ciGate -Name 'conclusion').Value
|
|
286
|
+
if (-not (Test-PythonValueEqual -Actual $conclusion -Expected 'success')) {
|
|
287
|
+
$errors.Add('Checkpoint completion validation failed: ci_gate.conclusion must be success.')
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# The head_sha match runs only when a pr_gate object records a non-null
|
|
291
|
+
# head_sha; without one there is nothing to match against.
|
|
292
|
+
$prGate = (Get-CheckpointObjectMember -Owner $State -Name 'pr_gate').Value
|
|
293
|
+
$prHeadSha = $null
|
|
294
|
+
if (Test-CheckpointObjectValue -Value $prGate) {
|
|
295
|
+
$prHeadSha = (Get-CheckpointObjectMember -Owner $prGate -Name 'head_sha').Value
|
|
296
|
+
}
|
|
297
|
+
if ($null -ne $prHeadSha) {
|
|
298
|
+
$ciHeadSha = (Get-CheckpointObjectMember -Owner $ciGate -Name 'head_sha').Value
|
|
299
|
+
if (-not (Test-PythonValueEqual -Actual $ciHeadSha -Expected $prHeadSha)) {
|
|
300
|
+
$errors.Add('Checkpoint completion validation failed: ci_gate.head_sha must match pr_gate.head_sha.')
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return $errors.ToArray()
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function Get-OrchestratorStatePhaseCompletenessError {
|
|
308
|
+
<#
|
|
309
|
+
.SYNOPSIS
|
|
310
|
+
Return the mandatory-phase errors for the selected route (row C5.1).
|
|
311
|
+
.DESCRIPTION
|
|
312
|
+
Mirrors validate_phase_completeness. The mandatory-phase set is read from
|
|
313
|
+
a static map, not from the routing matrix, so no matrix parameter exists.
|
|
314
|
+
A route absent from the map, or an unusable route id, imposes no
|
|
315
|
+
requirement. A `completed_steps` value that is not a list of non-blank
|
|
316
|
+
strings is treated as recording no completed phases.
|
|
317
|
+
.PARAMETER State
|
|
318
|
+
The parsed checkpoint object.
|
|
319
|
+
.OUTPUTS
|
|
320
|
+
System.String[] - one error per missing mandatory phase.
|
|
321
|
+
#>
|
|
322
|
+
[CmdletBinding()]
|
|
323
|
+
[OutputType([string[]])]
|
|
324
|
+
param(
|
|
325
|
+
[Parameter(Mandatory = $true)]
|
|
326
|
+
[psobject] $State
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
330
|
+
|
|
331
|
+
$routeId = Get-OrchestratorStateSelectedRouteId -State $State
|
|
332
|
+
if ($null -eq $routeId -or -not $script:MANDATORY_ROUTE_PHASES.ContainsKey($routeId)) {
|
|
333
|
+
return $errors.ToArray()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# A malformed completed_steps records no phases, so every mandatory phase is
|
|
337
|
+
# reported missing rather than the malformed shape being reported separately.
|
|
338
|
+
$completed = (Get-CheckpointObjectMember -Owner $State -Name 'completed_steps').Value
|
|
339
|
+
$present = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
|
|
340
|
+
if (Test-CheckpointListValue -Value $completed) {
|
|
341
|
+
$wellFormed = $true
|
|
342
|
+
foreach ($item in @($completed)) {
|
|
343
|
+
if (-not ($item -is [string]) -or [string]::IsNullOrWhiteSpace([string]$item)) {
|
|
344
|
+
$wellFormed = $false
|
|
345
|
+
break
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if ($wellFormed) {
|
|
349
|
+
foreach ($item in @($completed)) { [void]$present.Add([string]$item) }
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
foreach ($phase in $script:MANDATORY_ROUTE_PHASES[$routeId]) {
|
|
354
|
+
if (-not $present.Contains($phase)) {
|
|
355
|
+
$errors.Add("Checkpoint completion validation failed: route $routeId is missing mandatory phase $phase.")
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return $errors.ToArray()
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function Get-OrchestratorStatePreparationTerminalError {
|
|
363
|
+
<#
|
|
364
|
+
.SYNOPSIS
|
|
365
|
+
Return the preparation terminal-contract errors (rows C7.1-C7.2).
|
|
366
|
+
.DESCRIPTION
|
|
367
|
+
Mirrors validate_preparation_terminal_contract. The check is value-gated
|
|
368
|
+
on the RAW route value being exactly the string `preparation`, so a
|
|
369
|
+
checkpoint on any other route contributes nothing. Both messages render
|
|
370
|
+
the offending value with Python repr() semantics.
|
|
371
|
+
.PARAMETER State
|
|
372
|
+
The parsed checkpoint object.
|
|
373
|
+
.OUTPUTS
|
|
374
|
+
System.String[] - zero or more error strings.
|
|
375
|
+
#>
|
|
376
|
+
[CmdletBinding()]
|
|
377
|
+
[OutputType([string[]])]
|
|
378
|
+
param(
|
|
379
|
+
[Parameter(Mandatory = $true)]
|
|
380
|
+
[psobject] $State
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
384
|
+
|
|
385
|
+
$routeValue = Get-OrchestratorStateRawRouteValue -State $State
|
|
386
|
+
if (-not (Test-PythonValueEqual -Actual $routeValue -Expected $script:PREPARATION_ROUTE_ID)) {
|
|
387
|
+
return $errors.ToArray()
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
$nextStep = (Get-CheckpointObjectMember -Owner $State -Name 'next_step').Value
|
|
391
|
+
if (-not (Test-PythonValueEqual -Actual $nextStep -Expected $script:PREPARATION_EXPECTED_NEXT_STEP)) {
|
|
392
|
+
$expectedText = ConvertTo-PythonReprText -Value $script:PREPARATION_EXPECTED_NEXT_STEP
|
|
393
|
+
$errors.Add("Preparation checkpoint next_step must be $expectedText, found $(ConvertTo-PythonReprText -Value $nextStep).")
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
# A preparation run performs no execution steps, so all six step keys must
|
|
397
|
+
# read not-applicable; each deviation is reported with its own key.
|
|
398
|
+
foreach ($key in $script:STEP_STATUS_KEYS) {
|
|
399
|
+
$value = (Get-CheckpointObjectMember -Owner $State -Name $key).Value
|
|
400
|
+
if (-not (Test-PythonValueEqual -Actual $value -Expected $script:PREPARATION_NOT_APPLICABLE)) {
|
|
401
|
+
$errors.Add("Preparation checkpoint $key must be 'not-applicable', found $(ConvertTo-PythonReprText -Value $value).")
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return $errors.ToArray()
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
# Each check family is exported individually so the completion entry point can
|
|
409
|
+
# compose them in the Python reference's order; the gate-key helper stays private.
|
|
410
|
+
Export-ModuleMember -Function `
|
|
411
|
+
Get-OrchestratorStateCompletionStepStatusError, `
|
|
412
|
+
Get-OrchestratorStateCompletionBlockedReasonError, `
|
|
413
|
+
Get-OrchestratorStateCompletionPrGateError, `
|
|
414
|
+
Get-OrchestratorStateCompletionCiGateError, `
|
|
415
|
+
Get-OrchestratorStatePhaseCompletenessError, `
|
|
416
|
+
Get-OrchestratorStatePreparationTerminalError
|