@danmoisan/drm-copilot-mcp 1.1.3 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danmoisan/drm-copilot-mcp",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "Stdio MCP server exposing drm-copilot repo-automation tools.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -19,10 +19,7 @@ tools:
19
19
  skills:
20
20
  - policy-compliance-order
21
21
  - epic-orchestrate
22
- - feature-promotion-lifecycle
23
- - atomic-plan-contract
24
22
  - acceptance-criteria-tracking
25
- - evidence-and-timestamp-conventions
26
23
  memory: project
27
24
  hooks:
28
25
  SubagentStop:
@@ -54,15 +51,13 @@ maintenance. This agent frames the *who* and *when*; the skill documents the *ho
54
51
 
55
52
  On every invocation:
56
53
 
57
- 1. Read `CLAUDE.md` for repository tone policy and architecture context.
58
- 2. Read applicable `.claude/rules/` files for languages in scope.
59
- 3. Read `artifacts/orchestration/epic-orchestrator-state.json` to check for existing epic
54
+ 1. Read `artifacts/orchestration/epic-orchestrator-state.json` to check for existing epic
60
55
  checkpoint state.
61
- 4. If a valid epic checkpoint exists with a matching `epic_feature_folder`, resume from the
56
+ 2. If a valid epic checkpoint exists with a matching `epic_feature_folder`, resume from the
62
57
  recorded `next_step` (re-deriving durable ground truth via `git worktree list --porcelain`,
63
58
  `git branch`, and `gh pr view --json state,mergedAt,headRefOid` per the `epic-orchestrate`
64
59
  skill's resume procedure, not from in-memory notifications alone).
65
- 5. If no checkpoint exists or the objective is new, begin from manifest parsing
60
+ 3. If no checkpoint exists or the objective is new, begin from manifest parsing
66
61
  (`docs/features/epics/<epic-slug>/epic.md`).
67
62
 
68
63
  ## Invocation Origin
@@ -104,7 +99,8 @@ You delegate exclusively through two channels:
104
99
 
105
100
  - `Agent(orchestrator)` — one delegation per child feature in the manifest, carrying the epic-mode
106
101
  kickoff line and, for dependent features, the upstream-context citation lines (both defined in
107
- `spec.md` §4 and §10 of this feature and restated procedurally in the `epic-orchestrate` skill).
102
+ `.claude/skills/epic-orchestrate/SKILL.md` under `## Merge-on-Green Kickoff Parameter` and
103
+ `## Context Handoff to Dependent Features`).
108
104
  Each child `orchestrator` runs its own full small/large route (including its own delegation to
109
105
  `atomic-planner`, `atomic-executor`, `feature-review`, and, on CI-green in epic mode, the
110
106
  merge-on-green S9 step 6 extension) inside its own isolated worktree
@@ -133,7 +129,9 @@ at your own `SubagentStop` time.
133
129
  ## Checkpoint Persistence
134
130
 
135
131
  Update `artifacts/orchestration/epic-orchestrator-state.json` after every completed step, per the
136
- full schema defined in `spec.md` §6: `objective`, `route_id: "epic"`, `epic_feature_folder`,
132
+ full schema enforced by `validate_epic_orchestrator_state_text`, implemented in
133
+ `scripts/dev_tools/validate_epic_orchestrator_state.py`: `objective`, `route_id: "epic"`,
134
+ `epic_feature_folder`,
137
135
  `epic_manifest_path`, `epic_status_doc_path`, `integration_branch`, `completed_steps`, `next_step`,
138
136
  `last_updated`, `current_wave`, `waves[]`, `features[]` (including `merge_status` and the four
139
137
  lifecycle timestamps), `epic_merge_pr`, and the three receipt arrays
@@ -14,13 +14,31 @@
14
14
  Feature folder resolution order:
15
15
  1. Scan the prompt text for any path matching
16
16
  docs/features/active/<token>, accepting both forward-slash and
17
- backslash separators. The longest match wins; when it points at a
18
- file (ends with .md), use its parent directory.
19
- 2. If no candidate was found in the prompt, read the feature-folder field
17
+ backslash separators. Truncate every match to two segments past the
18
+ docs/features/active/ prefix -- that is, to exactly four path segments:
19
+ docs, features, active, and the feature-folder name. Truncation is
20
+ depth-insensitive, so the feature folder itself, a spec.md path, a
21
+ research/ artifact path, and an evidence/ artifact path all resolve to
22
+ the same folder. A match that truncates to fewer than four segments is
23
+ rejected. Candidates are deduplicated preserving first-occurrence
24
+ order.
25
+ 2. Select among the distinct candidates: one candidate is used directly;
26
+ otherwise the candidate equal to the checkpoint's feature-folder field
27
+ is preferred, because the checkpoint is the orchestrator's own record of
28
+ which feature is in flight; otherwise the earliest-occurring candidate
29
+ in the prompt wins, because the orchestrator names the active feature
30
+ folder before citing artifacts inside it.
31
+ 3. If no candidate was found in the prompt, read the feature-folder field
20
32
  from artifacts/orchestration/orchestrator-state.json.
21
- 3. If neither yields a folder, block with a reason instructing the caller
33
+ 4. If neither yields a folder, block with a reason instructing the caller
22
34
  to reference a feature folder explicitly.
23
35
 
36
+ Known limitation: resolution stops at the feature-folder segment, so it does
37
+ not descend into a version folder (v1/, v2/). No versioned folder exists
38
+ under docs/features/active/ today, and issue.md sits at the feature root in
39
+ every case, so the limitation is inert; it is recorded here rather than coded
40
+ around.
41
+
24
42
  Once the folder is resolved, the hook reads the persisted work-mode marker
25
43
  (`- Work Mode: minor-audit|full-feature|full-bug|full`) from that folder's
26
44
  issue.md, per the mode contract in
@@ -30,11 +48,16 @@
30
48
  - full-bug -> spec.md only is required.
31
49
  - minor-audit -> neither is required; issue.md carries the acceptance
32
50
  criteria for this mode.
33
- - marker absent, unreadable, or unrecognized -> fail closed to the
34
- strictest set (spec.md and user-story.md), and the block reason states
35
- that the work mode could not be determined so the operator can tell
36
- this case apart from a genuine missing prerequisite. The legacy `full`
37
- marker normalizes to full-feature's requirement set.
51
+ - marker absent, unreadable, or unrecognized -> deny on a distinct
52
+ decision path that names the resolved folder and the issue.md path it
53
+ probed and states adding or correcting the marker as the remedy. That
54
+ path does not run the required-file probe and names neither prerequisite
55
+ document, because when the mode is unknown no prerequisite set is
56
+ knowable: a set containing user-story.md cannot be satisfied by full-bug
57
+ or minor-audit work without violating the lifecycle contract, and the
58
+ empty set would fail open. The delegation is still denied, so the gate
59
+ remains fail-closed. The legacy `full` marker normalizes to
60
+ full-feature's requirement set.
38
61
 
39
62
  If any required file is missing, the script emits a PreToolUse JSON
40
63
  response with hookSpecificOutput.permissionDecision='deny' and a reason
@@ -137,9 +160,14 @@ function Get-PrdFeatureRequiredFile {
137
160
  allowed.
138
161
  .DESCRIPTION
139
162
  full-feature requires spec.md and user-story.md; full-bug requires
140
- spec.md only; minor-audit requires neither. A $null or unrecognized
141
- mode fails closed to the strictest set (spec.md and user-story.md) so
142
- an undeterminable mode never becomes permissive.
163
+ spec.md only; minor-audit requires neither.
164
+
165
+ The default arm returns spec.md alone. It is not reached from the
166
+ decision path for an undeterminable mode, which denies on its own branch
167
+ without probing at all; the arm exists so a direct caller passing a $null
168
+ or unrecognized mode never receives a permissive empty set, and it must
169
+ not name user-story.md, because that document is required to be ABSENT
170
+ for full-bug and minor-audit work.
143
171
  #>
144
172
  [CmdletBinding()]
145
173
  [OutputType([string[]])]
@@ -154,7 +182,7 @@ function Get-PrdFeatureRequiredFile {
154
182
  'full-feature' { return [string[]]@('spec.md', 'user-story.md') }
155
183
  'full-bug' { return [string[]]@('spec.md') }
156
184
  'minor-audit' { return [string[]]@() }
157
- default { return [string[]]@('spec.md', 'user-story.md') }
185
+ default { return [string[]]@('spec.md') }
158
186
  }
159
187
  }
160
188
 
@@ -191,9 +219,22 @@ function Get-PrdFeatureCheckpointFolder {
191
219
  function Find-PrdFeatureFolderFromPrompt {
192
220
  <#
193
221
  .SYNOPSIS
194
- Scans a prompt string for docs/features/active/<...> path tokens and
195
- returns the longest unique match resolved to a folder path. Returns
196
- $null when no match is found.
222
+ Scans a prompt string for docs/features/active/<...> path tokens,
223
+ truncates each to exactly four path segments, and returns the selected
224
+ feature folder. Returns $null when no token truncates to four segments.
225
+ .DESCRIPTION
226
+ Truncation to four segments -- docs, features, active, and the
227
+ feature-folder name -- is two segments past the docs/features/active/
228
+ prefix, so the depth at which an artifact is cited cannot change which
229
+ folder is resolved. Candidates are deduplicated preserving
230
+ first-occurrence order; selection among two or more distinct candidates
231
+ prefers the checkpoint's feature-folder field and otherwise takes the
232
+ earliest occurrence in the prompt.
233
+
234
+ The return value is a repo-relative path normalized to forward slashes,
235
+ or $null. The function reads no file except through the existing
236
+ checkpoint seam, and it is deterministic for a given prompt and
237
+ checkpoint value.
197
238
  #>
198
239
  [CmdletBinding()]
199
240
  [OutputType([string])]
@@ -214,22 +255,56 @@ function Find-PrdFeatureFolderFromPrompt {
214
255
  return $null
215
256
  }
216
257
 
217
- $unique = @{}
258
+ # Deduplicate preserving FIRST-OCCURRENCE order. A [hashtable] must not be
259
+ # used here: PowerShell hashtable key enumeration order is unspecified, so a
260
+ # first-occurrence selection rule fed by a hashtable is not deterministic.
261
+ [System.Collections.Generic.List[string]] $candidates = [System.Collections.Generic.List[string]]::new()
218
262
  foreach ($m in $matchList) {
219
263
  $normalized = ($m.Value -replace '\\', '/').TrimEnd('/')
220
- $unique[$normalized] = $true
264
+
265
+ # Truncate to exactly two segments past the docs/features/active/ prefix,
266
+ # that is, to the four segments docs, features, active, and the feature
267
+ # folder name. Truncation is depth-insensitive, so a folder path, a
268
+ # spec.md path, a research/ artifact path, and an evidence/ artifact path
269
+ # all reduce to the same value. A '.' component is a path no-op and is
270
+ # discarded first, so a degenerate token such as docs/features/active/.
271
+ # yields three segments and is rejected rather than resolved.
272
+ $segments = @($normalized -split '/' | Where-Object { $_ -ne '' -and $_ -ne '.' })
273
+ if ($segments.Count -lt 4) {
274
+ continue
275
+ }
276
+
277
+ $truncated = ($segments[0..3] -join '/')
278
+ if (-not $candidates.Contains($truncated)) {
279
+ $candidates.Add($truncated)
280
+ }
221
281
  }
222
282
 
223
- $candidates = @(@($unique.Keys) | Sort-Object -Property Length -Descending)
224
- $best = $candidates[0]
283
+ if ($candidates.Count -eq 0) {
284
+ return $null
285
+ }
225
286
 
226
- # If the longest match ends in .md, treat it as a file and use its parent.
227
- if ($best -match '\.md$') {
228
- $parent = $best -replace '/[^/]+\.md$', ''
229
- return $parent
287
+ # One distinct candidate is used directly, so the common case never consults
288
+ # the checkpoint.
289
+ if ($candidates.Count -eq 1) {
290
+ return $candidates[0]
291
+ }
292
+
293
+ # More than one distinct feature folder was cited. Prefer the folder the
294
+ # orchestrator itself records as in flight: the checkpoint is the
295
+ # authoritative disambiguator, and it reuses a seam this hook already owns.
296
+ $checkpointFolder = Get-PrdFeatureCheckpointFolder
297
+ if ($checkpointFolder) {
298
+ $checkpointNormalized = ($checkpointFolder -replace '\\', '/').TrimEnd('/')
299
+ if ($candidates.Contains($checkpointNormalized)) {
300
+ return $checkpointNormalized
301
+ }
230
302
  }
231
303
 
232
- return $best
304
+ # Tiebreak of last resort: the orchestrator supplies the active feature folder
305
+ # among its delegation inputs and names it before citing artifacts inside it,
306
+ # so a cross-reference to another feature appears later in the prompt.
307
+ return $candidates[0]
233
308
  }
234
309
 
235
310
  function Get-PrdFeatureMissingFile {
@@ -308,10 +383,32 @@ function Invoke-PrdFeatureBeforePlannerDecision {
308
383
 
309
384
  # Derive the prerequisite set from the persisted work-mode marker rather
310
385
  # than a fixed spec.md/user-story.md pair. A marker that cannot be read or
311
- # recognized must fail closed to the strictest set, not fail open.
386
+ # recognized must fail closed, not fail open: it denies on its own branch
387
+ # below, naming no prerequisite set and probing for no required file.
312
388
  $issueContent = Get-PrdFeatureIssueContent -FeatureFolder $folderNormalized
313
389
  $workMode = Resolve-PrdFeatureWorkMode -IssueContent $issueContent
314
- $modeDetermined = [bool]$workMode
390
+
391
+ # An indeterminate mode is its own decision path, and it deliberately does NOT
392
+ # run the required-file probe. When the mode is unknown no prerequisite set is
393
+ # knowable, so any set the gate named would be wrong for at least one mode:
394
+ # a set containing user-story.md is unsatisfiable for full-bug and minor-audit
395
+ # without violating the lifecycle contract, and the empty set fails open. The
396
+ # only remedy true in all three modes is repairing the marker, so that is what
397
+ # the reason states. This still DENIES, so the gate remains fail-closed.
398
+ if (-not $workMode) {
399
+ return [ordered]@{
400
+ hookSpecificOutput = [ordered]@{
401
+ hookEventName = 'PreToolUse'
402
+ permissionDecision = 'deny'
403
+ permissionDecisionReason = "PRD_FEATURE_BLOCKED: resolved feature folder '$folderNormalized', " +
404
+ "but its work mode could not be determined from '$folderNormalized/issue.md' " +
405
+ '(the ''- Work Mode:'' marker is absent, unreadable, or unrecognized). ' +
406
+ 'Confirm that is the intended feature folder, then add or correct the ' +
407
+ '''- Work Mode:'' marker in that file so the prerequisite set can be derived.'
408
+ }
409
+ }
410
+ }
411
+
315
412
  # Force array wrapping: PowerShell unravels a zero-element array return down
316
413
  # the pipeline to $null, which would otherwise fail the Mandatory
317
414
  # -RequiredFile parameter on Get-PrdFeatureMissingFile for minor-audit mode.
@@ -322,13 +419,13 @@ function Invoke-PrdFeatureBeforePlannerDecision {
322
419
  return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
323
420
  }
324
421
 
422
+ # Lead with the resolved folder, not with the remedy: a reader who sees a
423
+ # folder they did not intend diagnoses a path problem immediately instead of
424
+ # re-running a step that has already completed correctly.
325
425
  $list = ($missing -join ', ')
326
- if ($modeDetermined) {
327
- $reason = "PRD_FEATURE_BLOCKED: cannot delegate to atomic-planner before prd-feature outputs are present in '$folderNormalized'. Missing: $list (work mode: $workMode). Invoke the prd-feature subagent first."
328
- }
329
- else {
330
- $reason = "PRD_FEATURE_BLOCKED: cannot delegate to atomic-planner before prd-feature outputs are present in '$folderNormalized'. Missing: $list. Work mode could not be determined from '$folderNormalized/issue.md' (marker absent, unreadable, or unrecognized); failing closed to the strictest prerequisite set (spec.md, user-story.md). Invoke the prd-feature subagent first."
331
- }
426
+ $reason = "PRD_FEATURE_BLOCKED: resolved feature folder '$folderNormalized' is missing: " +
427
+ "$list (work mode: $workMode). Confirm that is the intended feature folder, then " +
428
+ 'invoke the prd-feature subagent to produce the missing output(s).'
332
429
 
333
430
  return [ordered]@{
334
431
  hookSpecificOutput = [ordered]@{
@@ -1,3 +1,10 @@
1
+ ---
2
+ paths:
3
+ - "scripts/benchmarks/**"
4
+ - "**/baseline*.json"
5
+ description: Runner-environment parity and provenance rules for committed benchmark baselines.
6
+ ---
7
+
1
8
  # Benchmark Baseline Provenance
2
9
 
3
10
  This rule governs performance baselines used by benchmark regression gates. It exists because a baseline captured on a developer workstation was compared against a `windows-latest` runner, producing deterministic latency regressions that the benchmark gate could not survive (issue #26, PR #30).
@@ -1,3 +1,9 @@
1
+ ---
2
+ paths:
3
+ - ".github/workflows/**"
4
+ description: Exit-code rules for GitHub Actions workflow steps that run pwsh.
5
+ ---
6
+
1
7
  # CI Workflow Authoring
2
8
 
3
9
  This rule governs GitHub Actions workflow steps that run PowerShell (`pwsh`). It exists because a `pwsh` step that intentionally invoked a failing nested command left `$LASTEXITCODE == 1` after its verification logic had already succeeded, leaking a failure to GitHub Actions even though the step's intent was satisfied (issue #26, PR #30).
@@ -1,3 +1,27 @@
1
+ ---
2
+ paths:
3
+ - "artifacts/orchestration/*orchestrator-state.json"
4
+ - "artifacts/orchestration/*planner-state.json"
5
+ - "scripts/dev_tools/*orchestrator_state*"
6
+ - "extensions/drm-copilot/src/lib/validate/orchestrator-state-*"
7
+ - "scripts/dev_tools/compute_complexity_floor.py"
8
+ - "scripts/dev_tools/resolve_delegation_model.py"
9
+ - ".claude/hooks/validate-orchestrator-output.ps1"
10
+ - ".claude/hooks/enforce-model-routing-receipt.ps1"
11
+ - "config/orchestration-routing.json"
12
+ - ".claude/agents/orchestrator.md"
13
+ - ".claude/agents/epic-orchestrator.md"
14
+ - ".claude/agents/parallel-orchestrator.md"
15
+ - ".claude/agents/epic-planner.md"
16
+ - ".claude/agents/parallel-planner.md"
17
+ - ".claude/skills/orchestrate/SKILL.md"
18
+ - ".claude/skills/epic-orchestrate/SKILL.md"
19
+ - ".claude/skills/parallel-orchestrate/SKILL.md"
20
+ - ".claude/skills/epic-plan/SKILL.md"
21
+ - ".claude/skills/parallel-plan/SKILL.md"
22
+ description: Checkpoint invariants for the orchestration state artifact and the surfaces that write or validate it.
23
+ ---
24
+
1
25
  # Orchestrator-State Remediation-Cycle and Human-Interaction Invariants
2
26
 
3
27
  This rule governs remediation-cycle records and the optional `human_interaction` block in the orchestrator-state checkpoint at `artifacts/orchestration/orchestrator-state.json`. It documents three invariants that must hold for each remediation cycle, plus three invariants for the `human_interaction` block, so that resume and review workflows do not depend on a structurally invalid checkpoint.
@@ -1,3 +1,24 @@
1
+ ---
2
+ paths:
3
+ - "artifacts/orchestration/parallel-*"
4
+ - "docs/features/parallel/**"
5
+ - "scripts/dev_tools/*parallel*"
6
+ - "extensions/drm-copilot/src/lib/validate/parallel-*"
7
+ - "scripts/dev_tools/*blast_radius*"
8
+ - "config/blast-radius.json"
9
+ - "**/config/blast-radius.json"
10
+ - "extensions/drm-copilot/src/lib/push-down/claude-blast-radius-derive-core.ts"
11
+ - ".claude/lib/blast-radius/**"
12
+ - ".claude/lib/bash/parallel-yaml-scan.sh"
13
+ - "scripts/dev_tools/validate_orchestration_artifacts.py"
14
+ - "extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts"
15
+ - ".claude/hooks/enforce-epic-merge-gate.ps1"
16
+ - ".claude/agents/parallel-orchestrator.md"
17
+ - ".claude/agents/parallel-planner.md"
18
+ - ".claude/skills/parallel-*/SKILL.md"
19
+ description: Artifact invariants and blast-radius contention doctrine for the parallel orchestration surface.
20
+ ---
21
+
1
22
  # Parallel Orchestration Artifact Invariants
2
23
 
3
24
  This rule governs the three artifacts of the `parallel` orchestration surface: the parallel-run manifest at `docs/features/parallel/<slug>/parallel.md`, the parallel-orchestrator checkpoint at `artifacts/orchestration/parallel-orchestrator-state.json`, and the parallel-planner checkpoint at `artifacts/orchestration/parallel-planner-state.json`. It records the invariants those artifacts must satisfy as numbered prose so that downstream features consume a fixed schema and add behavior only.
@@ -1,3 +1,15 @@
1
+ ---
2
+ paths:
3
+ - "scripts/dev_tools/plan_gate_*"
4
+ - "scripts/dev_tools/validate_orchestration_artifacts.py"
5
+ - "extensions/drm-copilot/src/lib/validate/plan-gate-*"
6
+ - "extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts"
7
+ - "docs/features/**/plan.*.md"
8
+ - "docs/features/**/remediation-plan.*.md"
9
+ - ".claude/skills/atomic-plan-contract/SKILL.md"
10
+ description: Acceptance-gate rules G1 through G6 applied to the shell commands an atomic plan states as acceptance conditions.
11
+ ---
12
+
1
13
  # Atomic-Plan Acceptance Gates (G1 through G6)
2
14
 
3
15
  This rule governs the acceptance-gate rules the plan validator applies to the shell commands an atomic plan states as acceptance conditions. It exists because a plan can state an acceptance condition that cannot fail: a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. Such a condition reads as a verification step and gates nothing (issue #486).
@@ -19,14 +19,6 @@ checkpoint handling, wave computation, integration-branch lifecycle, wave barrie
19
19
  merge-conflict handling, worktree cleanup, and documentation-maintenance procedures so the
20
20
  procedure is not re-derived ad hoc on each epic run.
21
21
 
22
- ## Prerequisites
23
-
24
- Before proceeding, `epic-orchestrator` must:
25
-
26
- 1. Read `CLAUDE.md` for repository tone policy and architectural context.
27
- 2. Read applicable `.claude/rules/` files for the languages in scope.
28
- 3. Read the policy files listed in the compliance reading order section of `CLAUDE.md`.
29
-
30
22
  ## Epic Dependency Manifest
31
23
 
32
24
  The epic manifest is the YAML frontmatter of the single epic home
@@ -123,7 +115,7 @@ function of the DAG.
123
115
  When `epic-orchestrator` delegates a child feature to `Agent(orchestrator)`, the prompt includes
124
116
  the literal epic-mode kickoff line:
125
117
 
126
- > `Epic mode: true. epic_feature_folder: <epic-slug>. integration_branch: epic/<epic-slug>-integration. epic_checkpoint_path: artifacts/orchestration/epic-orchestrator-state.json. PR base branch MUST be <integration_branch>, not main; pass --base <integration_branch> to gh pr create.`
118
+ > `Epic mode: true. epic_feature_folder: <epic-slug>. integration_branch: epic/<epic-slug>-integration. epic_checkpoint_path: artifacts/orchestration/epic-orchestrator-state.json. PR base branch MUST be <integration_branch>, not main; pass --base <integration_branch> to gh pr create. Your final report MUST be exactly the bounded return shape (issue_num, feature_folder, merge_status, pr_number, merge_commit_sha, blocked_reason, branch_name, worktree_path) and nothing else; any additional narrative is discarded because the parent re-derives authoritative state regardless.`
127
119
 
128
120
  The child's own `orchestrator`, on reading this line, records `epic_mode: true` and
129
121
  `epic_context: { epic_feature_folder, integration_branch, epic_checkpoint_path }` at its first
@@ -131,6 +123,31 @@ checkpoint write, and on CI-green (S9 step 6) merges its own PR into the integra
131
123
  recording `epic_merge: { merge_commit_sha, target_branch, merged_at }`. Standalone (non-epic)
132
124
  orchestration is unchanged: `epic_mode` absent or `false` makes S9 step 6 a no-op.
133
125
 
126
+ ## Bounded Child Return Contract
127
+
128
+ A child `orchestrator`'s final report is consumed as a fixed eight-field shape and nothing else:
129
+
130
+ - `issue_num` — the child's GitHub issue number.
131
+ - `feature_folder` — the child's feature-folder path.
132
+ - `merge_status` — the child's terminal merge-status enum value.
133
+ - `pr_number` — the child's pull-request number, or null when none was opened.
134
+ - `merge_commit_sha` — the merge commit, or null when the child did not merge.
135
+ - `blocked_reason` — a short reason string when the child is blocked, otherwise null.
136
+ - `branch_name` — the child's feature branch.
137
+ - `worktree_path` — the child's isolated worktree path.
138
+
139
+ Content beyond these eight fields is **discarded**. A child that returns a longer narrative is not
140
+ in error; the excess is simply not read into the parent's context, which is what keeps the parent's
141
+ footprint flat as the child count grows.
142
+
143
+ Discarding is safe because the parent re-derives authoritative state regardless, from
144
+ `git worktree list --porcelain`, `git branch`, and
145
+ `gh pr view --json state,mergedAt,headRefOid`. `branch_name` and `worktree_path` are carried in the
146
+ shape only to spare the parent a re-parse of porcelain output per child before
147
+ `git worktree remove`; they are not authoritative and are re-derived like every other field. The
148
+ governing argument is the cache doctrine already recorded in
149
+ `.claude/rules/parallel-orchestration.md`, which is cited here rather than restated.
150
+
134
151
  ## Model Selection
135
152
 
136
153
  When `epic-orchestrator` delegates a child feature to `Agent(orchestrator)`, the prompt appends the
@@ -265,7 +282,7 @@ checkpoint JSON remains the durable, machine-authoritative source.
265
282
  `docs/features/epics/<epic-slug>/epic.md`), `epic_status_doc_path`, `integration_branch`,
266
283
  `completed_steps`, `next_step`, `last_updated`, `current_wave`, `waves[]`, `features[]`,
267
284
  `epic_merge_pr`, and the three receipt arrays (`delegation_receipts[]`, `skill_receipts[]`,
268
- `mcp_call_receipts[]`) — the full schema is defined in `spec.md` §6 of this feature. The
285
+ `mcp_call_receipts[]`). The
269
286
  `merge_status` enum is: `not_started`, `worktree_created`, `pr_open`, `ci_green`,
270
287
  `merge_conflict`, `blocked_conflict_loop_limit`, `merged`, `worktree_removed`. The optional
271
288
  `intent` object (projection of the `epic.md` intent block) is validated presence-gated.
@@ -96,6 +96,16 @@ A delegation prompt carrying the literal marker `Preparation mode: true` (issued
96
96
  - **Terminal checkpoint.** Stop with `completed_steps` containing `S3_promotion` and `S4_atomic_planning`, `next_step: "S5_atomic_execution"`, out-of-scope step statuses set to `not-applicable`, and `blocked_reason: "none"`. Do NOT assert completion (`next_step: "complete"`, `S12_complete`, or a `completed` step8/9/10 status): the run has no PR or CI evidence, and the route's `requires_ci_gate: false` exempts it from `ci_gate` at the completion validator instead.
97
97
  - **Commit.** Commit the prepared feature folder and plan to the current branch (the worktree branch created off the epic integration branch) before stopping, and report the `plan-path` and preflight status in the final output.
98
98
 
99
+ ## Epic Mode Bounded Return
100
+
101
+ Under `Epic mode: true`, your final report must be exactly this eight-field shape and nothing else:
102
+ `issue_num`, `feature_folder`, `merge_status`, `pr_number`, `merge_commit_sha`, `blocked_reason`,
103
+ `branch_name`, `worktree_path`.
104
+
105
+ Content beyond those fields is discarded unread, so spend no effort on it. The parent
106
+ `epic-orchestrator` re-derives authoritative state from git and `gh` regardless, per
107
+ `## Bounded Child Return Contract` in `.claude/skills/epic-orchestrate/SKILL.md`.
108
+
99
109
  ## Model Selection
100
110
 
101
111
  Model selection is a second axis, strictly separate from `route`. `route` (`small | large | remediation | preparation | epic`) is deterministic — file-count driven for `small`/`large`, marker-driven for `preparation` (the `Preparation mode: true` kickoff line) and `epic`; it governs `required_agents`, `required_skills`, and `required_mcp_tools` only. `route` is NOT an input to model selection anywhere. The sole feature-level input to the delegation model tier is a judgment-based `complexity_band` (`C1 | C2 | C3 | C4`). The authoritative values live in the `model_policy` block of `config/orchestration-routing.json`.
@@ -2,7 +2,7 @@ default_permissions = ":danger-full-access"
2
2
 
3
3
  [mcp_servers.drm-copilot]
4
4
  command = "npx"
5
- args = ["-y", "@danmoisan/drm-copilot-mcp@1.1.3"]
5
+ args = ["-y", "@danmoisan/drm-copilot-mcp@1.1.4"]
6
6
  required = true
7
7
  enabled_tools = [
8
8
  "collect_commit_context",
@@ -210,6 +210,28 @@
210
210
  '.claude/hooks/enforce-prd-feature-before-planner.ps1'
211
211
  '.claude/hooks/enforce-parallel-cohort-barrier-helpers.ps1'
212
212
  '.claude/hooks/enforce-pr-author-skill-helpers.ps1'
213
+ # Issue #526 added this out-of-band release-verification module (Layer B of the
214
+ # missed-npm-publish defence). CodeCoverage.Path is an explicit per-file
215
+ # allow-list, so the new production file is registered here; without it the file
216
+ # would sit outside the coverage denominator, which the Coverage Exclusion Policy
217
+ # forbids. Its Pester suite dot-sources the file (guarded entry-point body), so
218
+ # line attribution is valid.
219
+ 'scripts/dev-tools/Invoke-ReleaseVerification.ps1'
220
+ # Issue #526 split the pure helpers of the verification module into this sibling
221
+ # file, because the parent stood one line under the 500-line cap. CodeCoverage.Path
222
+ # is an explicit per-file allow-list, so the new production file must be registered
223
+ # here to stay inside the coverage denominator; without it the relocated lines would
224
+ # leave the denominator entirely, which the Coverage Exclusion Policy forbids. Its
225
+ # Pester suite dot-sources the file, and the file declares no entry-point block, so
226
+ # line attribution is valid.
227
+ 'scripts/dev-tools/Invoke-ReleaseVerificationHelpers.ps1'
228
+ # Issue #526 added this release-reconciliation module (Layer C of the
229
+ # missed-npm-publish defence). CodeCoverage.Path is an explicit per-file
230
+ # allow-list, so the new production file is registered here; without it the file
231
+ # would sit outside the coverage denominator, which the Coverage Exclusion Policy
232
+ # forbids. Its Pester suite dot-sources the file (guarded entry-point body), so
233
+ # line attribution is valid.
234
+ 'scripts/dev-tools/Invoke-ReleaseReconciliation.ps1'
213
235
  )
214
236
  # Optional: don't fail the run on coverage percentage
215
237
  CoveragePercentTarget = 0