@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
@@ -1,37 +1,68 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Portable completion-gate presence checks for the orchestrator-state checkpoint.
3
+ Complete-parity completion-gate validation for the orchestrator-state checkpoint.
4
4
 
5
5
  .DESCRIPTION
6
- Provides the destination-runtime PowerShell mirror of the completion-gate
7
- presence checks the pushed-down validate-orchestrator-output hook needs when the
8
- authoritative Python validator (`scripts/dev_tools`) is not importable. It
9
- reuses the shared load, field-accessor, and base-presence primitives from the
10
- sibling `OrchestratorState.psm1` and imports `.claude/lib/model-routing/ModelRouting.psm1`
11
- so per-receipt model formulas are available where practical.
12
-
13
- The single public function `Test-OrchestratorStateCompletionReadiness` fails
14
- closed on a missing checkpoint file, invalid JSON, or an invalid base shape, then
15
- applies the model-routing "required once delegated" existence gate - the
16
- delegated-agent set (derived from `delegation_receipts[].agent_name` plus a
17
- delegating `next_step`) must be a subset of `model_routing_receipts[].agent` -
18
- mirroring `scripts/dev_tools/_orchestrator_state_model_routing_gate.py`. Deep
19
- per-receipt routing-contract correctness that requires full Python authority is a
20
- documented Non-Goal for the portable path; the gate performs the presence-level
21
- existence check and reports missing receipts with error text containing the
22
- literal token `model_routing_receipts`, so the completion hook maps a failure to
23
- its `MODEL_ROUTING_BLOCKED:` block reason. The Python validator remains
24
- authoritative; this module is the fallback mirror only.
6
+ Provides the destination-runtime PowerShell implementation of the completion
7
+ validation the pushed-down validate-orchestrator-output hook performs. As of
8
+ issue #475 this is a COMPLETE-PARITY port of the Python validator's call
9
+ surface `orchestrator-state --require-complete --require-model-routing`,
10
+ measured row by row against the parity inventory. It is no longer a
11
+ presence-level subset and no longer a fallback for an importable Python
12
+ validator: the portable path is the only path.
13
+
14
+ `Test-OrchestratorStateCompletionReadiness` composes, in the Python
15
+ reference's order:
16
+
17
+ U1 the loader contract (missing file, invalid JSON, non-object root),
18
+ fail-closed, from `Get-OrchestratorStateCheckpoint`
19
+ U2-U6 the whole unconditional block, from
20
+ `Get-OrchestratorStateUnconditionalError`
21
+ C1,C2 completion step statuses and blocked_reason
22
+ C3,C4 the route-gated pr_gate and ci_gate contracts
23
+ C5 mandatory route phases
24
+ C6 the routing contract, from `OrchestratorStateRoutingContract.psm1`
25
+ C7 the preparation terminal contract
26
+ M1 model-routing receipt required once delegated
27
+ M2 a complexity assessment for every matched receipt phase
28
+ M3 per-entry re-validation of the U6.C and U6.M families
29
+
30
+ PD-2 SINGLE EMISSION (declared divergence). The Python reference emits the
31
+ U6.C and U6.M per-entry errors TWICE for this flag pair: once in the
32
+ unconditional block and again inside the model-routing gate's M3 re-run. This
33
+ port emits each error string exactly once. The M3 reuse requirement is
34
+ satisfied by INVOKING the same per-entry validator implementation
35
+ (`Get-OrchestratorStateComplexityAssessmentError` and
36
+ `Get-OrchestratorStateModelRoutingReceiptError` from
37
+ `OrchestratorStateModelReceipts.psm1`) inside the gate, exactly as the Python
38
+ gate reuses its validators, and then adding only strings the accumulated
39
+ result does not already carry. Reuse is therefore real, and duplication is
40
+ not. The divergence is deliberate: a hook that counted errors would behave
41
+ differently against a duplicating validator.
42
+
43
+ The `MODEL_ROUTING_BLOCKED` routing guarantee is preserved: a missing routing
44
+ receipt still yields error text containing the literal token
45
+ `model_routing_receipts`, so the completion hook maps the failure to its
46
+ `MODEL_ROUTING_BLOCKED:` block reason.
25
47
  #>
26
48
 
27
49
  Set-StrictMode -Version Latest
28
50
 
29
- # Import the sibling shared module and the portable model-routing module, resolved
30
- # relative to this module's directory so the imports travel with the pushed-down
31
- # pack regardless of the consumer repository's working directory.
51
+ # Import the sibling shared module, the portable model-routing formulas, and the
52
+ # ported check families, resolved relative to this module's directory so every
53
+ # import travels with the pushed-down pack regardless of the working directory.
32
54
  Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorState.psm1') -Force
33
55
  $script:ModelRoutingModulePath = Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '..') -ChildPath (Join-Path -Path 'model-routing' -ChildPath 'ModelRouting.psm1')
34
56
  Import-Module $script:ModelRoutingModulePath -Force
57
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force
58
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateModelReceipts.psm1') -Force
59
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateUnconditional.psm1') -Force
60
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCompletionChecks.psm1') -Force
61
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateRoutingContract.psm1') -Force
62
+
63
+ # The two optional keys the M3 leg re-validates, guarded on key presence so an
64
+ # absent key does not emit a spurious "must be a list when present" error.
65
+ $script:COMPLEXITY_ASSESSMENTS_KEY = 'complexity_assessments'
35
66
 
36
67
  # The subagent types delegated via the Agent tool that can be named by a delegating
37
68
  # next_step. Pinned to _DELEGATING_AGENTS in
@@ -182,32 +213,173 @@ function Get-OrchestratorStateModelRoutingGateError {
182
213
 
183
214
  $receiptAgents = @(Get-OrchestratorStateRoutingReceiptAgent -State $State)
184
215
 
185
- # Existence invariant: the routing-receipt agent set must be a superset of the
186
- # delegated-agent set. Report each delegated agent with no receipt, sorted for
187
- # deterministic error ordering.
216
+ # M1: the routing-receipt agent set must be a superset of the delegated-agent
217
+ # set. Report each delegated agent with no receipt, sorted for deterministic
218
+ # error ordering.
188
219
  $missing = $delegated | Where-Object { $receiptAgents -notcontains $_ } | Sort-Object
189
220
  foreach ($agent in $missing) {
190
221
  $errors.Add("Checkpoint model_routing_receipts is missing a receipt for delegated agent: $agent.")
191
222
  }
192
223
 
224
+ # M2: every phase named by a receipt that MATCHED a delegated agent must carry
225
+ # a complexity assessment. Only matched receipts impose the requirement, so an
226
+ # unrelated receipt cannot force an assessment.
227
+ $matchedPhases = @(Get-OrchestratorStateMatchedReceiptPhase -State $State -DelegatedAgent $delegated)
228
+ $assessedPhases = @(Get-OrchestratorStateAssessedPhase -State $State)
229
+ $unassessed = $matchedPhases | Where-Object { $assessedPhases -cnotcontains $_ } | Sort-Object
230
+ foreach ($phase in $unassessed) {
231
+ $errors.Add("Checkpoint complexity_assessments is missing an entry for phase $phase referenced by a model_routing_receipts entry.")
232
+ }
233
+
234
+ # M3: re-validate the U6.M and U6.C families by INVOKING the same per-entry
235
+ # validator implementation the unconditional block uses, exactly as the Python
236
+ # gate reuses its validators. Both calls are key-gated so an absent key does
237
+ # not emit a spurious "must be a list when present" error. Emission is left to
238
+ # the caller, which applies the PD-2 single-emission rule.
239
+ $routingField = Get-CheckpointObjectMember -Owner $State -Name $script:MODEL_ROUTING_RECEIPTS_KEY
240
+ if ($routingField.Present) {
241
+ $errors.AddRange([string[]]@(Get-OrchestratorStateModelRoutingReceiptError -Value $routingField.Value))
242
+ }
243
+ $complexityField = Get-CheckpointObjectMember -Owner $State -Name $script:COMPLEXITY_ASSESSMENTS_KEY
244
+ if ($complexityField.Present) {
245
+ $errors.AddRange([string[]]@(Get-OrchestratorStateComplexityAssessmentError -Value $complexityField.Value))
246
+ }
247
+
193
248
  return $errors.ToArray()
194
249
  }
195
250
 
251
+ function Get-OrchestratorStateMatchedReceiptPhase {
252
+ <#
253
+ .SYNOPSIS
254
+ Collect the phases named by routing receipts that matched a delegated agent.
255
+ .DESCRIPTION
256
+ Private helper mirroring the matched-phase half of
257
+ ``_routing_receipt_agents_and_matched_phases``. Only a receipt whose
258
+ ``agent`` is in the delegated set contributes its ``phase``, so an
259
+ unrelated receipt cannot force a complexity assessment.
260
+ .PARAMETER State
261
+ The parsed checkpoint object.
262
+ .PARAMETER DelegatedAgent
263
+ The delegated-agent names.
264
+ .OUTPUTS
265
+ System.String[] - the matched phases, rendered with Python str() semantics
266
+ so a non-string phase still yields a stable, comparable key.
267
+ #>
268
+ [CmdletBinding()]
269
+ [OutputType([string[]])]
270
+ param(
271
+ [Parameter(Mandatory = $true)]
272
+ [psobject] $State,
273
+
274
+ [Parameter(Mandatory = $true)]
275
+ [AllowEmptyCollection()]
276
+ [string[]] $DelegatedAgent
277
+ )
278
+
279
+ $phases = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
280
+ $receipts = (Get-CheckpointObjectMember -Owner $State -Name $script:MODEL_ROUTING_RECEIPTS_KEY).Value
281
+ if (-not (Test-CheckpointListValue -Value $receipts)) { return [string[]]@($phases) }
282
+
283
+ foreach ($receipt in @($receipts)) {
284
+ if (-not (Test-CheckpointObjectValue -Value $receipt)) { continue }
285
+ $agent = (Get-CheckpointObjectMember -Owner $receipt -Name 'agent').Value
286
+ if (($agent -is [string]) -and ($DelegatedAgent -ccontains [string]$agent)) {
287
+ $phase = (Get-CheckpointObjectMember -Owner $receipt -Name 'phase').Value
288
+ [void]$phases.Add((ConvertTo-PythonDisplayText -Value $phase))
289
+ }
290
+ }
291
+ return [string[]]@($phases)
292
+ }
293
+
294
+ function Get-OrchestratorStateAssessedPhase {
295
+ <#
296
+ .SYNOPSIS
297
+ Collect the phases that carry a complexity-assessment entry.
298
+ .DESCRIPTION
299
+ Private helper mirroring ``_assessed_phases``. Every well-formed
300
+ assessment object contributes its ``phase`` value, including a null one,
301
+ so a receipt phase paired with an assessment is not reported missing.
302
+ .PARAMETER State
303
+ The parsed checkpoint object.
304
+ .OUTPUTS
305
+ System.String[] - the assessed phases, rendered with Python str()
306
+ semantics to match the matched-phase keys.
307
+ #>
308
+ [CmdletBinding()]
309
+ [OutputType([string[]])]
310
+ param(
311
+ [Parameter(Mandatory = $true)]
312
+ [psobject] $State
313
+ )
314
+
315
+ $phases = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
316
+ $assessments = (Get-CheckpointObjectMember -Owner $State -Name $script:COMPLEXITY_ASSESSMENTS_KEY).Value
317
+ if (-not (Test-CheckpointListValue -Value $assessments)) { return [string[]]@($phases) }
318
+
319
+ foreach ($assessment in @($assessments)) {
320
+ if (-not (Test-CheckpointObjectValue -Value $assessment)) { continue }
321
+ $phase = (Get-CheckpointObjectMember -Owner $assessment -Name 'phase').Value
322
+ [void]$phases.Add((ConvertTo-PythonDisplayText -Value $phase))
323
+ }
324
+ return [string[]]@($phases)
325
+ }
326
+
327
+ function Add-OrchestratorStateErrorOnce {
328
+ <#
329
+ .SYNOPSIS
330
+ Append error strings the accumulated list does not already carry.
331
+ .DESCRIPTION
332
+ Private helper implementing the PD-2 single-emission rule. The M3 leg
333
+ deliberately re-invokes the U6.C and U6.M per-entry validators, which the
334
+ unconditional block already ran, so its output overlaps. Appending only
335
+ the strings not already present keeps the reuse real while emitting each
336
+ error exactly once, the declared divergence from the Python reference's
337
+ duplicate emission.
338
+ .PARAMETER Accumulated
339
+ The accumulated error list, appended in place.
340
+ .PARAMETER Candidate
341
+ The candidate error strings.
342
+ .OUTPUTS
343
+ None. The Accumulated list is appended in place.
344
+ #>
345
+ [CmdletBinding()]
346
+ [OutputType([void])]
347
+ param(
348
+ [Parameter(Mandatory = $true)]
349
+ [AllowEmptyCollection()]
350
+ [System.Collections.Generic.List[string]] $Accumulated,
351
+
352
+ [Parameter(Mandatory = $true)]
353
+ [AllowEmptyCollection()]
354
+ [string[]] $Candidate
355
+ )
356
+
357
+ foreach ($item in $Candidate) {
358
+ if (-not $Accumulated.Contains($item)) { $Accumulated.Add($item) }
359
+ }
360
+ }
361
+
196
362
  function Test-OrchestratorStateCompletionReadiness {
197
363
  <#
198
364
  .SYNOPSIS
199
- Validate a checkpoint satisfies the portable completion-gate presence checks.
365
+ Validate a checkpoint against the complete-parity completion contract.
200
366
  .DESCRIPTION
201
- Public entry point used by the pushed-down validate-orchestrator-output hook
202
- when the authoritative Python validator is not importable. Loads the
203
- checkpoint (fail-closed on missing file / invalid JSON / invalid base shape),
204
- runs the base-presence check (required keys, step-status validity,
205
- blocked_reason validity), then applies the model-routing required-once-
206
- delegated existence gate. Returns a hashtable compatible with the hook's
207
- invoker contract: ExitCode is 1 whenever any error is present, and Output
208
- carries the newline-joined error text (empty on success). A missing routing
209
- receipt yields error text containing ``model_routing_receipts`` so the hook
210
- surfaces it under ``MODEL_ROUTING_BLOCKED:``.
367
+ Public entry point used by the pushed-down validate-orchestrator-output
368
+ hook. Loads the checkpoint (fail-closed on missing file, invalid JSON, or
369
+ non-object root), then runs the whole unconditional block, the C family,
370
+ and the M family in the Python reference's order. Returns a hashtable
371
+ compatible with the hook's invoker contract: ExitCode is 1 whenever any
372
+ error is present, and Output carries the newline-joined error text (empty
373
+ on success).
374
+
375
+ PD-2 single emission applies to the M3 leg only: the per-entry U6.C and
376
+ U6.M validators are invoked again there, as the Python gate does, but a
377
+ string already emitted by the unconditional block is not repeated. Every
378
+ other check contributes its errors directly.
379
+
380
+ A missing routing receipt yields error text containing
381
+ ``model_routing_receipts`` so the hook surfaces it under
382
+ ``MODEL_ROUTING_BLOCKED:``.
211
383
  .PARAMETER CheckpointPath
212
384
  The path to the orchestrator-state checkpoint JSON file.
213
385
  .OUTPUTS
@@ -220,18 +392,35 @@ function Test-OrchestratorStateCompletionReadiness {
220
392
  [string] $CheckpointPath
221
393
  )
222
394
 
223
- # Fail closed when the checkpoint cannot be loaded: the load error is the whole
224
- # output and ExitCode is 1.
395
+ # U1: fail closed when the checkpoint cannot be loaded. The load error is the
396
+ # whole output and ExitCode is 1.
225
397
  $loaded = Get-OrchestratorStateCheckpoint -CheckpointPath $CheckpointPath
226
398
  if (-not $loaded.Ok) {
227
399
  return @{ ExitCode = 1; Output = $loaded.Error }
228
400
  }
401
+ $state = $loaded.State
229
402
 
230
- # Accumulate base-presence errors and existence-gate errors; any error yields a
231
- # non-zero ExitCode so the completion hook blocks DONE.
232
403
  $errors = [System.Collections.Generic.List[string]]::new()
233
- $errors.AddRange([string[]]@(Get-OrchestratorStateBasePresenceError -State $loaded.State))
234
- $errors.AddRange([string[]]@(Get-OrchestratorStateModelRoutingGateError -State $loaded.State))
404
+
405
+ # U2 through U6: the whole unconditional block, in reference order.
406
+ $errors.AddRange([string[]]@(Get-OrchestratorStateUnconditionalError -State $state))
407
+
408
+ # C family, in the reference's require_complete order: step statuses,
409
+ # blocked_reason, pr_gate, ci_gate, phase completeness, routing contract, and
410
+ # the preparation terminal contract.
411
+ $errors.AddRange([string[]]@(Get-OrchestratorStateCompletionStepStatusError -State $state))
412
+ $errors.AddRange([string[]]@(Get-OrchestratorStateCompletionBlockedReasonError -State $state))
413
+ $errors.AddRange([string[]]@(Get-OrchestratorStateCompletionPrGateError -State $state))
414
+ $errors.AddRange([string[]]@(Get-OrchestratorStateCompletionCiGateError -State $state))
415
+ $errors.AddRange([string[]]@(Get-OrchestratorStatePhaseCompletenessError -State $state))
416
+ $errors.AddRange([string[]]@(Get-OrchestratorStateRoutingContractError -State $state))
417
+ $errors.AddRange([string[]]@(Get-OrchestratorStatePreparationTerminalError -State $state))
418
+
419
+ # M family. The gate's M3 leg re-invokes the U6.C and U6.M validators, so its
420
+ # output is merged under the PD-2 single-emission rule rather than appended
421
+ # wholesale.
422
+ Add-OrchestratorStateErrorOnce -Accumulated $errors `
423
+ -Candidate ([string[]]@(Get-OrchestratorStateModelRoutingGateError -State $state))
235
424
 
236
425
  if ($errors.Count -gt 0) {
237
426
  return @{ ExitCode = 1; Output = ($errors -join [System.Environment]::NewLine) }