@danmoisan/drm-copilot-mcp 1.1.16 → 1.1.18

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 (105) hide show
  1. package/out/mcp-server.js +1139 -133
  2. package/package.json +4 -3
  3. package/resources/claude-customizations/.claude/agents/feature-review.md +10 -1
  4. package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -3
  5. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +18 -6
  6. package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +3 -3
  7. package/resources/claude-customizations/.claude/hooks/{enforce-powershell-batch-budget-route.ps1 → enforce-batch-budget-route.ps1} +12 -10
  8. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +221 -0
  9. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +42 -66
  10. package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +58 -10
  11. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +144 -0
  12. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +36 -47
  13. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +179 -27
  14. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +21 -38
  15. package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +4 -4
  16. package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +58 -10
  17. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +59 -9
  18. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +114 -37
  19. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +3 -3
  20. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +99 -64
  21. package/resources/claude-customizations/.claude/lib/bash/abandon-parallel-item.sh +176 -0
  22. package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
  23. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConflict.psm1 +193 -14
  24. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +51 -28
  25. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +5 -8
  26. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
  27. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +375 -0
  28. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
  29. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
  30. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
  31. package/resources/claude-customizations/.claude/lib/parallel-drift/Invoke-ParallelDriftDetection.ps1 +336 -0
  32. package/resources/claude-customizations/.claude/lib/parallel-drift/ParallelDrift.psm1 +467 -0
  33. package/resources/claude-customizations/.claude/lib/parallel-drift/ParallelDriftHalt.psm1 +388 -0
  34. package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeResolution.psm1 +53 -32
  35. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +19 -4
  36. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +497 -0
  37. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +119 -3
  38. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +21 -0
  39. package/resources/claude-customizations/.claude/rules/quality-tiers.md +1 -1
  40. package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  41. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -0
  42. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
  43. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
  44. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +169 -5
  45. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
  46. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
  47. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +4 -15
  48. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +15 -6
  49. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  50. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
  51. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +3 -1
  52. package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -0
  53. package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +4 -0
  54. package/resources/claude-customizations/.claude/skills/invoke-python-engineer/SKILL.md +6 -3
  55. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +33 -13
  56. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +50 -21
  57. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +10 -10
  58. package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +11 -35
  59. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +5 -1
  60. package/resources/claude-customizations/pack-manifests/core.json +10 -0
  61. package/resources/claude-customizations/pack-manifests/powershell.json +0 -1
  62. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  63. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +5 -3
  64. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  65. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  66. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
  67. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +3 -1
  68. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -1
  69. package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +2 -3
  70. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +30 -7
  71. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
  72. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +18 -3
  73. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +10 -34
  74. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +1 -1
  75. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
  76. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
  77. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
  78. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
  79. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
  80. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
  81. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
  82. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +1 -1
  83. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +1 -1
  84. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +1 -1
  85. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +1 -1
  86. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +1 -1
  87. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +1 -1
  88. package/resources/codex-and-agents-customizations/.codex/agents/python-orchestrator.toml +2 -2
  89. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +3 -3
  90. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +3 -3
  91. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +3 -3
  92. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +3 -3
  93. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +3 -3
  94. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +3 -3
  95. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  96. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-batch-budget-route.ps1 +139 -0
  97. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +4 -124
  98. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +169 -79
  99. package/resources/codex-and-agents-customizations/pack-manifests/core.json +1 -0
  100. package/resources/customizations/.github/agents/python-orchestrator.agent.md +4 -4
  101. package/resources/customizations/.github/agents/python-typed-engineer.agent.md +7 -8
  102. package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +3 -3
  103. package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  104. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  105. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +16 -1
@@ -0,0 +1,337 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Portable remediation-loop review-outcome and accounting checks (R5-R11).
4
+
5
+ .DESCRIPTION
6
+ Destination-runtime PowerShell port of the issue #484 invariants the
7
+ authoritative Python validator applies to a checkpoint's remediation_loop:
8
+ the review-outcome rules R8a, R8b, R9a-R9d, and R10, and the accounting
9
+ rules R5, R6, R7a, R7b, and R11, matching the error-string templates in
10
+ `scripts/dev_tools/_orchestrator_state_remediation_loop.py` and the rules
11
+ document `.claude/rules/orchestrator-state.md`.
12
+
13
+ The receipts module calls the exported entry point after its unchanged
14
+ per-cycle checks, passing the cycle list or $null when cycles is absent or
15
+ not a list, so the new checks also run for a loop with review outcomes and
16
+ no cycles.
17
+
18
+ Every comparison against the verdict and class vocabulary is case-sensitive
19
+ (-ccontains, -cnotcontains, -ceq). An integer is a JSON number deserialized
20
+ as [int] or [long]; a boolean is never an integer. Values interpolated into
21
+ a message ({v}) render through ConvertTo-PythonDisplayText so the text
22
+ matches Python's str().
23
+
24
+ Every function is pure: it reads no file, starts no process, and never
25
+ mutates its input. Each check returns a string array, empty when valid.
26
+ CONVENTION: this module fails fast at module scope and imports its siblings with -ErrorAction Stop.
27
+ #>
28
+
29
+ Set-StrictMode -Version Latest
30
+ $ErrorActionPreference = 'Stop'
31
+
32
+ # Import the shared checkpoint-value primitives, resolved relative to this
33
+ # module's directory so the import travels with the pushed-down pack.
34
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force -ErrorAction Stop
35
+
36
+ # Loop and cycle keys read by the accounting rules.
37
+ $script:REVIEW_OUTCOMES_KEY = 'review_outcomes'
38
+ $script:COMPLETED_ATTEMPTS_KEY = 'completed_attempts'
39
+ $script:CANDIDATE_APPLIED_KEY = 'candidate_applied'
40
+ $script:OPENED_BY_REVIEW_KEY = 'opened_by_review'
41
+ $script:COMPLETED_EXECUTION_STATUS = 'complete'
42
+
43
+ # Review verdicts and remediability classes in spec table order, and the two
44
+ # derived class partitions. Pinned to the Python constants of the same names.
45
+ $script:REVIEW_VERDICTS = @('PASS', 'REMEDIATION_REQUIRED', 'HALT_NON_REMEDIABLE', 'AWAITING_CI')
46
+ $script:REMEDIABILITY_CLASSES = @('autonomous', 'external_dependency', 'policy_hold', 'awaiting_ci', 'human_decision_required')
47
+ $script:NON_REMEDIABLE_CLASSES = @('external_dependency', 'policy_hold', 'awaiting_ci', 'human_decision_required')
48
+ $script:HALT_CLASSES = @('external_dependency', 'policy_hold', 'human_decision_required')
49
+ $script:REMEDIABLE_CLASS = 'autonomous'
50
+ $script:REMEDIATION_REQUIRED_VERDICT = 'REMEDIATION_REQUIRED'
51
+
52
+
53
+ function Test-RemediationStrictInteger {
54
+ <#
55
+ .SYNOPSIS
56
+ Report whether a deserialized JSON value is an integer and not a boolean.
57
+ .DESCRIPTION
58
+ Private predicate mirroring Python's isinstance(value, int) and not
59
+ isinstance(value, bool). ConvertFrom-Json materializes a JSON integer as
60
+ [int] or [long] and a JSON boolean as [bool].
61
+ .PARAMETER Value
62
+ The deserialized JSON value to classify. May be $null.
63
+ .OUTPUTS
64
+ System.Boolean - $true only for an [int] or [long] value.
65
+ #>
66
+ [CmdletBinding()]
67
+ [OutputType([bool])]
68
+ param(
69
+ [Parameter(Mandatory = $true)]
70
+ [AllowNull()]
71
+ [object] $Value
72
+ )
73
+
74
+ return (($Value -is [int]) -or ($Value -is [long])) -and -not ($Value -is [bool])
75
+ }
76
+
77
+ function Get-RemediationReviewVerdict {
78
+ <#
79
+ .SYNOPSIS
80
+ Derive a review verdict from its findings' remediability classes.
81
+ .DESCRIPTION
82
+ Private helper mirroring derive_review_verdict. Evaluates, in order: no
83
+ classes yields PASS; any autonomous class yields REMEDIATION_REQUIRED;
84
+ any member of HALT_CLASSES yields HALT_NON_REMEDIABLE; otherwise
85
+ AWAITING_CI. A member outside REMEDIABILITY_CLASSES (compared
86
+ case-sensitively) raises a terminating error whose message begins
87
+ 'invalid remediability: '.
88
+ .PARAMETER Remediability
89
+ The remediability class of every blocking finding; may be empty and may
90
+ repeat a class.
91
+ .OUTPUTS
92
+ System.String - one of the four review verdicts.
93
+ #>
94
+ [CmdletBinding()]
95
+ [OutputType([string])]
96
+ param(
97
+ [Parameter(Mandatory = $true)]
98
+ [AllowEmptyCollection()]
99
+ [string[]] $Remediability
100
+ )
101
+
102
+ foreach ($value in $Remediability) {
103
+ if ($script:REMEDIABILITY_CLASSES -cnotcontains $value) {
104
+ throw "invalid remediability: $value"
105
+ }
106
+ }
107
+
108
+ if ($Remediability.Count -eq 0) { return 'PASS' }
109
+ if ($Remediability -ccontains $script:REMEDIABLE_CLASS) { return 'REMEDIATION_REQUIRED' }
110
+ foreach ($value in $Remediability) {
111
+ if ($script:HALT_CLASSES -ccontains $value) { return 'HALT_NON_REMEDIABLE' }
112
+ }
113
+ return 'AWAITING_CI'
114
+ }
115
+
116
+ function Get-RemediationReviewOutcomeError {
117
+ <#
118
+ .SYNOPSIS
119
+ Return one review outcome's errors (R9a-R9d, then R10).
120
+ .DESCRIPTION
121
+ Private helper mirroring _validate_review_outcome. Checks the verdict
122
+ (string check before membership), the findings list, and each finding's
123
+ remediability (string check before membership); R10 runs only when none
124
+ of those checks produced an error for the outcome.
125
+ .PARAMETER Index
126
+ The outcome's zero-based position, used for error context.
127
+ .PARAMETER Outcome
128
+ The deserialized outcome object.
129
+ .OUTPUTS
130
+ System.String[] - zero or more error strings.
131
+ #>
132
+ [CmdletBinding()]
133
+ [OutputType([string[]])]
134
+ param(
135
+ [Parameter(Mandatory = $true)]
136
+ [int] $Index,
137
+
138
+ [Parameter(Mandatory = $true)]
139
+ [psobject] $Outcome
140
+ )
141
+
142
+ $errors = [System.Collections.Generic.List[string]]::new()
143
+ $prefix = "Checkpoint remediation review outcome #$Index"
144
+
145
+ $verdict = (Get-CheckpointObjectMember -Owner $Outcome -Name 'verdict').Value
146
+ if (-not ($verdict -is [string]) -or ($script:REVIEW_VERDICTS -cnotcontains [string]$verdict)) {
147
+ $rendered = ConvertTo-PythonDisplayText -Value $verdict
148
+ $errors.Add("$prefix verdict must be one of PASS, REMEDIATION_REQUIRED, HALT_NON_REMEDIABLE, AWAITING_CI; got: $rendered")
149
+ }
150
+
151
+ $classes = [System.Collections.Generic.List[string]]::new()
152
+ $findings = (Get-CheckpointObjectMember -Owner $Outcome -Name 'findings').Value
153
+ if (-not (Test-CheckpointListValue -Value $findings)) {
154
+ $errors.Add("$prefix findings must be a list.")
155
+ } else {
156
+ $findingIndex = 0
157
+ foreach ($finding in @($findings)) {
158
+ if (-not (Test-CheckpointObjectValue -Value $finding)) {
159
+ $errors.Add("$prefix finding #$findingIndex must be an object.")
160
+ } else {
161
+ $remediability = (Get-CheckpointObjectMember -Owner $finding -Name 'remediability').Value
162
+ if (-not ($remediability -is [string]) -or ($script:REMEDIABILITY_CLASSES -cnotcontains [string]$remediability)) {
163
+ $rendered = ConvertTo-PythonDisplayText -Value $remediability
164
+ $errors.Add("$prefix finding #$findingIndex remediability must be one of autonomous, external_dependency, policy_hold, awaiting_ci, human_decision_required; got: $rendered")
165
+ } else {
166
+ $classes.Add([string]$remediability)
167
+ }
168
+ }
169
+ $findingIndex++
170
+ }
171
+ }
172
+
173
+ # R10 compares only a well-formed outcome; any shape error above suppresses it.
174
+ if ($errors.Count -eq 0) {
175
+ $expected = Get-RemediationReviewVerdict -Remediability $classes.ToArray()
176
+ if (-not ([string]$verdict -ceq $expected)) {
177
+ $errors.Add("$prefix verdict $verdict does not match its findings (expected $expected).")
178
+ }
179
+ }
180
+
181
+ return $errors.ToArray()
182
+ }
183
+
184
+ function Get-RemediationReviewOutcomeListError {
185
+ <#
186
+ .SYNOPSIS
187
+ Return the review-outcome errors (R8a, R8b, then each outcome).
188
+ .DESCRIPTION
189
+ Private helper mirroring _validate_review_outcomes. An absent
190
+ review_outcomes key yields no errors; a present non-list value yields R8a
191
+ alone; otherwise each non-object outcome yields R8b and is skipped.
192
+ .PARAMETER RemediationLoop
193
+ The deserialized remediation_loop object.
194
+ .OUTPUTS
195
+ System.String[] - zero or more error strings.
196
+ #>
197
+ [CmdletBinding()]
198
+ [OutputType([string[]])]
199
+ param(
200
+ [Parameter(Mandatory = $true)]
201
+ [psobject] $RemediationLoop
202
+ )
203
+
204
+ $errors = [System.Collections.Generic.List[string]]::new()
205
+ $member = Get-CheckpointObjectMember -Owner $RemediationLoop -Name $script:REVIEW_OUTCOMES_KEY
206
+ if (-not $member.Present) { return $errors.ToArray() }
207
+ if (-not (Test-CheckpointListValue -Value $member.Value)) {
208
+ $errors.Add('Checkpoint remediation_loop review_outcomes must be a list.')
209
+ return $errors.ToArray()
210
+ }
211
+
212
+ $index = 0
213
+ foreach ($outcome in @($member.Value)) {
214
+ if (-not (Test-CheckpointObjectValue -Value $outcome)) {
215
+ $errors.Add("Checkpoint remediation review outcome #$index must be an object.")
216
+ } else {
217
+ $errors.AddRange([string[]]@(Get-RemediationReviewOutcomeError -Index $index -Outcome $outcome))
218
+ }
219
+ $index++
220
+ }
221
+
222
+ return $errors.ToArray()
223
+ }
224
+
225
+ function Test-RemediationOpenedByReview {
226
+ <#
227
+ .SYNOPSIS
228
+ Report whether an index names a REMEDIATION_REQUIRED outcome object.
229
+ .DESCRIPTION
230
+ Private predicate for R11: the value must be an integer (not a boolean)
231
+ from 0 to one less than the outcome count of a list review_outcomes, and
232
+ the indexed entry must be an object whose verdict is exactly
233
+ REMEDIATION_REQUIRED. A negative index is out of range.
234
+ .PARAMETER OpenedByReview
235
+ The raw opened_by_review value. May be $null.
236
+ .PARAMETER Outcomes
237
+ The raw review_outcomes value. May be $null.
238
+ .OUTPUTS
239
+ System.Boolean - $true only when the reference is valid.
240
+ #>
241
+ [CmdletBinding()]
242
+ [OutputType([bool])]
243
+ param(
244
+ [Parameter(Mandatory = $true)]
245
+ [AllowNull()]
246
+ [object] $OpenedByReview,
247
+
248
+ [Parameter(Mandatory = $true)]
249
+ [AllowNull()]
250
+ [object] $Outcomes
251
+ )
252
+
253
+ if (-not (Test-RemediationStrictInteger -Value $OpenedByReview)) { return $false }
254
+ if (-not (Test-CheckpointListValue -Value $Outcomes)) { return $false }
255
+ $outcomeList = @($Outcomes)
256
+ if ($OpenedByReview -lt 0 -or $OpenedByReview -ge $outcomeList.Count) { return $false }
257
+ $target = $outcomeList[[int]$OpenedByReview]
258
+ if (-not (Test-CheckpointObjectValue -Value $target)) { return $false }
259
+ $verdict = (Get-CheckpointObjectMember -Owner $target -Name 'verdict').Value
260
+ return ($verdict -is [string]) -and ([string]$verdict -ceq $script:REMEDIATION_REQUIRED_VERDICT)
261
+ }
262
+
263
+ function Get-OrchestratorStateRemediationAccountingError {
264
+ <#
265
+ .SYNOPSIS
266
+ Return the remediation_loop review-outcome and accounting errors (R5-R11).
267
+ .DESCRIPTION
268
+ Public entry mirroring the issue #484 tail of _validate_remediation_loop.
269
+ Returns, in order: the review-outcome errors (R8a; otherwise per outcome
270
+ R8b, R9a, R9b, R9c or R9d per finding, then R10); then, for each object
271
+ cycle in order, R5, R6, and R11; then R7a, otherwise R7b. With none of the
272
+ new keys present it returns nothing.
273
+ .PARAMETER RemediationLoop
274
+ The deserialized remediation_loop object.
275
+ .PARAMETER Cycle
276
+ The loop's cycles list, or $null when cycles is absent or not a list.
277
+ .OUTPUTS
278
+ System.String[] - zero or more error strings.
279
+ #>
280
+ [CmdletBinding()]
281
+ [OutputType([string[]])]
282
+ param(
283
+ [Parameter(Mandatory = $true)]
284
+ [psobject] $RemediationLoop,
285
+
286
+ [Parameter(Mandatory = $true)]
287
+ [AllowNull()]
288
+ [AllowEmptyCollection()]
289
+ [object] $Cycle
290
+ )
291
+
292
+ $errors = [System.Collections.Generic.List[string]]::new()
293
+ $errors.AddRange([string[]]@(Get-RemediationReviewOutcomeListError -RemediationLoop $RemediationLoop))
294
+
295
+ $outcomes = (Get-CheckpointObjectMember -Owner $RemediationLoop -Name $script:REVIEW_OUTCOMES_KEY).Value
296
+ $appliedCount = 0
297
+ $cycleItems = @()
298
+ if ($null -ne $Cycle) { $cycleItems = @($Cycle) }
299
+ $index = 0
300
+ foreach ($item in $cycleItems) {
301
+ if (Test-CheckpointObjectValue -Value $item) {
302
+ $prefix = "Checkpoint remediation cycle #$index"
303
+ $applied = Get-CheckpointObjectMember -Owner $item -Name $script:CANDIDATE_APPLIED_KEY
304
+ if ($applied.Present) {
305
+ if (-not ($applied.Value -is [bool])) {
306
+ $errors.Add("$prefix candidate_applied must be a boolean.")
307
+ } elseif ($applied.Value) {
308
+ $appliedCount++
309
+ $executionStatus = (Get-CheckpointObjectMember -Owner $item -Name 'execution_status').Value
310
+ if (-not ($executionStatus -is [string]) -or -not ([string]$executionStatus -ceq $script:COMPLETED_EXECUTION_STATUS)) {
311
+ $errors.Add("$prefix candidate_applied is true but execution_status is not 'complete'.")
312
+ }
313
+ }
314
+ }
315
+ $opened = Get-CheckpointObjectMember -Owner $item -Name $script:OPENED_BY_REVIEW_KEY
316
+ if ($opened.Present -and -not (Test-RemediationOpenedByReview -OpenedByReview $opened.Value -Outcomes $outcomes)) {
317
+ $errors.Add("$prefix opened_by_review must reference a review outcome whose verdict is REMEDIATION_REQUIRED.")
318
+ }
319
+ }
320
+ $index++
321
+ }
322
+
323
+ $attempts = Get-CheckpointObjectMember -Owner $RemediationLoop -Name $script:COMPLETED_ATTEMPTS_KEY
324
+ if ($attempts.Present) {
325
+ if (-not (Test-RemediationStrictInteger -Value $attempts.Value) -or $attempts.Value -lt 0) {
326
+ $errors.Add('Checkpoint remediation_loop completed_attempts must be a non-negative integer.')
327
+ } elseif ($attempts.Value -ne $appliedCount) {
328
+ $errors.Add("Checkpoint remediation_loop completed_attempts is $($attempts.Value) but $appliedCount cycles have candidate_applied true.")
329
+ }
330
+ }
331
+
332
+ return $errors.ToArray()
333
+ }
334
+
335
+ # Only the entry point is exported; the verdict helper and the per-outcome and
336
+ # per-reference checks stay private to this module.
337
+ Export-ModuleMember -Function Get-OrchestratorStateRemediationAccountingError
@@ -5,7 +5,8 @@
5
5
  .DESCRIPTION
6
6
  Destination-runtime PowerShell port of `validate_routing_contract` in
7
7
  `scripts/dev_tools/_orchestrator_state_routing.py`, covering parity-inventory
8
- rows C6.1 through C6.14:
8
+ rows C6.1 through C6.15. The C6.15 adoption waiver affects only receipt
9
+ presence (C6.9); the declared-list equality checks are unchanged:
9
10
 
10
11
  C6.1 routing matrix carries no routes object (returns)
11
12
  C6.2 no route selected (returns)
@@ -21,6 +22,7 @@
21
22
  C6.12 lifecycle_operations must be a list when present
22
23
  C6.13 per non-object lifecycle operation
23
24
  C6.14 per lifecycle operation that did not use the MCP surface
25
+ C6.15 issue_adoption field and waiver rules (OrchestratorStateIssueAdoption.psm1)
24
26
 
25
27
  The routing matrix is read from `OrchestratorStateRoutingMatrix.psm1`, which
26
28
  implements deviation PD-1: the constants are pinned and no disk read occurs at
@@ -56,6 +58,7 @@ $ErrorActionPreference = 'Stop'
56
58
  # pushed-down pack regardless of the working directory.
57
59
  Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force -ErrorAction Stop
58
60
  Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateRoutingMatrix.psm1') -Force -ErrorAction Stop
61
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateIssueAdoption.psm1') -Force -ErrorAction Stop
59
62
 
60
63
  # The promotion-entry MCP tools and the promotion type that triggers substitution.
61
64
  $script:FEATURE_PROMOTION_ENTRY_TOOL = 'new_potential_entry'
@@ -410,11 +413,16 @@ function Get-OrchestratorStateRoutingContractError {
410
413
  }
411
414
 
412
415
  $actualTools = @(Get-CheckpointAcknowledgedName -State $State -ArrayKey 'mcp_call_receipts' -NameKey 'tool' -FlagKey 'ok')
416
+ # C6.15: a valid issue_adoption record waives the receipt requirement for the
417
+ # tools it lists; any adoption error waives nothing.
418
+ $adoption = Get-OrchestratorStateIssueAdoptionResult -State $State -RouteId $routeId -RequiredMcpTool ([string[]]$requiredMcpTools) -SuccessfulTool ([string[]]$actualTools)
413
419
  foreach ($tool in $requiredMcpTools) {
420
+ if (@($adoption.WaivedTools) -ccontains $tool) { continue }
414
421
  if ($actualTools -cnotcontains $tool) {
415
422
  $errors.Add("Checkpoint missing successful MCP receipt: $tool.")
416
423
  }
417
424
  }
425
+ $errors.AddRange([string[]]@($adoption.Errors))
418
426
 
419
427
  # C6.10 to C6.14: the two empty-list fields and the lifecycle operations.
420
428
  foreach ($key in $script:COMPLETION_EMPTY_LIST_KEYS) {