@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,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
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|