@danmoisan/drm-copilot-mcp 1.0.16 → 1.0.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 +1287 -548
- package/package.json +5 -4
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +9 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +17 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_commit_push_memory_before_pr.md +16 -0
- package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +64 -0
- package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +64 -0
- package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +63 -0
- package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +64 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +213 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +237 -0
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +5 -5
- package/resources/claude-customizations/.claude/rules/shell.md +88 -0
- package/resources/claude-customizations/.claude/settings.json +8 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +65 -0
- package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +66 -0
- package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +63 -0
- package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +80 -0
- package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +63 -0
- package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +79 -0
- package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +146 -0
- package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +1 -1
- package/resources/claude-customizations/pack-manifests/core.json +14 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +0 -2
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +24 -2
- package/resources/powershell/PoshQC/PoshQC.psm1 +32 -6
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +13 -0
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +3 -3
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
SubagentStop hook that validates discovery artifacts referenced in a
|
|
4
|
+
terminating subagent's final output.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Invoked by the Claude Code SubagentStop hook under the existing broad
|
|
8
|
+
generic-agent matcher group. The hook reads $env:CLAUDE_HOOK_INPUT JSON
|
|
9
|
+
containing .output (the terminating subagent's final text), scans that
|
|
10
|
+
text for discovery-artifact path references via Get-DiscoveryArtifactType,
|
|
11
|
+
and for each recognized reference (when a required-artifact declaration is
|
|
12
|
+
present) invokes the discovery validator CLI via
|
|
13
|
+
Invoke-DiscoveryValidatorExe.
|
|
14
|
+
|
|
15
|
+
Any referenced artifact that fails validation blocks the subagent's
|
|
16
|
+
termination: the hook writes an error with a
|
|
17
|
+
DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix and exits with a non-zero code.
|
|
18
|
+
When no reference fails validation, or when no discovery-artifact path is
|
|
19
|
+
referenced, or when the required-artifact declaration is absent
|
|
20
|
+
(fail-open), the hook allows termination.
|
|
21
|
+
|
|
22
|
+
This hook provides the authoritative, defense-in-depth check of final
|
|
23
|
+
workspace state, regardless of which tool produced the artifact,
|
|
24
|
+
complementing the PreToolUse gate in
|
|
25
|
+
enforce-discovery-artifact-gate.ps1. Neither hook implements or
|
|
26
|
+
reimplements discovery-validator logic; both only route to the validator
|
|
27
|
+
CLI delivered by a separate feature and interpret its exit code and
|
|
28
|
+
captured output.
|
|
29
|
+
|
|
30
|
+
.NOTES
|
|
31
|
+
Compatible with PowerShell 7+. Read-only validation gate; the validator
|
|
32
|
+
subprocess is the only external process invoked.
|
|
33
|
+
#>
|
|
34
|
+
[CmdletBinding()]
|
|
35
|
+
param()
|
|
36
|
+
|
|
37
|
+
function Invoke-DiscoveryValidatorExe {
|
|
38
|
+
<#
|
|
39
|
+
.SYNOPSIS
|
|
40
|
+
Wrapper around the discovery-artifact validator CLI. Mockable seam.
|
|
41
|
+
.DESCRIPTION
|
|
42
|
+
Invokes `python -m scripts.dev_tools.validate_discovery_artifacts` with
|
|
43
|
+
the supplied arguments and captures both stdout and stderr. Tests mock
|
|
44
|
+
this function directly; production code must never mock `python`.
|
|
45
|
+
#>
|
|
46
|
+
[CmdletBinding()]
|
|
47
|
+
[OutputType([hashtable])]
|
|
48
|
+
param(
|
|
49
|
+
[Parameter(Mandatory = $true)]
|
|
50
|
+
[string[]] $ValidatorArgs
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
$output = & python -m scripts.dev_tools.validate_discovery_artifacts @ValidatorArgs 2>&1
|
|
54
|
+
return @{ ExitCode = $LASTEXITCODE; Output = ($output | Out-String).Trim() }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function Get-DiscoveryArtifactType {
|
|
58
|
+
<#
|
|
59
|
+
.SYNOPSIS
|
|
60
|
+
Maps a normalized file path to a discovery-artifact-type token.
|
|
61
|
+
.DESCRIPTION
|
|
62
|
+
Returns one of the eight validator subcommand tokens (profile,
|
|
63
|
+
feature-contract, coverage-ledger, runtime-scenario, parity-matrix,
|
|
64
|
+
unspecified-behavior, product-decision, evidence-reference), or $null
|
|
65
|
+
when the path does not resolve to a recognized discovery-artifact
|
|
66
|
+
type.
|
|
67
|
+
|
|
68
|
+
# TODO(#9002): this is a narrow, replaceable directory/filename lookup.
|
|
69
|
+
The schema-versioned directory/filename convention this mapping
|
|
70
|
+
depends on is owned by #9002 and is not finalized in this branch.
|
|
71
|
+
Replace this lookup once #9002 ships its versioning convention.
|
|
72
|
+
#>
|
|
73
|
+
[CmdletBinding()]
|
|
74
|
+
[OutputType([string])]
|
|
75
|
+
param(
|
|
76
|
+
[Parameter(Mandatory = $true)]
|
|
77
|
+
[string] $Path
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
$normalized = $Path -replace '\\', '/'
|
|
81
|
+
|
|
82
|
+
$typeMap = [ordered]@{
|
|
83
|
+
'discovery/profile' = 'profile'
|
|
84
|
+
'discovery/feature-contract' = 'feature-contract'
|
|
85
|
+
'discovery/coverage-ledger' = 'coverage-ledger'
|
|
86
|
+
'discovery/runtime-scenario' = 'runtime-scenario'
|
|
87
|
+
'discovery/parity-matrix' = 'parity-matrix'
|
|
88
|
+
'discovery/unspecified-behavior' = 'unspecified-behavior'
|
|
89
|
+
'discovery/product-decision' = 'product-decision'
|
|
90
|
+
'discovery/evidence-reference' = 'evidence-reference'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
foreach ($prefix in $typeMap.Keys) {
|
|
94
|
+
if ($normalized -match "(^|/)$([regex]::Escape($prefix))") {
|
|
95
|
+
return $typeMap[$prefix]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return $null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function Get-RequiredDiscoveryArtifactDeclaration {
|
|
103
|
+
<#
|
|
104
|
+
.SYNOPSIS
|
|
105
|
+
Reads the domain-profile required-artifact declaration, if present.
|
|
106
|
+
.DESCRIPTION
|
|
107
|
+
# TODO(#9001): this is a narrow, injectable RequiredArtifactPathsReader
|
|
108
|
+
seam. The discovery-workspace root and which of the eight artifact
|
|
109
|
+
types are "required" for a given gate are domain-profile runtime
|
|
110
|
+
configuration owned by #9001, which has no shipped parser/schema in
|
|
111
|
+
this branch.
|
|
112
|
+
|
|
113
|
+
Default behavior on absence is documented inline as fail-open
|
|
114
|
+
(allow/exit 0): when no domain profile is present, this function
|
|
115
|
+
returns an object with Present = $false, and callers must treat that
|
|
116
|
+
as "always allow, never invoke the validator" rather than as an error.
|
|
117
|
+
#>
|
|
118
|
+
[CmdletBinding()]
|
|
119
|
+
[OutputType([hashtable])]
|
|
120
|
+
param(
|
|
121
|
+
[Parameter(Mandatory = $false)]
|
|
122
|
+
[scriptblock] $ProfileReader = { $null }
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
$declaration = & $ProfileReader
|
|
126
|
+
if ($null -eq $declaration) {
|
|
127
|
+
# Fail open: no domain profile / required-artifact declaration present.
|
|
128
|
+
return @{ Present = $false }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return @{ Present = $true; Declaration = $declaration }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function Find-DiscoveryArtifactReference {
|
|
135
|
+
<#
|
|
136
|
+
.SYNOPSIS
|
|
137
|
+
Extracts candidate discovery-artifact path references from subagent
|
|
138
|
+
output text.
|
|
139
|
+
.DESCRIPTION
|
|
140
|
+
Splits the output text into whitespace-delimited tokens and returns
|
|
141
|
+
the distinct set of tokens that resolve to a recognized
|
|
142
|
+
discovery-artifact type via Get-DiscoveryArtifactType. This is a
|
|
143
|
+
lightweight text scan, not a JSON/markdown parser, matching the
|
|
144
|
+
precision needed for a defense-in-depth completion gate.
|
|
145
|
+
#>
|
|
146
|
+
[CmdletBinding()]
|
|
147
|
+
[OutputType([string[]])]
|
|
148
|
+
param(
|
|
149
|
+
[Parameter(Mandatory = $true)]
|
|
150
|
+
[AllowEmptyString()]
|
|
151
|
+
[string] $OutputText
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if ([string]::IsNullOrWhiteSpace($OutputText)) {
|
|
155
|
+
return [string[]]@()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
$tokens = $OutputText -split '\s+' | Where-Object { $_ }
|
|
159
|
+
$foundReferences = New-Object System.Collections.Generic.List[string]
|
|
160
|
+
foreach ($token in $tokens) {
|
|
161
|
+
$trimmed = $token.Trim('`', '"', "'", ',', ';', '(', ')', '[', ']')
|
|
162
|
+
if (Get-DiscoveryArtifactType -Path $trimmed) {
|
|
163
|
+
if (-not $foundReferences.Contains($trimmed)) {
|
|
164
|
+
$foundReferences.Add($trimmed)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return [string[]]$foundReferences
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function Invoke-DiscoveryArtifactGateValidation {
|
|
173
|
+
<#
|
|
174
|
+
.SYNOPSIS
|
|
175
|
+
Parses CLAUDE_HOOK_INPUT and returns an Ok/Message validation result
|
|
176
|
+
for a discovery-artifact completion gate.
|
|
177
|
+
#>
|
|
178
|
+
[CmdletBinding()]
|
|
179
|
+
[OutputType([hashtable])]
|
|
180
|
+
param(
|
|
181
|
+
[string] $RawPayload,
|
|
182
|
+
|
|
183
|
+
[Parameter(Mandatory = $false)]
|
|
184
|
+
[scriptblock] $RequiredArtifactReader = { Get-RequiredDiscoveryArtifactDeclaration }
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if ([string]::IsNullOrWhiteSpace($RawPayload)) {
|
|
188
|
+
return @{ Ok = $false; Message = 'discovery artifact gate hook: CLAUDE_HOOK_INPUT is empty' }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
$payload = $RawPayload | ConvertFrom-Json -ErrorAction Stop
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return @{ Ok = $false; Message = "discovery artifact gate hook: CLAUDE_HOOK_INPUT is not valid JSON: $_" }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
$outputText = ''
|
|
199
|
+
if ($null -ne $payload -and ($payload.PSObject.Properties.Name -contains 'output')) {
|
|
200
|
+
$outputText = [string]$payload.output
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
$references = Find-DiscoveryArtifactReference -OutputText $outputText
|
|
204
|
+
if ($references.Count -eq 0) {
|
|
205
|
+
return @{ Ok = $true; Message = $null }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
$requiredDeclaration = & $RequiredArtifactReader
|
|
209
|
+
if (-not $requiredDeclaration.Present) {
|
|
210
|
+
# Fail open: no domain profile / required-artifact declaration present.
|
|
211
|
+
return @{ Ok = $true; Message = $null }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
foreach ($reference in $references) {
|
|
215
|
+
$artifactType = Get-DiscoveryArtifactType -Path $reference
|
|
216
|
+
$result = Invoke-DiscoveryValidatorExe -ValidatorArgs @($artifactType, $reference)
|
|
217
|
+
$hasErrorOutput = -not [string]::IsNullOrWhiteSpace($result.Output)
|
|
218
|
+
if ($result.ExitCode -ne 0 -or $hasErrorOutput) {
|
|
219
|
+
return @{ Ok = $false; Message = "DISCOVERY_ARTIFACT_GATE_BLOCKED: $($result.Output)" }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return @{ Ok = $true; Message = $null }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
227
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
228
|
+
return
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
$result = Invoke-DiscoveryArtifactGateValidation -RawPayload $env:CLAUDE_HOOK_INPUT
|
|
232
|
+
if (-not $result.Ok) {
|
|
233
|
+
Write-Error $result.Message
|
|
234
|
+
exit 1
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
exit 0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<#
|
|
1
|
+
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
3
|
SubagentStop hook for the atomic-planner subagent.
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- output contains `PREFLIGHT: ALL CLEAR` or
|
|
15
15
|
`PREFLIGHT: REVISIONS REQUIRED`,
|
|
16
16
|
- the advertised plan exists on disk,
|
|
17
|
-
- the plan contains canonical `### Phase N
|
|
17
|
+
- the plan contains canonical `### Phase N — <Title>` headings,
|
|
18
18
|
- Phase 0 exists and includes policy-read and baseline tasks,
|
|
19
19
|
- each task uses `- [ ] [P#-T#]` (or checked equivalent),
|
|
20
20
|
- task numbering is sequential within each phase,
|
|
@@ -118,7 +118,7 @@ function Get-PlanStructureValidationReport {
|
|
|
118
118
|
[string[]] $Lines
|
|
119
119
|
)
|
|
120
120
|
|
|
121
|
-
$phasePattern = '^### Phase (?<Phase>\d+)\s
|
|
121
|
+
$phasePattern = '^### Phase (?<Phase>\d+)\s+—\s+(?<Title>.+)$'
|
|
122
122
|
$taskPattern = '^- \[(?<State>[ xX])\] \[P(?<Phase>\d+)-T(?<Task>\d+)\] (?<Text>.+)$'
|
|
123
123
|
$errors = [System.Collections.Generic.List[string]]::new()
|
|
124
124
|
$tasksByPhase = @{}
|
|
@@ -134,7 +134,7 @@ function Get-PlanStructureValidationReport {
|
|
|
134
134
|
if ($line -match '^### Phase ') {
|
|
135
135
|
$phaseMatch = [regex]::Match($line, $phasePattern)
|
|
136
136
|
if (-not $phaseMatch.Success) {
|
|
137
|
-
$errors.Add("Line ${lineNumber}: phase heading must match `### Phase N
|
|
137
|
+
$errors.Add("Line ${lineNumber}: phase heading must match `### Phase N — <Title>`.")
|
|
138
138
|
$currentPhase = $null
|
|
139
139
|
continue
|
|
140
140
|
}
|
|
@@ -245,7 +245,7 @@ function Invoke-PlannerOutputValidation {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
$agentOutput = $null
|
|
248
|
-
if ($payload.PSObject.Properties
|
|
248
|
+
if ($null -ne $payload.PSObject.Properties['output']) {
|
|
249
249
|
$agentOutput = $payload.output
|
|
250
250
|
}
|
|
251
251
|
if ([string]::IsNullOrWhiteSpace($agentOutput)) {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.sh"
|
|
4
|
+
- "**/*.bats"
|
|
5
|
+
- "scripts/bash/**"
|
|
6
|
+
- "tests/shell/**"
|
|
7
|
+
description: Shell (bash) toolchain and coding standards.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Shell (Bash) Code Standards
|
|
11
|
+
|
|
12
|
+
This rule file summarizes the shell-specific policies for this repository. The shell
|
|
13
|
+
quality-control toolchain is native bash and has no Python or Poetry dependency.
|
|
14
|
+
|
|
15
|
+
## Toolchain
|
|
16
|
+
|
|
17
|
+
Run the toolchain in this order and restart from step 1 if any step fails or rewrites files:
|
|
18
|
+
|
|
19
|
+
1. **Formatting — shfmt**: Format all shell scripts with shfmt (write mode). Command:
|
|
20
|
+
`bash scripts/bash/shell-qc.sh format`. The `check` command runs shfmt in diff mode
|
|
21
|
+
(`shfmt -d`) as its first stage.
|
|
22
|
+
2. **Linting — shellcheck**: Lint all shell scripts with shellcheck. Command:
|
|
23
|
+
`bash scripts/bash/shell-qc.sh check`. `check` runs `shfmt -d` once over the full file
|
|
24
|
+
list and then `shellcheck` once per file, returning the maximum exit code.
|
|
25
|
+
3. **Type checking — not applicable**: Bash has no separate type-check stage. An optional
|
|
26
|
+
syntax check is available via `bash -n`; the VS Code task "Shell QC: 3 bash: type-check"
|
|
27
|
+
provides it. Skip to testing.
|
|
28
|
+
4. **Testing — bats**: Run bats tests with `bash scripts/bash/shell-qc.sh test`. Line coverage
|
|
29
|
+
via kcov with `bash scripts/bash/shell-qc.sh test --coverage`.
|
|
30
|
+
|
|
31
|
+
Do not stop the loop until formatting, linting, and testing complete without errors in a
|
|
32
|
+
single pass. Do not substitute the VS Code task wrappers for the native command in automation.
|
|
33
|
+
|
|
34
|
+
## Native Invocation and Environment
|
|
35
|
+
|
|
36
|
+
- The toolchain is native bash: the wrapper `scripts/bash/shell-qc.sh` and its library
|
|
37
|
+
`scripts/bash/shell_qc_lib.sh` invoke `shfmt`, `shellcheck`, `bats`, and `kcov` directly.
|
|
38
|
+
No Python interpreter, no Poetry, and no `poetry run` are involved.
|
|
39
|
+
- On Windows, run the toolchain under WSL.
|
|
40
|
+
- In CI, the toolchain runs on `ubuntu-latest` (`.github/workflows/_shell-coverage.yml` for
|
|
41
|
+
coverage; `.github/workflows/_build-check.yml` runs `--help` as an installability smoke).
|
|
42
|
+
- Per-tool path overrides are available for testing via `SHELL_QC_<TOOL>_BIN` (for `shfmt`,
|
|
43
|
+
`shellcheck`, `bats`, `kcov`); an empty or nonexistent value is treated as missing. The
|
|
44
|
+
coverage output directory is `SHELL_QC_KCOV_OUT_DIR` (default `artifacts/pester/kcov`).
|
|
45
|
+
|
|
46
|
+
## Discovery Contract
|
|
47
|
+
|
|
48
|
+
- Search roots: `tools/` and `scripts/`, relative to the current working directory; a missing
|
|
49
|
+
root is silently skipped.
|
|
50
|
+
- A file is a shell script when its suffix (lowercased) is `.sh` or its first line is a
|
|
51
|
+
shebang whose resolved interpreter is `bash` or `sh` (including `env` and `env -S`/`-flag`
|
|
52
|
+
forms; the shebang is lowercased before parsing, so `#!/usr/bin/env BASH` qualifies).
|
|
53
|
+
- Excluded directories (pruned at any depth): `.venv`, `.git`, `node_modules`, `dist`,
|
|
54
|
+
`build`.
|
|
55
|
+
- The discovered set is de-duplicated and sorted with `LC_ALL=C` for deterministic ordering.
|
|
56
|
+
- bats test directories: `tests/shell` and `tests/bash`, whichever exist, in that order.
|
|
57
|
+
|
|
58
|
+
## Coverage Expectations
|
|
59
|
+
|
|
60
|
+
- Coverage is measured with kcov, which emits a single merged Cobertura report `cov.xml` under
|
|
61
|
+
`artifacts/pester/kcov` (or `SHELL_QC_KCOV_OUT_DIR`). The run prints
|
|
62
|
+
`Bash coverage (lines): NN.N%`.
|
|
63
|
+
- kcov reports **line coverage only**. The uniform line-coverage threshold (>= 85% per
|
|
64
|
+
`.claude/rules/quality-tiers.md`) applies. Branch coverage is not measurable by kcov for
|
|
65
|
+
bash; there is no bash branch-coverage gate.
|
|
66
|
+
|
|
67
|
+
## CI-vs-Local Version Drift
|
|
68
|
+
|
|
69
|
+
- CI pins shfmt 3.8.0 (installed as a binary), uses apt-packaged shellcheck and bats, and
|
|
70
|
+
builds kcov v43 from source. Local WSL installs (winget or apt) may drift from these
|
|
71
|
+
versions.
|
|
72
|
+
- CI versions are canonical. When local and CI results disagree, defer to CI.
|
|
73
|
+
|
|
74
|
+
## Coding Standards
|
|
75
|
+
|
|
76
|
+
- Begin executable scripts with `set -euo pipefail`. Tools that legitimately return non-zero
|
|
77
|
+
(shfmt diff mode, shellcheck, bats, kcov) must be captured with `|| rc=$?` so an intended
|
|
78
|
+
non-zero exit does not abort under `set -e`.
|
|
79
|
+
- Keep scripts shellcheck-clean. Suppressions are permitted only when justified inline with a
|
|
80
|
+
`# shellcheck disable=SCxxxx` comment stating the reason.
|
|
81
|
+
- Use shfmt default formatting (tab indentation, as in `scripts/bash/coverage_lib.sh`).
|
|
82
|
+
- Quote all expansions; resolve tools with `command -v` (honoring the `SHELL_QC_<TOOL>_BIN`
|
|
83
|
+
override seam).
|
|
84
|
+
- No production, test, or reusable shell file may exceed 500 lines.
|
|
85
|
+
- Tests live in `tests/shell/*.bats` and mirror `scripts/bash/`. Tests must not create
|
|
86
|
+
temporary files; use checked-in fixtures under `tests/fixtures/` and checked-in stub
|
|
87
|
+
binaries under `tests/fixtures/shell_qc/stub-bin/` wired through the `SHELL_QC_<TOOL>_BIN`
|
|
88
|
+
seam.
|
|
@@ -155,6 +155,10 @@
|
|
|
155
155
|
{
|
|
156
156
|
"type": "command",
|
|
157
157
|
"command": "pwsh -NoProfile -File .claude/hooks/enforce-completion-consistency.ps1"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"type": "command",
|
|
161
|
+
"command": "pwsh -NoProfile -File .claude/hooks/enforce-discovery-artifact-gate.ps1"
|
|
158
162
|
}
|
|
159
163
|
]
|
|
160
164
|
},
|
|
@@ -191,6 +195,10 @@
|
|
|
191
195
|
{
|
|
192
196
|
"type": "command",
|
|
193
197
|
"command": "pwsh -NoProfile -Command \"$input = $env:CLAUDE_HOOK_INPUT | ConvertFrom-Json; $output = $input.output; if (-not ($output -match '(plan-path|research-path|review-artifact|PREFLIGHT|evidence/)')) { Write-Error 'Subagent stopped without required completion artifact path'; exit 1 }; exit 0\""
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"type": "command",
|
|
201
|
+
"command": "pwsh -NoProfile -File .claude/hooks/validate-discovery-artifact-gate.ps1"
|
|
194
202
|
}
|
|
195
203
|
]
|
|
196
204
|
},
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cleanup-merged-worktrees
|
|
3
|
+
description: 'Detect, consolidate, and delete git worktrees/branches that are fully merged into main; use after an epic or feature''s PRs have merged and stale drm-copilot-wt-* branches/worktrees remain, driving the detect -> report -> consolidate -> pr-author handoff -> post-merge deletion workflow.'
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- "Bash(bash scripts/bash/cleanup-worktrees.sh *)"
|
|
7
|
+
- "Bash(git fetch *)"
|
|
8
|
+
- "Bash(git merge-base *)"
|
|
9
|
+
- "Bash(git push *)"
|
|
10
|
+
- "Bash(git rev-parse *)"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Cleanup Merged Worktrees
|
|
14
|
+
|
|
15
|
+
Drive the end-to-end cleanup of stale git worktrees and branches after their work has
|
|
16
|
+
merged into `main`. The deterministic classification, consolidation staging, and
|
|
17
|
+
deletion mechanics live in `scripts/bash/cleanup-worktrees.sh` (wrapping
|
|
18
|
+
`scripts/bash/cleanup_worktrees_lib.sh` and
|
|
19
|
+
`scripts/bash/cleanup_worktrees_actions_lib.sh`). This skill owns the editorial and
|
|
20
|
+
orchestration layer: deciding whether flagged unique content is genuinely
|
|
21
|
+
documentation/memory material, driving consolidation onto a single
|
|
22
|
+
`documentationandmemories` branch, delegating PR creation to `Agent(pr-author)`, and
|
|
23
|
+
running the destructive apply pass only after the consolidation PR has merged.
|
|
24
|
+
|
|
25
|
+
The script is deterministic and owns the safe/unsafe decision; the LLM/editorial
|
|
26
|
+
judgment (which flagged commits are documentation/memory content) is this skill's job
|
|
27
|
+
and is out of the script's scope.
|
|
28
|
+
|
|
29
|
+
## When to Use This Skill
|
|
30
|
+
|
|
31
|
+
- After an epic or feature's PRs have all merged and two to five stale
|
|
32
|
+
`drm-copilot-wt-*` branches or worktrees remain.
|
|
33
|
+
- When you need a trustworthy, machine-parseable report of which branches/worktrees are
|
|
34
|
+
safe to delete (`MERGED_CLEAN`, `MERGED_CONTENT_NEUTRAL`, `MERGED_EQUIVALENT`) versus
|
|
35
|
+
which carry unmerged or unique work (`NOT_MERGED`, `HAS_UNIQUE_RESIDUALS`).
|
|
36
|
+
- When stranded documentation/agent-memory commits were appended to a worktree branch
|
|
37
|
+
after its feature content already merged and must be preserved before deletion.
|
|
38
|
+
- Do not use this skill to manage remote branches; its scope is local branches and
|
|
39
|
+
local worktree registrations only.
|
|
40
|
+
|
|
41
|
+
## Report Line Contract
|
|
42
|
+
|
|
43
|
+
The script emits pipe-delimited, `LC_ALL=C`-ordered records, one per line:
|
|
44
|
+
|
|
45
|
+
- `BRANCH|<name>|<state>` — `state` in `NOT_MERGED | MERGED_CLEAN |
|
|
46
|
+
MERGED_CONTENT_NEUTRAL | MERGED_EQUIVALENT | HAS_UNIQUE_RESIDUALS | PROTECTED_CURRENT`.
|
|
47
|
+
- `COMMIT|<branch>|<sha>|<state>|<paths-csv>|<author>|<author-date>` — per-commit state
|
|
48
|
+
in `EQUIVALENT | CONTENT_ON_MAIN | EMPTY | UNIQUE | CONFLICT`. A `UNIQUE` COMMIT record
|
|
49
|
+
is a cherry-pick candidate for editorial triage.
|
|
50
|
+
- `WORKTREE|<path>|<branch-or-DETACHED>|<flags>` — worktree registrations.
|
|
51
|
+
- `WARN|main-divergence|<local-sha>|<origin-sha>` — local `main` differs from
|
|
52
|
+
`origin/main` (advisory; classification still runs).
|
|
53
|
+
- `DIRTY|<worktree-path>|<status-porcelain-line>` — a dirty worktree that blocked
|
|
54
|
+
removal.
|
|
55
|
+
- `ACTION|<verb>|<target>|<result>` — apply-mode action results.
|
|
56
|
+
|
|
57
|
+
## End-to-End Workflow
|
|
58
|
+
|
|
59
|
+
1. **Detect and report (dry run).** Run `bash scripts/bash/cleanup-worktrees.sh`
|
|
60
|
+
(report mode is the default and mutates nothing). It verifies local `main` against
|
|
61
|
+
`origin/main` (emitting `WARN|main-divergence` on drift), enumerates branches and
|
|
62
|
+
worktrees, and prints one `BRANCH|` line per branch plus `COMMIT|...|UNIQUE|...`
|
|
63
|
+
records for each unique residual commit.
|
|
64
|
+
|
|
65
|
+
2. **Editorial triage of the cherry-pick candidates.** Review each
|
|
66
|
+
`COMMIT|...|UNIQUE|...` record — this is the LLM-judgment boundary. Confirm
|
|
67
|
+
editorially that the unique commits are genuinely documentation/agent-memory
|
|
68
|
+
content (for example paths under `docs/**`, `.claude/agent-memory/**`, or `**/*.md`).
|
|
69
|
+
The script only reports the deterministic facts (SHA, paths, author, date); deciding
|
|
70
|
+
what counts as documentation is this skill's responsibility.
|
|
71
|
+
|
|
72
|
+
3. **Consolidate onto `documentationandmemories`.** When the candidate list is
|
|
73
|
+
non-empty, the script creates the `documentationandmemories` branch off `main` in a
|
|
74
|
+
dedicated worktree (never the caller's worktree) and cherry-picks the flagged commits
|
|
75
|
+
oldest-first per source branch, branches in `LC_ALL=C` order, with `-x` provenance. A
|
|
76
|
+
pre-existing `documentationandmemories` branch stops the run with a report — never
|
|
77
|
+
reuse it silently. Conflicts are aborted and surfaced as `CONFLICT` for editorial
|
|
78
|
+
resolution, never auto-resolved.
|
|
79
|
+
|
|
80
|
+
4. **Push and hand off PR creation to `Agent(pr-author)`.** Push the consolidation
|
|
81
|
+
branch (`git push`). Refresh the PR-context bundle with
|
|
82
|
+
`mcp__drm-copilot__collect_pr_context` using base branch `main` (producing
|
|
83
|
+
`artifacts/pr_context.summary.txt` and `artifacts/pr_context.appendix.txt`).
|
|
84
|
+
Validate the orchestrator-state checkpoint
|
|
85
|
+
(`artifacts/orchestration/orchestrator-state.json`) with `--require-pr-creation-ready`
|
|
86
|
+
and record the `pr_author_preflight` result; delegation is prohibited when that
|
|
87
|
+
validation fails. Then delegate PR creation to `Agent(pr-author)` per
|
|
88
|
+
`.claude/skills/pr-author/SKILL.md`, using `<N> = 396` for the body-file and receipt
|
|
89
|
+
contract. This skill never authors or creates the PR itself.
|
|
90
|
+
|
|
91
|
+
5. **Wait for merge and verify git-natively.** After the consolidation PR merges,
|
|
92
|
+
verify it with `git fetch` followed by
|
|
93
|
+
`git merge-base --is-ancestor documentationandmemories main`. Exit 0 confirms every
|
|
94
|
+
consolidated commit is now reachable from `main`; that is the only state that unlocks
|
|
95
|
+
deletion of branches whose unique content was consolidated.
|
|
96
|
+
|
|
97
|
+
6. **Run the apply-mode deletion.** Run `bash scripts/bash/cleanup-worktrees.sh --apply`.
|
|
98
|
+
It re-verifies each candidate's ancestry/equivalence in-process, removes worktrees
|
|
99
|
+
(without force; a dirty worktree is reported via `DIRTY|` lines and skipped), then
|
|
100
|
+
deletes branches with `git branch -D`. The now-merged `documentationandmemories`
|
|
101
|
+
branch and its worktree become `MERGED_CLEAN` instances and are cleaned up by the same
|
|
102
|
+
mechanics.
|
|
103
|
+
|
|
104
|
+
## Nothing to Consolidate (Short Path)
|
|
105
|
+
|
|
106
|
+
When report mode classifies every candidate as `MERGED_CLEAN` or `MERGED_EQUIVALENT`
|
|
107
|
+
with an empty cherry-pick-candidate list, skip steps 3-5 entirely: proceed directly from
|
|
108
|
+
the report to `bash scripts/bash/cleanup-worktrees.sh --apply`. Cleanup completes in a
|
|
109
|
+
single session with no PR.
|
|
110
|
+
|
|
111
|
+
## Prohibited Shortcuts
|
|
112
|
+
|
|
113
|
+
- Never invoke `gh pr create` or `gh pr edit --body*` from this skill or the scripts. PR
|
|
114
|
+
authoring is `Agent(pr-author)`'s exclusive responsibility and is enforced by the
|
|
115
|
+
`enforce-pr-author-skill.ps1` PreToolUse hook.
|
|
116
|
+
- Never pass a force flag to `git worktree remove`. A dirty worktree blocks deletion and
|
|
117
|
+
is reported for manual handling; it is never force-removed.
|
|
118
|
+
- Never execute `git worktree prune`. Prunable registrations are report-only.
|
|
119
|
+
- Never act on `NOT_MERGED`, `HAS_UNIQUE_RESIDUALS`, or `PROTECTED_CURRENT` candidates;
|
|
120
|
+
the caller's worktree and branch, and the main worktree, are never mutated.
|
|
121
|
+
- Never use commit-message text matching as a classification input, and never
|
|
122
|
+
auto-resolve cherry-pick conflicts.
|
|
123
|
+
|
|
124
|
+
## Cross-References
|
|
125
|
+
|
|
126
|
+
- `.claude/skills/pr-author/SKILL.md` — the PR body/receipt contract and the delegation
|
|
127
|
+
target for step 4.
|
|
128
|
+
- `.claude/skills/pr-context-artifacts/SKILL.md` — how the PR-context bundle is collected
|
|
129
|
+
and the base-branch resolution rules.
|
|
130
|
+
- `.claude/rules/shell.md` — the bash toolchain (shfmt/shellcheck/bats/kcov), the
|
|
131
|
+
500-line cap, the no-temp-files test policy, and the `CLEANUP_WT_GIT_BIN` seam
|
|
132
|
+
convention.
|
package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: discovery-behavior-reconciliation
|
|
3
|
+
description: 'Capture unspecified or contradictory behavior and reconcile it into product decisions in the discovery workflow. Use when recording unspecified-behavior findings from the parity matrix and reconciling them into product-decision records via the reconciler role. Sixth stage, after parity and before the validation gate.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Discovery Behavior Reconciliation
|
|
7
|
+
|
|
8
|
+
Runs the reconciliation stage of the discovery and parity-definition workflow.
|
|
9
|
+
It captures behavior that is unspecified or contradictory across the legacy
|
|
10
|
+
source, the runtime observations, and the parity matrix, then reconciles each
|
|
11
|
+
finding into a product decision. All domain specificity is read from the domain
|
|
12
|
+
profile at runtime.
|
|
13
|
+
|
|
14
|
+
## When to Use This Skill
|
|
15
|
+
|
|
16
|
+
- The parity matrix has flagged gaps or contradictions that need a documented
|
|
17
|
+
resolution.
|
|
18
|
+
- You need product-decision records before the final validation gate.
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- `discovery-parity-matrix` has completed.
|
|
23
|
+
- The domain profile is loaded and valid.
|
|
24
|
+
|
|
25
|
+
## Workflow
|
|
26
|
+
|
|
27
|
+
1. **Capture unspecified behavior.** Record each unspecified or contradictory
|
|
28
|
+
behavior as a record conforming to the schema
|
|
29
|
+
`schemas/discovery/v1/unspecified-behavior-record.schema.json`, citing the
|
|
30
|
+
parity-matrix entry and evidence that surfaced it.
|
|
31
|
+
|
|
32
|
+
2. **Reconcile into product decisions.** For each captured record, produce a
|
|
33
|
+
product-decision record conforming to the schema
|
|
34
|
+
`schemas/discovery/v1/product-decision-record.schema.json`, stating the
|
|
35
|
+
decision and its rationale.
|
|
36
|
+
|
|
37
|
+
3. **Route reconciliation.** Hand the records to the reconciler role for the
|
|
38
|
+
reconciliation decision (see `## Worker Routing`).
|
|
39
|
+
|
|
40
|
+
## Worker Routing
|
|
41
|
+
|
|
42
|
+
- Worker: `requirements-reconciler`
|
|
43
|
+
|
|
44
|
+
The reconciler role decides how each unspecified or contradictory behavior is
|
|
45
|
+
resolved and records the outcome as a product decision.
|
|
46
|
+
|
|
47
|
+
## Validation
|
|
48
|
+
|
|
49
|
+
- Validate unspecified-behavior records with
|
|
50
|
+
`dev.discovery.validate-unspecified-behavior`.
|
|
51
|
+
- Validate product-decision records with
|
|
52
|
+
`dev.discovery.validate-product-decision`.
|
|
53
|
+
- An empty error list is a pass. On any error, follow the direction in
|
|
54
|
+
`discovery-validate-artifacts`.
|
|
55
|
+
|
|
56
|
+
## Referenced Skills
|
|
57
|
+
|
|
58
|
+
- `discovery-workflow` — stage order and the canonical Referenced Contracts
|
|
59
|
+
registry.
|
|
60
|
+
- `discovery-validate-artifacts` — pass/fail semantics and error routing.
|
|
61
|
+
|
|
62
|
+
## Notes
|
|
63
|
+
|
|
64
|
+
- Product-decision records complete the artifact set consumed by the final
|
|
65
|
+
validation gate in `discovery-validate-artifacts`.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: discovery-coverage-ledger
|
|
3
|
+
description: 'Produce feature contracts and the coverage ledger from inventory output in the discovery workflow. Use when deriving the feature contract set and the migration coverage ledger from the repository inventory and routing coverage review to the coverage role. Third stage, after inventory and before runtime characterization.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Discovery Coverage Ledger
|
|
7
|
+
|
|
8
|
+
Runs the coverage stage of the discovery and parity-definition workflow. It
|
|
9
|
+
derives feature contracts and the coverage ledger from the inventory output, so
|
|
10
|
+
that every inventoried unit of behavior has a contract and a tracked coverage
|
|
11
|
+
state. All domain specificity is read from the domain profile at runtime.
|
|
12
|
+
|
|
13
|
+
## When to Use This Skill
|
|
14
|
+
|
|
15
|
+
- The inventory stage has produced analyzer outputs under the profile's artifact
|
|
16
|
+
root.
|
|
17
|
+
- You need the feature contract set and the coverage ledger before runtime
|
|
18
|
+
characterization and parity analysis.
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- `discovery-repo-inventory` has completed and recorded its outputs.
|
|
23
|
+
- The domain profile is loaded and valid.
|
|
24
|
+
|
|
25
|
+
## Workflow
|
|
26
|
+
|
|
27
|
+
1. **Derive feature contracts.** From the inventory output, produce one feature
|
|
28
|
+
contract per inventoried unit of behavior, conforming to the schema
|
|
29
|
+
`schemas/discovery/v1/feature-contract.schema.json`.
|
|
30
|
+
|
|
31
|
+
2. **Build the coverage ledger.** Aggregate the feature contracts into the
|
|
32
|
+
coverage ledger, conforming to the schema
|
|
33
|
+
`schemas/discovery/v1/coverage-ledger.schema.json`. The ledger records the
|
|
34
|
+
coverage state of each contract so later stages can measure parity progress.
|
|
35
|
+
|
|
36
|
+
3. **Route coverage review.** Hand the ledger to the coverage role for review
|
|
37
|
+
(see `## Worker Routing`).
|
|
38
|
+
|
|
39
|
+
## Worker Routing
|
|
40
|
+
|
|
41
|
+
- Worker: `migration-coverage-reviewer`
|
|
42
|
+
|
|
43
|
+
The coverage role reviews the derived feature contracts and the coverage ledger
|
|
44
|
+
for completeness and correctness before the workflow proceeds to runtime
|
|
45
|
+
characterization.
|
|
46
|
+
|
|
47
|
+
## Validation
|
|
48
|
+
|
|
49
|
+
- Validate feature contracts with `dev.discovery.validate-feature-contract`.
|
|
50
|
+
- Validate the coverage ledger with `dev.discovery.validate-coverage-ledger`.
|
|
51
|
+
- An empty error list is a pass. On any error, follow the direction in
|
|
52
|
+
`discovery-validate-artifacts`.
|
|
53
|
+
|
|
54
|
+
## Referenced Skills
|
|
55
|
+
|
|
56
|
+
- `discovery-workflow` — stage order and the canonical Referenced Contracts
|
|
57
|
+
registry.
|
|
58
|
+
- `discovery-validate-artifacts` — pass/fail semantics and error routing.
|
|
59
|
+
|
|
60
|
+
## Notes
|
|
61
|
+
|
|
62
|
+
- Feature contracts and the coverage ledger are jointly derived from the
|
|
63
|
+
inventory, so contract authorship is assigned to this stage and reviewed by
|
|
64
|
+
the coverage role.
|
|
65
|
+
- Outputs from this stage feed `discovery-runtime-characterization` and
|
|
66
|
+
`discovery-parity-matrix`.
|