@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,375 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Issue-adoption record validation and receipt waivers (inventory row C6.15).
4
+
5
+ .DESCRIPTION
6
+ Destination-runtime PowerShell port of `resolve_issue_adoption` in
7
+ `scripts/dev_tools/_orchestrator_state_issue_adoption.py`. The optional
8
+ checkpoint object `issue_adoption` records that the orchestration adopted a
9
+ GitHub issue that existed before orchestration started. A valid record
10
+ waives the successful-receipt requirement for `potential_to_issue` and,
11
+ optionally, for the checkpoint's promotion-entry tool.
12
+
13
+ Invariants:
14
+ - When the `issue_adoption` member is absent, no error is produced and no
15
+ tool is waived, so existing checkpoints validate exactly as before.
16
+ - Errors accumulate in the fixed rule order of the feature specification.
17
+ - Fail-closed: WaivedTools is empty whenever Errors is non-empty.
18
+ - Every string comparison is ordinal and case-sensitive.
19
+ - Messages interpolate only non-blank `waived_tools` entries and the route id.
20
+
21
+ Every function is pure: it reads no file, starts no process, and never mutates
22
+ its input.
23
+ CONVENTION: this module fails fast at module scope and imports its siblings with -ErrorAction Stop.
24
+ #>
25
+
26
+ Set-StrictMode -Version Latest
27
+ $ErrorActionPreference = 'Stop'
28
+
29
+ # Import the shared checkpoint-value primitives, resolved relative to this
30
+ # module's directory so the import travels with the pushed-down pack.
31
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force -ErrorAction Stop
32
+
33
+ $script:ISSUE_ADOPTION_KEY = 'issue_adoption'
34
+ $script:POTENTIAL_TO_ISSUE_TOOL = 'potential_to_issue'
35
+ $script:FEATURE_PROMOTION_ENTRY_TOOL = 'new_potential_entry'
36
+ $script:BUG_PROMOTION_ENTRY_TOOL = 'new_potential_bug_entry'
37
+ $script:ORIGIN_VALUES = [string[]]@('transferred', 'filed_before_orchestration', 'epic_decomposition')
38
+ $script:VERIFIED_VIA_VALUES = [string[]]@('gh_issue_view', 'gh_api_get', 'github_mcp_issue_read')
39
+
40
+ # The closed set of tools an adoption record may waive: the issue-creation tool
41
+ # and the two promotion-type-specific promotion-entry tools.
42
+ $script:WAIVABLE_TOOLS = [string[]]@($script:POTENTIAL_TO_ISSUE_TOOL, $script:FEATURE_PROMOTION_ENTRY_TOOL, $script:BUG_PROMOTION_ENTRY_TOOL)
43
+ $script:PROMOTION_ENTRY_TOOLS = [string[]]@($script:FEATURE_PROMOTION_ENTRY_TOOL, $script:BUG_PROMOTION_ENTRY_TOOL)
44
+ $script:POTENTIAL_RECORD_PREFIX = 'docs/features/potential/'
45
+ $script:POTENTIAL_RECORD_SUFFIX = '.md'
46
+ $script:ISSUE_NUM_PATTERN = '\A[1-9][0-9]*\z'
47
+
48
+ $script:ERROR_NOT_OBJECT = 'Checkpoint issue_adoption must be an object when present.'
49
+ $script:ERROR_ISSUE_NUM_FORMAT = 'Checkpoint issue_adoption.issue_num must be a string of decimal digits without a leading zero.'
50
+ $script:ERROR_ISSUE_NUM_MISMATCH = 'Checkpoint issue_adoption.issue_num must equal the checkpoint issue-num.'
51
+ $script:ERROR_ISSUE_URL = 'Checkpoint issue_adoption.issue_url must end with /issues/ followed by issue_num.'
52
+ $script:ERROR_ORIGIN = 'Checkpoint issue_adoption.origin must be one of transferred, filed_before_orchestration, epic_decomposition.'
53
+ $script:ERROR_VERIFIED_VIA = 'Checkpoint issue_adoption.verified_via must be one of gh_issue_view, gh_api_get, github_mcp_issue_read.'
54
+ $script:ERROR_VERIFIED_AT = 'Checkpoint issue_adoption.verified_at must be present.'
55
+ $script:ERROR_EVIDENCE = 'Checkpoint issue_adoption.evidence must be a non-empty string.'
56
+ $script:ERROR_WAIVED_TOOLS_SHAPE = 'Checkpoint issue_adoption.waived_tools must be a non-empty list of tool names.'
57
+ $script:ERROR_WAIVED_TOOLS_INCLUDE = 'Checkpoint issue_adoption.waived_tools must include potential_to_issue.'
58
+
59
+
60
+ function Test-AdoptionNonBlankString {
61
+ <#
62
+ .SYNOPSIS
63
+ Report whether a value is a string with non-whitespace content.
64
+ .PARAMETER Value
65
+ The deserialized JSON value to inspect. May be $null.
66
+ .OUTPUTS
67
+ System.Boolean
68
+ #>
69
+ [CmdletBinding()]
70
+ [OutputType([bool])]
71
+ param(
72
+ [Parameter(Mandatory = $true)]
73
+ [AllowNull()]
74
+ [object] $Value
75
+ )
76
+
77
+ return (($Value -is [string]) -and -not [string]::IsNullOrWhiteSpace([string]$Value))
78
+ }
79
+
80
+ function Get-AdoptionIssueIdentityError {
81
+ <#
82
+ .SYNOPSIS
83
+ Validate issue_num and issue_url (rules 2 and 3).
84
+ .PARAMETER Adoption
85
+ The issue_adoption object.
86
+ .PARAMETER State
87
+ The parsed checkpoint object, read for its hyphenated issue-num key.
88
+ .OUTPUTS
89
+ System.String[] - zero or more error strings.
90
+ #>
91
+ [CmdletBinding()]
92
+ [OutputType([string[]])]
93
+ param(
94
+ [Parameter(Mandatory = $true)]
95
+ [psobject] $Adoption,
96
+
97
+ [Parameter(Mandatory = $true)]
98
+ [psobject] $State
99
+ )
100
+
101
+ $errors = [System.Collections.Generic.List[string]]::new()
102
+ $rawIssueNum = (Get-CheckpointObjectMember -Owner $Adoption -Name 'issue_num').Value
103
+ $issueNum = $null
104
+ if (($rawIssueNum -is [string]) -and ([string]$rawIssueNum -cmatch $script:ISSUE_NUM_PATTERN)) {
105
+ $issueNum = [string]$rawIssueNum
106
+ }
107
+
108
+ if ($null -ceq $issueNum) {
109
+ $errors.Add($script:ERROR_ISSUE_NUM_FORMAT)
110
+ }
111
+ else {
112
+ # The equality check applies only when the checkpoint records its own
113
+ # issue number as a string; other shapes are validated elsewhere.
114
+ $checkpointIssueNum = (Get-CheckpointObjectMember -Owner $State -Name 'issue-num').Value
115
+ if (($checkpointIssueNum -is [string]) -and -not [string]::Equals([string]$checkpointIssueNum, $issueNum, [System.StringComparison]::Ordinal)) {
116
+ $errors.Add($script:ERROR_ISSUE_NUM_MISMATCH)
117
+ }
118
+ }
119
+
120
+ $issueUrl = (Get-CheckpointObjectMember -Owner $Adoption -Name 'issue_url').Value
121
+ $urlIsValid = ($null -cne $issueNum) -and ($issueUrl -is [string]) -and ([string]$issueUrl).EndsWith("/issues/$issueNum", [System.StringComparison]::Ordinal)
122
+ if (-not $urlIsValid) {
123
+ $errors.Add($script:ERROR_ISSUE_URL)
124
+ }
125
+ return $errors.ToArray()
126
+ }
127
+
128
+ function Get-AdoptionProvenanceError {
129
+ <#
130
+ .SYNOPSIS
131
+ Validate origin, verified_via, verified_at, and evidence (rules 4 to 7).
132
+ .PARAMETER Adoption
133
+ The issue_adoption object.
134
+ .OUTPUTS
135
+ System.String[] - zero or more error strings.
136
+ #>
137
+ [CmdletBinding()]
138
+ [OutputType([string[]])]
139
+ param(
140
+ [Parameter(Mandatory = $true)]
141
+ [psobject] $Adoption
142
+ )
143
+
144
+ $errors = [System.Collections.Generic.List[string]]::new()
145
+
146
+ $origin = (Get-CheckpointObjectMember -Owner $Adoption -Name 'origin').Value
147
+ if (-not (($origin -is [string]) -and ($script:ORIGIN_VALUES -ccontains [string]$origin))) {
148
+ $errors.Add($script:ERROR_ORIGIN)
149
+ }
150
+
151
+ $verifiedVia = (Get-CheckpointObjectMember -Owner $Adoption -Name 'verified_via').Value
152
+ if (-not (($verifiedVia -is [string]) -and ($script:VERIFIED_VIA_VALUES -ccontains [string]$verifiedVia))) {
153
+ $errors.Add($script:ERROR_VERIFIED_VIA)
154
+ }
155
+
156
+ # Presence-only: any non-null value other than a blank string passes,
157
+ # including a System.DateTime produced by ConvertFrom-Json.
158
+ $verifiedAt = (Get-CheckpointObjectMember -Owner $Adoption -Name 'verified_at').Value
159
+ if (($null -ceq $verifiedAt) -or (($verifiedAt -is [string]) -and [string]::IsNullOrWhiteSpace([string]$verifiedAt))) {
160
+ $errors.Add($script:ERROR_VERIFIED_AT)
161
+ }
162
+
163
+ if (-not (Test-AdoptionNonBlankString -Value (Get-CheckpointObjectMember -Owner $Adoption -Name 'evidence').Value)) {
164
+ $errors.Add($script:ERROR_EVIDENCE)
165
+ }
166
+ return $errors.ToArray()
167
+ }
168
+
169
+ function Get-AdoptionWaivedToolList {
170
+ <#
171
+ .SYNOPSIS
172
+ Return the waived tools when they form a non-empty list of non-blank strings.
173
+ .PARAMETER Value
174
+ The deserialized waived_tools value. May be $null.
175
+ .OUTPUTS
176
+ System.Collections.Hashtable with keys Ok (bool) and Value (string[]).
177
+ #>
178
+ [CmdletBinding()]
179
+ [OutputType([hashtable])]
180
+ param(
181
+ [Parameter(Mandatory = $true)]
182
+ [AllowNull()]
183
+ [object] $Value
184
+ )
185
+
186
+ if (-not (Test-CheckpointListValue -Value $Value)) {
187
+ return @{ Ok = $false; Value = [string[]]@() }
188
+ }
189
+ $items = @($Value)
190
+ if ($items.Count -ceq 0) {
191
+ return @{ Ok = $false; Value = [string[]]@() }
192
+ }
193
+ foreach ($item in $items) {
194
+ if (-not (Test-AdoptionNonBlankString -Value $item)) {
195
+ return @{ Ok = $false; Value = [string[]]@() }
196
+ }
197
+ }
198
+ return @{ Ok = $true; Value = [string[]]$items }
199
+ }
200
+
201
+ function Get-AdoptionWaivedToolError {
202
+ <#
203
+ .SYNOPSIS
204
+ Validate each waived tool entry and the mandatory issue-creation waiver (rule 8).
205
+ .PARAMETER WaivedTool
206
+ The well-formed waived tool list, in checkpoint order.
207
+ .PARAMETER RouteId
208
+ The selected route id, interpolated into route errors.
209
+ .PARAMETER RequiredMcpTool
210
+ The route's required MCP tools after promotion-type resolution.
211
+ .PARAMETER SuccessfulTool
212
+ Tools that hold a successful MCP receipt.
213
+ .OUTPUTS
214
+ System.String[] - zero or more error strings.
215
+ #>
216
+ [CmdletBinding()]
217
+ [OutputType([string[]])]
218
+ param(
219
+ [Parameter(Mandatory = $true)]
220
+ [string[]] $WaivedTool,
221
+
222
+ [Parameter(Mandatory = $true)]
223
+ [string] $RouteId,
224
+
225
+ [Parameter(Mandatory = $true)]
226
+ [AllowEmptyCollection()]
227
+ [string[]] $RequiredMcpTool,
228
+
229
+ [Parameter(Mandatory = $true)]
230
+ [AllowEmptyCollection()]
231
+ [string[]] $SuccessfulTool
232
+ )
233
+
234
+ $errors = [System.Collections.Generic.List[string]]::new()
235
+ $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
236
+ foreach ($tool in $WaivedTool) {
237
+ # Each entry receives only the first rule it violates, in rule order.
238
+ if ($seen.Contains($tool)) {
239
+ $errors.Add("Checkpoint issue_adoption.waived_tools lists a tool more than once: $tool.")
240
+ }
241
+ elseif ($script:WAIVABLE_TOOLS -cnotcontains $tool) {
242
+ $errors.Add("Checkpoint issue_adoption.waived_tools names a tool that cannot be waived: $tool.")
243
+ }
244
+ elseif ($RequiredMcpTool -cnotcontains $tool) {
245
+ $errors.Add("Checkpoint issue_adoption.waived_tools names a tool that is not required by route ${RouteId}: $tool.")
246
+ }
247
+ elseif ($SuccessfulTool -ccontains $tool) {
248
+ $errors.Add("Checkpoint issue_adoption.waived_tools names a tool that has a successful MCP receipt: $tool.")
249
+ }
250
+ [void]$seen.Add($tool)
251
+ }
252
+
253
+ if (-not $seen.Contains($script:POTENTIAL_TO_ISSUE_TOOL)) {
254
+ $errors.Add($script:ERROR_WAIVED_TOOLS_INCLUDE)
255
+ }
256
+ return $errors.ToArray()
257
+ }
258
+
259
+ function Get-AdoptionPotentialRecordError {
260
+ <#
261
+ .SYNOPSIS
262
+ Require a potential record when a promotion-entry tool is waived (rule 9).
263
+ .PARAMETER WaivedTool
264
+ The well-formed waived tool list, in checkpoint order.
265
+ .PARAMETER PotentialRecord
266
+ The deserialized potential_record value. May be $null.
267
+ .OUTPUTS
268
+ System.String[] - zero or more error strings.
269
+ #>
270
+ [CmdletBinding()]
271
+ [OutputType([string[]])]
272
+ param(
273
+ [Parameter(Mandatory = $true)]
274
+ [string[]] $WaivedTool,
275
+
276
+ [Parameter(Mandatory = $true)]
277
+ [AllowNull()]
278
+ [object] $PotentialRecord
279
+ )
280
+
281
+ $recordIsValid = $false
282
+ if ($PotentialRecord -is [string]) {
283
+ $record = [string]$PotentialRecord
284
+ $recordIsValid = $record.StartsWith($script:POTENTIAL_RECORD_PREFIX, [System.StringComparison]::Ordinal) -and $record.EndsWith($script:POTENTIAL_RECORD_SUFFIX, [System.StringComparison]::Ordinal)
285
+ }
286
+ if ($recordIsValid) { return [string[]]@() }
287
+
288
+ $errors = [System.Collections.Generic.List[string]]::new()
289
+ $reported = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
290
+ foreach ($tool in $WaivedTool) {
291
+ if (($script:PROMOTION_ENTRY_TOOLS -ccontains $tool) -and -not $reported.Contains($tool)) {
292
+ $errors.Add("Checkpoint issue_adoption.potential_record must name a markdown file under docs/features/potential/ when waiving $tool.")
293
+ [void]$reported.Add($tool)
294
+ }
295
+ }
296
+ return $errors.ToArray()
297
+ }
298
+
299
+ function Get-OrchestratorStateIssueAdoptionResult {
300
+ <#
301
+ .SYNOPSIS
302
+ Validate the checkpoint's issue_adoption record and resolve its waivers.
303
+ .DESCRIPTION
304
+ Public entry mirroring resolve_issue_adoption. Absent key: no errors and
305
+ no waivers. A present value that is not an object (null included) yields
306
+ only the not-an-object error. Otherwise rules 2 to 9 accumulate errors in
307
+ order, and the waived-tool set is populated only when no error was found.
308
+ .PARAMETER State
309
+ The parsed checkpoint object.
310
+ .PARAMETER RouteId
311
+ The selected route id, interpolated into route errors.
312
+ .PARAMETER RequiredMcpTool
313
+ The route's required MCP tools after promotion-type resolution.
314
+ .PARAMETER SuccessfulTool
315
+ Tools that hold a successful MCP receipt in the checkpoint.
316
+ .OUTPUTS
317
+ System.Collections.Hashtable with keys Errors (string[]) and WaivedTools (string[]).
318
+ #>
319
+ [CmdletBinding()]
320
+ [OutputType([hashtable])]
321
+ param(
322
+ [Parameter(Mandatory = $true)]
323
+ [psobject] $State,
324
+
325
+ [Parameter(Mandatory = $true)]
326
+ [string] $RouteId,
327
+
328
+ [Parameter(Mandatory = $true)]
329
+ [AllowEmptyCollection()]
330
+ [string[]] $RequiredMcpTool,
331
+
332
+ [Parameter(Mandatory = $true)]
333
+ [AllowEmptyCollection()]
334
+ [string[]] $SuccessfulTool
335
+ )
336
+
337
+ $member = Get-CheckpointObjectMember -Owner $State -Name $script:ISSUE_ADOPTION_KEY
338
+ if (-not $member.Present) {
339
+ return @{ Errors = [string[]]@(); WaivedTools = [string[]]@() }
340
+ }
341
+
342
+ $adoption = $member.Value
343
+ if (-not (Test-CheckpointObjectValue -Value $adoption)) {
344
+ return @{ Errors = [string[]]@($script:ERROR_NOT_OBJECT); WaivedTools = [string[]]@() }
345
+ }
346
+
347
+ $errors = [System.Collections.Generic.List[string]]::new()
348
+ $errors.AddRange([string[]]@(Get-AdoptionIssueIdentityError -Adoption $adoption -State $State))
349
+ $errors.AddRange([string[]]@(Get-AdoptionProvenanceError -Adoption $adoption))
350
+
351
+ $waived = Get-AdoptionWaivedToolList -Value (Get-CheckpointObjectMember -Owner $adoption -Name 'waived_tools').Value
352
+ if (-not $waived.Ok) {
353
+ # A malformed list stops rule 8 and skips rule 9 entirely.
354
+ $errors.Add($script:ERROR_WAIVED_TOOLS_SHAPE)
355
+ return @{ Errors = $errors.ToArray(); WaivedTools = [string[]]@() }
356
+ }
357
+
358
+ $errors.AddRange([string[]]@(Get-AdoptionWaivedToolError -WaivedTool $waived.Value -RouteId $RouteId -RequiredMcpTool $RequiredMcpTool -SuccessfulTool $SuccessfulTool))
359
+ $potentialRecord = (Get-CheckpointObjectMember -Owner $adoption -Name 'potential_record').Value
360
+ $errors.AddRange([string[]]@(Get-AdoptionPotentialRecordError -WaivedTool $waived.Value -PotentialRecord $potentialRecord))
361
+
362
+ if ($errors.Count -gt 0) {
363
+ return @{ Errors = $errors.ToArray(); WaivedTools = [string[]]@() }
364
+ }
365
+
366
+ # The waived-tool set is the distinct entries in first-occurrence order.
367
+ $distinct = [System.Collections.Generic.List[string]]::new()
368
+ foreach ($tool in $waived.Value) {
369
+ if (-not $distinct.Contains($tool)) { $distinct.Add($tool) }
370
+ }
371
+ return @{ Errors = [string[]]@(); WaivedTools = $distinct.ToArray() }
372
+ }
373
+
374
+ # Only the family entry point is exported; the rule helpers stay private.
375
+ Export-ModuleMember -Function Get-OrchestratorStateIssueAdoptionResult
@@ -37,6 +37,7 @@ $ErrorActionPreference = 'Stop'
37
37
  # module's directory so the import travels with the pushed-down pack regardless
38
38
  # of the consumer repository's working directory.
39
39
  Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateCheckpointValue.psm1') -Force -ErrorAction Stop
40
+ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'OrchestratorStateRemediationAccounting.psm1') -Force -ErrorAction Stop
40
41
 
41
42
  # The eight keys every list-form delegation receipt must carry. Pinned to
42
43
  # REQUIRED_RECEIPT_KEYS in scripts/dev_tools/validate_orchestrator_state.py.
@@ -290,12 +291,15 @@ function Get-RemediationCycleError {
290
291
  function Get-OrchestratorStateRemediationLoopError {
291
292
  <#
292
293
  .SYNOPSIS
293
- Return the remediation_loop errors (inventory rows U6.R1-U6.R4).
294
+ Return the remediation_loop errors (inventory rows U6.R1-U6.R4, R5-R11).
294
295
  .DESCRIPTION
295
296
  Public entry mirroring _validate_remediation_loop. A non-object
296
- remediation_loop, or a cycles value that is not a list, carries no cycles
297
- to validate and deliberately yields ZERO errors, matching the Python
298
- tolerance rather than fabricating a structural error.
297
+ remediation_loop deliberately yields ZERO errors, matching the Python
298
+ tolerance rather than fabricating a structural error. When cycles is a
299
+ list each cycle is validated independently (U6.R1-U6.R4); the issue #484
300
+ review-outcome and accounting invariants R5-R11 then run through
301
+ Get-OrchestratorStateRemediationAccountingError with the cycle list, or
302
+ $null when cycles is absent or not a list.
299
303
  .PARAMETER Value
300
304
  The raw deserialized value of the checkpoint's remediation_loop key.
301
305
  .OUTPUTS
@@ -313,21 +317,24 @@ function Get-OrchestratorStateRemediationLoopError {
313
317
 
314
318
  if (-not (Test-CheckpointObjectValue -Value $Value)) { return $errors.ToArray() }
315
319
  $cycles = (Get-CheckpointObjectMember -Owner $Value -Name $script:REMEDIATION_CYCLES_KEY).Value
316
- if (-not (Test-CheckpointListValue -Value $cycles)) { return $errors.ToArray() }
317
-
318
- # Validate each cycle independently so a malformed entry does not mask the
319
- # errors of the cycles that follow it.
320
- $index = 0
321
- foreach ($cycle in @($cycles)) {
322
- if (-not (Test-CheckpointObjectValue -Value $cycle)) {
323
- $errors.Add("Checkpoint remediation cycle #$index must be an object.")
320
+ $cycleList = $null
321
+ if (Test-CheckpointListValue -Value $cycles) {
322
+ $cycleList = $cycles
323
+ # Validate each cycle independently so a malformed entry does not mask the
324
+ # errors of the cycles that follow it.
325
+ $index = 0
326
+ foreach ($cycle in @($cycles)) {
327
+ if (-not (Test-CheckpointObjectValue -Value $cycle)) {
328
+ $errors.Add("Checkpoint remediation cycle #$index must be an object.")
329
+ $index++
330
+ continue
331
+ }
332
+ $errors.AddRange([string[]]@(Get-RemediationCycleError -Index $index -Cycle $cycle))
324
333
  $index++
325
- continue
326
334
  }
327
- $errors.AddRange([string[]]@(Get-RemediationCycleError -Index $index -Cycle $cycle))
328
- $index++
329
335
  }
330
336
 
337
+ $errors.AddRange([string[]]@(Get-OrchestratorStateRemediationAccountingError -RemediationLoop $Value -Cycle $cycleList))
331
338
  return $errors.ToArray()
332
339
  }
333
340