@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.
- package/out/mcp-server.js +1139 -133
- package/package.json +4 -3
- package/resources/claude-customizations/.claude/agents/feature-review.md +10 -1
- package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -3
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +18 -6
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +3 -3
- package/resources/claude-customizations/.claude/hooks/{enforce-powershell-batch-budget-route.ps1 → enforce-batch-budget-route.ps1} +12 -10
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +221 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +42 -66
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +58 -10
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +144 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +36 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +179 -27
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +21 -38
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +4 -4
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +58 -10
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +59 -9
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +114 -37
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +3 -3
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +99 -64
- package/resources/claude-customizations/.claude/lib/bash/abandon-parallel-item.sh +176 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConflict.psm1 +193 -14
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +51 -28
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +5 -8
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +375 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
- package/resources/claude-customizations/.claude/lib/parallel-drift/Invoke-ParallelDriftDetection.ps1 +336 -0
- package/resources/claude-customizations/.claude/lib/parallel-drift/ParallelDrift.psm1 +467 -0
- package/resources/claude-customizations/.claude/lib/parallel-drift/ParallelDriftHalt.psm1 +388 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/EpicScopeResolution.psm1 +53 -32
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +19 -4
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +497 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +119 -3
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +21 -0
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +1 -1
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +8 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +169 -5
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +4 -15
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +15 -6
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -0
- package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +4 -0
- package/resources/claude-customizations/.claude/skills/invoke-python-engineer/SKILL.md +6 -3
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +33 -13
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +50 -21
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +10 -10
- package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +11 -35
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +5 -1
- package/resources/claude-customizations/pack-manifests/core.json +10 -0
- package/resources/claude-customizations/pack-manifests/powershell.json +0 -1
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +5 -3
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +3 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +2 -3
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +30 -7
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +18 -3
- package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +10 -34
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-orchestrator.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-batch-budget-route.ps1 +139 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +4 -124
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +169 -79
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +1 -0
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +4 -4
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +7 -8
- package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +3 -3
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +8 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
- 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.
|
|
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) {
|