@danmoisan/drm-copilot-mcp 1.1.9 → 1.1.11
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 +3526 -1037
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +15 -2
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +3 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +49 -14
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +52 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +103 -6
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +58 -3
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +37 -5
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +13 -2
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +35 -7
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +483 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +483 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +254 -5
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +18 -75
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConflict.psm1 +290 -0
- package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +415 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/ProjectFileMerge.psm1 +355 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/ProjectFileMergeGrammar.psm1 +318 -0
- package/resources/claude-customizations/.claude/lib/project-file-merge/Resolve-MergeableConflict.ps1 +229 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +66 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +311 -16
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +36 -2
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/powershell-orchestration-state-machine/SKILL.md +29 -1
- package/resources/claude-customizations/config/blast-radius.json +7 -0
- package/resources/claude-customizations/pack-manifests/core.json +7 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +41 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -0
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +26 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +49 -3
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +57 -12
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +34 -8
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +34 -7
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +483 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +483 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +130 -2
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +6 -1
- package/resources/config/orchestration-handoff-registry.json +138 -0
- package/resources/config/orchestration-handoff.schema.json +472 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +38 -0
|
@@ -17,6 +17,7 @@ allowed-tools:
|
|
|
17
17
|
- "Bash(git diff *)"
|
|
18
18
|
- "Bash(git branch -r*)"
|
|
19
19
|
- "Bash(git worktree list*)"
|
|
20
|
+
- "Bash(git worktree remove *)"
|
|
20
21
|
- "Bash(gh issue view *)"
|
|
21
22
|
- mcp__drm-copilot__new_potential_bug_entry
|
|
22
23
|
- mcp__drm-copilot__potential_to_issue
|
|
@@ -64,11 +65,83 @@ The script emits pipe-delimited, `LC_ALL=C`-ordered records, one per line:
|
|
|
64
65
|
in `EQUIVALENT | CONTENT_ON_MAIN | EMPTY | UNIQUE | CONFLICT`. A `UNIQUE` COMMIT record
|
|
65
66
|
is a cherry-pick candidate for editorial triage.
|
|
66
67
|
- `WORKTREE|<path>|<branch-or-DETACHED>|<flags>` — worktree registrations.
|
|
68
|
+
- `WORKTREE|<path>|DETACHED|<state>|<flags>` — a detached-HEAD worktree registration,
|
|
69
|
+
classified on its own HEAD SHA. This five-field record replaces the four-field record
|
|
70
|
+
above for a detached registration; it is not emitted in addition to it. `state` is one
|
|
71
|
+
of `MERGED_CLEAN | MERGED_CONTENT_NEUTRAL | MERGED_EQUIVALENT | NOT_MERGED |
|
|
72
|
+
HAS_UNIQUE_RESIDUALS | PROTECTED_CURRENT | ANCESTRY_ERROR`, where `ANCESTRY_ERROR` is
|
|
73
|
+
the fail-closed verdict for a hard git failure at any rung of the classification. The
|
|
74
|
+
fifth field carries the porcelain flag set unchanged, so the `locked` and `prunable`
|
|
75
|
+
markers are preserved in the record.
|
|
67
76
|
- `WARN|main-divergence|<local-sha>|<origin-sha>` — local `main` differs from
|
|
68
77
|
`origin/main` (advisory; classification still runs).
|
|
69
78
|
- `DIRTY|<worktree-path>|<status-porcelain-line>` — a dirty worktree that blocked
|
|
70
|
-
removal.
|
|
79
|
+
removal. This record is apply mode only, and its three-field shape is unchanged by the
|
|
80
|
+
dirt classifier: the classifier adds the two records below rather than altering or
|
|
81
|
+
replacing this one.
|
|
82
|
+
- `DIRTFILE|<worktree-path>|<verdict>|<detail>|<xy>|<file-path>` — one record per
|
|
83
|
+
`git status --porcelain` entry in a dirty worktree, emitted by report mode in porcelain
|
|
84
|
+
order immediately after that worktree's `WORKTREE|` record. `verdict` is exactly one of
|
|
85
|
+
`DISPOSABLE_BUILD_ARTIFACT | DISPOSABLE_SESSION_ARTIFACT | CONTENT_ON_MAIN |
|
|
86
|
+
CONTENT_IN_HISTORY | STAGED_TREE_IS_COMMIT | UNIQUE`, and no other verdict token is ever
|
|
87
|
+
produced. `detail` carries the commit SHA that justifies the verdict for
|
|
88
|
+
`STAGED_TREE_IS_COMMIT` and `CONTENT_IN_HISTORY`, and is empty for the other four
|
|
89
|
+
verdicts. `xy` is the porcelain two-character status field, preserved verbatim including
|
|
90
|
+
its space. The file path is the last field, so a path containing a pipe character cannot
|
|
91
|
+
shift any later field. A classification read that fails maps its entry to `UNIQUE`: that
|
|
92
|
+
is the fail-closed direction, because an entry the tool could not classify is treated as
|
|
93
|
+
content that must be preserved. `CONTENT_ON_MAIN` is emitted for a tracked entry
|
|
94
|
+
only when `main` contains the path, so an entry whose content exists only as a staged
|
|
95
|
+
blob is reported `UNIQUE` rather than as content that is already on `main`. An entry
|
|
96
|
+
whose porcelain status shows content in both the index and the working tree is likewise
|
|
97
|
+
reported `UNIQUE`, because the rungs that could otherwise resolve it compare working-tree
|
|
98
|
+
content only and would leave the differing staged blob unaccounted for.
|
|
99
|
+
`DISPOSABLE_SESSION_ARTIFACT` matches three fixed
|
|
100
|
+
repository paths under `artifacts/`, is repository-agnostic, and cannot fire in a checkout
|
|
101
|
+
that gitignores `artifacts/` — which drm-copilot does at `.gitignore:6` — because the
|
|
102
|
+
status read never carries `--ignored`; the verdict is retained for consumer checkouts
|
|
103
|
+
where those paths are not ignored, and it must not be made reachable by adding
|
|
104
|
+
`--ignored`.
|
|
105
|
+
- `DIRTSUM|<worktree-path>|<aggregate>|<detail>` — exactly one record per dirty worktree,
|
|
106
|
+
emitted by report mode immediately after that worktree's `DIRTFILE|` records.
|
|
107
|
+
`aggregate` is `ALL_DISPOSABLE` if and only if the worktree has at least one status
|
|
108
|
+
entry and none of them is `UNIQUE`, and `HAS_UNIQUE` otherwise. `detail` carries the
|
|
109
|
+
first non-empty per-entry detail. A worktree with zero status entries emits neither this
|
|
110
|
+
record nor any `DIRTFILE|` record. Both records are read-only: an `ALL_DISPOSABLE`
|
|
111
|
+
aggregate unlocks nothing on its own, and clearing happens only when the operator
|
|
112
|
+
supplies `--clear-disposable` in apply mode.
|
|
113
|
+
|
|
114
|
+
Report-mode exit status. When a candidate worktree's `git status --porcelain` read
|
|
115
|
+
fails, report mode emits no `DIRTFILE|` and no `DIRTSUM|` record for that worktree and
|
|
116
|
+
returns git's non-zero exit code. A checkout containing such a worktree therefore exits
|
|
117
|
+
non-zero from report mode where the same checkout previously exited 0 and produced a
|
|
118
|
+
complete report. This is deliberate. A worktree whose status read failed produces no dirt
|
|
119
|
+
records at all, so a report that also exited 0 would be indistinguishable from a report
|
|
120
|
+
about a clean worktree, and an operator would make a deletion decision on silently
|
|
121
|
+
incomplete data. The non-zero exit is the only channel that carries the incompleteness to
|
|
122
|
+
a wrapping script. See the analogous apply-mode note in the End-to-End Workflow, where a
|
|
123
|
+
blocked detached removal sets a non-zero exit status for the same reason.
|
|
71
124
|
- `ACTION|<verb>|<target>|<result>` — apply-mode action results.
|
|
125
|
+
- `PRESERVE|<worktree-path>|<source-path>|<verdict>` — a manifest `preserved_files[]`
|
|
126
|
+
finding staged onto the consolidation branch; `verdict` in `DEAD_ONE_OFF |
|
|
127
|
+
ALREADY_SOLVED_ELSEWHERE | STALE_OR_CONTRADICTED | GENUINELY_NEW | STILL_RELEVANT`. The
|
|
128
|
+
per-file outcome is reported by the companion `ACTION|preserve-stage|...` record.
|
|
129
|
+
- `ORPHAN_DIR|<path>|<size>` — a directory under a worktree-tracking root that carries
|
|
130
|
+
no `.git` pointer file and no `git worktree list` entry. `<size>` is best-effort and
|
|
131
|
+
may be the literal `unknown`. The record is advisory: it reports the directory, and
|
|
132
|
+
nothing in apply mode acts on it. For the disposition, see the Dirty Worktree Triage
|
|
133
|
+
Procedure's step 7, which governs how an orphaned directory is handled.
|
|
134
|
+
- `STALE_REF|<refname>` — a `refs/remotes/<name>/*` ref whose `<name>` is not a
|
|
135
|
+
configured remote, named in full ref form. Advisory only; no ref is ever pruned by
|
|
136
|
+
this tool.
|
|
137
|
+
- `CHILD_OF|<branch>|<ancestor>` — `branch` is a git ancestor of `ancestor`, and both
|
|
138
|
+
resolved exactly `NOT_MERGED` through their own full ladders. It is emitted alongside,
|
|
139
|
+
never instead of, the branch's own `BRANCH|<branch>|NOT_MERGED` line, and names the
|
|
140
|
+
containment relationship so an operator can see that the branch's work is not lost
|
|
141
|
+
when the named ancestor is retained.
|
|
142
|
+
- `WARN|registration-lost|<path>` — a worktree directory whose `.git` pointer file names
|
|
143
|
+
a gitdir target that no longer exists. Git commands run inside such a directory fail
|
|
144
|
+
in confusing ways. Advisory only.
|
|
72
145
|
|
|
73
146
|
## End-to-End Workflow
|
|
74
147
|
|
|
@@ -101,11 +174,25 @@ The script emits pipe-delimited, `LC_ALL=C`-ordered records, one per line:
|
|
|
101
174
|
(`artifacts/orchestration/orchestrator-state.json`) with `--require-pr-creation-ready`
|
|
102
175
|
and record the `pr_author_preflight` result; delegation is prohibited when that
|
|
103
176
|
validation fails. Then delegate PR creation to `Agent(pr-author)` per
|
|
104
|
-
`.claude/skills/pr-author/SKILL.md`,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
177
|
+
`.claude/skills/pr-author/SKILL.md`, which owns the body-file and receipt contract;
|
|
178
|
+
defer to that skill for it rather than restating any value from it here. For `<N>`,
|
|
179
|
+
use the GitHub issue number the run executes under when the run has one. When the run
|
|
180
|
+
has none, `<N>` is an arbitrary run-scoped identifier chosen by the pr-author agent.
|
|
181
|
+
It is not a pull-request number, and the only requirement on it is that the body-file
|
|
182
|
+
path, the receipt's `number` field, and the body bytes all agree. This skill never
|
|
183
|
+
authors or creates the PR itself.
|
|
184
|
+
|
|
185
|
+
5. **Wait for merge and verify git-natively.** The consolidation PR's merge is
|
|
186
|
+
**human-performed**: the operator merges it outside the agent session; this skill
|
|
187
|
+
never issues the merge itself. This is why: `gh pr merge` is absent from this skill's
|
|
188
|
+
`allowed-tools`; the project permission allow-list (`permissions.allow` in
|
|
189
|
+
`.claude/settings.json`) carries no `gh` entry; and `.claude/hooks/enforce-epic-merge-gate.ps1`
|
|
190
|
+
would deny the command with `EPIC_MERGE_GATE_BLOCKED` if it were attempted. At this
|
|
191
|
+
boundary the agent reports the consolidation pull request's URL or number to the
|
|
192
|
+
operator and stops. The ruleset on `main` sets `strict_required_status_checks_policy`,
|
|
193
|
+
so the branch must be up to date with `main` before the merge becomes available to the
|
|
194
|
+
operator; the wait for the merge is unbounded within a session. After the consolidation
|
|
195
|
+
PR merges, verify it with `git fetch` followed by
|
|
109
196
|
`git merge-base --is-ancestor documentationandmemories main`. Exit 0 confirms every
|
|
110
197
|
consolidated commit is now reachable from `main`; that is the only state that unlocks
|
|
111
198
|
deletion of branches whose unique content was consolidated.
|
|
@@ -119,6 +206,31 @@ The script emits pipe-delimited, `LC_ALL=C`-ordered records, one per line:
|
|
|
119
206
|
branch classified `NOT_MERGED` or `HAS_UNIQUE_RESIDUALS` — is not abandoned; it moves
|
|
120
207
|
to the Dirty Worktree Triage Procedure below.
|
|
121
208
|
|
|
209
|
+
A consolidation branch whose tip equals `main`, which is the state of
|
|
210
|
+
`documentationandmemories` between its creation off `main` and its first commit, is
|
|
211
|
+
reported `NOT_ANCESTOR` by a tip-equality pre-check that runs before any network fetch
|
|
212
|
+
and is therefore not delete-eligible; the post-merge cleanup described above is
|
|
213
|
+
unaffected, because a merged consolidation branch's tip differs from `main`, and an
|
|
214
|
+
empty or unresolvable tip on either side is reported `ANCESTRY_ERROR` rather than
|
|
215
|
+
treated as equality.
|
|
216
|
+
|
|
217
|
+
Detached-HEAD worktrees are handled on the same terms. Apply mode classifies each on
|
|
218
|
+
its own HEAD SHA, emits the five-field `WORKTREE|<path>|DETACHED|<state>|<flags>`
|
|
219
|
+
record from that verdict, and acts only on the delete-eligible states `MERGED_CLEAN`,
|
|
220
|
+
`MERGED_CONTENT_NEUTRAL`, and `MERGED_EQUIVALENT`. A delete-eligible detached worktree
|
|
221
|
+
is re-verified in the same process immediately before the destructive action and is
|
|
222
|
+
then removed without force. A locked one is skipped with the result token
|
|
223
|
+
`ACTION|worktree-remove|<path>|BLOCKED-LOCKED`; the locked test reads the porcelain
|
|
224
|
+
flags already in hand and precedes every git invocation, so no `git worktree remove`
|
|
225
|
+
command is issued for it. A prunable one is report-only: it produces its registration
|
|
226
|
+
record and no further line, with no removal and no prune. A dirty one reaches the same
|
|
227
|
+
non-forced removal path as a branch-backed worktree and is reported `BLOCKED-DIRTY`
|
|
228
|
+
with its accompanying `DIRTY|` lines.
|
|
229
|
+
In apply mode a blocked detached removal — `BLOCKED-DIRTY`, `BLOCKED-LOCKED`, or
|
|
230
|
+
`BLOCKED-REVERIFY` — sets a non-zero exit status, so a checkout holding dirty or locked
|
|
231
|
+
detached worktrees exits non-zero from `--apply` where the same checkout previously
|
|
232
|
+
exited 0.
|
|
233
|
+
|
|
122
234
|
## Nothing to Consolidate (Short Path)
|
|
123
235
|
|
|
124
236
|
When report mode classifies every candidate as `MERGED_CLEAN` or `MERGED_EQUIVALENT`
|
|
@@ -134,7 +246,12 @@ accompanying `DIRTY|<path>|<status-porcelain-line>` records), or a branch classi
|
|
|
134
246
|
script correctly refuses to discard. That refusal is correct and this procedure never
|
|
135
247
|
overrides it — a dirty worktree is never force-removed. This procedure is the systematic
|
|
136
248
|
follow-up: deciding, per worktree, whether that content is disposable or must be
|
|
137
|
-
preserved before the worktree can ever be deleted.
|
|
249
|
+
preserved before the worktree can ever be deleted. Report mode now precedes this
|
|
250
|
+
procedure with a machine-readable first pass: one `DIRTFILE|` record per status entry
|
|
251
|
+
giving that entry's verdict, and one `DIRTSUM|` record per worktree giving the aggregate
|
|
252
|
+
`ALL_DISPOSABLE` or `HAS_UNIQUE`. Steps 1-9 below apply to the worktrees carrying at
|
|
253
|
+
least one `UNIQUE` verdict, which are exactly the ones the classifier could not establish
|
|
254
|
+
as disposable and which therefore still require human editorial judgement.
|
|
138
255
|
|
|
139
256
|
Steps 1-7 are read-only investigation. Run them per worktree, or fan out one
|
|
140
257
|
`Agent(general-purpose)` investigation per worktree (or small batch) concurrently per
|
|
@@ -185,7 +302,12 @@ specific files or commit SHAs, before step 9 acts on any finding.
|
|
|
185
302
|
build artifacts (a modified `.csproj`/`packages.config`/`app.config` from a build run
|
|
186
303
|
in that worktree) rather than documentation. Diff a representative sample against
|
|
187
304
|
`main` (`git diff main -- <path>`) to characterize the change before deciding it is
|
|
188
|
-
disposable.
|
|
305
|
+
disposable. The classifier scopes this class narrowly: it labels a project file
|
|
306
|
+
`DISPOSABLE_BUILD_ARTIFACT` only when every changed line in that entry's diff is an
|
|
307
|
+
analyzer `HintPath` rewrite. A project file whose diff touches anything else — a
|
|
308
|
+
`Compile Include` registration, a package reference, a target or property change — is
|
|
309
|
+
reported `UNIQUE` and is not disposable, so this step's manual characterization is
|
|
310
|
+
still required for it.
|
|
189
311
|
|
|
190
312
|
7. **Recognize orphaned non-worktree directories.** A path can still exist on disk
|
|
191
313
|
under a worktree-tracking folder after `git worktree remove` partially ran or
|
|
@@ -210,13 +332,32 @@ specific files or commit SHAs, before step 9 acts on any finding.
|
|
|
210
332
|
`mcp__drm-copilot__potential_to_issue` per
|
|
211
333
|
`.claude/skills/feature-promotion-lifecycle/SKILL.md`. For a `SAFE_TO_DELETE`
|
|
212
334
|
verdict, discard the content as a distinct, individually confirmed manual action —
|
|
213
|
-
clear the dirty working tree,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
335
|
+
clear the dirty working tree, delete a disposable `NOT_MERGED`/`HAS_UNIQUE_RESIDUALS`
|
|
336
|
+
branch directly, or remove the worktree itself through a
|
|
337
|
+
manifest-authorized removal. A manifest-authorized removal is a single
|
|
338
|
+
`git worktree remove <path>` covering one worktree, issued as its own Bash tool call,
|
|
339
|
+
one call per worktree, and it is authorized only when the Sanctioned Removal Manifest
|
|
340
|
+
below carries a record for that exact path whose `removal_disposition` is
|
|
341
|
+
`SAFE_TO_DELETE` and whose `branch_state` is `NOT_MERGED` or `HAS_UNIQUE_RESIDUALS`.
|
|
342
|
+
Never pass a force flag to that command: a dirty worktree blocks deletion and is
|
|
343
|
+
reported for manual handling, and it is never force-removed. This is never automated:
|
|
344
|
+
the script's classification ladder and apply-mode allowlist are never changed to
|
|
345
|
+
accept these states, so a `--apply` run never deletes them on its own, before or
|
|
346
|
+
after triage. If discarding the working-tree content changes the branch's
|
|
347
|
+
classification (for example to content-neutral against `main`), a follow-up
|
|
348
|
+
report/apply pass then picks it up through the normal deterministic path.
|
|
349
|
+
|
|
350
|
+
Distinguish two different discards. The sentence above governs the editorial discard
|
|
351
|
+
of `UNIQUE` content — content a human judged safe to lose — and that discard stays
|
|
352
|
+
manual and individually confirmed. Separately, dirt the classifier established as
|
|
353
|
+
disposable, meaning a worktree whose `DIRTSUM|` aggregate is `ALL_DISPOSABLE`, can be
|
|
354
|
+
cleared by the tool itself under the opt-in `--clear-disposable` flag in apply mode.
|
|
355
|
+
That path never touches a `UNIQUE` verdict: one `UNIQUE` entry refuses the clear for
|
|
356
|
+
the whole worktree, and a classification read that errors produces a fail-closed
|
|
357
|
+
`UNIQUE` with the same effect. It is also not force-removal — it clears the working
|
|
358
|
+
tree and retries the same unforced `git worktree remove` after a fresh in-process
|
|
359
|
+
re-verification. The classification ladder and the apply-mode allowlist remain
|
|
360
|
+
unchanged by it.
|
|
220
361
|
|
|
221
362
|
10. **After local branch deletion, check origin too.** This skill is local-only by
|
|
222
363
|
design (see "When to Use This Skill"), which leaves stale branches on the remote for
|
|
@@ -228,13 +369,148 @@ specific files or commit SHAs, before step 9 acts on any finding.
|
|
|
228
369
|
cleanup, and never rely on this skill's general `Bash(git push *)` allowance to
|
|
229
370
|
perform it silently.
|
|
230
371
|
|
|
372
|
+
## Sanctioned Removal Manifest
|
|
373
|
+
|
|
374
|
+
**Write the manifest before step 9 of the Dirty Worktree Triage Procedure acts on any
|
|
375
|
+
`SAFE_TO_DELETE` verdict.** The run records its triage verdicts in
|
|
376
|
+
`artifacts/orchestration/cleanup-worktrees-manifest.json`. The two PreToolUse gates
|
|
377
|
+
`.claude/hooks/enforce-epic-worktree-removal-gate.ps1` and
|
|
378
|
+
`.claude/hooks/enforce-parallel-worktree-removal-gate.ps1` read that document and admit a
|
|
379
|
+
`git worktree remove <path>` command only when a record in it covers that exact path. A removal
|
|
380
|
+
issued with no covering record is denied with each gate's existing, unchanged reason code.
|
|
381
|
+
|
|
382
|
+
The document is UTF-8 JSON with `snake_case` keys. It carries six top-level fields. Its `removals`
|
|
383
|
+
and `preserved_files` entries are sibling arrays and are never nested: removal records are keyed by
|
|
384
|
+
worktree path, preserve records by the pair of worktree path and file path, and the gates must
|
|
385
|
+
never traverse preserve data.
|
|
386
|
+
|
|
387
|
+
### Top-level fields
|
|
388
|
+
|
|
389
|
+
- `tool` — string, required, exactly `cleanup-merged-worktrees`. The self-identifying
|
|
390
|
+
discriminator. Absent, non-string, or any other value and no record authorizes anything.
|
|
391
|
+
- `schema_version` — integer, required, exactly `1`. Absent, non-integer, or any other value fails
|
|
392
|
+
closed; a forward version is not accepted by silence.
|
|
393
|
+
- `generated_at` — string, required, an ISO-8601 UTC timestamp recording when the run wrote the
|
|
394
|
+
document. Absent, unparseable, in the future, or older than the 24-hour freshness bound fails
|
|
395
|
+
closed.
|
|
396
|
+
- `run_id` — string, required, non-empty. An opaque per-run identifier for audit correlation.
|
|
397
|
+
- `removals` — array, required, of removal records. It may be empty; absent, non-array, or empty
|
|
398
|
+
authorizes no removal.
|
|
399
|
+
- `preserved_files` — array, required, of preserve records. It may be empty. Neither gate ever
|
|
400
|
+
reads it, and its absence or malformation must not affect any gate decision.
|
|
401
|
+
|
|
402
|
+
### `removals[]` record fields
|
|
403
|
+
|
|
404
|
+
- `worktree_path` — string, required, non-empty. The absolute path of the worktree to remove. A
|
|
405
|
+
record with it absent or empty is skipped.
|
|
406
|
+
- `branch` — string or `null`, key required. The worktree's branch, or `null` for a detached
|
|
407
|
+
worktree. An absent key means the record does not authorize; `null` is a valid, meaningful value.
|
|
408
|
+
- `branch_state` — string, required. The classification the report emitted for that branch: one of
|
|
409
|
+
`MERGED_CLEAN`, `MERGED_CONTENT_NEUTRAL`, `MERGED_EQUIVALENT`, `NOT_MERGED`,
|
|
410
|
+
`HAS_UNIQUE_RESIDUALS`, or `PROTECTED_CURRENT`. Only `NOT_MERGED` and `HAS_UNIQUE_RESIDUALS`
|
|
411
|
+
authorize a removal; every other member, and any value outside the vocabulary, does not.
|
|
412
|
+
- `removal_disposition` — string, required. The triage disposition that authorizes removal. The
|
|
413
|
+
allowed set is exactly the single member `SAFE_TO_DELETE`. This key is deliberately distinct from
|
|
414
|
+
the `merge_status` key the orchestration checkpoints carry.
|
|
415
|
+
- `verdict` — string, required. The step-5 content classification that produced the disposition:
|
|
416
|
+
one of `DEAD_ONE_OFF`, `ALREADY_SOLVED_ELSEWHERE`, `STALE_OR_CONTRADICTED`, `GENUINELY_NEW`, or
|
|
417
|
+
`STILL_RELEVANT`. Absent, out of vocabulary, or preserve-implying and the record does not
|
|
418
|
+
authorize.
|
|
419
|
+
- `evidence` — string, required, non-empty. The justification step 9 requires, citing specific
|
|
420
|
+
files or commit SHAs. Absent, empty, or whitespace-only and the record does not authorize.
|
|
421
|
+
|
|
422
|
+
### `preserved_files[]` record fields
|
|
423
|
+
|
|
424
|
+
These records serve the consolidation consumer and are never read by either gate.
|
|
425
|
+
|
|
426
|
+
- `worktree_path` — string, required, non-empty. The worktree holding the file, and where the
|
|
427
|
+
consumer reads that worktree's `MEMORY.md`.
|
|
428
|
+
- `source_path` — string, required, repo-relative within that worktree. The file to preserve.
|
|
429
|
+
- `change_class` — string, required, either `untracked` or `modified`, recording whether staging
|
|
430
|
+
adds a new file or carries a working-tree modification.
|
|
431
|
+
- `disposition` — string, required, exactly `PRESERVE`.
|
|
432
|
+
- `verdict` — string, required, a member of the step-5 verdict vocabulary listed above.
|
|
433
|
+
- `target_path` — string, required, repo-relative on the consolidation branch. Required because the
|
|
434
|
+
same relative path may already exist on `main` with different content and a lesson file may be
|
|
435
|
+
re-namespaced; the consumer must not guess it.
|
|
436
|
+
- `memory_index_line` — string or `null`, key required. The source worktree's `MEMORY.md` index
|
|
437
|
+
line, or `null` when the file is not a memory entry.
|
|
438
|
+
- `line_ending` — string, required, one of `crlf`, `lf`, or `absent`. Advisory only: it records the
|
|
439
|
+
target file's existing convention, and the consumer re-derives and compares rather than trusting
|
|
440
|
+
it.
|
|
441
|
+
- `host_token_scan` — object, required, carrying a `result` member and a `pattern_set_id` member.
|
|
442
|
+
It records the scan outcome and the identifier of the pattern set used, never the patterns
|
|
443
|
+
themselves.
|
|
444
|
+
- `evidence` — string, required, non-empty.
|
|
445
|
+
|
|
446
|
+
### Example
|
|
447
|
+
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"tool": "cleanup-merged-worktrees",
|
|
451
|
+
"schema_version": 1,
|
|
452
|
+
"generated_at": "2026-09-07T03:40:00Z",
|
|
453
|
+
"run_id": "cleanup-2026-09-07T03-40-00Z-a47a5e33",
|
|
454
|
+
"removals": [
|
|
455
|
+
{
|
|
456
|
+
"worktree_path": "C:/Users/DanMoisan/repos/drm-copilot/.claude/worktrees/agent-0f1c2d",
|
|
457
|
+
"branch": "drm-copilot-wt-2026-08-14T09-02",
|
|
458
|
+
"branch_state": "HAS_UNIQUE_RESIDUALS",
|
|
459
|
+
"removal_disposition": "SAFE_TO_DELETE",
|
|
460
|
+
"verdict": "ALREADY_SOLVED_ELSEWHERE",
|
|
461
|
+
"evidence": "Unique residual commit 3f9a1c2 records the cleanup-worktrees ancestry error; main already fixes it at scripts/bash/cleanup_worktrees_lib.sh:214-231 under issue #612."
|
|
462
|
+
}
|
|
463
|
+
],
|
|
464
|
+
"preserved_files": [
|
|
465
|
+
{
|
|
466
|
+
"worktree_path": "C:/Users/DanMoisan/repos/drm-copilot/.claude/worktrees/agent-91ee43",
|
|
467
|
+
"source_path": ".claude/agent-memory/general-purpose/hook-payload-anomaly.md",
|
|
468
|
+
"change_class": "untracked",
|
|
469
|
+
"disposition": "PRESERVE",
|
|
470
|
+
"verdict": "GENUINELY_NEW",
|
|
471
|
+
"target_path": ".claude/agent-memory/general-purpose/hook-payload-anomaly-envelope.md",
|
|
472
|
+
"memory_index_line": "- [Hook payload anomaly envelope](hook-payload-anomaly-envelope.md) - the deny path a malformed envelope takes",
|
|
473
|
+
"line_ending": "crlf",
|
|
474
|
+
"host_token_scan": {
|
|
475
|
+
"result": "clean",
|
|
476
|
+
"pattern_set_id": "child-f-host-tokens-v1"
|
|
477
|
+
},
|
|
478
|
+
"evidence": "No equivalent file on main under .claude/agent-memory/**; grep for 'payload anomaly' returns only this worktree."
|
|
479
|
+
}
|
|
480
|
+
]
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Accepted residual
|
|
485
|
+
|
|
486
|
+
Both gates read the command text of the `Bash` tool call they are given. A removal routed
|
|
487
|
+
indirectly — for example by writing the command into a file and invoking that file with `bash
|
|
488
|
+
<file>` — presents command text the gates do not match, so the manifest requirement does not reach
|
|
489
|
+
it. This design does not close that indirection, and the requirement is recorded here as an
|
|
490
|
+
accepted residual rather than left implicit.
|
|
491
|
+
|
|
492
|
+
The manifest requirement is a policy-level integrity check, on the same terms
|
|
493
|
+
`.claude/hooks/enforce-pr-author-skill.ps1` records for its own receipt mechanism: it prevents
|
|
494
|
+
accidental bypass and requires a deliberate, documented act to circumvent. It is not a
|
|
495
|
+
cryptographic or security boundary, and it must not be described as tamper-proof. Routing a
|
|
496
|
+
removal through such an indirection in order to avoid the manifest requirement is a deliberate act
|
|
497
|
+
and is prohibited by this skill, which is the term the residual rests on.
|
|
498
|
+
|
|
231
499
|
## Prohibited Shortcuts
|
|
232
500
|
|
|
233
501
|
- Never invoke `gh pr create` or `gh pr edit --body*` from this skill or the scripts. PR
|
|
234
502
|
authoring is `Agent(pr-author)`'s exclusive responsibility and is enforced by the
|
|
235
503
|
`enforce-pr-author-skill.ps1` PreToolUse hook.
|
|
236
504
|
- Never pass a force flag to `git worktree remove`. A dirty worktree blocks deletion and
|
|
237
|
-
is reported for manual handling; it is never force-removed.
|
|
505
|
+
is reported for manual handling; it is never force-removed. The `--clear-disposable`
|
|
506
|
+
flag is not an exception to this rule and is not force-removal: it clears the working
|
|
507
|
+
tree first and then retries the same unforced `git worktree remove`, so the removal it
|
|
508
|
+
retries is the identical unforced call that was blocked. It runs only when every
|
|
509
|
+
per-file verdict for that worktree is non-`UNIQUE`, only in apply mode, only when the
|
|
510
|
+
operator explicitly requests it, and only after a fresh in-process re-verification that
|
|
511
|
+
the branch is still delete-eligible. A single `UNIQUE` verdict refuses the clear for the
|
|
512
|
+
whole worktree, including the fail-closed `UNIQUE` assigned when a classification read
|
|
513
|
+
errors.
|
|
238
514
|
- Never execute `git worktree prune`. Prunable registrations are report-only.
|
|
239
515
|
- Never act on `NOT_MERGED`, `HAS_UNIQUE_RESIDUALS`, or `PROTECTED_CURRENT` candidates
|
|
240
516
|
through the script or its apply-mode allowlist; `--apply` never mutates them, and the
|
|
@@ -249,6 +525,20 @@ specific files or commit SHAs, before step 9 acts on any finding.
|
|
|
249
525
|
worktree-tracking directory, without explicit per-item user confirmation — both are
|
|
250
526
|
outside this skill's pre-approved tool surface regardless of how the triage verdict
|
|
251
527
|
came out.
|
|
528
|
+
- Never issue the consolidation merge command, and never write or edit an orchestration
|
|
529
|
+
checkpoint in order to satisfy `.claude/hooks/enforce-epic-merge-gate.ps1`. This
|
|
530
|
+
forecloses the specific evasion of writing an
|
|
531
|
+
`artifacts/orchestration/orchestrator-state.json` whose `epic_mode` and `step9_status`
|
|
532
|
+
fields the gate's child-feature accept shape would honour for any pull-request number.
|
|
533
|
+
- Never widen the definition of disposable dirt. The session-artifact list is a fixed
|
|
534
|
+
in-script array of exactly three paths with no configuration override, no environment
|
|
535
|
+
variable, and no per-repository extension point; adding a path to it is a change to the
|
|
536
|
+
classifier, not a setting. The build-artifact rule requires both conditions together —
|
|
537
|
+
the `*.csproj` path pattern and the content confinement that every changed line in the
|
|
538
|
+
entry's diff is an analyzer `HintPath` rewrite — and a project file whose diff touches
|
|
539
|
+
anything else is `UNIQUE`. Ignored files are never cleared, because they are never
|
|
540
|
+
classified: `git status --porcelain` is read without `--ignored`, so an ignored file
|
|
541
|
+
never becomes an entry, and `git clean` is never given `-x`, `-X`, or `-ff`.
|
|
252
542
|
|
|
253
543
|
## Cross-References
|
|
254
544
|
|
|
@@ -262,3 +552,8 @@ specific files or commit SHAs, before step 9 acts on any finding.
|
|
|
262
552
|
- `.claude/skills/feature-promotion-lifecycle/SKILL.md` — the potential-entry-to-issue
|
|
263
553
|
promotion path used by the Dirty Worktree Triage Procedure's step 9 for `PRESERVE`
|
|
264
554
|
findings that describe unresolved product scope.
|
|
555
|
+
- `.claude/hooks/enforce-epic-merge-gate.ps1` — the PreToolUse gate on the consolidation
|
|
556
|
+
merge command, backed by orchestration checkpoints. A cleanup run satisfies none of its
|
|
557
|
+
three checkpoint shapes: it is neither a per-feature orchestration, nor an epic
|
|
558
|
+
integration, nor a parallel run, so it writes none of the three checkpoints the gate
|
|
559
|
+
reads.
|
|
@@ -34,6 +34,48 @@ On every invocation, the main session must:
|
|
|
34
34
|
2. If a valid checkpoint exists with a matching objective, resume from the recorded `next_step`.
|
|
35
35
|
3. If no checkpoint exists or the objective is new, begin the orchestration lifecycle from the start.
|
|
36
36
|
|
|
37
|
+
## Prepared-State Portable Handoff Intake
|
|
38
|
+
|
|
39
|
+
Treat a portable prepared-state checkpoint as a request to resume the recorded
|
|
40
|
+
lifecycle, not as a new orchestration intake. Before any destination launch:
|
|
41
|
+
|
|
42
|
+
1. Validate the envelope through the published, workspace-explicit handoff
|
|
43
|
+
authority. Require exact repository, workspace, branch lineage, issue,
|
|
44
|
+
feature folder, work mode, scheduler, capability, and transition bindings.
|
|
45
|
+
Supply the complete caller-controlled independent expected context on every
|
|
46
|
+
call to `resolve_orchestration_topology`, `resolve_provider_routing`, and
|
|
47
|
+
`transition_prepared_orchestration`: `expected_repository_id`,
|
|
48
|
+
`expected_workspace_root`, `expected_branch`, `expected_source_head_sha`,
|
|
49
|
+
`allowed_head_relationship`, `expected_issue_number`,
|
|
50
|
+
`expected_feature_folder`, `expected_work_mode`, `expected_plan_path`, and
|
|
51
|
+
`expected_plan_sha256`. Derive each value from the destination checkout and
|
|
52
|
+
the caller's own record. A call that omits a value, or that copies one from
|
|
53
|
+
the envelope under validation, is rejected before any service invocation.
|
|
54
|
+
2. Prove the plan using only the independently expected repository-relative
|
|
55
|
+
path and raw-byte SHA-256 the caller supplied in `expected_plan_path` and
|
|
56
|
+
`expected_plan_sha256`. Do not rediscover, rename, or substitute a plan, and
|
|
57
|
+
do not read the plan identity from the envelope.
|
|
58
|
+
3. Use `transition_prepared_orchestration` as the only authority that may
|
|
59
|
+
materialize a provider-native destination checkpoint. Dry run validates and
|
|
60
|
+
projects state without source archival or canonical-checkpoint replacement.
|
|
61
|
+
4. Preserve the envelope's completed phases and reject replay before mutation.
|
|
62
|
+
Promotion, research, feature-document authoring, atomic planning, and
|
|
63
|
+
preflight remain complete when the source recorded them as complete.
|
|
64
|
+
5. Keep source-provider model, reasoning, profile, topology, launch, worktree,
|
|
65
|
+
and receipt evidence opaque. Create destination routing evidence only for
|
|
66
|
+
the first new delegation after materialization.
|
|
67
|
+
|
|
68
|
+
When Claude is the destination, resolve its model through the existing Claude
|
|
69
|
+
model-routing procedure and launch with the existing `Agent(...)` and Claude
|
|
70
|
+
worktree mechanisms. Do not translate Codex deployment receipts into Claude
|
|
71
|
+
launch evidence. When Claude is the source, preserve Claude launch and
|
|
72
|
+
worktree evidence in the portable source expression and allow the Codex
|
|
73
|
+
destination to resolve its own topology and model. An ordinary handoff whose
|
|
74
|
+
recorded transition is `atomic_execution` resumes the exact approved plan at
|
|
75
|
+
that transition without invoking a parent scheduler. Any validation,
|
|
76
|
+
authority, plan, replay, or materialization failure returns the deterministic
|
|
77
|
+
blocked result before launch.
|
|
78
|
+
|
|
37
79
|
### Model-choice reconciliation on resume
|
|
38
80
|
|
|
39
81
|
Because model selection is required once delegation occurs (see `## Model Selection`), a resuming orchestrator must repair a missing model choice deterministically before delegating at a delegating `next_step`. When the resumed `next_step` is a delegating step:
|
|
@@ -66,7 +66,9 @@ re-derivation is mandatory and is not an optimization to skip when the checkpoin
|
|
|
66
66
|
(Join-Path $repoRoot '.claude/lib/blast-radius/BlastRadius.psm1') -Force -ErrorAction Stop`).
|
|
67
67
|
Its two radius arguments are the two items' radius hashtables, not strings, and the third
|
|
68
68
|
argument is the required parsed `config/blast-radius.json` mapping, which push-down publishes
|
|
69
|
-
into the destination workspace.
|
|
69
|
+
into the destination workspace. That mapping's optional `mergeable_paths` list is read by
|
|
70
|
+
`Test-BlastRadiusConflict`, which contributes no `path_overlap` edge for a path matching it
|
|
71
|
+
while the path stays in the declared radius. `conflicts(a, b, config)` in
|
|
70
72
|
`scripts/dev_tools/compute_blast_radius.py` (defined in
|
|
71
73
|
`scripts/dev_tools/_blast_radius_conflicts.py`) remains the repository authority and the parity
|
|
72
74
|
reference. Read the verdict from `$result['conflict']`; do not test the returned hashtable
|
|
@@ -344,6 +344,29 @@ Remediation is child-owned and parent-initiated. The conflict is always between
|
|
|
344
344
|
branch and `origin/main`; there is no integration branch and therefore no fan-in conflict path on
|
|
345
345
|
this surface.
|
|
346
346
|
|
|
347
|
+
Project-file conflicts are resolved by the parent first (issue #643); the numbered steps below are
|
|
348
|
+
the escalation path.
|
|
349
|
+
|
|
350
|
+
- (a) On a conflicted `gh pr merge --merge`, the parent runs the two commands
|
|
351
|
+
`git -C <worktree_path> fetch origin main` and
|
|
352
|
+
`git -C <worktree_path> merge --no-commit origin/main`.
|
|
353
|
+
- (b) The parent then runs
|
|
354
|
+
`pwsh -NoProfile -File .claude/lib/project-file-merge/Resolve-MergeableConflict.ps1 -Worktree <worktree_path>`
|
|
355
|
+
and parses its single JSON object. A `result` of `escalate` makes the parent run
|
|
356
|
+
`git -C <worktree_path> merge --abort`
|
|
357
|
+
and continue with step 1 below, including `escalate_paths` in the Blocking finding.
|
|
358
|
+
- (c) On `resolved` the parent stages and commits the resolved paths with a message body listing
|
|
359
|
+
every entry added from each side and every version choice, then runs the three commands
|
|
360
|
+
`dotnet tool restore --tool-manifest <worktree_path>/.config/dotnet-tools.json`,
|
|
361
|
+
`dotnet csharpier check <worktree_path>`, and
|
|
362
|
+
`dotnet build <worktree_path>/<solution>`, each with path arguments rather than `cd`.
|
|
363
|
+
A failing check reverts with
|
|
364
|
+
`git -C <worktree_path> reset --hard HEAD~1`
|
|
365
|
+
and escalates with the tool output as the finding.
|
|
366
|
+
- (d) On success the parent pushes the item branch, records `mergeable_conflicts_resolved` on the
|
|
367
|
+
item, sets `merge_status: pr_open`, regenerates `parallel-status.md`, and re-enters
|
|
368
|
+
`## Per-Item Merge to Main (Merge-on-Green)` at the durable `gh pr checks` confirmation step.
|
|
369
|
+
|
|
347
370
|
1. On a conflicted `gh pr merge --merge`, the parent detects the failure and re-delegates that item's
|
|
348
371
|
child orchestration, passing the conflict signal and the instruction to resolve against
|
|
349
372
|
`origin/main`. The conflict capture and the finding write both belong to the child's
|
|
@@ -427,6 +450,14 @@ whose rows appear only once F6 populates that array; section `## Drift Events` p
|
|
|
427
450
|
`drift_events[]`, which only F8 populates. An empty array renders an empty section rather than an
|
|
428
451
|
omitted one.
|
|
429
452
|
|
|
453
|
+
The projection's `## Mergeable Conflicts Resolved` heading renders
|
|
454
|
+
`items[].mergeable_conflicts_resolved`: for each entry the path, the `resolved_at` stamp, the
|
|
455
|
+
`merged_against` ref, the `merge_commit_sha`, the entries added from each side, and the version
|
|
456
|
+
resolutions. The same resolution is cited in three further places: the body of the resolution
|
|
457
|
+
commit message, the pull-request body, and an evidence artifact at
|
|
458
|
+
`docs/features/parallel/<slug>/evidence/other/mergeable-conflicts.<yyyy-MM-ddTHH-mm>.md` carrying
|
|
459
|
+
`Timestamp`, `Command`, `EXIT_CODE`, and the script's JSON output verbatim.
|
|
460
|
+
|
|
430
461
|
Regeneration boundaries — regenerate at each of the following, not only at final completion:
|
|
431
462
|
|
|
432
463
|
- Run kickoff, seeding the initial projection from the manifest and the seeded cohorts.
|
|
@@ -435,6 +466,7 @@ Regeneration boundaries — regenerate at each of the following, not only at fin
|
|
|
435
466
|
- Every `recolor_generation` increment.
|
|
436
467
|
- Every append to `mutations[]`.
|
|
437
468
|
- Every append to `drift_events[]`.
|
|
469
|
+
- Every append to an item's `mergeable_conflicts_resolved`.
|
|
438
470
|
- Run completion in `closed` mode, or run close in `open` mode.
|
|
439
471
|
|
|
440
472
|
Defining the `mutations[]` and `drift_events[]` appends as regeneration boundaries here means F6 and
|
|
@@ -444,8 +476,10 @@ F8 need no amendment to these projection rules.
|
|
|
444
476
|
|
|
445
477
|
This section is consumption documentation only. The checkpoint schema is owned by F3, defined once
|
|
446
478
|
as prose invariants in `.claude/rules/parallel-orchestration.md`, and enforced by
|
|
447
|
-
`scripts/dev_tools/validate_parallel_orchestrator_state.py`. Consume that schema;
|
|
448
|
-
|
|
479
|
+
`scripts/dev_tools/validate_parallel_orchestrator_state.py`. Consume that schema;
|
|
480
|
+
add no field to it that `.claude/rules/parallel-orchestration.md` does not declare,
|
|
481
|
+
and extend no enum in it. `mergeable_conflicts_resolved` is the one declared optional item
|
|
482
|
+
field.
|
|
449
483
|
|
|
450
484
|
Fields `parallel-orchestrator` writes to `artifacts/orchestration/parallel-orchestrator-state.json`:
|
|
451
485
|
`objective`, `route_id: "parallel"`, `parallel_slug`, `parallel_manifest_path`,
|
|
@@ -196,6 +196,10 @@ The facade re-exports the five functions this skill needs: `Get-PlanPaths` (port
|
|
|
196
196
|
call to `Test-BlastRadius` in `@(...)`: it writes its findings to the pipeline, so a zero-element
|
|
197
197
|
result writes nothing and a one-element result writes a single object.
|
|
198
198
|
|
|
199
|
+
`Test-BlastRadiusConflict` reads the optional `mergeable_paths` list from that truth table and
|
|
200
|
+
contributes no `path_overlap` edge for a path matching it, while the path itself stays in the
|
|
201
|
+
declared radius and is still read by every audit.
|
|
202
|
+
|
|
199
203
|
The truth table the port reads is `config/blast-radius.json`, which push-down publishes into the
|
|
200
204
|
destination workspace alongside `.claude`.
|
|
201
205
|
|
|
@@ -312,6 +316,8 @@ The library returns the partition; the planner supplies the record fields.
|
|
|
312
316
|
`Test-BlastRadiusConflict` to every unordered pair of `declared` radii, then pass the pairs as
|
|
313
317
|
`--edges "<a>:<b> ..."` and the item keys as `--keys "<k1> <k2> ..."`.
|
|
314
318
|
Read the verdict from the conflict key of the returned hashtable.
|
|
319
|
+
`Test-BlastRadiusConflict` contributes no `path_overlap` edge for a path matching the truth
|
|
320
|
+
table's optional `mergeable_paths` list, and the path stays in the declared radius.
|
|
315
321
|
The hashtable itself is always truthy, so a bare boolean test on the result treats every pair as
|
|
316
322
|
conflicting and serializes the whole run. This is the sibling hazard to the `@(...)` warning
|
|
317
323
|
above for `Test-BlastRadius`: that function writes an `IList`-shaped pipeline result whose
|
|
@@ -42,6 +42,35 @@ For short-path runs, also persist:
|
|
|
42
42
|
- `phase0_execution_summary`
|
|
43
43
|
- `resume_after_manual_bootstrap` (next step token)
|
|
44
44
|
|
|
45
|
+
## Portable Prepared-State Projection
|
|
46
|
+
|
|
47
|
+
When the PowerShell delivery flow resumes from a provider-neutral prepared-state
|
|
48
|
+
handoff, the active destination projection is
|
|
49
|
+
`artifacts/orchestration/orchestrator-state.json`. Validate and retain:
|
|
50
|
+
|
|
51
|
+
- the destination provider, checkpoint expression, selected projector,
|
|
52
|
+
`plan-path`, and exact recorded `next_step`;
|
|
53
|
+
- the portable handoff ID, envelope and latest-history SHA-256 values, selected
|
|
54
|
+
adapter, source validator, identity, repository/workspace/branch binding,
|
|
55
|
+
exact plan proof, lifecycle, capabilities, and scheduler context;
|
|
56
|
+
- the source checkpoint path/hash/archive facts and opaque historical receipt
|
|
57
|
+
references without converting them into Claude receipts; and
|
|
58
|
+
- `destination_evidence: { status: "pending_first_delegation", receipts: [] }`
|
|
59
|
+
until the first new Claude delegation after materialization.
|
|
60
|
+
|
|
61
|
+
Do not rediscover the plan or rerun any phase listed in
|
|
62
|
+
`portable_handoff.lifecycle.completed_phases`. Resume only the recorded
|
|
63
|
+
transition. Record Claude model, launch, worktree, and receipt evidence through
|
|
64
|
+
Claude-native fields for new work; functional parity does not require copying
|
|
65
|
+
Codex field names or launch representations.
|
|
66
|
+
|
|
67
|
+
For a scheduled parallel or epic child, validate the run/item, parent
|
|
68
|
+
checkpoint path/hash, scheduler and child owners, return contract, exact plan
|
|
69
|
+
hash, child checkpoint hash, and result hash before returning a result. The
|
|
70
|
+
ordinary child may update only its bounded status/result projection. Cohort or
|
|
71
|
+
wave order, barriers, fan-in, integration, cleanup, worktree lifecycle, and
|
|
72
|
+
parent completion remain owned by the parent scheduler.
|
|
73
|
+
|
|
45
74
|
## Update Protocol
|
|
46
75
|
|
|
47
76
|
- Write checkpoint after every completed orchestration sub-step.
|
|
@@ -55,4 +84,3 @@ On invocation:
|
|
|
55
84
|
2) If incomplete, resume from `next_step` without re-running `completed_steps`.
|
|
56
85
|
3) If missing or completed, start at phase-0 intake.
|
|
57
86
|
4) If user explicitly requests restart, reset checkpoint and start phase-0.
|
|
58
|
-
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
".claude/hooks/enforce-pr-author-skill-helpers.ps1",
|
|
47
47
|
".claude/hooks/enforce-prd-feature-before-planner.ps1",
|
|
48
48
|
".claude/hooks/enforce-promotion-mcp-only.ps1",
|
|
49
|
+
".claude/hooks/hook-command-invocation.ps1",
|
|
50
|
+
".claude/hooks/hook-command-scanner.ps1",
|
|
49
51
|
".claude/hooks/persist-session-id.ps1",
|
|
50
52
|
".claude/hooks/validate-bash.ps1",
|
|
51
53
|
".claude/hooks/validate-discovery-artifact-gate.ps1",
|
|
@@ -134,6 +136,11 @@
|
|
|
134
136
|
".claude/lib/blast-radius/BlastRadius.psm1",
|
|
135
137
|
".claude/lib/blast-radius/BlastRadiusNormalization.psm1",
|
|
136
138
|
".claude/lib/blast-radius/BlastRadiusTokenShape.psm1",
|
|
139
|
+
".claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1",
|
|
140
|
+
".claude/lib/blast-radius/BlastRadiusConflict.psm1",
|
|
141
|
+
".claude/lib/project-file-merge/ProjectFileMergeGrammar.psm1",
|
|
142
|
+
".claude/lib/project-file-merge/ProjectFileMerge.psm1",
|
|
143
|
+
".claude/lib/project-file-merge/Resolve-MergeableConflict.ps1",
|
|
137
144
|
".claude/rules/parallel-orchestration.md",
|
|
138
145
|
".claude/rules/shell.md",
|
|
139
146
|
".claude/lib/bash/compute-cohorts.sh",
|