@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.
Files changed (32) hide show
  1. package/out/mcp-server.js +1287 -548
  2. package/package.json +5 -4
  3. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +9 -0
  4. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +17 -0
  5. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -0
  6. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_commit_push_memory_before_pr.md +16 -0
  7. package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +64 -0
  8. package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +64 -0
  9. package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +63 -0
  10. package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +64 -0
  11. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +213 -0
  12. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +237 -0
  13. package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +5 -5
  14. package/resources/claude-customizations/.claude/rules/shell.md +88 -0
  15. package/resources/claude-customizations/.claude/settings.json +8 -0
  16. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +132 -0
  17. package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +65 -0
  18. package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +66 -0
  19. package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +63 -0
  20. package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +80 -0
  21. package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +63 -0
  22. package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +79 -0
  23. package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +146 -0
  24. package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +1 -1
  25. package/resources/claude-customizations/pack-manifests/core.json +14 -0
  26. package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +1 -1
  27. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  28. package/resources/config/orchestration-routing.json +0 -2
  29. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +24 -2
  30. package/resources/powershell/PoshQC/PoshQC.psm1 +32 -6
  31. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +13 -0
  32. 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 - <Title>` headings,
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+-\s+(?<Title>.+)$'
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 - <Title>`.")
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.Name -contains 'output') {
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.
@@ -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`.