@danmoisan/drm-copilot-mcp 1.0.23 → 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/.claude-variants/csharp-legacy/rules/csharp.md +4 -4
- package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +5 -3
- 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/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +5 -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,408 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Portable delegation-receipt, remediation-cycle, and human-interaction checks.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Destination-runtime PowerShell port of the unconditional optional-key checks
|
|
7
|
+
the authoritative Python validator performs for the completion hook's call.
|
|
8
|
+
The rows ported here are the parity-inventory families U5 (delegation_receipts
|
|
9
|
+
shape), U6.R (remediation_loop cycle invariants), and U6.H (human_interaction
|
|
10
|
+
shape), matching the error-string templates in
|
|
11
|
+
`scripts/dev_tools/validate_orchestrator_state.py` and
|
|
12
|
+
`scripts/dev_tools/_orchestrator_state_human_interaction.py`.
|
|
13
|
+
|
|
14
|
+
U6.H reconciliation (spec Parity Contract): these library checks are ADDITIVE
|
|
15
|
+
to the stricter hook-internal `Test-HumanInteractionShape` in
|
|
16
|
+
`.claude/hooks/validate-orchestrator-output.ps1`, which blocks a `halt`
|
|
17
|
+
response and verifies runbook-file existence. That hook check is retained
|
|
18
|
+
unchanged and continues to run alongside these rows; strictness never
|
|
19
|
+
decreases. A checkpoint that fails either layer is blocked.
|
|
20
|
+
|
|
21
|
+
The shared JSON shape predicates, the absent-versus-null member accessor, the
|
|
22
|
+
ordinal key sort, the Python zero-equivalence rule, and the Python
|
|
23
|
+
`str()`/`repr()` interpolation renderers live in the sibling helper module
|
|
24
|
+
`OrchestratorStateCheckpointValue.psm1`, created under the plan's
|
|
25
|
+
pre-authorized split so no parity module exceeds the 500-line file cap. Every
|
|
26
|
+
module in this family imports those primitives from that one implementation.
|
|
27
|
+
|
|
28
|
+
Every function is pure: it reads no file, starts no process, and never mutates
|
|
29
|
+
its input. Each check returns a string array, empty when the block is valid.
|
|
30
|
+
#>
|
|
31
|
+
|
|
32
|
+
Set-StrictMode -Version Latest
|
|
33
|
+
|
|
34
|
+
# Import the shared checkpoint-value primitives, resolved relative to this
|
|
35
|
+
# module's directory so the import travels with the pushed-down pack regardless
|
|
36
|
+
# of the consumer repository's working directory.
|
|
37
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force
|
|
38
|
+
|
|
39
|
+
# The eight keys every list-form delegation receipt must carry. Pinned to
|
|
40
|
+
# REQUIRED_RECEIPT_KEYS in scripts/dev_tools/validate_orchestrator_state.py.
|
|
41
|
+
$script:REQUIRED_RECEIPT_KEYS = @(
|
|
42
|
+
'step',
|
|
43
|
+
'agent_name',
|
|
44
|
+
'agent_id',
|
|
45
|
+
'skill_source',
|
|
46
|
+
'started_at',
|
|
47
|
+
'completed_at',
|
|
48
|
+
'result_signal',
|
|
49
|
+
'artifact_paths'
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# The only two namespaces the object form of delegation_receipts may carry, and
|
|
53
|
+
# the three sub-keys the promotion namespace may carry.
|
|
54
|
+
$script:AGENT_RECEIPT_NAMESPACE_KEY = 'agents'
|
|
55
|
+
$script:PROMOTION_RECEIPT_NAMESPACE_KEY = 'promotion'
|
|
56
|
+
$script:PROMOTION_RECEIPT_KEYS = @('potential_entry', 'issue', 'feature_folder')
|
|
57
|
+
|
|
58
|
+
# Remediation-cycle constants: the cycles array key, the execution statuses that
|
|
59
|
+
# may only be recorded once preflight cleared, and the cleared status literal.
|
|
60
|
+
$script:REMEDIATION_CYCLES_KEY = 'cycles'
|
|
61
|
+
$script:EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT = @('in_progress', 'complete', 'failed')
|
|
62
|
+
$script:PREFLIGHT_CLEARED_STATUS = 'clear'
|
|
63
|
+
|
|
64
|
+
# Human-interaction constants: the requirements list key, the three permitted
|
|
65
|
+
# response values, and the response that additionally requires a runbook path.
|
|
66
|
+
$script:HUMAN_INTERACTION_REQUIREMENTS_KEY = 'requirements'
|
|
67
|
+
$script:HUMAN_INTERACTION_RESPONSE_ENUM = @('scope_change', 'exception', 'halt')
|
|
68
|
+
$script:HUMAN_INTERACTION_EXCEPTION_RESPONSE = 'exception'
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
function Get-DelegationReceiptListError {
|
|
72
|
+
<#
|
|
73
|
+
.SYNOPSIS
|
|
74
|
+
Return the list-form delegation-receipt errors (rows U5.1-U5.3).
|
|
75
|
+
.DESCRIPTION
|
|
76
|
+
Private helper mirroring _validate_list_delegation_receipts. Validates each
|
|
77
|
+
receipt independently so callers receive a complete error list.
|
|
78
|
+
.PARAMETER Receipts
|
|
79
|
+
The deserialized JSON array of receipt objects.
|
|
80
|
+
.OUTPUTS
|
|
81
|
+
System.String[] - zero or more error strings.
|
|
82
|
+
#>
|
|
83
|
+
[CmdletBinding()]
|
|
84
|
+
[OutputType([string[]])]
|
|
85
|
+
param(
|
|
86
|
+
[Parameter(Mandatory = $true)]
|
|
87
|
+
[AllowNull()]
|
|
88
|
+
[object] $Receipts
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
92
|
+
$index = 0
|
|
93
|
+
|
|
94
|
+
# Walk every receipt position so each malformed entry is reported with its own
|
|
95
|
+
# index; a non-object entry short-circuits that entry's key checks.
|
|
96
|
+
foreach ($receipt in @($Receipts)) {
|
|
97
|
+
if (-not (Test-CheckpointObjectValue -Value $receipt)) {
|
|
98
|
+
$errors.Add("Checkpoint delegation receipt #$index must be an object.")
|
|
99
|
+
$index++
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Key PRESENCE is the Python test (`key not in receipt`), so a present key
|
|
104
|
+
# holding null satisfies the requirement.
|
|
105
|
+
$names = @(Get-CheckpointObjectMemberName -Owner $receipt)
|
|
106
|
+
foreach ($key in $script:REQUIRED_RECEIPT_KEYS) {
|
|
107
|
+
if ($names -notcontains $key) {
|
|
108
|
+
$errors.Add("Checkpoint delegation receipt #$index missing key: $key")
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# artifact_paths may be absent or null, but a present non-null value must
|
|
113
|
+
# be a list.
|
|
114
|
+
$artifactPaths = (Get-CheckpointObjectMember -Owner $receipt -Name 'artifact_paths').Value
|
|
115
|
+
if ($null -ne $artifactPaths -and -not (Test-CheckpointListValue -Value $artifactPaths)) {
|
|
116
|
+
$errors.Add("Checkpoint delegation receipt #$index artifact_paths must be a list.")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
$index++
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return $errors.ToArray()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function Get-DelegationReceiptNamespaceError {
|
|
126
|
+
<#
|
|
127
|
+
.SYNOPSIS
|
|
128
|
+
Return the object-form delegation-receipt errors (rows U5.4-U5.7).
|
|
129
|
+
.DESCRIPTION
|
|
130
|
+
Private helper mirroring _validate_namespaced_delegation_receipts. Reports
|
|
131
|
+
unsupported top-level namespaces in ordinal order, applies the list-form
|
|
132
|
+
checks to the agents namespace, and rejects an unsupported promotion
|
|
133
|
+
sub-key or a non-object promotion namespace.
|
|
134
|
+
.PARAMETER Receipts
|
|
135
|
+
The deserialized JSON object form of delegation_receipts.
|
|
136
|
+
.OUTPUTS
|
|
137
|
+
System.String[] - zero or more error strings.
|
|
138
|
+
#>
|
|
139
|
+
[CmdletBinding()]
|
|
140
|
+
[OutputType([string[]])]
|
|
141
|
+
param(
|
|
142
|
+
[Parameter(Mandatory = $true)]
|
|
143
|
+
[psobject] $Receipts
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
147
|
+
$names = @(Get-CheckpointObjectMemberName -Owner $Receipts)
|
|
148
|
+
|
|
149
|
+
# Reject every namespace outside {agents, promotion}, ordered ordinally so the
|
|
150
|
+
# error sequence matches Python's sorted() output.
|
|
151
|
+
$unsupported = @($names | Where-Object {
|
|
152
|
+
$_ -ne $script:AGENT_RECEIPT_NAMESPACE_KEY -and $_ -ne $script:PROMOTION_RECEIPT_NAMESPACE_KEY
|
|
153
|
+
})
|
|
154
|
+
foreach ($key in (Get-CheckpointOrdinalSortedName -Name ([string[]]$unsupported))) {
|
|
155
|
+
$errors.Add("Checkpoint delegation_receipts object contains unsupported key: $key")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# A present agents namespace must be a list; when it is, the list-form rows
|
|
159
|
+
# apply to its entries unchanged.
|
|
160
|
+
if ($names -contains $script:AGENT_RECEIPT_NAMESPACE_KEY) {
|
|
161
|
+
$agentReceipts = (Get-CheckpointObjectMember -Owner $Receipts -Name $script:AGENT_RECEIPT_NAMESPACE_KEY).Value
|
|
162
|
+
if (-not (Test-CheckpointListValue -Value $agentReceipts)) {
|
|
163
|
+
$errors.Add('Checkpoint delegation_receipts.agents must be a list.')
|
|
164
|
+
} else {
|
|
165
|
+
$errors.AddRange([string[]]@(Get-DelegationReceiptListError -Receipts $agentReceipts))
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# An absent or null promotion namespace ends the check; a present non-object
|
|
170
|
+
# value is malformed and stops further promotion inspection.
|
|
171
|
+
$promotion = (Get-CheckpointObjectMember -Owner $Receipts -Name $script:PROMOTION_RECEIPT_NAMESPACE_KEY).Value
|
|
172
|
+
if ($null -eq $promotion) {
|
|
173
|
+
return $errors.ToArray()
|
|
174
|
+
}
|
|
175
|
+
if (-not (Test-CheckpointObjectValue -Value $promotion)) {
|
|
176
|
+
$errors.Add('Checkpoint delegation_receipts.promotion must be an object namespace.')
|
|
177
|
+
return $errors.ToArray()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
$promotionNames = @(Get-CheckpointObjectMemberName -Owner $promotion)
|
|
181
|
+
$unsupportedPromotion = @($promotionNames | Where-Object { $script:PROMOTION_RECEIPT_KEYS -notcontains $_ })
|
|
182
|
+
foreach ($key in (Get-CheckpointOrdinalSortedName -Name ([string[]]$unsupportedPromotion))) {
|
|
183
|
+
$errors.Add("Checkpoint delegation_receipts.promotion contains unsupported key: $key")
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return $errors.ToArray()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function Get-OrchestratorStateDelegationReceiptError {
|
|
190
|
+
<#
|
|
191
|
+
.SYNOPSIS
|
|
192
|
+
Return the delegation_receipts errors (inventory rows U5.1-U5.8).
|
|
193
|
+
.DESCRIPTION
|
|
194
|
+
Public dispatch mirroring the delegation-receipt branch of
|
|
195
|
+
validate_orchestrator_state_text: a null or absent value contributes no
|
|
196
|
+
errors, a list routes to the legacy list-form checks, an object routes to
|
|
197
|
+
the namespaced checks, and any other value is itself the error.
|
|
198
|
+
.PARAMETER Value
|
|
199
|
+
The raw deserialized value of the checkpoint's delegation_receipts key.
|
|
200
|
+
.OUTPUTS
|
|
201
|
+
System.String[] - zero or more error strings.
|
|
202
|
+
#>
|
|
203
|
+
[CmdletBinding()]
|
|
204
|
+
[OutputType([string[]])]
|
|
205
|
+
param(
|
|
206
|
+
[Parameter(Mandatory = $true)]
|
|
207
|
+
[AllowNull()]
|
|
208
|
+
[object] $Value
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
212
|
+
|
|
213
|
+
# A null value is the Python `receipts is not None` guard: nothing to check.
|
|
214
|
+
if ($null -eq $Value) { return $errors.ToArray() }
|
|
215
|
+
|
|
216
|
+
# Route on the deserialized shape: the list branch is the legacy form, the
|
|
217
|
+
# object branch is the additive namespace form, anything else is invalid.
|
|
218
|
+
if (Test-CheckpointListValue -Value $Value) {
|
|
219
|
+
$errors.AddRange([string[]]@(Get-DelegationReceiptListError -Receipts $Value))
|
|
220
|
+
} elseif (Test-CheckpointObjectValue -Value $Value) {
|
|
221
|
+
$errors.AddRange([string[]]@(Get-DelegationReceiptNamespaceError -Receipts $Value))
|
|
222
|
+
} else {
|
|
223
|
+
$errors.Add('Checkpoint delegation_receipts must be a list or object namespace.')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return $errors.ToArray()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function Get-RemediationCycleError {
|
|
230
|
+
<#
|
|
231
|
+
.SYNOPSIS
|
|
232
|
+
Return one remediation cycle's errors (rows U6.R2-U6.R4).
|
|
233
|
+
.DESCRIPTION
|
|
234
|
+
Private helper mirroring _validate_remediation_cycle: a non-empty
|
|
235
|
+
plan_path, execution only after a cleared preflight, and a satisfied exit
|
|
236
|
+
gate only with zero blocking findings.
|
|
237
|
+
.PARAMETER Index
|
|
238
|
+
The cycle's zero-based position, used for error context.
|
|
239
|
+
.PARAMETER Cycle
|
|
240
|
+
The deserialized cycle object.
|
|
241
|
+
.OUTPUTS
|
|
242
|
+
System.String[] - zero or more error strings.
|
|
243
|
+
#>
|
|
244
|
+
[CmdletBinding()]
|
|
245
|
+
[OutputType([string[]])]
|
|
246
|
+
param(
|
|
247
|
+
[Parameter(Mandatory = $true)]
|
|
248
|
+
[int] $Index,
|
|
249
|
+
|
|
250
|
+
[Parameter(Mandatory = $true)]
|
|
251
|
+
[psobject] $Cycle
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
255
|
+
|
|
256
|
+
# Invariant 1: plan_path must be a non-empty, non-whitespace string.
|
|
257
|
+
$planPath = (Get-CheckpointObjectMember -Owner $Cycle -Name 'plan_path').Value
|
|
258
|
+
if (-not ($planPath -is [string]) -or [string]::IsNullOrWhiteSpace([string]$planPath)) {
|
|
259
|
+
$errors.Add("Checkpoint remediation cycle #$Index plan_path must be a non-empty string.")
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# Invariant 2: an execution status in the blocked set requires the nested
|
|
263
|
+
# preflight to report exactly the cleared status; a missing or non-object
|
|
264
|
+
# preflight cannot satisfy it.
|
|
265
|
+
$executionStatus = (Get-CheckpointObjectMember -Owner $Cycle -Name 'execution_status').Value
|
|
266
|
+
if ($executionStatus -is [string] -and
|
|
267
|
+
($script:EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT -contains [string]$executionStatus)) {
|
|
268
|
+
$preflight = (Get-CheckpointObjectMember -Owner $Cycle -Name 'preflight').Value
|
|
269
|
+
$preflightStatus = (Get-CheckpointObjectMember -Owner $preflight -Name 'final_status').Value
|
|
270
|
+
if (-not ($preflightStatus -is [string]) -or ([string]$preflightStatus -ne $script:PREFLIGHT_CLEARED_STATUS)) {
|
|
271
|
+
$errors.Add("Checkpoint remediation cycle #$Index execution_status is $executionStatus but preflight.final_status is not 'clear'.")
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Invariant 3: a satisfied exit gate requires zero blocking findings. The exit
|
|
276
|
+
# flag must be the boolean True (Python `is True`), not merely truthy.
|
|
277
|
+
$exitConditionMet = (Get-CheckpointObjectMember -Owner $Cycle -Name 'exit_condition_met').Value
|
|
278
|
+
if (($exitConditionMet -is [bool]) -and $exitConditionMet) {
|
|
279
|
+
$blockingCount = (Get-CheckpointObjectMember -Owner $Cycle -Name 'blocking_count').Value
|
|
280
|
+
if (-not (Test-PythonZeroEquivalent -Value $blockingCount)) {
|
|
281
|
+
$errors.Add("Checkpoint remediation cycle #$Index exit_condition_met is true but blocking_count is not 0.")
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return $errors.ToArray()
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function Get-OrchestratorStateRemediationLoopError {
|
|
289
|
+
<#
|
|
290
|
+
.SYNOPSIS
|
|
291
|
+
Return the remediation_loop errors (inventory rows U6.R1-U6.R4).
|
|
292
|
+
.DESCRIPTION
|
|
293
|
+
Public entry mirroring _validate_remediation_loop. A non-object
|
|
294
|
+
remediation_loop, or a cycles value that is not a list, carries no cycles
|
|
295
|
+
to validate and deliberately yields ZERO errors, matching the Python
|
|
296
|
+
tolerance rather than fabricating a structural error.
|
|
297
|
+
.PARAMETER Value
|
|
298
|
+
The raw deserialized value of the checkpoint's remediation_loop key.
|
|
299
|
+
.OUTPUTS
|
|
300
|
+
System.String[] - zero or more error strings.
|
|
301
|
+
#>
|
|
302
|
+
[CmdletBinding()]
|
|
303
|
+
[OutputType([string[]])]
|
|
304
|
+
param(
|
|
305
|
+
[Parameter(Mandatory = $true)]
|
|
306
|
+
[AllowNull()]
|
|
307
|
+
[object] $Value
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
311
|
+
|
|
312
|
+
if (-not (Test-CheckpointObjectValue -Value $Value)) { return $errors.ToArray() }
|
|
313
|
+
$cycles = (Get-CheckpointObjectMember -Owner $Value -Name $script:REMEDIATION_CYCLES_KEY).Value
|
|
314
|
+
if (-not (Test-CheckpointListValue -Value $cycles)) { return $errors.ToArray() }
|
|
315
|
+
|
|
316
|
+
# Validate each cycle independently so a malformed entry does not mask the
|
|
317
|
+
# errors of the cycles that follow it.
|
|
318
|
+
$index = 0
|
|
319
|
+
foreach ($cycle in @($cycles)) {
|
|
320
|
+
if (-not (Test-CheckpointObjectValue -Value $cycle)) {
|
|
321
|
+
$errors.Add("Checkpoint remediation cycle #$index must be an object.")
|
|
322
|
+
$index++
|
|
323
|
+
continue
|
|
324
|
+
}
|
|
325
|
+
$errors.AddRange([string[]]@(Get-RemediationCycleError -Index $index -Cycle $cycle))
|
|
326
|
+
$index++
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return $errors.ToArray()
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function Get-OrchestratorStateHumanInteractionError {
|
|
333
|
+
<#
|
|
334
|
+
.SYNOPSIS
|
|
335
|
+
Return the human_interaction errors (inventory rows U6.H1-U6.H5).
|
|
336
|
+
.DESCRIPTION
|
|
337
|
+
Public entry mirroring _validate_human_interaction: the block must be an
|
|
338
|
+
object carrying a requirements list, each requirement must be an object
|
|
339
|
+
whose response is within the permitted enum, and an exception response
|
|
340
|
+
must carry a non-empty runbook_path. These rows are additive to the
|
|
341
|
+
stricter hook-internal Test-HumanInteractionShape described in the module
|
|
342
|
+
header; they never relax it.
|
|
343
|
+
.PARAMETER Value
|
|
344
|
+
The raw deserialized value of the checkpoint's human_interaction key.
|
|
345
|
+
.OUTPUTS
|
|
346
|
+
System.String[] - zero or more error strings.
|
|
347
|
+
#>
|
|
348
|
+
[CmdletBinding()]
|
|
349
|
+
[OutputType([string[]])]
|
|
350
|
+
param(
|
|
351
|
+
[Parameter(Mandatory = $true)]
|
|
352
|
+
[AllowNull()]
|
|
353
|
+
[object] $Value
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
357
|
+
|
|
358
|
+
# The key was present, so a non-object value is a malformed block rather than
|
|
359
|
+
# an absent one, and there is nothing further to inspect.
|
|
360
|
+
if (-not (Test-CheckpointObjectValue -Value $Value)) {
|
|
361
|
+
$errors.Add('Checkpoint human_interaction must be an object when present.')
|
|
362
|
+
return $errors.ToArray()
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
$requirements = (Get-CheckpointObjectMember -Owner $Value -Name $script:HUMAN_INTERACTION_REQUIREMENTS_KEY).Value
|
|
366
|
+
if (-not (Test-CheckpointListValue -Value $requirements)) {
|
|
367
|
+
$errors.Add('Checkpoint human_interaction.requirements must be a list.')
|
|
368
|
+
return $errors.ToArray()
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
# Validate each requirement independently; an out-of-enum response stops that
|
|
372
|
+
# requirement so the runbook rule is not applied to an unknown response.
|
|
373
|
+
$index = 0
|
|
374
|
+
foreach ($requirement in @($requirements)) {
|
|
375
|
+
if (-not (Test-CheckpointObjectValue -Value $requirement)) {
|
|
376
|
+
$errors.Add("Checkpoint human_interaction.requirements #$index must be an object.")
|
|
377
|
+
$index++
|
|
378
|
+
continue
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
$response = (Get-CheckpointObjectMember -Owner $requirement -Name 'response').Value
|
|
382
|
+
if (-not ($response -is [string]) -or ($script:HUMAN_INTERACTION_RESPONSE_ENUM -notcontains [string]$response)) {
|
|
383
|
+
$rendered = ConvertTo-PythonDisplayText -Value $response
|
|
384
|
+
$errors.Add("Checkpoint human_interaction.requirements #$index response must be one of scope_change, exception, halt; got: $rendered")
|
|
385
|
+
$index++
|
|
386
|
+
continue
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if ([string]$response -eq $script:HUMAN_INTERACTION_EXCEPTION_RESPONSE) {
|
|
390
|
+
$runbookPath = (Get-CheckpointObjectMember -Owner $requirement -Name 'runbook_path').Value
|
|
391
|
+
if (-not ($runbookPath -is [string]) -or [string]::IsNullOrWhiteSpace([string]$runbookPath)) {
|
|
392
|
+
$errors.Add("Checkpoint human_interaction.requirements #$index response is exception but runbook_path is missing or empty.")
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
$index++
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return $errors.ToArray()
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
# The three family entry points are exported for the U-family aggregator; the
|
|
403
|
+
# shared primitives stay exported from the sibling OrchestratorStateCheckpointValue
|
|
404
|
+
# module so there is exactly one implementation of each.
|
|
405
|
+
Export-ModuleMember -Function `
|
|
406
|
+
Get-OrchestratorStateDelegationReceiptError, `
|
|
407
|
+
Get-OrchestratorStateRemediationLoopError, `
|
|
408
|
+
Get-OrchestratorStateHumanInteractionError
|