@danmoisan/drm-copilot-mcp 1.0.21 → 1.0.23
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 +1730 -139
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +257 -0
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +183 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
- package/resources/claude-customizations/.claude/lib/bash/compute-cohorts.sh +143 -0
- package/resources/claude-customizations/.claude/lib/bash/compute-concurrency-batches.sh +122 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +330 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-common.sh +238 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-items-validate.sh +244 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +187 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-emit.sh +340 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-scan.sh +335 -0
- package/resources/claude-customizations/.claude/lib/bash/validate-parallel-manifest.sh +134 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
- package/resources/claude-customizations/.claude/rules/shell.md +7 -2
- package/resources/claude-customizations/.claude/settings.json +28 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +152 -0
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +971 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +461 -0
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
- package/resources/claude-customizations/config/blast-radius.json +16 -0
- package/resources/claude-customizations/config/orchestration-routing.json +355 -0
- package/resources/claude-customizations/pack-manifests/core.json +32 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +22 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +29 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: parallel-plan
|
|
3
|
+
description: Prepare a set of thematically unrelated items for concurrent execution before any execution begins - item intake over issue numbers and potential-entry paths, concurrent preparation-mode child orchestrator delegations, blast-radius computation and V1-V3 validation, cohort seeding with a recomputation-parity check, run-manifest and planner-checkpoint authoring, and the parallel-orchestrator kickoff artifact.
|
|
4
|
+
argument-hint: "[items: issue numbers and/or potential-entry paths]"
|
|
5
|
+
context: fork
|
|
6
|
+
agent: parallel-planner
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Parallel Plan Skill
|
|
10
|
+
|
|
11
|
+
A user invocation (`/parallel-plan <slug> <item> [<item> ...]`) forks the `parallel-planner` agent
|
|
12
|
+
with this procedure in context. The run slug and item list for this run are:
|
|
13
|
+
|
|
14
|
+
$ARGUMENTS
|
|
15
|
+
|
|
16
|
+
This skill frames work for the `parallel-planner` agent, parallel to how
|
|
17
|
+
`.claude/skills/epic-plan/SKILL.md` frames work for `epic-planner`. The `parallel` surface
|
|
18
|
+
schedules thematically unrelated items by computed blast-radius contention: there is no worthiness
|
|
19
|
+
assessment, no operator-supplied ordering, and no shared branch into which item work merges.
|
|
20
|
+
Planning ends at preflight clearance and cohort seeding; no atomic execution, PR authoring, or CI
|
|
21
|
+
monitoring occurs under this skill.
|
|
22
|
+
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
Before proceeding, `parallel-planner` must:
|
|
26
|
+
|
|
27
|
+
1. Read `CLAUDE.md` for repository tone policy and architectural context.
|
|
28
|
+
2. Read applicable `.claude/rules/` files for the languages in scope, including
|
|
29
|
+
`.claude/rules/parallel-orchestration.md`, which is the schema authority for the run manifest,
|
|
30
|
+
both parallel checkpoints, and the nine parallel enums.
|
|
31
|
+
3. Read the policy files listed in the compliance reading order section of `CLAUDE.md`.
|
|
32
|
+
|
|
33
|
+
## Item Intake
|
|
34
|
+
|
|
35
|
+
Invocation shape: `/parallel-plan <slug> <item> [<item> ...]`, where each `<item>` is either a
|
|
36
|
+
GitHub issue number (already-promoted work) or a potential-entry path (unpromoted work). This is
|
|
37
|
+
the same intake domain as `/parallel-add`, so initial intake here and F6's add operation accept
|
|
38
|
+
identical forms.
|
|
39
|
+
|
|
40
|
+
- **Promotion.** Unpromoted items are promoted by their own preparation-mode child, not by the
|
|
41
|
+
planner. The `preparation` route already carries the promotion MCP tools (`new_potential_entry`,
|
|
42
|
+
`potential_to_issue`, `new_active_feature_folder`).
|
|
43
|
+
- **`issue_num` resolution.** `issue_num` is the primary key for every item reference. It is known
|
|
44
|
+
at intake for issue-number items. For potential-entry items, record negative placeholders in
|
|
45
|
+
intake order (`-1`, `-2`, ...) and back-fill the real number from each child's promotion receipt
|
|
46
|
+
as preparation completes. Ordering is safe by construction: cohort seeding requires declared
|
|
47
|
+
radii, radii require approved plans, and plans require promotion, so every placeholder resolves
|
|
48
|
+
before seeding runs.
|
|
49
|
+
- **Fully resolved before kickoff.** The manifest is committed in fully resolved form — no negative
|
|
50
|
+
`issue_num` remaining — before the kickoff artifact is written.
|
|
51
|
+
- **`feature_folder`.** Recorded at intake as a resolvable-hint basename, then resolved to a
|
|
52
|
+
concrete `docs/features/active/<basename>` path after promotion with any lifecycle prefix
|
|
53
|
+
stripped, per the `epic-orchestrate` convention. The concrete location is additionally fixed by
|
|
54
|
+
the per-item `branch_name` recorded in the checkpoint.
|
|
55
|
+
- **`kind`.** Record `kind: feature | bug` at intake from the item source (issue labels, or the
|
|
56
|
+
potential entry's declared kind). When the source is indeterminate, default to `feature` and note
|
|
57
|
+
the choice `[recommendation, not upstream-constrained]`.
|
|
58
|
+
|
|
59
|
+
The operator is never asked for ordering edges, cohort assignments, or a worthiness verdict.
|
|
60
|
+
Intake proceeds directly to preparation fan-out.
|
|
61
|
+
|
|
62
|
+
## Preparation Fan-Out
|
|
63
|
+
|
|
64
|
+
One preparation-mode `Agent(orchestrator)` run per item. Preparation produces documents and plans
|
|
65
|
+
rather than code, and items carry no ordering constraint, so launch ALL item preparations
|
|
66
|
+
concurrently: one message, N `Agent` calls, each `isolation: "worktree"` and
|
|
67
|
+
`run_in_background: true`. Create each preparation worktree's branch from `origin/main`.
|
|
68
|
+
|
|
69
|
+
Each delegation prompt includes this literal kickoff line, followed by the model-budget marker
|
|
70
|
+
line:
|
|
71
|
+
|
|
72
|
+
> `Preparation mode: true. route_id: preparation. parallel_slug: <slug>. Perform promotion, research, feature documents (spec.md, user-story.md), atomic planning, and preflight clearance only. Atomic execution, PR authoring, and CI monitoring are out of scope for this run and are executed later by parallel-orchestrator. After the atomic-executor preflight returns PREFLIGHT: ALL CLEAR, commit the feature folder and plan to the current branch, push the current branch to origin, set out-of-scope step statuses to not-applicable, set next_step to S5_atomic_execution, and stop, reporting the plan-path and preflight status.`
|
|
73
|
+
>
|
|
74
|
+
> `model_budget.fable_policy: <disabled|available|preferred>.`
|
|
75
|
+
|
|
76
|
+
Properties of that line, each individually load-bearing:
|
|
77
|
+
|
|
78
|
+
- The markers `Preparation mode: true.` and `route_id: preparation.` are reused verbatim. Route
|
|
79
|
+
selection is marker-driven, so no issuer identity is required.
|
|
80
|
+
- `parallel_slug: <slug>.` replaces the epic context fields.
|
|
81
|
+
- The push instruction is an addition to the planner's own prompt, not to the child contract text
|
|
82
|
+
in `.claude/skills/orchestrate/SKILL.md`. It is required so each item's prepared work is durable
|
|
83
|
+
before its worktree is removed.
|
|
84
|
+
- Downstream attribution reads "executed later by parallel-orchestrator". The planner authors its
|
|
85
|
+
own prompt; the `orchestrate` skill text is untouched.
|
|
86
|
+
- The `model_budget.fable_policy` marker line is appended per the pattern in
|
|
87
|
+
`.claude/skills/epic-orchestrate/SKILL.md` `## Model Selection`. The default is `disabled` when
|
|
88
|
+
the marker is absent.
|
|
89
|
+
|
|
90
|
+
**Deliberate omissions.** The kickoff line above carries neither mode marker. It contains no
|
|
91
|
+
`Epic mode: true`, so `enforce-epic-wave-barrier.ps1` — which gates execution-phase delegations —
|
|
92
|
+
does not apply to preparation. It contains no `Parallel mode: true`, so F7's future cohort-barrier
|
|
93
|
+
hook, which matches that marker, will not gate preparation either. Both omissions are intentional
|
|
94
|
+
and must be preserved verbatim when the line is emitted.
|
|
95
|
+
|
|
96
|
+
**No edit to shared surfaces.** No edit is made to `.claude/skills/orchestrate/SKILL.md` or to
|
|
97
|
+
`config/orchestration-routing.json`, including the `preparation` route. The route mechanism is
|
|
98
|
+
marker-driven; the child contract's "commit ... to the current branch" wording is satisfied by a
|
|
99
|
+
branch created off `origin/main`; and `routes.preparation` declares no epic-specific required
|
|
100
|
+
agent, skill, or MCP tool.
|
|
101
|
+
|
|
102
|
+
**Collected per child at termination:** `plan-path`, preflight status, the promotion receipt (the
|
|
103
|
+
`issue_num` back-fill source), the model-routing receipt with `logical_agent: "orchestrator"`, the
|
|
104
|
+
topology receipt, `branch_name`, and `worktree_path`. There is no fan-in merge step: the planner
|
|
105
|
+
fetches and records each pushed item branch, back-fills `issue_num` into the manifest on
|
|
106
|
+
`parallel/<slug>-plan`, and updates the checkpoint.
|
|
107
|
+
|
|
108
|
+
## Artifact Home
|
|
109
|
+
|
|
110
|
+
**Per-item artifacts.** Each item's prepared feature folder and approved atomic plan live on that
|
|
111
|
+
item's own feature branch, created from `origin/main` at preparation time, committed by the
|
|
112
|
+
unchanged `route_id: preparation` terminal step, pushed to `origin` before its worktree is removed,
|
|
113
|
+
and reused unchanged as the item's execution branch. Record `branch_name` and `worktree_path` per
|
|
114
|
+
item in the checkpoint.
|
|
115
|
+
|
|
116
|
+
**Run-level artifacts.** `docs/features/parallel/<slug>/parallel.md` (the run manifest) and
|
|
117
|
+
`docs/features/parallel/<slug>/parallel-kickoff.md` (the durable kickoff copy) live on the
|
|
118
|
+
planner-owned branch `parallel/<slug>-plan`, created off `origin/main` and pushed. That branch is
|
|
119
|
+
explicitly not an integration branch: no item branch ever merges into it, it never merges into any
|
|
120
|
+
item branch, and it holds only `docs/features/parallel/<slug>/**`, a subtree no item's blast radius
|
|
121
|
+
may include. Each item opens its own pull request against `main`.
|
|
122
|
+
|
|
123
|
+
**Read access.** Readers — validators and the future `parallel-orchestrator` — reach both artifact
|
|
124
|
+
classes by ref: `git fetch origin <branch>` followed by `git show <ref>:<path>`, without checking
|
|
125
|
+
the ref out, per the technique documented in `.claude/skills/epic-run/SKILL.md`.
|
|
126
|
+
|
|
127
|
+
Three residual risks are recorded rather than eliminated:
|
|
128
|
+
|
|
129
|
+
1. **Stale execution base.** An item branch created at preparation time is based on an older `main`
|
|
130
|
+
tip by the time its cohort executes. Mitigation is F5-owned (the execution-phase child merges
|
|
131
|
+
`origin/main` at start, and cohort construction keeps peers non-conflicting); real overlap is
|
|
132
|
+
caught by F8 drift detection. This skill records the branch-reuse contract only.
|
|
133
|
+
2. **Branch accumulation on withdrawal.** Withdrawn or abandoned items leave pushed preparation
|
|
134
|
+
branches. F6's `--disposition abandon` path is expected to delete the branch; the cleanup
|
|
135
|
+
expectation is recorded here so F6 can implement it.
|
|
136
|
+
3. **Per-branch git-integrity requirement — F4-owned.** The readiness gate's git-integrity check
|
|
137
|
+
must verify committed plan blobs against each per-item branch ref plus the
|
|
138
|
+
`parallel/<slug>-plan` ref, rather than against a single shared ref. This obligation belongs to
|
|
139
|
+
the planner surface, not to the schema feature: `.claude/rules/parallel-orchestration.md` states
|
|
140
|
+
that F3's `require_ready_for_execution` gate is structural only and leaves git-integrity checks,
|
|
141
|
+
launch-evidence binding, and kickoff-contract cross-checks to F4.
|
|
142
|
+
|
|
143
|
+
## Radius Computation and Validation
|
|
144
|
+
|
|
145
|
+
Reach blast-radius derivation, validation, and contention through the **destination-runtime
|
|
146
|
+
PowerShell port** under `.claude/lib/blast-radius/`, which is published by push-down and needs no
|
|
147
|
+
Python interpreter:
|
|
148
|
+
|
|
149
|
+
```powershell
|
|
150
|
+
Import-Module .claude/lib/blast-radius/BlastRadius.psm1 -Force
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The facade re-exports the five functions this skill needs: `Get-PlanPaths` (port of
|
|
154
|
+
`extract_plan_paths`), `Get-BlastRadius` (port of `derive_blast_radius`),
|
|
155
|
+
`Get-BlastRadiusFromObservedPaths` (port of `radius_from_observed_paths`), `Test-BlastRadius`
|
|
156
|
+
(port of `validate_blast_radius`), and `Test-BlastRadiusConflict` (port of `conflicts`). Wrap a
|
|
157
|
+
call to `Test-BlastRadius` in `@(...)`: it writes its findings to the pipeline, so a zero-element
|
|
158
|
+
result writes nothing and a one-element result writes a single object.
|
|
159
|
+
|
|
160
|
+
The truth table the port reads is `config/blast-radius.json`, which push-down publishes into the
|
|
161
|
+
destination workspace alongside `.claude`.
|
|
162
|
+
|
|
163
|
+
The Python modules named below remain the repository authority and the parity reference; they are
|
|
164
|
+
cited for their contract, not invoked on the destination-runtime path. Landed contract, consumed
|
|
165
|
+
as-is and never reimplemented here:
|
|
166
|
+
|
|
167
|
+
- **Derivation.**
|
|
168
|
+
`derive_blast_radius(plan_text, spec_text, feature_folder, config, *, source, computed_at) -> BlastRadius`
|
|
169
|
+
in `scripts/dev_tools/compute_blast_radius.py`. It takes the approved atomic plan's **document
|
|
170
|
+
text** and the feature `spec.md`'s **document text**, the feature folder name, and the parsed
|
|
171
|
+
`config/blast-radius.json` truth table. It does not take file paths: read the documents and pass
|
|
172
|
+
their text.
|
|
173
|
+
- **Serialized shape.** `BlastRadius.to_dict()` yields exactly the key set
|
|
174
|
+
`("paths", "modules", "shared_surfaces", "contracts", "source", "computed_at")`, which is the
|
|
175
|
+
shape both the manifest and the checkpoint record.
|
|
176
|
+
- **Validation.** `validate_blast_radius(radius, plan_text, config, *, tracked_file_count)` in
|
|
177
|
+
`scripts/dev_tools/_blast_radius_validation.py` returns findings over three rules:
|
|
178
|
+
`RULE_COVERAGE = "V1"`, `RULE_SHARED_SURFACE = "V2"`, and `RULE_OVER_BREADTH = "V3"`. Each finding
|
|
179
|
+
carries a severity of `Blocking` or `Advisory`.
|
|
180
|
+
- **Contention.** `conflicts(a, b, config) -> ConflictResult`, re-exported from
|
|
181
|
+
`compute_blast_radius.py`. The signature takes three arguments; the third is the parsed
|
|
182
|
+
`config/blast-radius.json`. Reasons come from the fixed vocabulary
|
|
183
|
+
`{path_overlap, module_overlap, shared_surface_overlap, contract_dependency}`, and the relation
|
|
184
|
+
fails closed.
|
|
185
|
+
|
|
186
|
+
**The F1a corrections (issue #452, merged PR #453) are load-bearing.** Derivation now reaches
|
|
187
|
+
separator-free repository-root shared surfaces from plan and spec text, admitting such a token only
|
|
188
|
+
as an exact ordinal member of the configured `shared_surfaces` list in `config/blast-radius.json`;
|
|
189
|
+
and the contention path comparison now honours listed-directory prefixes on both sides, aligning
|
|
190
|
+
with `is_path_subsumed`. Both corrections move results in the fail-closed direction — they report
|
|
191
|
+
more contention, not less. Do not work around either correction, and do not narrow a radius in
|
|
192
|
+
order to suppress a conflict edge they produce.
|
|
193
|
+
|
|
194
|
+
### Planner procedure
|
|
195
|
+
|
|
196
|
+
1. After an item's plan is approved and preflight-clear, read the approved plan text and the
|
|
197
|
+
feature `spec.md` text, derive the radius with `source: "declared"`, and record it on the item.
|
|
198
|
+
The `declared` radius is the authoritative input to scheduling.
|
|
199
|
+
2. Validate the radius and record the findings under the item's `radius_validation` entry.
|
|
200
|
+
3. **V1 (coverage) or V2 (shared-surface enumeration) Blocking failure.** The item does NOT
|
|
201
|
+
transition to `prepared`. Record the findings in the checkpoint and issue a follow-up
|
|
202
|
+
preparation-mode delegation for that item carrying the findings as plan-revision instructions —
|
|
203
|
+
the same iterate-until-clear posture the child already applies to preflight. The item is
|
|
204
|
+
re-planned, not rejected. Withdrawal is a caller decision made through F6's remove operation and
|
|
205
|
+
is never a planner default.
|
|
206
|
+
4. **V3 (over-breadth) Advisory.** Record it in the checkpoint and surface it in the completion
|
|
207
|
+
report. It has no state effect.
|
|
208
|
+
5. **Readiness conjunction.** `prepared` requires BOTH `preflight_status == "PREFLIGHT: ALL CLEAR"`
|
|
209
|
+
AND a `declared` radius that passed V1 and V2.
|
|
210
|
+
|
|
211
|
+
Derivation, the V1-V3 rules, and the contention relation are implemented upstream. This skill calls
|
|
212
|
+
them; it defines none of them.
|
|
213
|
+
|
|
214
|
+
## Cohort Seeding
|
|
215
|
+
|
|
216
|
+
Reach cohort computation through the **destination-runtime bash entry point** under
|
|
217
|
+
`.claude/lib/bash/`, which is published by push-down and needs no Python interpreter:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
bash .claude/lib/bash/compute-cohorts.sh --keys "<k1> <k2> ..." --edges "<a>:<b> <a>:<b> ..."
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
`--edges` is optional; omitting it, or passing an empty string, means the conflict graph has no
|
|
224
|
+
edges. The entry point prints a compact JSON array of arrays on stdout, identical to Python
|
|
225
|
+
`json.dumps(..., separators=(",", ":"))`. On malformed input it prints the reference
|
|
226
|
+
implementation's exact message on stderr and exits 1; a token outside the accepted integer lexis
|
|
227
|
+
`-?(0|[1-9][0-9]*)` is rejected fail-closed with exit 2.
|
|
228
|
+
|
|
229
|
+
Landed contract, mirrored byte for byte by the bash entry point:
|
|
230
|
+
|
|
231
|
+
- `compute_cohorts(item_keys, conflict_edges) -> list[list[int]]` in
|
|
232
|
+
`scripts/dev_tools/parallel_cohort_computation.py` is the repository authority and the parity
|
|
233
|
+
reference. The signature accepts exactly two parameters, `item_keys: Iterable[int]` and
|
|
234
|
+
`conflict_edges: Iterable[tuple[int, int]]`. There is no third parameter and nothing further to
|
|
235
|
+
supply at seeding time.
|
|
236
|
+
- The return value is a plain list of lists in deterministic Welsh-Powell order: vertices are
|
|
237
|
+
visited by the composite key `(-degree, item_key)` ascending — descending distinct-neighbour
|
|
238
|
+
degree with ties broken by ascending item key — and each vertex takes the lowest cohort index not
|
|
239
|
+
already held by one of its neighbours.
|
|
240
|
+
- Recoloring support belongs to F6 and F8, which is why the landed seeding signature needs no
|
|
241
|
+
additional state input.
|
|
242
|
+
|
|
243
|
+
**Mapping to the recorded shape.** This planner maps the returned list of lists into the F3-owned
|
|
244
|
+
`cohorts[]` object shape, supplying `index` from the outer-list position and `generation: 0` itself.
|
|
245
|
+
The library returns the partition; the planner supplies the record fields.
|
|
246
|
+
|
|
247
|
+
### Seeding procedure
|
|
248
|
+
|
|
249
|
+
1. Invoke `compute-cohorts.sh` exactly once per plan run, over the full conflict graph, after every
|
|
250
|
+
item is `prepared` and radius-validated. Derive the conflict edge set by applying
|
|
251
|
+
`Test-BlastRadiusConflict` to every unordered pair of `declared` radii, then pass the pairs as
|
|
252
|
+
`--edges "<a>:<b> ..."` and the item keys as `--keys "<k1> <k2> ..."`.
|
|
253
|
+
2. Record `cohorts[]` at `generation: 0`, each cohort's `item_keys[]` sorted ascending.
|
|
254
|
+
3. Record `conflict_edges[]` as `{a, b, reason}` entries for auditability.
|
|
255
|
+
4. Record `recolor_generation: 0` and `current_cohort: 0`.
|
|
256
|
+
5. Record `max_concurrency` — default 4, bounded 1 through 8 by the F3 schema — without enforcing
|
|
257
|
+
it. Enforcement is F5's, through
|
|
258
|
+
`bash .claude/lib/bash/compute-concurrency-batches.sh --keys "<k1> ..." --max-concurrency <n>`
|
|
259
|
+
(the bash port of `compute_concurrency_batches(cohort_item_keys, max_concurrency)`), which fills
|
|
260
|
+
slots in ascending item-key order. Recoloring under add, remove, or drift mutation is F6 and F8
|
|
261
|
+
scope. This skill performs seeding only.
|
|
262
|
+
|
|
263
|
+
### Recomputation parity (planner-owned check)
|
|
264
|
+
|
|
265
|
+
Planner invariant P5 in `.claude/rules/parallel-orchestration.md` is deliberately absent from the
|
|
266
|
+
F3 validator and states that recomputation parity against the cohort-computation module is the
|
|
267
|
+
planner-surface feature's check — the analogue of the epic planner's wave-number cross-check. This
|
|
268
|
+
skill discharges that obligation as documented procedure, not as a new module:
|
|
269
|
+
|
|
270
|
+
1. After writing `cohorts[]` into the checkpoint and **before** emitting the kickoff artifact,
|
|
271
|
+
re-invoke `compute_cohorts` over exactly the `item_keys` and `conflict_edges` recorded in the
|
|
272
|
+
checkpoint.
|
|
273
|
+
2. Assert that the recomputed list of lists maps to exactly the recorded `cohorts[]` at
|
|
274
|
+
`generation: 0`: the same partition, the same `index` assignment, and the same ascending
|
|
275
|
+
`item_keys[]` ordering.
|
|
276
|
+
3. A mismatch is a **Blocking** condition. Stop the run and report the mismatch. Do not
|
|
277
|
+
auto-correct the recorded cohorts, and do not emit the kickoff artifact.
|
|
278
|
+
|
|
279
|
+
No production module is added for this check; it is a re-invocation of the landed library.
|
|
280
|
+
|
|
281
|
+
## Manifest Authoring
|
|
282
|
+
|
|
283
|
+
Write `docs/features/parallel/<slug>/parallel.md` conforming to the F3-owned frontmatter schema
|
|
284
|
+
recorded in `.claude/rules/parallel-orchestration.md` (manifest invariants M1-M7):
|
|
285
|
+
|
|
286
|
+
- `parallel` — the run slug, a non-empty string.
|
|
287
|
+
- `mode` — `closed` or `open`; defaults to `closed` when absent.
|
|
288
|
+
- `max_concurrency` — an integer from 1 through 8; defaults to `4` when absent.
|
|
289
|
+
- `created_at` — a non-empty ISO-8601 string.
|
|
290
|
+
- `items[]` — one entry per item, each carrying `issue_num` (a positive integer, unique across
|
|
291
|
+
items), `feature_folder` (a non-empty string), `kind` (`feature` or `bug`), `state`, and
|
|
292
|
+
`blast_radius` carrying `paths`, `modules`, `shared_surfaces`, `contracts`, `source: "declared"`,
|
|
293
|
+
and `computed_at`.
|
|
294
|
+
|
|
295
|
+
The manifest carries no `depends_on` field at any level and no top-level `integration_branch`
|
|
296
|
+
field; both are prohibited-key rejections in the schema. Commit it to `parallel/<slug>-plan` in
|
|
297
|
+
fully resolved form — every negative placeholder `issue_num` replaced by its promoted number —
|
|
298
|
+
before the kickoff artifact is written.
|
|
299
|
+
|
|
300
|
+
Validate the manifest with the **destination-runtime bash entry point**, which is published by
|
|
301
|
+
push-down and needs no Python interpreter:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
bash .claude/lib/bash/validate-parallel-manifest.sh <manifest-path>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
It prints validation errors one per line on stdout and exits 0 for a valid manifest, 1 for an
|
|
308
|
+
invalid one, and 2 for an unreadable file or a YAML construct outside the supported subset. The two
|
|
309
|
+
default-resolving accessors are subcommands of the same entry point:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
bash .claude/lib/bash/validate-parallel-manifest.sh --print-mode <manifest-path>
|
|
313
|
+
bash .claude/lib/bash/validate-parallel-manifest.sh --print-max-concurrency <manifest-path>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
They resolve the documented defaults `closed` and `4` when the manifest omits the key or carries a
|
|
317
|
+
malformed value. Consume `mode` and `max_concurrency` through these accessors rather than reading
|
|
318
|
+
the frontmatter directly.
|
|
319
|
+
|
|
320
|
+
`scripts/dev_tools/parallel_manifest_contract.py` (`validate_parallel_manifest_text`,
|
|
321
|
+
`manifest_mode`, `manifest_max_concurrency`) remains the repository authority and the parity
|
|
322
|
+
reference. Manifest validation is deliberately not an MCP `artifact_type`; do not attempt to
|
|
323
|
+
validate the manifest through `mcp__drm-copilot__validate_orchestration_artifacts`.
|
|
324
|
+
|
|
325
|
+
## Checkpoint Persistence
|
|
326
|
+
|
|
327
|
+
Write `artifacts/orchestration/parallel-planner-state.json` after every completed step.
|
|
328
|
+
|
|
329
|
+
Top-level fields: `objective`, `parallel_slug`, `parallel_manifest_path`, `mode`,
|
|
330
|
+
`max_concurrency`, `plan_home_branch` (`parallel/<slug>-plan`), `items[]`, `cohorts[]`,
|
|
331
|
+
`conflict_edges[]`, `recolor_generation`, `kickoff_prompt_path`
|
|
332
|
+
(`artifacts/orchestration/parallel-kickoff-<slug>.md`), `completed_steps`, `next_step`, and
|
|
333
|
+
`last_updated`. F3's landed required-key set (planner invariant P1) is a strict subset of this
|
|
334
|
+
list, and `plan_home_branch` is a permitted additional field.
|
|
335
|
+
|
|
336
|
+
Per item: `issue_num`, `feature_folder`, `kind`, `state`, `complexity_band`, `preparation_status`,
|
|
337
|
+
`research_path`, `plan_path`, `preflight_status`, `branch_name`, `worktree_path`, `blast_radius`
|
|
338
|
+
(with `source: "declared"`), `radius_validation` (the `v1`, `v2`, and `v3` results with their
|
|
339
|
+
severities), `model_routing_receipt`, and `topology_receipt`.
|
|
340
|
+
|
|
341
|
+
**Deliberately absent:** any `epic_worthiness` analogue, any `depends_on` field, and any `wave`
|
|
342
|
+
field. The parallel surface renders no worthiness verdict and expresses ordering only as
|
|
343
|
+
blast-radius overlap.
|
|
344
|
+
|
|
345
|
+
**Readiness contract.** Before reporting completion the checkpoint must satisfy F3's
|
|
346
|
+
`require_ready_for_execution` gate: at least two items (invariant P6); every item
|
|
347
|
+
`preparation_status: prepared` with `preflight_status` exactly `PREFLIGHT: ALL CLEAR`, non-empty
|
|
348
|
+
`research_path` and `plan_path`, and `blast_radius.source == "declared"` (P7); `next_step` exactly
|
|
349
|
+
the ready sentinel `PARALLEL_EXECUTION_READY` (P8); and `kickoff_prompt_path` exactly
|
|
350
|
+
`artifacts/orchestration/parallel-kickoff-<slug>.md` (P9).
|
|
351
|
+
|
|
352
|
+
**Git integrity is F4-owned.** F3's `require_ready_for_execution` gate is structural only, so
|
|
353
|
+
verifying that each item's committed plan blob exists on that item's pushed branch ref — and that
|
|
354
|
+
the manifest and durable kickoff exist on the `parallel/<slug>-plan` ref — is this planner
|
|
355
|
+
surface's obligation, layered behind the planner's own check without changing the F3 schema.
|
|
356
|
+
Perform it with `git cat-file -e <ref>:<path>` and `git show <ref>:<path>` against each per-item
|
|
357
|
+
branch ref plus `parallel/<slug>-plan`.
|
|
358
|
+
|
|
359
|
+
**Cache doctrine.** The checkpoint is a cache of durable state, not the source of truth. On resume,
|
|
360
|
+
re-derive ground truth from `git branch`, `git worktree list --porcelain`, and the pushed refs.
|
|
361
|
+
Where the checkpoint and the repository disagree, the repository wins and the checkpoint is
|
|
362
|
+
rewritten from it.
|
|
363
|
+
|
|
364
|
+
Validate the checkpoint through `mcp__drm-copilot__validate_orchestration_artifacts` with
|
|
365
|
+
`artifact_type: "parallel-planner-state"` before reporting completion.
|
|
366
|
+
|
|
367
|
+
## F3 Ownership Boundary
|
|
368
|
+
|
|
369
|
+
The following surfaces are owned by the schema-and-validator feature (F3). This planner writes
|
|
370
|
+
conforming instances and consumes the fixed enums; it never extends or redefines them:
|
|
371
|
+
|
|
372
|
+
- The manifest schema and the planner-checkpoint schema, recorded as prose invariants in
|
|
373
|
+
`.claude/rules/parallel-orchestration.md`, together with all nine parallel enums.
|
|
374
|
+
- `scripts/dev_tools/validate_parallel_planner_state.py` and
|
|
375
|
+
`scripts/dev_tools/validate_parallel_orchestrator_state.py`.
|
|
376
|
+
- The two state MCP `artifact_type` values `parallel-planner-state` and
|
|
377
|
+
`parallel-orchestrator-state`.
|
|
378
|
+
- The `route_id: parallel` entry in `config/orchestration-routing.json`.
|
|
379
|
+
|
|
380
|
+
The kickoff contract is **not** F3-owned. `scripts/dev_tools/parallel_kickoff_contract.py` and the
|
|
381
|
+
MCP `artifact_type: "parallel-kickoff"` are F4-owned and are **delivered by this feature**, per the
|
|
382
|
+
epic-manifest adjudication "Planner Adjudication: the kickoff-contract boundary (F3 / F4)" and the
|
|
383
|
+
matching "F3 Scope Boundary — kickoff contract deferred to F4" section of
|
|
384
|
+
`.claude/rules/parallel-orchestration.md`. Both are landed modules, not a recommendation carrying a
|
|
385
|
+
pending contingency.
|
|
386
|
+
|
|
387
|
+
The single-item-run floor question is resolved by F3's landed ready-gate invariant P6, which
|
|
388
|
+
requires at least two items under `require_ready_for_execution`. A one-item run cannot reach a ready
|
|
389
|
+
checkpoint.
|
|
390
|
+
|
|
391
|
+
## Kickoff Artifact
|
|
392
|
+
|
|
393
|
+
Write the working copy to `artifacts/orchestration/parallel-kickoff-<slug>.md` (a gitignored tree)
|
|
394
|
+
and commit a byte-identical durable copy to `docs/features/parallel/<slug>/parallel-kickoff.md` on
|
|
395
|
+
`parallel/<slug>-plan`.
|
|
396
|
+
|
|
397
|
+
```markdown
|
|
398
|
+
# Parallel Kickoff: <slug>
|
|
399
|
+
|
|
400
|
+
Planned by parallel-planner on <iso8601>. All items are prepared: promoted, active folders created,
|
|
401
|
+
research complete, spec and user-story written, atomic plans approved, preflight ALL CLEAR, blast
|
|
402
|
+
radii declared and V1/V2-clear. Planning state:
|
|
403
|
+
artifacts/orchestration/parallel-planner-state.json (run branch: parallel/<slug>-plan).
|
|
404
|
+
|
|
405
|
+
## Invocation Prompt
|
|
406
|
+
|
|
407
|
+
Run `/parallel-run <slug>` to execute this run, or paste the prompt below.
|
|
408
|
+
|
|
409
|
+
Use the parallel-orchestrator subagent to execute the prepared run whose manifest is
|
|
410
|
+
docs/features/parallel/<slug>/parallel.md on the plan-home branch parallel/<slug>-plan. Each item
|
|
411
|
+
resumes at atomic execution from its committed plan-path on its own pushed feature branch rather
|
|
412
|
+
than re-planning, and each item opens its own pull request against main.
|
|
413
|
+
|
|
414
|
+
## Item Summary
|
|
415
|
+
|
|
416
|
+
| issue_num | feature_folder | cohort | complexity | branch | plan-path |
|
|
417
|
+
| --- | --- | --- | --- | --- | --- |
|
|
418
|
+
| ... | ... | ... | ... | ... | ... |
|
|
419
|
+
|
|
420
|
+
## Integrity
|
|
421
|
+
|
|
422
|
+
planning_commit: <hex>
|
|
423
|
+
|
|
424
|
+
| plan-path | plan-hash |
|
|
425
|
+
| --- | --- |
|
|
426
|
+
| ... | ... |
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Structural requirements enforced by the contract module:
|
|
430
|
+
|
|
431
|
+
- The first line is exactly `# Parallel Kickoff: <slug>`, with the slug matching
|
|
432
|
+
`[a-z0-9][a-z0-9-]*`.
|
|
433
|
+
- `## Invocation Prompt` must name `` Run `/parallel-run <slug>` ``, the manifest path
|
|
434
|
+
`docs/features/parallel/<slug>/parallel.md`, the plan-home branch `parallel/<slug>-plan`, and the
|
|
435
|
+
resume-boundary sentence stating that each item resumes at atomic execution from its committed
|
|
436
|
+
plan-path on its own pushed feature branch.
|
|
437
|
+
- `## Item Summary` is a strict pipe table with the exact ordered headers
|
|
438
|
+
`issue_num | feature_folder | cohort | complexity | branch | plan-path` and at least one data row.
|
|
439
|
+
`issue_num` and `cohort` are integers; `complexity` is one of `C1`, `C2`, `C3`, `C4`.
|
|
440
|
+
- `## Integrity` is optional. When present it carries a `planning_commit:` field holding the head
|
|
441
|
+
commit of `parallel/<slug>-plan` as run-level provenance and a per-item `plan-path | plan-hash`
|
|
442
|
+
table whose hashes are 40 to 64 hex characters with no repeated plan path.
|
|
443
|
+
|
|
444
|
+
Validate the artifact through `mcp__drm-copilot__validate_orchestration_artifacts` with
|
|
445
|
+
`artifact_type: "parallel-kickoff"`. That artifact type dispatches to
|
|
446
|
+
`scripts/dev_tools/parallel_kickoff_contract.py`, which this feature delivers.
|
|
447
|
+
|
|
448
|
+
## Completion Report
|
|
449
|
+
|
|
450
|
+
The final report to the operator must include:
|
|
451
|
+
|
|
452
|
+
- The manifest path `docs/features/parallel/<slug>/parallel.md` and the run branch
|
|
453
|
+
`parallel/<slug>-plan`.
|
|
454
|
+
- Per item: one `plan-path:` line, the branch name, the preflight status, and the
|
|
455
|
+
radius-validation result, including any V3 Advisory findings.
|
|
456
|
+
- The cohort table at `generation 0`, together with the result of the recomputation-parity check.
|
|
457
|
+
- Both kickoff artifact paths: `artifacts/orchestration/parallel-kickoff-<slug>.md` and
|
|
458
|
+
`docs/features/parallel/<slug>/parallel-kickoff.md`.
|
|
459
|
+
|
|
460
|
+
End with the statement that execution has NOT started and begins only when the operator runs
|
|
461
|
+
`/parallel-run <slug>` or replays the kickoff prompt from the main session.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: parallel-remove
|
|
3
|
+
description: Remove one item from a running parallel run per the state-dependent removal behavior table — withdraw and recolor for an unstarted item, detach or abandon for an in-flight item, reject for a merged item. No default disposition is ever inferred. The abandon path runs through one deterministic CLI invocation and is hook-gated.
|
|
4
|
+
argument-hint: "[item] [--disposition detach|abandon]"
|
|
5
|
+
context: fork
|
|
6
|
+
agent: parallel-orchestrator
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Parallel Remove Skill
|
|
10
|
+
|
|
11
|
+
A user invocation (`/parallel-remove <item> [--disposition detach|abandon]`) forks the
|
|
12
|
+
`parallel-orchestrator` agent with this procedure in context. The item key and optional disposition
|
|
13
|
+
are:
|
|
14
|
+
|
|
15
|
+
$ARGUMENTS
|
|
16
|
+
|
|
17
|
+
This skill implements the mutation-protocol remove operation (spec FR2). It mutates a parallel run
|
|
18
|
+
that is already executing, so the pinning invariant and the recompute boundary in the
|
|
19
|
+
`## Mutation Protocol (F6)` section of `.claude/skills/parallel-orchestrate/SKILL.md` govern what
|
|
20
|
+
this operation may disturb. Read that section before applying anything here.
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- A parallel run is in progress and `artifacts/orchestration/parallel-orchestrator-state.json`
|
|
25
|
+
tracks its `parallel_slug`.
|
|
26
|
+
- `$ARGUMENTS` names exactly one item key — an integer `items[].issue_num`. Item keys are integers
|
|
27
|
+
throughout this surface; there is no string key.
|
|
28
|
+
|
|
29
|
+
## Re-Derive Durable State Before Applying Anything
|
|
30
|
+
|
|
31
|
+
The checkpoint is a CACHE of durable state, not the source of truth
|
|
32
|
+
(`.claude/rules/parallel-orchestration.md`, Cache Doctrine). Before deciding a removal, re-derive
|
|
33
|
+
the target item's true state and rewrite the checkpoint from it when they disagree:
|
|
34
|
+
|
|
35
|
+
- `git worktree list --porcelain` — worktree existence and path.
|
|
36
|
+
- `git branch` — branch existence and name.
|
|
37
|
+
- `gh pr view <pr> --json state,mergedAt,headRefOid` — pull-request state and merge outcome.
|
|
38
|
+
|
|
39
|
+
The removal branch is selected by the item's state, so a stale state selects the wrong branch. An
|
|
40
|
+
item the checkpoint calls `scheduled` but which is really `in_flight` would be silently withdrawn
|
|
41
|
+
and recolored, moving work that is already running. The re-derivation is therefore mandatory.
|
|
42
|
+
|
|
43
|
+
## State-Dependent Behavior Table (Normative)
|
|
44
|
+
|
|
45
|
+
Implement this table exactly, one branch per row:
|
|
46
|
+
|
|
47
|
+
| Item state | Behavior |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `proposed`, `admitted`, `prepared`, `scheduled` | Mark `withdrawn`, drop the vertex, recolor the unstarted subgraph (recompute). |
|
|
50
|
+
| `in_flight` | **Reject** unless `--disposition` is supplied. A default disposition is never inferred. |
|
|
51
|
+
| `in_flight` with `--disposition detach` | Let the item finish and merge on its own; the run stops tracking it. No recompute. |
|
|
52
|
+
| `in_flight` with `--disposition abandon` | Close the PR, remove the worktree, mark `withdrawn`. Destructive; hook-gated. No recompute. |
|
|
53
|
+
| `merged` | Reject; the change is already in `main`. |
|
|
54
|
+
|
|
55
|
+
An item already `withdrawn` or `blocked` is not a live removal target and is rejected as an unknown
|
|
56
|
+
item.
|
|
57
|
+
|
|
58
|
+
## No Default Disposition
|
|
59
|
+
|
|
60
|
+
Removing an item that is `in_flight` without an explicit `--disposition` is REJECTED. No default is
|
|
61
|
+
inferred, in either direction. The choice between letting running work finish and destroying it
|
|
62
|
+
changes what happens to a pull request and a worktree, so it belongs to the caller and never to
|
|
63
|
+
this procedure. Do not guess, do not prompt-and-assume, and do not pick `detach` because it is the
|
|
64
|
+
non-destructive option.
|
|
65
|
+
|
|
66
|
+
## Rejected Removals Change Nothing
|
|
67
|
+
|
|
68
|
+
A rejected removal — `in_flight` without a disposition, `merged`, or an unknown or already-withdrawn
|
|
69
|
+
item — fails fast with a specific error, appends NO `mutations[]` entry, and makes NO state change.
|
|
70
|
+
Do not record a partial removal, and do not record the rejection itself in `mutations[]`.
|
|
71
|
+
|
|
72
|
+
## Procedure
|
|
73
|
+
|
|
74
|
+
1. Re-derive durable state as above and resolve the item key against `items[]`.
|
|
75
|
+
|
|
76
|
+
2. Decide the removal by calling `decide_removal(item_key, items, disposition)` from
|
|
77
|
+
`scripts/dev_tools/parallel_mutation_protocol.py`. The engine raises the dedicated rejection
|
|
78
|
+
exception for every rejected row; surface its message and stop.
|
|
79
|
+
|
|
80
|
+
3. **Unstarted removal (recompute).** Set the item's state to `withdrawn`, drop its vertex, and
|
|
81
|
+
recolor by calling `recolor_unstarted(unstarted_items, conflict_edges, pinned,
|
|
82
|
+
current_generation, current_cohort=current_cohort)`. Write
|
|
83
|
+
`RecolorResult.cohort_assignments` into `cohorts[]` and set the top-level `recolor_generation`
|
|
84
|
+
to `RecolorResult.generation`; the generation increments by exactly one. The result names no
|
|
85
|
+
pinned key, so no in-flight item moves.
|
|
86
|
+
|
|
87
|
+
`current_cohort` is F3's top-level field, read from the re-verified durable state, and is the
|
|
88
|
+
index the pinned items occupy. The returned indices are ABSOLUTE and are written VERBATIM into
|
|
89
|
+
`cohorts[].index`, never re-based to zero. Returned keys whose index equals `current_cohort` are
|
|
90
|
+
MERGED into the single existing current-generation cohort entry at that index alongside its
|
|
91
|
+
pinned members, never written as a second entry carrying the same `index`, which F3 invariant 13
|
|
92
|
+
rejects.
|
|
93
|
+
|
|
94
|
+
4. **`detach` (no recompute).** Set the item's state to `withdrawn` and record
|
|
95
|
+
`disposition: "detach"` in the mutation entry. `recolor_generation` is UNCHANGED: the detached
|
|
96
|
+
item was pinned and was never a vertex of the unstarted subgraph, so its departure cannot change
|
|
97
|
+
the induced subgraph. Perform no side effect — the item's own pull request continues to its own
|
|
98
|
+
merge outcome and the run simply stops tracking it. The `closed`-mode completion predicate
|
|
99
|
+
excludes withdrawn items, so the run does not wait for a detached item.
|
|
100
|
+
|
|
101
|
+
5. **`abandon` (no recompute, destructive, CLI-only).** Set the item's state to `withdrawn` and
|
|
102
|
+
record `disposition: "abandon"` in the mutation entry. `recolor_generation` is UNCHANGED, for the
|
|
103
|
+
same reason as `detach`. Execute the destructive side effects — closing the pull request and
|
|
104
|
+
removing the worktree — through the single deterministic CLI invocation below and through nothing
|
|
105
|
+
else:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
poetry run python scripts/dev_tools/parallel_mutation_abandon_cli.py --item <key> --disposition abandon --confirm-abandon --pr <pr-number> --worktree <worktree-path>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Executing the abandon disposition through ad hoc `gh pr close` or `git worktree remove` commands
|
|
112
|
+
is PROHIBITED. The prohibition is not stylistic: the abandon gate matches on the tokens of the
|
|
113
|
+
invocation above, so an ad hoc command is not matchable and would bypass the confirmation
|
|
114
|
+
contract entirely. One invocation, one item, both side effects.
|
|
115
|
+
|
|
116
|
+
6. **Append exactly one `mutations[]` entry** for a successful removal, built by
|
|
117
|
+
`build_remove_entry` from `scripts/dev_tools/parallel_mutation_protocol.py`:
|
|
118
|
+
|
|
119
|
+
| Case | `op` | `item_key` | `prior_state` | `new_state` | `disposition` | `recolor_generation` |
|
|
120
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
121
|
+
| Remove, unstarted | `remove` | item key | prior state (`proposed`/`admitted`/`prepared`/`scheduled`) | `withdrawn` | null | `g` + 1 |
|
|
122
|
+
| Remove, `detach` | `remove` | item key | `in_flight` | `withdrawn` | `detach` | `g` (unchanged) |
|
|
123
|
+
| Remove, `abandon` | `remove` | item key | `in_flight` | `withdrawn` | `abandon` | `g` (unchanged) |
|
|
124
|
+
|
|
125
|
+
`disposition` is non-null only on an in-flight removal and is null on the unstarted row. The `at`
|
|
126
|
+
timestamp comes from the engine's injected clock seam.
|
|
127
|
+
|
|
128
|
+
7. **Validate the checkpoint** before treating the removal as applied. Run the
|
|
129
|
+
`validate_orchestration_artifacts` MCP tool with `artifact_type:
|
|
130
|
+
"parallel-orchestrator-state"`. A non-empty error list means the removal was applied incorrectly;
|
|
131
|
+
correct the checkpoint rather than proceeding.
|
|
132
|
+
|
|
133
|
+
## Abandon Confirmation-Marker Contract
|
|
134
|
+
|
|
135
|
+
The abandon path is guarded by the PreToolUse hook
|
|
136
|
+
`.claude/hooks/enforce-parallel-abandon-gate.ps1` on the `Bash` matcher. The contract is:
|
|
137
|
+
|
|
138
|
+
- A Bash command carrying the disposition token for abandon MUST also carry the explicit
|
|
139
|
+
confirmation marker `--confirm-abandon` in the SAME command.
|
|
140
|
+
- A command carrying the abandon disposition token WITHOUT the confirmation marker is DENIED. The
|
|
141
|
+
deny reason is prefixed `PARALLEL_ABANDON_BLOCKED`.
|
|
142
|
+
- A command carrying both tokens is allowed.
|
|
143
|
+
- A command carrying neither is out of scope and is allowed unchanged.
|
|
144
|
+
|
|
145
|
+
The two token values are declared once each in
|
|
146
|
+
`scripts/dev_tools/parallel_mutation_abandon_cli.py` (the producer) and once each in the hook (the
|
|
147
|
+
consumer), and the seam test
|
|
148
|
+
`tests/scripts/dev_tools/test_parallel_abandon_token_seam.py` parses all three artifacts — the CLI,
|
|
149
|
+
the hook, and the invocation line in step 5 above — at run time to prove they still agree. Renaming
|
|
150
|
+
a token in one artifact without the identical rename in the other two fails that test. The
|
|
151
|
+
invocation in step 5 is the file's only executable abandon command line, and the seam test parses
|
|
152
|
+
that one line; do not add a second one.
|
|
153
|
+
|
|
154
|
+
When the gate denies a command, the correct response is to add the confirmation marker
|
|
155
|
+
deliberately, not to reformulate the command to evade the match. Reformulating to evade the gate
|
|
156
|
+
defeats the only mechanism protecting a destructive operation.
|
|
157
|
+
|
|
158
|
+
## Constraints
|
|
159
|
+
|
|
160
|
+
- One removal per invocation; at most one `mutations[]` entry per invocation.
|
|
161
|
+
- No field and no enum member is added to `mutations[]`, `items[]`, or any state or merge-status
|
|
162
|
+
enum. The nine parallel enums are owned by `.claude/rules/parallel-orchestration.md` and are
|
|
163
|
+
consumed, never extended.
|
|
164
|
+
- Neither `detach` nor `abandon` recomputes. An unstarted item previously deferred because of a
|
|
165
|
+
conflict with the removed item keeps its cohort assignment: the assignment stays valid and is at
|
|
166
|
+
most conservative, and no opportunistic recompute is performed.
|
|
167
|
+
- No in-flight item other than the removal target changes cohort or state.
|
|
168
|
+
|
|
169
|
+
## Completion Requirements
|
|
170
|
+
|
|
171
|
+
- Report the item key, the branch of the behavior table taken, the disposition recorded, the
|
|
172
|
+
resulting `recolor_generation`, and the single appended `mutations[]` entry — or, for a rejected
|
|
173
|
+
removal, the rejection and the explicit confirmation that nothing was appended and no state
|
|
174
|
+
changed.
|
|
175
|
+
- For an abandon, report the CLI's exit code and both side-effect outcomes.
|
|
176
|
+
- Report the checkpoint validation result.
|