@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.
Files changed (43) hide show
  1. package/out/mcp-server.js +504 -174
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/feature-review.md +5 -3
  4. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +11 -4
  5. package/resources/claude-customizations/.claude/agents/parallel-planner.md +5 -2
  6. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +28 -8
  7. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +28 -8
  8. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +117 -46
  9. package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +115 -3
  10. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +312 -0
  11. package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +392 -0
  12. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +500 -0
  13. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +58 -67
  14. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCheckpointValue.psm1 +383 -0
  15. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexModelReceipts.psm1 +297 -0
  16. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexTopologyReceipts.psm1 +298 -0
  17. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +232 -43
  18. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +416 -0
  19. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateModelReceipts.psm1 +366 -0
  20. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +408 -0
  21. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +428 -0
  22. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingMatrix.psm1 +377 -0
  23. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateUnconditional.psm1 +166 -0
  24. package/resources/claude-customizations/.claude/rules/general-unit-test.md +1 -1
  25. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +28 -3
  26. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  27. package/resources/claude-customizations/.claude/rules/quality-tiers.md +3 -3
  28. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -4
  29. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +10 -5
  30. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +108 -34
  31. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +71 -9
  32. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +7 -3
  33. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +1 -1
  34. package/resources/claude-customizations/.claude-variants/csharp-legacy/rules/csharp.md +4 -4
  35. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +5 -3
  36. package/resources/claude-customizations/config/blast-radius.json +1 -3
  37. package/resources/claude-customizations/pack-manifests/core.json +12 -0
  38. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +1 -1
  39. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +3 -3
  40. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +3 -3
  41. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +5 -3
  42. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  43. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +21 -0
@@ -0,0 +1,428 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Portable routing-contract completion checks (inventory family C6).
4
+
5
+ .DESCRIPTION
6
+ Destination-runtime PowerShell port of `validate_routing_contract` in
7
+ `scripts/dev_tools/_orchestrator_state_routing.py`, covering parity-inventory
8
+ rows C6.1 through C6.14:
9
+
10
+ C6.1 routing matrix carries no routes object (returns)
11
+ C6.2 no route selected (returns)
12
+ C6.3 selected route has no routing-matrix entry (returns)
13
+ C6.4 required_agents must match the matrix
14
+ C6.5 required_skills must match the matrix
15
+ C6.6 required_mcp_tools must match the matrix
16
+ C6.7 per required agent with no delegation receipt
17
+ C6.8 per required skill with no acknowledged receipt
18
+ C6.9 per required MCP tool with no successful receipt
19
+ C6.10 local_execution_overrides empty-list rules (two message variants)
20
+ C6.11 delegation_bypasses empty-list rules (two message variants)
21
+ C6.12 lifecycle_operations must be a list when present
22
+ C6.13 per non-object lifecycle operation
23
+ C6.14 per lifecycle operation that did not use the MCP surface
24
+
25
+ The routing matrix is read from `OrchestratorStateRoutingMatrix.psm1`, which
26
+ implements deviation PD-1: the constants are pinned and no disk read occurs at
27
+ validation time. The optional -RoutingMatrix override mirrors the Python
28
+ `routing_matrix` keyword and is what makes row C6.1 reachable.
29
+
30
+ Bug-promotion tool substitution (C6.6 and C6.9). The routing matrix records
31
+ the feature-type promotion-entry tool `new_potential_entry` in every route's
32
+ `required_mcp_tools`. A bug-type promotion genuinely exercises
33
+ `new_potential_bug_entry` instead, so a bug-type checkpoint could never
34
+ truthfully record a `new_potential_entry` receipt. When, and only when, the
35
+ checkpoint's hyphenated `promotion-type` is exactly `"bug"`, each occurrence
36
+ is substituted, preserving matrix order and every other tool. The substituted
37
+ list drives both the exact-match check and the receipt-presence loop, so the
38
+ two never disagree.
39
+
40
+ Empty-list semantics (C6.10 and C6.11). The Python rule requires the key to
41
+ EXIST as a list: an ABSENT key is not a list and therefore produces the
42
+ "must be an empty list at completion" variant. That is deliberately stricter
43
+ than the PR-creation-readiness analogue in `OrchestratorState.psm1`, which
44
+ tolerates absence; both behaviours are preserved as-is.
45
+
46
+ Every function is pure: it reads no file, starts no process, and never mutates
47
+ its input.
48
+ #>
49
+
50
+ Set-StrictMode -Version Latest
51
+
52
+ # Import the shared checkpoint-value primitives and the pinned routing matrix,
53
+ # resolved relative to this module's directory so both imports travel with the
54
+ # pushed-down pack regardless of the working directory.
55
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force
56
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateRoutingMatrix.psm1') -Force
57
+
58
+ # The promotion-entry MCP tools and the promotion type that triggers substitution.
59
+ $script:FEATURE_PROMOTION_ENTRY_TOOL = 'new_potential_entry'
60
+ $script:BUG_PROMOTION_ENTRY_TOOL = 'new_potential_bug_entry'
61
+ $script:BUG_PROMOTION_TYPE = 'bug'
62
+ $script:PROMOTION_TYPE_KEY = 'promotion-type'
63
+
64
+ # The two checkpoint fields that must exist as empty lists at completion.
65
+ $script:COMPLETION_EMPTY_LIST_KEYS = @('local_execution_overrides', 'delegation_bypasses')
66
+
67
+ # The lifecycle-operation surface every recorded operation must have used.
68
+ $script:LIFECYCLE_MCP_SURFACE = 'mcp'
69
+
70
+
71
+ function Get-CheckpointNonBlankStringList {
72
+ <#
73
+ .SYNOPSIS
74
+ Return a value as a list of non-blank strings, or $null when malformed.
75
+ .DESCRIPTION
76
+ Private helper mirroring the `_string_list` variant used by the routing
77
+ contract, which requires every member to be a non-blank string. A non-list
78
+ value, or any blank or non-string member, disqualifies the whole value.
79
+ .PARAMETER Value
80
+ The deserialized JSON value to inspect. May be $null.
81
+ .OUTPUTS
82
+ System.Collections.Hashtable with keys Ok (bool) and Value (string[]).
83
+ #>
84
+ [CmdletBinding()]
85
+ [OutputType([hashtable])]
86
+ param(
87
+ [Parameter(Mandatory = $true)]
88
+ [AllowNull()]
89
+ [object] $Value
90
+ )
91
+
92
+ if (-not (Test-CheckpointListValue -Value $Value)) {
93
+ return @{ Ok = $false; Value = [string[]]@() }
94
+ }
95
+ foreach ($item in @($Value)) {
96
+ if (-not ($item -is [string]) -or [string]::IsNullOrWhiteSpace([string]$item)) {
97
+ return @{ Ok = $false; Value = [string[]]@() }
98
+ }
99
+ }
100
+ return @{ Ok = $true; Value = [string[]]@($Value) }
101
+ }
102
+
103
+ function Get-ResolvedRequiredMcpTool {
104
+ <#
105
+ .SYNOPSIS
106
+ Resolve the promotion-entry MCP tool to the checkpoint's promotion type.
107
+ .DESCRIPTION
108
+ Private helper mirroring _resolve_promotion_entry_tools. Only an explicit
109
+ bug-type promotion swaps the promotion-entry tool; a feature type, an
110
+ absent key, a non-string value, and any other value leave the matrix list
111
+ untouched, so feature-type and legacy checkpoints validate exactly as
112
+ before. Matrix order is preserved.
113
+ .PARAMETER RequiredMcpTool
114
+ The route's declared required_mcp_tools list, in matrix order.
115
+ .PARAMETER State
116
+ The parsed checkpoint object, read for its hyphenated promotion-type key.
117
+ .OUTPUTS
118
+ System.String[] - the resolved tool list, in matrix order.
119
+ #>
120
+ [CmdletBinding()]
121
+ [OutputType([string[]])]
122
+ param(
123
+ [Parameter(Mandatory = $true)]
124
+ [AllowEmptyCollection()]
125
+ [string[]] $RequiredMcpTool,
126
+
127
+ [Parameter(Mandatory = $true)]
128
+ [psobject] $State
129
+ )
130
+
131
+ $promotionType = (Get-CheckpointObjectMember -Owner $State -Name $script:PROMOTION_TYPE_KEY).Value
132
+ if (-not (Test-PythonValueEqual -Actual $promotionType -Expected $script:BUG_PROMOTION_TYPE)) {
133
+ return [string[]]@($RequiredMcpTool)
134
+ }
135
+
136
+ # Substitute the bug-type promotion-entry tool for the feature-type one while
137
+ # preserving matrix order and every other required tool exactly.
138
+ $resolved = foreach ($tool in $RequiredMcpTool) {
139
+ if ($tool -ceq $script:FEATURE_PROMOTION_ENTRY_TOOL) { $script:BUG_PROMOTION_ENTRY_TOOL } else { $tool }
140
+ }
141
+ return [string[]]@($resolved)
142
+ }
143
+
144
+ function Get-CheckpointReceiptAgentName {
145
+ <#
146
+ .SYNOPSIS
147
+ Collect the agent names recorded by delegation receipts.
148
+ .DESCRIPTION
149
+ Private harvest mirroring _receipt_agents plus _list_receipts. The object
150
+ form of delegation_receipts contributes through its `agents` namespace;
151
+ any other non-list value contributes nothing. Only a non-blank string
152
+ agent_name counts.
153
+ .PARAMETER State
154
+ The parsed checkpoint object.
155
+ .OUTPUTS
156
+ System.String[] - the recorded agent names.
157
+ #>
158
+ [CmdletBinding()]
159
+ [OutputType([string[]])]
160
+ param(
161
+ [Parameter(Mandatory = $true)]
162
+ [psobject] $State
163
+ )
164
+
165
+ $receipts = (Get-CheckpointObjectMember -Owner $State -Name 'delegation_receipts').Value
166
+ if (Test-CheckpointObjectValue -Value $receipts) {
167
+ $receipts = (Get-CheckpointObjectMember -Owner $receipts -Name 'agents').Value
168
+ }
169
+
170
+ $agents = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
171
+ if (-not (Test-CheckpointListValue -Value $receipts)) { return [string[]]@($agents) }
172
+
173
+ # Harvest each well-formed receipt's agent name; a malformed entry is skipped
174
+ # rather than reported, because shape errors belong to the U5 family.
175
+ foreach ($receipt in @($receipts)) {
176
+ if (-not (Test-CheckpointObjectValue -Value $receipt)) { continue }
177
+ $name = (Get-CheckpointObjectMember -Owner $receipt -Name 'agent_name').Value
178
+ if (($name -is [string]) -and -not [string]::IsNullOrWhiteSpace([string]$name)) {
179
+ [void]$agents.Add([string]$name)
180
+ }
181
+ }
182
+ return [string[]]@($agents)
183
+ }
184
+
185
+ function Get-CheckpointAcknowledgedName {
186
+ <#
187
+ .SYNOPSIS
188
+ Collect acknowledged names from a receipt array with an evidence rule.
189
+ .DESCRIPTION
190
+ Private harvest shared by _receipt_skills and _mcp_tools, which differ
191
+ only in the array key, the name key, and the boolean flag key. A receipt
192
+ counts only when its name is a non-blank string, its flag is exactly the
193
+ boolean true, and its evidence is a non-blank string. Truthy-but-not-true
194
+ flags deliberately do not count.
195
+ .PARAMETER State
196
+ The parsed checkpoint object.
197
+ .PARAMETER ArrayKey
198
+ The checkpoint key holding the receipt array.
199
+ .PARAMETER NameKey
200
+ The per-receipt key holding the acknowledged name.
201
+ .PARAMETER FlagKey
202
+ The per-receipt key that must be exactly boolean true.
203
+ .OUTPUTS
204
+ System.String[] - the acknowledged names.
205
+ #>
206
+ [CmdletBinding()]
207
+ [OutputType([string[]])]
208
+ param(
209
+ [Parameter(Mandatory = $true)]
210
+ [psobject] $State,
211
+
212
+ [Parameter(Mandatory = $true)]
213
+ [string] $ArrayKey,
214
+
215
+ [Parameter(Mandatory = $true)]
216
+ [string] $NameKey,
217
+
218
+ [Parameter(Mandatory = $true)]
219
+ [string] $FlagKey
220
+ )
221
+
222
+ $names = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
223
+ $receipts = (Get-CheckpointObjectMember -Owner $State -Name $ArrayKey).Value
224
+ if (-not (Test-CheckpointListValue -Value $receipts)) { return [string[]]@($names) }
225
+
226
+ # All three conditions must hold together: an acknowledged name, an explicit
227
+ # true flag, and non-blank evidence. A receipt failing any one contributes
228
+ # nothing, so the requirement it would have satisfied is reported missing.
229
+ foreach ($receipt in @($receipts)) {
230
+ if (-not (Test-CheckpointObjectValue -Value $receipt)) { continue }
231
+ $name = (Get-CheckpointObjectMember -Owner $receipt -Name $NameKey).Value
232
+ $flag = (Get-CheckpointObjectMember -Owner $receipt -Name $FlagKey).Value
233
+ $evidence = (Get-CheckpointObjectMember -Owner $receipt -Name 'evidence').Value
234
+ if (($name -is [string]) -and -not [string]::IsNullOrWhiteSpace([string]$name) -and
235
+ ($flag -is [bool]) -and [bool]$flag -and
236
+ ($evidence -is [string]) -and -not [string]::IsNullOrWhiteSpace([string]$evidence)) {
237
+ [void]$names.Add([string]$name)
238
+ }
239
+ }
240
+ return [string[]]@($names)
241
+ }
242
+
243
+ function Get-CompletionEmptyListError {
244
+ <#
245
+ .SYNOPSIS
246
+ Return the empty-list-at-completion errors for one key (rows C6.10/C6.11).
247
+ .DESCRIPTION
248
+ Private helper mirroring _validate_empty_list_field. The key must EXIST as
249
+ a list: an absent key, a null value, and any non-list value all produce the
250
+ "must be an empty list at completion" variant, while a present non-empty
251
+ list produces the "must be empty at completion" variant.
252
+ .PARAMETER State
253
+ The parsed checkpoint object.
254
+ .PARAMETER Key
255
+ The checkpoint key to check.
256
+ .OUTPUTS
257
+ System.String[] - zero or one error string.
258
+ #>
259
+ [CmdletBinding()]
260
+ [OutputType([string[]])]
261
+ param(
262
+ [Parameter(Mandatory = $true)]
263
+ [psobject] $State,
264
+
265
+ [Parameter(Mandatory = $true)]
266
+ [string] $Key
267
+ )
268
+
269
+ $value = (Get-CheckpointObjectMember -Owner $State -Name $Key).Value
270
+ if (-not (Test-CheckpointListValue -Value $value)) {
271
+ return [string[]]@("Checkpoint $Key must be an empty list at completion.")
272
+ }
273
+ if (@($value).Count -gt 0) {
274
+ return [string[]]@("Checkpoint $Key must be empty at completion.")
275
+ }
276
+ return [string[]]@()
277
+ }
278
+
279
+ function Get-LifecycleOperationError {
280
+ <#
281
+ .SYNOPSIS
282
+ Return the lifecycle-operation errors (rows C6.12-C6.14).
283
+ .DESCRIPTION
284
+ Private helper mirroring _validate_lifecycle_operations. The key is
285
+ optional: an absent or null value contributes nothing. A present non-list
286
+ value is malformed, and each recorded operation must be an object whose
287
+ surface is exactly the MCP surface.
288
+ .PARAMETER State
289
+ The parsed checkpoint object.
290
+ .OUTPUTS
291
+ System.String[] - zero or more error strings.
292
+ #>
293
+ [CmdletBinding()]
294
+ [OutputType([string[]])]
295
+ param(
296
+ [Parameter(Mandatory = $true)]
297
+ [psobject] $State
298
+ )
299
+
300
+ $errors = [System.Collections.Generic.List[string]]::new()
301
+
302
+ $operations = (Get-CheckpointObjectMember -Owner $State -Name 'lifecycle_operations').Value
303
+ if ($null -eq $operations) { return $errors.ToArray() }
304
+ if (-not (Test-CheckpointListValue -Value $operations)) {
305
+ $errors.Add('Checkpoint lifecycle_operations must be a list when present.')
306
+ return $errors.ToArray()
307
+ }
308
+
309
+ # Report each malformed or non-MCP operation with its own index.
310
+ $index = 0
311
+ foreach ($operation in @($operations)) {
312
+ if (-not (Test-CheckpointObjectValue -Value $operation)) {
313
+ $errors.Add("Checkpoint lifecycle_operations #$index must be an object.")
314
+ $index++
315
+ continue
316
+ }
317
+ $surface = (Get-CheckpointObjectMember -Owner $operation -Name 'surface').Value
318
+ if (-not (Test-PythonValueEqual -Actual $surface -Expected $script:LIFECYCLE_MCP_SURFACE)) {
319
+ $errors.Add("Checkpoint lifecycle_operations #$index did not use MCP surface.")
320
+ }
321
+ $index++
322
+ }
323
+
324
+ return $errors.ToArray()
325
+ }
326
+
327
+ function Get-OrchestratorStateRoutingContractError {
328
+ <#
329
+ .SYNOPSIS
330
+ Return the routing-contract errors (inventory rows C6.1-C6.14).
331
+ .DESCRIPTION
332
+ Public entry mirroring validate_routing_contract. The first three rows are
333
+ terminal: a malformed matrix, an unselected route, and an unknown route
334
+ each return a single error, because none of the later checks can be
335
+ evaluated without a resolved route entry. The remaining rows accumulate.
336
+ .PARAMETER State
337
+ The parsed checkpoint object.
338
+ .PARAMETER RoutingMatrix
339
+ Optional matrix override. When omitted, the pinned matrix is used. A
340
+ matrix carrying no routes mapping is what makes row C6.1 reachable.
341
+ .OUTPUTS
342
+ System.String[] - zero or more error strings.
343
+ #>
344
+ [CmdletBinding()]
345
+ [OutputType([string[]])]
346
+ param(
347
+ [Parameter(Mandatory = $true)]
348
+ [psobject] $State,
349
+
350
+ [Parameter(Mandatory = $false)]
351
+ [AllowNull()]
352
+ [hashtable] $RoutingMatrix = $null
353
+ )
354
+
355
+ $errors = [System.Collections.Generic.List[string]]::new()
356
+
357
+ # C6.1: a matrix with no routes mapping cannot resolve any route.
358
+ $routes = Get-OrchestratorStateRoutingMatrixRouteMap -RoutingMatrix $RoutingMatrix
359
+ if ($null -eq $routes) {
360
+ return [string[]]@('Routing matrix missing routes object.')
361
+ }
362
+
363
+ # C6.2: the checkpoint must name a route as a non-blank string.
364
+ $routeId = Get-OrchestratorStateSelectedRouteId -State $State
365
+ if ($null -eq $routeId) {
366
+ return [string[]]@('Checkpoint route_id or path_selected must select a route.')
367
+ }
368
+
369
+ # C6.3: the named route must exist in the matrix.
370
+ $route = Get-OrchestratorStateRoute -RouteId $routeId -RoutingMatrix $RoutingMatrix
371
+ if ($null -eq $route) {
372
+ return [string[]]@("Checkpoint selected route has no routing-matrix entry: $routeId.")
373
+ }
374
+
375
+ $requiredAgents = @(Get-OrchestratorStateRouteRequiredList -RouteId $routeId -ListName 'required_agents' -RoutingMatrix $RoutingMatrix)
376
+ $requiredSkills = @(Get-OrchestratorStateRouteRequiredList -RouteId $routeId -ListName 'required_skills' -RoutingMatrix $RoutingMatrix)
377
+ $requiredMcpTools = @(Get-ResolvedRequiredMcpTool -State $State `
378
+ -RequiredMcpTool ([string[]]@(Get-OrchestratorStateRouteRequiredList -RouteId $routeId -ListName 'required_mcp_tools' -RoutingMatrix $RoutingMatrix)))
379
+
380
+ # C6.4 to C6.6: the checkpoint's own declared lists must equal the matrix
381
+ # lists exactly, in order. A malformed list is a mismatch, not a shape error.
382
+ $declaredLists = @(
383
+ @{ Key = 'required_agents'; Expected = $requiredAgents },
384
+ @{ Key = 'required_skills'; Expected = $requiredSkills },
385
+ @{ Key = 'required_mcp_tools'; Expected = $requiredMcpTools }
386
+ )
387
+ foreach ($declared in $declaredLists) {
388
+ $actual = Get-CheckpointNonBlankStringList -Value (Get-CheckpointObjectMember -Owner $State -Name $declared.Key).Value
389
+ if (-not $actual.Ok -or -not (Test-PythonValueEqual -Actual $actual.Value -Expected ([string[]]$declared.Expected))) {
390
+ $errors.Add("Checkpoint $($declared.Key) must match routing matrix for route $routeId.")
391
+ }
392
+ }
393
+
394
+ # C6.7 to C6.9: every required agent, skill, and MCP tool must be evidenced by
395
+ # a receipt, in matrix order so the report is deterministic.
396
+ $actualAgents = @(Get-CheckpointReceiptAgentName -State $State)
397
+ foreach ($agent in $requiredAgents) {
398
+ if ($actualAgents -cnotcontains $agent) {
399
+ $errors.Add("Checkpoint missing required agent receipt: $agent.")
400
+ }
401
+ }
402
+
403
+ $actualSkills = @(Get-CheckpointAcknowledgedName -State $State -ArrayKey 'skill_receipts' -NameKey 'skill' -FlagKey 'required')
404
+ foreach ($skill in $requiredSkills) {
405
+ if ($actualSkills -cnotcontains $skill) {
406
+ $errors.Add("Checkpoint missing required skill receipt: $skill.")
407
+ }
408
+ }
409
+
410
+ $actualTools = @(Get-CheckpointAcknowledgedName -State $State -ArrayKey 'mcp_call_receipts' -NameKey 'tool' -FlagKey 'ok')
411
+ foreach ($tool in $requiredMcpTools) {
412
+ if ($actualTools -cnotcontains $tool) {
413
+ $errors.Add("Checkpoint missing successful MCP receipt: $tool.")
414
+ }
415
+ }
416
+
417
+ # C6.10 to C6.14: the two empty-list fields and the lifecycle operations.
418
+ foreach ($key in $script:COMPLETION_EMPTY_LIST_KEYS) {
419
+ $errors.AddRange([string[]]@(Get-CompletionEmptyListError -State $State -Key $key))
420
+ }
421
+ $errors.AddRange([string[]]@(Get-LifecycleOperationError -State $State))
422
+
423
+ return $errors.ToArray()
424
+ }
425
+
426
+ # Only the family entry point is exported; the harvest and field helpers stay
427
+ # private so no consumer can evaluate a subset of the contract.
428
+ Export-ModuleMember -Function Get-OrchestratorStateRoutingContractError