@danmoisan/drm-copilot-mcp 1.1.26 → 1.1.27
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 +170 -52
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +3 -3
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +2 -2
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +7 -7
- package/resources/claude-customizations/.claude/agents/feature-review.md +6 -3
- package/resources/claude-customizations/.claude/agents/orchestrator.md +11 -7
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +7 -7
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +6 -6
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-review.ps1 +699 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +16 -1
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +50 -16
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -1
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +4 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +51 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +5 -2
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +116 -4
- package/resources/claude-customizations/.claude/rules/csharp.md +8 -8
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +28 -2
- package/resources/claude-customizations/.claude/rules/powershell.md +2 -2
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +8 -12
- package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +14 -15
- package/resources/claude-customizations/.claude/skills/epic-progress-report/SKILL.md +338 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Logic.ps1 +248 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Metrics.ps1 +232 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.Render.ps1 +196 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.State.ps1 +286 -0
- package/resources/claude-customizations/.claude/skills/epic-progress-report/scripts/Get-EpicProgressReport.ps1 +475 -0
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +18 -13
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +21 -9
- package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +5 -5
- package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/invoke-python-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +24 -2
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +8 -0
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +16 -17
- package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +15 -16
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +1 -1
- package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +6 -6
- package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/pack-manifests/core.json +7 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +8 -12
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +18 -13
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +5 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +18 -5
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +24 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +16 -1
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +15 -16
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +14 -15
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-di-unit-test-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +7 -7
- package/resources/codex-and-agents-customizations/.codex/agents/pytest-unit-test-coding.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-executor.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-execution-only-typed.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-orchestrator.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate-review.ps1 +699 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +29 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +51 -4
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +6 -6
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +1 -0
- package/resources/customizations/.github/agents/5.1-Beast-adjusted.agent.md +1 -1
- package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +20 -26
- package/resources/customizations/.github/agents/atomic_executor.agent.md +4 -4
- package/resources/customizations/.github/agents/atomic_planning.agent.md +4 -4
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
- package/resources/customizations/.github/agents/commit-steward.agent.md +1 -1
- package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +14 -14
- package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +4 -4
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +19 -22
- package/resources/customizations/.github/agents/epic-review.agent.md +1 -1
- package/resources/customizations/.github/agents/gpt-5-beast-mode.agent.md +3 -3
- package/resources/customizations/.github/agents/orchestrator.agent.md +8 -8
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +12 -12
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +4 -4
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -6
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +21 -24
- package/resources/customizations/.github/agents/pytest-unit-test-coding.agent.md +13 -17
- package/resources/customizations/.github/agents/python-atomic-executor.agent.md +11 -11
- package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +14 -17
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +7 -7
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +17 -20
- package/resources/customizations/.github/agents/staged-review.agent.md +2 -2
- package/resources/customizations/.github/agents/tdd-green.agent.md +1 -1
- package/resources/customizations/.github/agents/tdd-red.agent.md +3 -3
- package/resources/customizations/.github/agents/tdd-refactor.agent.md +2 -2
- package/resources/customizations/.github/agents/typescript-engineer.agent.md +3 -3
- package/resources/customizations/.github/codex/execute-hard-lock.prompt.md +3 -3
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +1 -1
- package/resources/customizations/.github/instructions/powershell-unit-test.instructions.md +1 -1
- package/resources/customizations/.github/instructions/python-code-change.instructions.md +5 -5
- package/resources/customizations/.github/instructions/python-suppressions.instructions.md +3 -3
- package/resources/customizations/.github/instructions/python-unit-test.instructions.md +1 -1
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +2 -2
- package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +2 -2
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +2 -2
- package/resources/customizations/.github/prompts/review-feature.prompt.md +1 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +8 -12
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +18 -13
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +15 -2
- package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +4 -4
- package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +3 -3
- package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +2 -2
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +2 -2
- package/resources/powershell/PoshQC/PoshQC.psm1 +3 -3
- package/resources/powershell/PoshQC/README.md +8 -8
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -2
- package/resources/templates/policy_audit/AGENTS.md +9 -10
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +19 -20
|
@@ -45,7 +45,11 @@
|
|
|
45
45
|
enqueues the pull request; only a pure --disable-auto is out of scope. The predicate and the
|
|
46
46
|
PR selector reader live in enforce-epic-merge-gate-command.ps1.
|
|
47
47
|
|
|
48
|
-
Design decision: branches 1-4 trust the on-disk checkpoint and
|
|
48
|
+
Design decision: without review_mode concurrent, branches 1-4 trust the on-disk checkpoint and
|
|
49
|
+
never call gh. Under that key the review guard (enforce-epic-merge-gate-review.ps1, issue #1097)
|
|
50
|
+
runs before branch 1 and makes one bounded gh pr view call and at most two git calls, and it
|
|
51
|
+
denies a merge with no passing review at a current head. Its shape check precedes the
|
|
52
|
+
out-of-scope allow and denies text that could be a merge and cannot be bound. The green-CI
|
|
49
53
|
branch makes at most one bounded gh pr view call, only after its pure stages A to C pass.
|
|
50
54
|
Its parallel exclusion is best-effort: the Parallel mode: true marker is in the delegation
|
|
51
55
|
prompt, not in a Bash payload, so a parallel child that no checkpoint records yet is not
|
|
@@ -100,6 +104,8 @@ try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-command.ps1') } catch
|
|
|
100
104
|
try { . (Join-Path $PSScriptRoot 'hook-docs-only-diff.ps1') } catch { Add-HookDependencyFailure -Name 'hook-docs-only-diff.ps1' -ErrorRecord $_ }
|
|
101
105
|
# Green-CI standalone merge branch: pure checks, the live-head seam, and the stage orchestrator (issue #997).
|
|
102
106
|
try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-green-ci.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-green-ci.ps1' -ErrorRecord $_ }
|
|
107
|
+
# Review guard under review_mode concurrent, byte-identical to the Codex copy (issue #1097).
|
|
108
|
+
try { . (Join-Path $PSScriptRoot 'enforce-epic-merge-gate-review.ps1') } catch { Add-HookDependencyFailure -Name 'enforce-epic-merge-gate-review.ps1' -ErrorRecord $_ }
|
|
103
109
|
|
|
104
110
|
function ConvertFrom-EpicMergeGateJson {
|
|
105
111
|
<#
|
|
@@ -349,6 +355,9 @@ function Invoke-EpicMergeGateDecision {
|
|
|
349
355
|
# Scope (issue #952): every gh pr merge invocation except a pure --disable-auto, and every gh api
|
|
350
356
|
# merge or enqueue mutation, is gated; Test-EpicMergeGateCommandInScope holds the predicate.
|
|
351
357
|
if (-not (Test-EpicMergeGateCommandInScope -CommandText $commandText)) {
|
|
358
|
+
if (-not (Test-EpicMergeGateReviewMergeText -CommandText $commandText)) { return Get-EpicMergeGateAllowDecision }
|
|
359
|
+
$unscopedDecision = Get-EpicMergeGateReviewUnscopedDecision -CommandText $commandText
|
|
360
|
+
if ($unscopedDecision.Denied) { return Get-EpicMergeGateBlockDecision -Reason $unscopedDecision.Reason }
|
|
352
361
|
return Get-EpicMergeGateAllowDecision
|
|
353
362
|
}
|
|
354
363
|
|
|
@@ -366,6 +375,12 @@ function Invoke-EpicMergeGateDecision {
|
|
|
366
375
|
$childRoot = if (@('SessionRoot', 'OtherWorktree') -contains $itemTarget.Status) { $itemTarget.WorktreeRoot } else { $null }
|
|
367
376
|
}
|
|
368
377
|
$childCheckpoint = if ($childRoot) { ConvertFrom-EpicMergeGateJson -Raw (Get-ChildOrchestratorCheckpointContent -Path (Get-WorktreeRunCheckpointPath -Kind item -WorktreeRoot $childRoot)) } else { $null }
|
|
378
|
+
|
|
379
|
+
# Review guard (issue #1097): inert without review_mode concurrent, so it precedes every allow branch.
|
|
380
|
+
$reviewDecision = Get-EpicMergeGateReviewShapeDecision -CommandText $commandText -KnownCheckpoint $childCheckpoint -KnownPrNumber $commandPrNumber -ReadCheckpoint ${function:Read-EpicMergeGateReviewItemCheckpoint}
|
|
381
|
+
if (-not $reviewDecision.Denied) { $reviewDecision = Get-EpicMergeGateReviewDecision -Checkpoint $childCheckpoint -CommandPrNumber $commandPrNumber -GhRoot $sessionRoot -GitRoot $childRoot }
|
|
382
|
+
if ($reviewDecision.Denied) { return Get-EpicMergeGateBlockDecision -Reason $reviewDecision.Reason }
|
|
383
|
+
|
|
369
384
|
if ((Test-ChildCheckpointAllowsEpicMerge -Checkpoint $childCheckpoint) -and
|
|
370
385
|
(Test-ChildCheckpointPrGateBinding -Checkpoint $childCheckpoint -CommandPrNumber $commandPrNumber)) {
|
|
371
386
|
return Get-EpicMergeGateAllowDecision
|
package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
Artifact-path rules, changed-language set, and coverage-row rule for the
|
|
3
|
+
Artifact-path rules, changed-language set, narrowing-line reader, and coverage-row rule for the
|
|
4
|
+
feature-review coverage hook.
|
|
4
5
|
|
|
5
6
|
.DESCRIPTION
|
|
6
7
|
Dot-sourced by validate-feature-review-coverage.ps1. Defines the advertised-path reader
|
|
7
8
|
(Get-ReviewArtifactPathFromOutput), the active-feature location rule (Get-ReviewArtifactInfo),
|
|
8
|
-
the changed-language reader for the PR context summary (Get-ChangedLanguageSet),
|
|
9
|
-
per-language coverage-row
|
|
9
|
+
the changed-language reader for the PR context summary (Get-ChangedLanguageSet), the
|
|
10
|
+
scope-narrowing line reader (Get-CoverageNarrowingLine), and the per-language coverage-row
|
|
11
|
+
rule (Test-LanguageCoverageRow).
|
|
10
12
|
|
|
11
13
|
The file has no param() block, writes nothing to the output stream, and runs no top-level
|
|
12
14
|
statement other than function definitions.
|
|
@@ -95,6 +97,50 @@ function Get-ChangedLanguageSet {
|
|
|
95
97
|
return $langs
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
function Get-CoverageNarrowingLine {
|
|
101
|
+
[CmdletBinding()]
|
|
102
|
+
[OutputType([string])]
|
|
103
|
+
param(
|
|
104
|
+
[Parameter(Mandatory = $true)]
|
|
105
|
+
[AllowEmptyString()]
|
|
106
|
+
[string[]]$Lines,
|
|
107
|
+
|
|
108
|
+
[Parameter(Mandatory = $true)]
|
|
109
|
+
[string]$LabelPattern,
|
|
110
|
+
|
|
111
|
+
[Parameter(Mandatory = $true)]
|
|
112
|
+
[string]$Language
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Sanctioned narrowing text is not a scope narrowing by the audit: a line inside a
|
|
116
|
+
# '## Rejected Scope Narrowing' section (caller text recorded verbatim), and a PowerShell
|
|
117
|
+
# line naming branch coverage but not line coverage (Pester measures no branch coverage).
|
|
118
|
+
# The policy-audit template prescribes the no-pre-change-run record in three positions only,
|
|
119
|
+
# so the record is removed there and stays a narrowing form everywhere else.
|
|
120
|
+
$narrowingPattern = '(?i)(informational only|context only|out of plan scope|out of scope|not applicable|\bN/A\b|\bUNVERIFIED\b)'
|
|
121
|
+
$recordPatterns = @(
|
|
122
|
+
'(?<=(?:\bBaseline|\bbaseline coverage artifact):\s*)N/A - no pre-change run'
|
|
123
|
+
'(?<=^\s*\|(?:[^|]*\|){4}\s*)N/A - no pre-change run(?=\s*\|)'
|
|
124
|
+
'(?<!:\s*)`N/A - no pre-change run`'
|
|
125
|
+
)
|
|
126
|
+
$insideRejectedSection = $false
|
|
127
|
+
foreach ($line in $Lines) {
|
|
128
|
+
if ($line -match '^##\s') { $insideRejectedSection = $line -match '^##\s+Rejected Scope Narrowing\b' }
|
|
129
|
+
elseif ($insideRejectedSection) { continue }
|
|
130
|
+
if ($line -notmatch $LabelPattern -or $line -notmatch '(?i)(coverage|lcov|line[s]?\s+hit|pester)') { continue }
|
|
131
|
+
$reducedLine = $line
|
|
132
|
+
foreach ($recordPattern in $recordPatterns) { $reducedLine = [regex]::Replace($reducedLine, $recordPattern, '') }
|
|
133
|
+
# Tested on the original line, because the removals above strip the record it names.
|
|
134
|
+
if ($line.Contains('Baseline: N/A - no pre-change run')) {
|
|
135
|
+
$reducedLine = [regex]::Replace($reducedLine, '(?<![\w/-])Change: N/A', '')
|
|
136
|
+
$reducedLine = $reducedLine.Replace('New/changed-code coverage: N/A - no production file changed', '')
|
|
137
|
+
}
|
|
138
|
+
if ($reducedLine -notmatch $narrowingPattern) { continue }
|
|
139
|
+
if ($Language -eq 'PowerShell' -and $line -match '(?i)\bbranch\b' -and $line -notmatch '(?i)\bline\s+coverage\b') { continue }
|
|
140
|
+
$line
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
98
144
|
function Test-LanguageCoverageRow {
|
|
99
145
|
[OutputType([System.Collections.Hashtable])]
|
|
100
146
|
param(
|
|
@@ -141,19 +187,7 @@ function Test-LanguageCoverageRow {
|
|
|
141
187
|
}
|
|
142
188
|
}
|
|
143
189
|
|
|
144
|
-
|
|
145
|
-
# '## Rejected Scope Narrowing' section (caller text recorded verbatim), and a PowerShell
|
|
146
|
-
# line naming branch coverage but not line coverage (Pester measures no branch coverage).
|
|
147
|
-
$narrowingPattern = '(?i)(informational only|context only|out of plan scope|out of scope|not applicable|\bN/A\b|\bUNVERIFIED\b)'
|
|
148
|
-
$insideRejectedSection = $false
|
|
149
|
-
$narrowing = foreach ($line in $lines) {
|
|
150
|
-
if ($line -match '^##\s') { $insideRejectedSection = $line -match '^##\s+Rejected Scope Narrowing\b' }
|
|
151
|
-
elseif ($insideRejectedSection) { continue }
|
|
152
|
-
if ($line -notmatch $labelPattern -or $line -notmatch '(?i)(coverage|lcov|line[s]?\s+hit|pester)' -or $line -notmatch $narrowingPattern) { continue }
|
|
153
|
-
if ($Language -eq 'PowerShell' -and $line -match '(?i)\bbranch\b' -and $line -notmatch '(?i)\bline\s+coverage\b') { continue }
|
|
154
|
-
$line
|
|
155
|
-
}
|
|
156
|
-
$narrowing = @($narrowing)
|
|
190
|
+
$narrowing = @(Get-CoverageNarrowingLine -Lines $lines -LabelPattern $labelPattern -Language $Language)
|
|
157
191
|
if ($narrowing.Count -gt 0) {
|
|
158
192
|
$first = ($narrowing | Select-Object -First 1).ToString().Trim()
|
|
159
193
|
return @{
|
package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1
CHANGED
|
@@ -297,7 +297,8 @@ function Get-OrchestratorStatePrCreationReadinessError {
|
|
|
297
297
|
.DESCRIPTION
|
|
298
298
|
Private readiness check mirroring validate_orchestrator_state_pr_creation_readiness in
|
|
299
299
|
_orchestrator_state_pr_creation_readiness.py: steps 5-8 must not be pending, blocked, or
|
|
300
|
-
blocked_remediation_loop_limit
|
|
300
|
+
blocked_remediation_loop_limit, except a pending step 7 under review_mode concurrent;
|
|
301
|
+
blocked_reason must be `none` or absent; and the
|
|
301
302
|
local_execution_overrides / delegation_bypasses lists must be empty when present. It does
|
|
302
303
|
not enforce completion, CI, PR, or routing-contract gates.
|
|
303
304
|
.PARAMETER State
|
|
@@ -313,11 +314,15 @@ function Get-OrchestratorStatePrCreationReadinessError {
|
|
|
313
314
|
)
|
|
314
315
|
|
|
315
316
|
$errors = [System.Collections.Generic.List[string]]::new()
|
|
317
|
+
$stateNames = @($State.PSObject.Properties | ForEach-Object { $_.Name })
|
|
318
|
+
$reviewMode = if ($stateNames -ccontains 'review_mode') { (Get-OrchestratorStateField -State $State -Name 'review_mode').Value } else { $null }
|
|
316
319
|
|
|
317
320
|
# Reject an upstream step recorded as pending, blocked, or blocked_remediation_loop_limit; steps
|
|
318
321
|
# 5-8 must have finished before the first PR of a branch is created.
|
|
319
322
|
foreach ($key in $script:PR_CREATION_READY_STEP_KEYS) {
|
|
320
323
|
$field = Get-OrchestratorStateField -State $State -Name $key
|
|
324
|
+
# Under review_mode concurrent the review runs beside CI and the merge guard holds the merge.
|
|
325
|
+
if ($key -ceq 'step7_status' -and $field.Value -ceq 'pending' -and $reviewMode -is [string] -and $reviewMode -ceq 'concurrent') { continue }
|
|
321
326
|
if ($field.Present -and (@('pending', 'blocked', 'blocked_remediation_loop_limit') -contains $field.Value)) {
|
|
322
327
|
$errors.Add("Checkpoint PR-creation readiness validation failed: $key is $($field.Value).")
|
|
323
328
|
}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
C5 mandatory route phases
|
|
24
24
|
C6 the routing contract, from `OrchestratorStateRoutingContract.psm1`
|
|
25
25
|
C7 the preparation terminal contract
|
|
26
|
+
C8 the review record under review_mode concurrent
|
|
26
27
|
M1 model-routing receipt required once delegated
|
|
27
28
|
M2 a complexity assessment for every matched receipt phase
|
|
28
29
|
M3 per-entry re-validation of the U6.C and U6.M families
|
|
@@ -408,8 +409,8 @@ function Test-OrchestratorStateCompletionReadiness {
|
|
|
408
409
|
$errors.AddRange([string[]]@(Get-OrchestratorStateUnconditionalError -State $state))
|
|
409
410
|
|
|
410
411
|
# C family, in the reference's require_complete order: step statuses,
|
|
411
|
-
# blocked_reason, pr_gate, ci_gate, phase completeness, routing contract,
|
|
412
|
-
#
|
|
412
|
+
# blocked_reason, pr_gate, ci_gate, phase completeness, routing contract, the
|
|
413
|
+
# preparation terminal contract, and the concurrent review record.
|
|
413
414
|
$errors.AddRange([string[]]@(Get-OrchestratorStateCompletionStepStatusError -State $state))
|
|
414
415
|
$errors.AddRange([string[]]@(Get-OrchestratorStateCompletionBlockedReasonError -State $state))
|
|
415
416
|
$errors.AddRange([string[]]@(Get-OrchestratorStateCompletionPrGateError -State $state))
|
|
@@ -417,6 +418,7 @@ function Test-OrchestratorStateCompletionReadiness {
|
|
|
417
418
|
$errors.AddRange([string[]]@(Get-OrchestratorStatePhaseCompletenessError -State $state))
|
|
418
419
|
$errors.AddRange([string[]]@(Get-OrchestratorStateRoutingContractError -State $state))
|
|
419
420
|
$errors.AddRange([string[]]@(Get-OrchestratorStatePreparationTerminalError -State $state))
|
|
421
|
+
$errors.AddRange([string[]]@(Get-OrchestratorStateCompletionConcurrentReviewError -State $state))
|
|
420
422
|
|
|
421
423
|
# M family. The gate's M3 leg re-invokes the U6.C and U6.M validators, so its
|
|
422
424
|
# output is merged under the PD-2 single-emission rule rather than appended
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
Portable completion-gate checks C1, C2, C3, C4, C5, and
|
|
3
|
+
Portable completion-gate checks C1, C2, C3, C4, C5, C7, and C8.
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
6
|
Destination-runtime PowerShell port of the `--require-complete` checks the
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
C5.1 mandatory route phases, from a static map
|
|
20
20
|
C7.1 preparation terminal next_step (value-gated, repr rendering)
|
|
21
21
|
C7.2 preparation terminal step statuses (value-gated, repr rendering)
|
|
22
|
+
C8 last review outcome under review_mode concurrent (value-gated)
|
|
22
23
|
|
|
23
24
|
Route gating for C3 and C4 is resolved through
|
|
24
25
|
`OrchestratorStateRoutingMatrix.psm1`, implementing deviation PD-1: the gate
|
|
@@ -407,6 +408,53 @@ function Get-OrchestratorStatePreparationTerminalError {
|
|
|
407
408
|
return $errors.ToArray()
|
|
408
409
|
}
|
|
409
410
|
|
|
411
|
+
function Get-OrchestratorStateCompletionConcurrentReviewError {
|
|
412
|
+
<#
|
|
413
|
+
.SYNOPSIS
|
|
414
|
+
Return the review-record error under review_mode concurrent (row C8).
|
|
415
|
+
.DESCRIPTION
|
|
416
|
+
Mirrors validate_concurrent_review_completion. Only the exact string concurrent
|
|
417
|
+
activates the check, and only the final review_outcomes element counts. The head
|
|
418
|
+
error is reported only when the verdict error does not apply. The check does no
|
|
419
|
+
git work: head currency stays with the merge guard.
|
|
420
|
+
.PARAMETER State
|
|
421
|
+
The parsed checkpoint object.
|
|
422
|
+
.OUTPUTS
|
|
423
|
+
System.String[] - zero or one error string.
|
|
424
|
+
#>
|
|
425
|
+
[CmdletBinding()]
|
|
426
|
+
[OutputType([string[]])]
|
|
427
|
+
param(
|
|
428
|
+
[Parameter(Mandatory = $true)]
|
|
429
|
+
[psobject] $State
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
$mode = $null
|
|
433
|
+
if ((Get-CheckpointObjectMemberName -Owner $State) -ccontains 'review_mode') { $mode = (Get-CheckpointObjectMember -Owner $State -Name 'review_mode').Value }
|
|
434
|
+
if (-not (($mode -is [string]) -and ($mode -ceq 'concurrent'))) {
|
|
435
|
+
return [string[]]@()
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
# A missing loop, a non-list value, an empty list, and a non-object last entry all
|
|
439
|
+
# leave $last unset, so each reports the verdict error.
|
|
440
|
+
$last = $null
|
|
441
|
+
$loop = (Get-CheckpointObjectMember -Owner $State -Name 'remediation_loop').Value
|
|
442
|
+
$outcomes = (Get-CheckpointObjectMember -Owner $loop -Name 'review_outcomes').Value
|
|
443
|
+
if ((Test-CheckpointListValue -Value $outcomes) -and $outcomes.Count -gt 0) {
|
|
444
|
+
$last = $outcomes[$outcomes.Count - 1]
|
|
445
|
+
}
|
|
446
|
+
$verdict = (Get-CheckpointObjectMember -Owner $last -Name 'verdict').Value
|
|
447
|
+
if (-not (($verdict -is [string]) -and ($verdict -ceq 'PASS'))) {
|
|
448
|
+
return [string[]]@('Checkpoint completion validation failed: review_mode concurrent requires a last review_outcomes entry with verdict PASS.')
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
$head = (Get-CheckpointObjectMember -Owner $last -Name 'head_sha').Value
|
|
452
|
+
if (-not (($head -is [string]) -and ($head -cmatch '\A[0-9a-f]{40}([0-9a-f]{24})?\z'))) {
|
|
453
|
+
return [string[]]@('Checkpoint completion validation failed: review_mode concurrent requires head_sha on the last review_outcomes entry.')
|
|
454
|
+
}
|
|
455
|
+
return [string[]]@()
|
|
456
|
+
}
|
|
457
|
+
|
|
410
458
|
# Each check family is exported individually so the completion entry point can
|
|
411
459
|
# compose them in the Python reference's order; the gate-key helper stays private.
|
|
412
460
|
Export-ModuleMember -Function `
|
|
@@ -415,4 +463,5 @@ Export-ModuleMember -Function `
|
|
|
415
463
|
Get-OrchestratorStateCompletionPrGateError, `
|
|
416
464
|
Get-OrchestratorStateCompletionCiGateError, `
|
|
417
465
|
Get-OrchestratorStatePhaseCompletenessError, `
|
|
418
|
-
Get-OrchestratorStatePreparationTerminalError
|
|
466
|
+
Get-OrchestratorStatePreparationTerminalError, `
|
|
467
|
+
Get-OrchestratorStateCompletionConcurrentReviewError
|
|
@@ -264,9 +264,12 @@ function Get-RemediationCycleError {
|
|
|
264
264
|
|
|
265
265
|
# Invariant 2: an execution status in the blocked set requires the nested
|
|
266
266
|
# preflight to report exactly the cleared status; a missing or non-object
|
|
267
|
-
# preflight cannot satisfy it.
|
|
267
|
+
# preflight cannot satisfy it. An exact light cycle runs no preflight and is
|
|
268
|
+
# checked by invariant 8 instead.
|
|
268
269
|
$executionStatus = (Get-CheckpointObjectMember -Owner $Cycle -Name 'execution_status').Value
|
|
269
|
-
|
|
270
|
+
$remediationPath = (Get-CheckpointObjectMember -Owner $Cycle -Name 'remediation_path').Value
|
|
271
|
+
$isLightCycle = ($remediationPath -is [string]) -and ([string]$remediationPath -ceq 'light')
|
|
272
|
+
if (-not $isLightCycle -and $executionStatus -is [string] -and
|
|
270
273
|
($script:EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT -contains [string]$executionStatus)) {
|
|
271
274
|
$preflight = (Get-CheckpointObjectMember -Owner $Cycle -Name 'preflight').Value
|
|
272
275
|
$preflightStatus = (Get-CheckpointObjectMember -Owner $preflight -Name 'final_status').Value
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
Destination-runtime PowerShell port of the issue #484 invariants the
|
|
7
7
|
authoritative Python validator applies to a checkpoint's remediation_loop:
|
|
8
8
|
the review-outcome rules R8a, R8b, R9a-R9d, and R10, and the accounting
|
|
9
|
-
rules R5, R6, R7a, R7b, and R11,
|
|
10
|
-
|
|
9
|
+
rules R5, R6, R7a, R7b, and R11, and the light-remediation invariant 8
|
|
10
|
+
(issue #1097), matching the error-string templates in
|
|
11
|
+
`scripts/dev_tools/_orchestrator_state_remediation_loop.py`,
|
|
12
|
+
`scripts/dev_tools/_orchestrator_state_light_cycle.py`, and the rules
|
|
11
13
|
document `.claude/rules/orchestrator-state.md`.
|
|
12
14
|
|
|
13
15
|
The receipts module calls the exported entry point after its unchanged
|
|
@@ -40,6 +42,14 @@ $script:CANDIDATE_APPLIED_KEY = 'candidate_applied'
|
|
|
40
42
|
$script:OPENED_BY_REVIEW_KEY = 'opened_by_review'
|
|
41
43
|
$script:COMPLETED_EXECUTION_STATUS = 'complete'
|
|
42
44
|
|
|
45
|
+
# Invariant 8 (light remediation) keys and limits. Pinned to the Python constants
|
|
46
|
+
# in _orchestrator_state_light_cycle.py.
|
|
47
|
+
$script:REMEDIATION_PATH_KEY = 'remediation_path'
|
|
48
|
+
$script:LIGHT_REMEDIATION_PATH = 'light'
|
|
49
|
+
$script:FULL_REMEDIATION_PATH = 'full'
|
|
50
|
+
$script:LIGHT_FINDING_LIMIT = 3
|
|
51
|
+
$script:CONTAINED_SCOPE = 'contained'
|
|
52
|
+
|
|
43
53
|
# Review verdicts and remediability classes in spec table order, and the two
|
|
44
54
|
# derived class partitions. Pinned to the Python constants of the same names.
|
|
45
55
|
$script:REVIEW_VERDICTS = @('PASS', 'REMEDIATION_REQUIRED', 'HALT_NON_REMEDIABLE', 'AWAITING_CI')
|
|
@@ -260,6 +270,106 @@ function Test-RemediationOpenedByReview {
|
|
|
260
270
|
return ($verdict -is [string]) -and ([string]$verdict -ceq $script:REMEDIATION_REQUIRED_VERDICT)
|
|
261
271
|
}
|
|
262
272
|
|
|
273
|
+
function Get-RemediationLightCycleError {
|
|
274
|
+
<#
|
|
275
|
+
.SYNOPSIS
|
|
276
|
+
Return the invariant 8 errors of every cycle that carries remediation_path.
|
|
277
|
+
.DESCRIPTION
|
|
278
|
+
Private helper mirroring validate_light_cycles (issue #1097). Per object cycle
|
|
279
|
+
whose key is present, in order: a value other than the exact string light or
|
|
280
|
+
full yields rule 1 alone; full yields nothing; light yields rule 2 (a preflight
|
|
281
|
+
key is present), rule 3 (opened_by_review is absent or fails the R11 predicate,
|
|
282
|
+
which skips rules 4 to 6), rule 4 (more than 3 findings; a non-list findings
|
|
283
|
+
value counts as empty), rule 5 per finding whose remediability is not exactly
|
|
284
|
+
autonomous, rule 6 per finding whose scope is not exactly contained, and rule 7
|
|
285
|
+
(the immediately prior element is an object whose remediation_path is exactly
|
|
286
|
+
light). Every string value is tested with -is [string] before -ceq, because
|
|
287
|
+
-ceq on an array filters rather than compares.
|
|
288
|
+
.PARAMETER Cycle
|
|
289
|
+
The loop's cycles list, or $null when cycles is absent or not a list.
|
|
290
|
+
.PARAMETER Outcomes
|
|
291
|
+
The raw review_outcomes value. May be $null.
|
|
292
|
+
.OUTPUTS
|
|
293
|
+
System.String[] - zero or more error strings.
|
|
294
|
+
#>
|
|
295
|
+
[CmdletBinding()]
|
|
296
|
+
[OutputType([string[]])]
|
|
297
|
+
param(
|
|
298
|
+
[Parameter(Mandatory = $true)]
|
|
299
|
+
[AllowNull()]
|
|
300
|
+
[AllowEmptyCollection()]
|
|
301
|
+
[object] $Cycle,
|
|
302
|
+
|
|
303
|
+
[Parameter(Mandatory = $true)]
|
|
304
|
+
[AllowNull()]
|
|
305
|
+
[object] $Outcomes
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
$errors = [System.Collections.Generic.List[string]]::new()
|
|
309
|
+
$cycleItems = @()
|
|
310
|
+
if ($null -ne $Cycle) { $cycleItems = @($Cycle) }
|
|
311
|
+
|
|
312
|
+
# Walk the cycles in order so each light cycle can see its immediate prior.
|
|
313
|
+
for ($index = 0; $index -lt $cycleItems.Count; $index++) {
|
|
314
|
+
$item = $cycleItems[$index]
|
|
315
|
+
if (-not (Test-CheckpointObjectValue -Value $item)) { continue }
|
|
316
|
+
$member = Get-CheckpointObjectMember -Owner $item -Name $script:REMEDIATION_PATH_KEY
|
|
317
|
+
if (-not $member.Present) { continue }
|
|
318
|
+
|
|
319
|
+
# Rule 1 routes by exact value: full has no further rule, and anything other
|
|
320
|
+
# than light is reported once and stops there.
|
|
321
|
+
$path = $member.Value
|
|
322
|
+
$isString = $path -is [string]
|
|
323
|
+
if ($isString -and ([string]$path -ceq $script:FULL_REMEDIATION_PATH)) { continue }
|
|
324
|
+
if (-not ($isString -and ([string]$path -ceq $script:LIGHT_REMEDIATION_PATH))) {
|
|
325
|
+
$errors.Add("Checkpoint remediation cycle #$index remediation_path must be light or full.")
|
|
326
|
+
continue
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
$prefix = "Checkpoint remediation cycle #$index remediation_path is light but"
|
|
330
|
+
if ((Get-CheckpointObjectMember -Owner $item -Name 'preflight').Present) {
|
|
331
|
+
$errors.Add("$prefix the cycle carries preflight.")
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
$opened = Get-CheckpointObjectMember -Owner $item -Name $script:OPENED_BY_REVIEW_KEY
|
|
335
|
+
if (-not $opened.Present -or -not (Test-RemediationOpenedByReview -OpenedByReview $opened.Value -Outcomes $Outcomes)) {
|
|
336
|
+
$errors.Add("$prefix opened_by_review does not name its opening review.")
|
|
337
|
+
} else {
|
|
338
|
+
$outcome = @($Outcomes)[[int]$opened.Value]
|
|
339
|
+
$findings = (Get-CheckpointObjectMember -Owner $outcome -Name 'findings').Value
|
|
340
|
+
$findingList = @()
|
|
341
|
+
if (Test-CheckpointListValue -Value $findings) { $findingList = @($findings) }
|
|
342
|
+
if ($findingList.Count -gt $script:LIGHT_FINDING_LIMIT) {
|
|
343
|
+
$errors.Add("$prefix its opening review has $($findingList.Count) findings; the limit is $($script:LIGHT_FINDING_LIMIT).")
|
|
344
|
+
}
|
|
345
|
+
# Report every finding a light cycle may not fix autonomously, then every
|
|
346
|
+
# finding whose fix is not contained; a non-object finding fails both.
|
|
347
|
+
foreach ($key in @('remediability', 'scope')) {
|
|
348
|
+
$required = if ($key -ceq 'remediability') { $script:REMEDIABLE_CLASS } else { $script:CONTAINED_SCOPE }
|
|
349
|
+
for ($findingIndex = 0; $findingIndex -lt $findingList.Count; $findingIndex++) {
|
|
350
|
+
$finding = $findingList[$findingIndex]
|
|
351
|
+
$value = $null
|
|
352
|
+
if (Test-CheckpointObjectValue -Value $finding) { $value = (Get-CheckpointObjectMember -Owner $finding -Name $key).Value }
|
|
353
|
+
if (-not (($value -is [string]) -and ([string]$value -ceq $required))) {
|
|
354
|
+
$suffix = if ($key -ceq 'remediability') { 'is not autonomous.' } else { 'scope is not contained.' }
|
|
355
|
+
$errors.Add("$prefix finding #$findingIndex $suffix")
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# Rule 7: two light cycles may not run back to back.
|
|
362
|
+
if ($index -gt 0 -and (Test-CheckpointObjectValue -Value $cycleItems[$index - 1])) {
|
|
363
|
+
$priorPath = (Get-CheckpointObjectMember -Owner $cycleItems[$index - 1] -Name $script:REMEDIATION_PATH_KEY).Value
|
|
364
|
+
if (($priorPath -is [string]) -and ([string]$priorPath -ceq $script:LIGHT_REMEDIATION_PATH)) {
|
|
365
|
+
$errors.Add("$prefix the prior cycle is light.")
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return $errors.ToArray()
|
|
371
|
+
}
|
|
372
|
+
|
|
263
373
|
function Get-OrchestratorStateRemediationAccountingError {
|
|
264
374
|
<#
|
|
265
375
|
.SYNOPSIS
|
|
@@ -268,8 +378,9 @@ function Get-OrchestratorStateRemediationAccountingError {
|
|
|
268
378
|
Public entry mirroring the issue #484 tail of _validate_remediation_loop.
|
|
269
379
|
Returns, in order: the review-outcome errors (R8a; otherwise per outcome
|
|
270
380
|
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
|
|
272
|
-
new keys present it
|
|
381
|
+
cycle in order, R5, R6, and R11; then R7a, otherwise R7b; then invariant 8
|
|
382
|
+
through Get-RemediationLightCycleError. With none of the new keys present it
|
|
383
|
+
returns nothing.
|
|
273
384
|
.PARAMETER RemediationLoop
|
|
274
385
|
The deserialized remediation_loop object.
|
|
275
386
|
.PARAMETER Cycle
|
|
@@ -329,6 +440,7 @@ function Get-OrchestratorStateRemediationAccountingError {
|
|
|
329
440
|
}
|
|
330
441
|
}
|
|
331
442
|
|
|
443
|
+
$errors.AddRange([string[]]@(Get-RemediationLightCycleError -Cycle $Cycle -Outcomes $outcomes))
|
|
332
444
|
return $errors.ToArray()
|
|
333
445
|
}
|
|
334
446
|
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
paths:
|
|
3
3
|
- "**/*.cs"
|
|
4
4
|
- "**/*.csproj"
|
|
5
|
-
description: C#-specific toolchain and coding standards (
|
|
5
|
+
description: C#-specific toolchain and coding standards (MSTest).
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# C# Code Standards
|
|
9
9
|
|
|
10
|
-
This rule file summarizes the C#-specific policies for this repository. It targets a host-neutral .NET foundation:
|
|
10
|
+
This rule file summarizes the C#-specific policies for this repository. It targets a host-neutral .NET foundation: MSTest, NSubstitute, FluentAssertions, `dotnet build`, the analyzer stack, `TimeProvider`, and uniform coverage thresholds.
|
|
11
11
|
|
|
12
12
|
## Toolchain
|
|
13
13
|
|
|
14
14
|
1. **Formatting — CSharpier**: All C# source files must be formatted with CSharpier. Do not use `dotnet format`. Command: `dotnet tool restore` followed by `dotnet csharpier check .` (or `dotnet csharpier .` to auto-format).
|
|
15
15
|
2. **Linting — .NET Analyzers**: C# code must pass Roslyn/.NET analyzer diagnostics. Analyzer enforcement is centralized in `Directory.Build.props` (`AnalysisLevel=latest-all`, `AnalysisMode=All`, `TreatWarningsAsErrors=true`). Command: `dotnet build` runs analyzers as part of the build.
|
|
16
16
|
3. **Type Checking — Nullable Analysis**: Nullable reference types are enabled solution-wide via `Directory.Build.props` (`Nullable=enable`, `TreatWarningsAsErrors=true`). Command: `dotnet build` enforces nullable warnings as errors.
|
|
17
|
-
4. **Testing —
|
|
17
|
+
4. **Testing — MSTest + NSubstitute + FluentAssertions**: Run tests with: `dotnet test --collect:"XPlat Code Coverage"`.
|
|
18
18
|
|
|
19
19
|
Run the toolchain in order: format → lint → type-check → architecture → test. Restart from step 1 if any step fails or changes files.
|
|
20
20
|
|
|
@@ -31,11 +31,11 @@ Run the toolchain in order: format → lint → type-check → architecture →
|
|
|
31
31
|
|
|
32
32
|
## Testing Standards
|
|
33
33
|
|
|
34
|
-
- Use **
|
|
35
|
-
- Use **`[
|
|
36
|
-
- Use **`
|
|
34
|
+
- Use **MSTest** (`Microsoft.VisualStudio.TestTools.UnitTesting`) as the test framework with `[TestClass]` and `[TestMethod]` attributes, on the VSTest runner (the `MSTest` package with `Microsoft.NET.Test.Sdk` and `coverlet.collector`).
|
|
35
|
+
- Use **`[TestMethod]` + `[DataRow]`** for parameterized tests.
|
|
36
|
+
- Use **`[ClassInitialize]`** to share expensive setup across tests within a class.
|
|
37
37
|
- Use **NSubstitute** for test doubles. Example: `var sut = Substitute.For<IService>(); sut.Get().Returns(value);`.
|
|
38
|
-
- Prefer **FluentAssertions** for assertions; use
|
|
38
|
+
- Prefer **FluentAssertions** for assertions; use MSTest `Assert` only when FluentAssertions is not practical.
|
|
39
39
|
- Follow Arrange–Act–Assert structure.
|
|
40
40
|
- No external dependencies in unit tests.
|
|
41
41
|
|
|
@@ -53,7 +53,7 @@ Run the toolchain in order: format → lint → type-check → architecture →
|
|
|
53
53
|
|
|
54
54
|
### Golden Tests
|
|
55
55
|
|
|
56
|
-
- **Verify.
|
|
56
|
+
- **Verify.MSTest**: required for T1 classifier-output modules, tested against a versioned corpus.
|
|
57
57
|
|
|
58
58
|
## Analyzer Stack
|
|
59
59
|
|
|
@@ -71,7 +71,7 @@ These invariants apply only when the checkpoint contains a top-level `remediatio
|
|
|
71
71
|
|
|
72
72
|
1. **Non-empty `plan_path`.** Each cycle's `plan_path` must be a non-empty string. A missing value, a non-string value, or an empty/whitespace-only string is a malformed cycle.
|
|
73
73
|
|
|
74
|
-
2. **Execution requires cleared preflight.** A cycle's `execution_status` may be in `{in_progress, complete, failed}` only when that cycle's `preflight.final_status` is exactly `'clear'`. Any other preflight status with one of those execution statuses is a malformed cycle (execution was recorded before preflight cleared).
|
|
74
|
+
2. **Execution requires cleared preflight.** A cycle's `execution_status` may be in `{in_progress, complete, failed}` only when that cycle's `preflight.final_status` is exactly `'clear'`. Any other preflight status with one of those execution statuses is a malformed cycle (execution was recorded before preflight cleared). The invariant does not apply to a cycle whose `remediation_path` is exactly the string `light`, compared ordinally, because a light cycle runs no preflight; invariant 8 governs that cycle.
|
|
75
75
|
|
|
76
76
|
3. **Exit gate requires zero blocking findings.** When a cycle's `exit_condition_met == true`, its `blocking_count` must be `0`. A non-zero `blocking_count` with `exit_condition_met == true` is a malformed cycle (the exit gate was marked satisfied while blocking findings remained).
|
|
77
77
|
|
|
@@ -83,6 +83,17 @@ These invariants apply only when the checkpoint contains a top-level `remediatio
|
|
|
83
83
|
|
|
84
84
|
7. **`completed_attempts` counts completed attempts (R7).** When `remediation_loop.completed_attempts` is present, it must be a non-negative integer (not a boolean) equal to the number of object cycles whose `candidate_applied` is `true` (zero when `cycles` is absent or not a list), and any other value is a malformed loop.
|
|
85
85
|
|
|
86
|
+
8. **Light remediation (issue #1097).** When a cycle object carries `remediation_path`, the rules below run in the accounting stage, after the R7 checks, per cycle in order, with byte-identical messages in `scripts/dev_tools/_orchestrator_state_light_cycle.py`, `extensions/drm-copilot/src/lib/validate/orchestrator-state-light-cycle.ts`, and `Get-RemediationLightCycleError` in `.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1`, pinned by the corpus `tests/fixtures/orchestrator_state_remediation_loop/`. A cycle without the key reaches none of them, so every existing checkpoint validates as before. `scope` on a finding is read only by these rules.
|
|
87
|
+
1. A value other than exactly `light` or `full`, null included: `Checkpoint remediation cycle #N remediation_path must be light or full.` Nothing further runs for the cycle, and nothing further runs for `full`.
|
|
88
|
+
2. A `preflight` key, whatever its value: `Checkpoint remediation cycle #N remediation_path is light but the cycle carries preflight.`
|
|
89
|
+
3. `opened_by_review` absent, or not naming a `REMEDIATION_REQUIRED` outcome by the R11 predicate: `Checkpoint remediation cycle #N remediation_path is light but opened_by_review does not name its opening review.` Rules 4 to 6 are then skipped.
|
|
90
|
+
4. More than 3 findings in that outcome (a non-list `findings` value counts as empty): `Checkpoint remediation cycle #N remediation_path is light but its opening review has M findings; the limit is 3.`
|
|
91
|
+
5. Per finding K whose `remediability` is not exactly `autonomous`, a non-object finding included: `Checkpoint remediation cycle #N remediation_path is light but finding #K is not autonomous.`
|
|
92
|
+
6. Per finding K whose `scope` is not exactly `contained`, absent included: `Checkpoint remediation cycle #N remediation_path is light but finding #K scope is not contained.`
|
|
93
|
+
7. The immediately prior list element is an object whose `remediation_path` is exactly `light`: `Checkpoint remediation cycle #N remediation_path is light but the prior cycle is light.`
|
|
94
|
+
|
|
95
|
+
Route (D9): the installed MCP validator applies invariant 8 only after the extension release that carries it is installed. Until then, a Claude run validates a light checkpoint through the repository-local Python CLI, and on Codex, whose completion boundary is the installed MCP validator, the light path is unavailable.
|
|
96
|
+
|
|
86
97
|
## Invariants (remediation_loop.review_outcomes)
|
|
87
98
|
|
|
88
99
|
These invariants apply only when `remediation_loop` contains a `review_outcomes` key. The orchestrator appends one entry per review, including a `PASS` review, in the shape `{"verdict": <verdict>, "findings": [{"remediability": <class>}, ...]}`, where `findings` lists the review's blocking findings only. A halt or wait verdict records no remediation cycle.
|
|
@@ -264,7 +275,7 @@ A standalone run (neither an epic child nor a parallel item) merges its own pull
|
|
|
264
275
|
3. The per-feature checkpoint has `epic_mode` absent, `null`, or JSON `false`; carries no `parallel_mode: true` and no non-blank `parallel_slug`; records `step9_status` exactly `passed` and `ci_gate.conclusion` exactly `success`; records `pr_gate.pr_number` as a JSON integer equal to the command number (an authorization record does not substitute); records `ci_gate.head_sha` as a lowercase 40 or 64 character object id; and, when `pr_gate.head_sha` is present and not `null`, records it equal to `ci_gate.head_sha`.
|
|
265
276
|
4. The live pull-request head from one bounded `gh pr view` call equals `ci_gate.head_sha`, and a `--match-head-commit` value, when present, equals the live head.
|
|
266
277
|
|
|
267
|
-
`parallel_mode`, `parallel_slug`, and `
|
|
278
|
+
`parallel_mode`, `parallel_slug`, `pr_merge`, and `stage_timing` are tolerated, unvalidated top-level checkpoint keys: no validator reads them. A parallel child records `parallel_mode: true` and `parallel_slug` at kickoff, and a standalone run records `pr_merge: { merge_commit_sha, target_branch, merged_at }` only after its merge is confirmed. The orchestrator main session writes `stage_timing`, a list of `{ stage, attempt, started_at, ended_at }` entries (issue 1097) of wall-clock times in which `ended_at` is null while a stage is open, and commits the same list as `FEATURE/evidence/other/stage-timing.<timestamp>.json` before the merge. The merge stage is not captured. The writer protocol is in the orchestrate skill.
|
|
268
279
|
|
|
269
280
|
Honest disclosure: the parallel exclusion is best-effort. The `Parallel mode: true` marker lives in the delegation prompt and is not present in a Bash `PreToolUse` payload, so a parallel child whose number and worktree path the parallel checkpoint has not yet recorded, and which omits the `parallel_mode` key, is not excluded by the hook. Like the authorization record above, the green-CI condition is a policy-level control, not a security control. A push after the live-head lookup can also change the head unless the command passes `--match-head-commit`, which the hook does not require.
|
|
270
281
|
|
|
@@ -317,6 +328,21 @@ A lifecycle record moved to `docs/features/potential/promoted/` satisfies the `p
|
|
|
317
328
|
|
|
318
329
|
Fail-closed behavior: any adoption error waives nothing, so each missing receipt is still reported as `Checkpoint missing successful MCP receipt: <tool>.`. Adoption errors are placed after the receipt-loop errors and before the `local_execution_overrides` errors. Rule 10 and rule 11 errors follow the rule 9 errors in the adoption error list, so a checkpoint that waives `new_active_feature_folder` without a valid record reports the missing-receipt line for each unreceipted required tool first, in `required_mcp_tools` order, and the rule 10 or rule 11 error after them. The waiver affects only receipt presence: the declared `required_mcp_tools` equality check with the routing matrix is unchanged, so a checkpoint must still declare every route tool it waives.
|
|
319
330
|
|
|
331
|
+
## Concurrent-Review Scope and Backward Compatibility
|
|
332
|
+
|
|
333
|
+
These rules apply only when a checkpoint contains the top-level key `review_mode` with the exact string `concurrent`, compared ordinally. An absent key, `null`, `sequential`, a case variant, a number, and every other value mean sequential, and a checkpoint without the key validates exactly as before: no `gh` call, no new denial, and no readiness relaxation. The key is tolerated and is not a member of `REQUIRED_STATE_KEYS`. `.claude/skills/orchestrate/SKILL.md` (`## Concurrent Review and CI (review_mode)`) defines the run sequence.
|
|
334
|
+
|
|
335
|
+
- **`head_sha`.** Each `remediation_loop.review_outcomes[]` entry of a concurrent run carries `head_sha`: the head the review ran against, a full lowercase object id of 40 or 64 characters. Plain validation does not read it.
|
|
336
|
+
- **Last-entry semantics.** Only the final `review_outcomes[]` element counts, so an earlier `PASS` never satisfies a rule.
|
|
337
|
+
- **Readiness.** Under the key, PR-creation readiness stops rejecting `step7_status` for the value `pending` only. `blocked`, and every other step, keep today's result. TypeScript has no readiness port.
|
|
338
|
+
- **Completion.** Under the key, `require_complete` appends exactly one of these strings after the existing completion checks, byte-identical in `scripts/dev_tools/_orchestrator_state_concurrent_review.py`, `extensions/drm-copilot/src/lib/validate/orchestrator-state-concurrent-review.ts`, and `Get-OrchestratorStateCompletionConcurrentReviewError` in `.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1`, and pinned by the corpus `tests/fixtures/orchestrator_state_concurrent_review/`. The second is reported only when the first does not apply. Validators do no git work.
|
|
339
|
+
- `Checkpoint completion validation failed: review_mode concurrent requires a last review_outcomes entry with verdict PASS.`
|
|
340
|
+
- `Checkpoint completion validation failed: review_mode concurrent requires head_sha on the last review_outcomes entry.`
|
|
341
|
+
- **Merge guard.** `.claude/hooks/enforce-epic-merge-gate-review.ps1`, byte-identical at `.codex/hooks/`, runs before every allow branch of both merge gates. It denies with `REVIEW_GATE_NOT_PASSED`, `REVIEW_GATE_HEAD_STALE`, or `REVIEW_GATE_HEAD_UNRESOLVED`, each after the token `EPIC_MERGE_GATE_BLOCKED`. A later head is current only when the reviewed head is its ancestor and every path changed since then lies inside `feature-folder`, so a code change after the review, including a merge of `origin/main`, is stale. A merge must be one plain `gh pr merge` of one number as its own Bash call: under the key, text that could be a merge and cannot be bound to one pull request is denied with `REVIEW_GATE_HEAD_UNRESOLVED`, before any process and before the out-of-scope allow of both gates.
|
|
342
|
+
- **Validator route (D9).** The TypeScript rule reaches the MCP surface only after an extension release. Until then, installed MCP accepts a checkpoint that the PowerShell stop hook and the Python CLI reject, so a concurrent checkpoint is checked through the Python CLI.
|
|
343
|
+
|
|
344
|
+
Honest disclosure (D10): the guard is a policy-level control, not a security control. A writer in the same session can edit the checkpoint. A merge outside the Bash hook surface is not gated. A merge whose item target does not resolve (`NoTarget` or `Ambiguous`), or whose child checkpoint does not parse, sees no key, and the parallel skill step is then the only backstop. A push after the lookup can change the head unless the command passes `--match-head-commit`. The `CI full run` requirement of the join is skill-level, because a docs-only head passes `CI Required Gate`. The authorization path reads no CI result, so the required `CI Required Gate` context is the control there. A text scan cannot read every merge: a script file performing the merge cannot be read, and neither can encoded or run-time composed text, a `gh` alias or shell function from an earlier call, or an endpoint held in a variable. A merge through a tool other than Bash is not gated: the Claude PowerShell tool and `mcp__*` tools, because the gate is registered on the `Bash` matcher only, and the Codex `shell_command` tool, because the gate is registered under `^Bash$` and returns for any other tool name. An already-queued auto-merge fires with no command, and `gh pr merge <PR> --disable-auto` removes it. A direct push to the base branch is not a pull-request merge, and the gate does not read it. A number-less merge text sees only the session checkpoint, so a key in another worktree is not found. The extra checkpoint read of the shape rule is best-effort: a failed read sees no key and keeps the decision of a run without the key. The extra read covers at most the first 4 numbers of the text, so a key held only by an item named after them is not found. Under the key the rule is fail-closed, so prose containing `pr merge` is denied in any command, including `git commit -m` and `grep`. The trigger is wider than `pr merge`: prose such as `pr (#12)` or `pr $HOME` is denied the same way, and a plain merge followed by a line feed or `;` is denied, because a bound merge must be the whole text. This trade is accepted because only concurrent runs carry the key and a merge is issued in its own call.
|
|
345
|
+
|
|
320
346
|
## Enforcement
|
|
321
347
|
|
|
322
348
|
- `scripts/dev_tools/validate_orchestrator_state.py` appends one error per violated invariant when a `remediation_loop` is present, using the existing validator message style (literal, checkpoint-context prefixed). The validator returns a list of error strings and does not mutate its input.
|
|
@@ -15,7 +15,7 @@ This rule file summarizes the PowerShell-specific policies for this repository.
|
|
|
15
15
|
1. **Formatting — Invoke-Formatter**: Format all PowerShell files via PoshQC. MCP command: `mcp__drm-copilot__run_poshqc_format`
|
|
16
16
|
2. **Linting — PSScriptAnalyzer**: Run PoshQC analyzer with repo settings. MCP command: `mcp__drm-copilot__run_poshqc_analyze`. Optional autofix: `mcp__drm-copilot__run_poshqc_analyze_autofix`
|
|
17
17
|
3. **Type checking**: Not applicable for PowerShell; skip to testing.
|
|
18
|
-
4. **Testing — Pester (
|
|
18
|
+
4. **Testing — Pester (v6.x)**: Run tests via MCP. MCP command: `mcp__drm-copilot__run_poshqc_test`. Use repo config at `scripts/powershell/PoshQC/settings/pester.runsettings.psd1`.
|
|
19
19
|
|
|
20
20
|
Run the toolchain in order: format → analyze → test. Restart from step 1 if any step fails or changes files. Use the MCP server functions; do not substitute VS Code task wrappers.
|
|
21
21
|
|
|
@@ -53,7 +53,7 @@ Introduce the smallest seam that enables reliable mocking. Apply these options i
|
|
|
53
53
|
|
|
54
54
|
## Testing Standards
|
|
55
55
|
|
|
56
|
-
- Use **Pester** (
|
|
56
|
+
- Use **Pester** (v6.x) as the test framework.
|
|
57
57
|
- Organize tests to mirror code structure (e.g., `tests/scripts/dev-tools/ScriptName.Tests.ps1`).
|
|
58
58
|
- Name test files `*.Tests.ps1`.
|
|
59
59
|
- Use `Describe`/`Context`/`It` blocks; one behavior per `It`.
|