From c60e93286fb7f1673e9e93cab8a7fcc7ad6625f1 Mon Sep 17 00:00:00 2001 From: Daniel Lam Date: Mon, 10 Aug 2026 22:08:37 +0700 Subject: [PATCH 1/2] feat: worktree-per-task wave execution File-scope disjointness alone co-schedules tasks that still contend on a shared mutable build root (Cargo's locked target/ is the canonical case), which in agent-executed pipelines degrades into hours of lock-thrash. Observed: two co-scheduled Rust tasks blocked on 'Blocking waiting for file lock' for 24+ hours with near-zero progress per turn. Phase 3 waves now dispatch each task into its own worktree and branch from a pinned wave base: build state becomes private by construction and each task gains a private branch, removing both reasons SDD serialized. The full dispatch/join/reconciliation/cleanup protocol lands in references/worktree-wave-execution.md; phase-3-execution.md's three path-scoped-package conditions collapse into per-task-branch packaging with a scope-overflow check. Spec-plan gains the Exclusive resources: task header (worktrees isolate paths, not daemons), ship gains the no-wip-commit ship gate, and handoff enumerates live task worktrees for mid-wave relays. --- skills/delivery-handoff/SKILL.md | 9 +- skills/delivery-pipeline/SKILL.md | 4 +- .../references/phase-3-execution.md | 57 +++-- .../references/worktree-wave-execution.md | 224 ++++++++++++++++++ skills/delivery-ship/SKILL.md | 7 +- skills/delivery-spec-plan/SKILL.md | 14 +- 6 files changed, 281 insertions(+), 34 deletions(-) create mode 100644 skills/delivery-pipeline/references/worktree-wave-execution.md diff --git a/skills/delivery-handoff/SKILL.md b/skills/delivery-handoff/SKILL.md index 55dc805..f645821 100644 --- a/skills/delivery-handoff/SKILL.md +++ b/skills/delivery-handoff/SKILL.md @@ -1,7 +1,7 @@ --- name: cmk:delivery-handoff description: This skill should be used when the user asks for "a handoff prompt", "a prompt for codex/grok/claude", "something I can paste into another agent", or wants to continue tracked work in a different tool — and at any phase boundary of the cmk:delivery-pipeline skill when the operator prefers a different agent for the next phase. -version: 0.1.0 +version: 0.2.0 --- # Delivery Handoff @@ -69,7 +69,12 @@ freely; completeness matters, sections don't): 2. **Workspace** — absolute worktree path, branch, base branch (= future PR base), the verify-before-touching commands, and the same-worktree rule. For clusters: the issue → worktree/branch/base table plus where - the orchestration plan lives and which wave is active. + the orchestration plan lives and which wave is active. For a handoff + mid-way through a phase-3 wave, additionally enumerate every live task + worktree — path, task branch, wave-base SHA, and join state (pending / + integrated / escalated), from the wave manifest in the ledger — and + state that task worktrees follow the wave protocol's retention rules, + never ad-hoc cleanup. 3. **Read first** — ordered absolute paths: the phase skill(s) to follow, the tracking contract (`cmk:delivery-workflow`), the context-efficiency reference, the receiver's runtime binding diff --git a/skills/delivery-pipeline/SKILL.md b/skills/delivery-pipeline/SKILL.md index 31a06de..d15787e 100644 --- a/skills/delivery-pipeline/SKILL.md +++ b/skills/delivery-pipeline/SKILL.md @@ -1,7 +1,7 @@ --- name: cmk:delivery-pipeline description: This skill should be used when the user asks to "work on", "deliver", "tackle", "pick up", or "implement" a tracker issue (TICKET-123), a list of issues, or a body of tracked work expected to finish without supervision — even if they never say "pipeline". Also use when handed a cluster of related issues, or a single issue whose surrounding cluster should be derived from tracker dependencies, expecting dependency-aware sequencing across worktrees. -version: 0.1.0 +version: 0.2.0 --- # Delivery Pipeline @@ -79,7 +79,7 @@ reads this instead of rediscovering it — keep it to those four things. | Phase | Skill / engine | CMK adds | |---|---|---| | 1. Intake | `cmk:delivery-intake` | all of it — the tracker has no superpowers equivalent | -| 2. Spec & plan | `cmk:delivery-spec-plan`, via `superpowers:brainstorming` + `superpowers:writing-plans` | design-doc inputs; `Depends on:`, `File scope:`, and binding obligations inside each task body | +| 2. Spec & plan | `cmk:delivery-spec-plan`, via `superpowers:brainstorming` + `superpowers:writing-plans` | design-doc inputs; `Depends on:`, `File scope:`, `Exclusive resources:`, and binding obligations inside each task body | | 3. Implement | `superpowers:subagent-driven-development` (below) | wave dispatch and its safety fixes | | 4. Review | `cmk:delivery-review` | lenses, evidence bar, adversarial verification, disposition, depth disclosure | | 5. Ship | `cmk:delivery-ship` | PR, tracker reconciliation, evidence | diff --git a/skills/delivery-pipeline/references/phase-3-execution.md b/skills/delivery-pipeline/references/phase-3-execution.md index d338b1e..98f624c 100644 --- a/skills/delivery-pipeline/references/phase-3-execution.md +++ b/skills/delivery-pipeline/references/phase-3-execution.md @@ -22,30 +22,39 @@ own model and effort; its "REQUIRED" caution exists for a stock agent that declares neither. The role also requires the worker to report each commit SHA, which is what the scope check below consumes. -CMK changes exactly one thing: **independent tasks run in the same wave.** -SDD serializes implementers because concurrent commits contaminate its -`BASE..HEAD` review packages — not merely because of file conflicts. Tasks -with no `Depends on:` and disjoint `File scope:` may be dispatched together -once three things hold: - -1. **Review packages are path-scoped.** SDD's own review-package assembly - cannot take a pathspec and lives in a plugin cache that is overwritten - on update, so use a path-scoped review-package script the repo may - provide — appending `-- ` to the same commit range — - otherwise assemble the diff with `git diff` scoped to the task's file - list. -2. **Each package has its own output path.** A commit-range-only filename - is keyed by BASE and HEAD alone, so two tasks in one wave sharing a - range resolve to the *same file* and one silently overwrites the other. - Give each its own name, e.g. `review-task--...diff`. -3. **Commits are checked against the declared scope.** A path-scoped diff - hides edits made outside that scope, so they would ship unreviewed. - Compare each task's actual commits against its `File scope:`; append - any overflow to the package so it still gets reviewed, and surface the - violation to the controller rather than silently reading past it. - -Disjoint scopes make independence *checkable*, not guaranteed. Never -describe it as proven. +CMK changes exactly one thing: **independent tasks run in the same wave, +each in its own worktree.** SDD serializes implementers for two reasons, +and per-task worktrees remove both: concurrent commits contaminate a +shared branch's `BASE..HEAD` review packages, and a shared mutable build +root — one Cargo `target/` and its exclusive lock — serializes +"independent" tasks into lock-thrash where every worker turn blocks and +nothing progresses. + +Wave eligibility: no `Depends on:`, disjoint `File scope:`, and no +intersecting `Exclusive resources:`. Disjoint scopes make independence +*checkable*, not guaranteed — never describe it as proven. + +The dispatch, join, reconciliation, and cleanup protocol — parent-WIP +snapshot commits, pinned wave base, per-task branches, cache seeding, +rebase-then-ff-only integration, retention on failure, and every guard — +is `references/worktree-wave-execution.md`. Follow it exactly; its MUSTs +are load-bearing. + +Review packages are per task branch: the range `wave-base..task-head`. +SDD's own review-package assembly cannot take a pathspec and lives in a +plugin cache overwritten on update, so use the repo's review-package +script where one exists — with an explicit per-task output path (a +range-keyed default silently collides between tasks sharing a base), the +task's `File scope:`, and its commits — otherwise assemble the diff with +`git diff` over the range. Either way, check each task's commits against +its declared scope: append any overflow to the package so it still gets +reviewed, and surface the violation to the controller rather than +silently reading past it. + +**Thrash detection.** Lock-wait build output or repeated no-progress +timeouts are a scheduling fault, not a task fault: stop the affected +tasks, re-serialize or isolate the contended resource, and record it in +the ledger — never let the loop tick for hours against a lock. Reading the ledger under waves: lines are keyed `Task :`, so filter by task ID **before** taking "the last line." Sequentially, the file's last diff --git a/skills/delivery-pipeline/references/worktree-wave-execution.md b/skills/delivery-pipeline/references/worktree-wave-execution.md new file mode 100644 index 0000000..ec0784f --- /dev/null +++ b/skills/delivery-pipeline/references/worktree-wave-execution.md @@ -0,0 +1,224 @@ +# Worktree-per-task wave execution + +The protocol phase 3 follows when dispatching independent tasks concurrently. +Every rule here is runtime-neutral — plain git and shell — so any harness can +implement it. A runtime binding may supply mechanics, never different rules. + +Why this protocol exists: file-scope disjointness alone is not independence. +Toolchains with a shared mutable build root — Cargo is the canonical case: one +workspace-level `target/` guarded by an exclusive file lock — serialize two +"independent" tasks into lock-thrash where every worker turn blocks on +`Blocking waiting for file lock` and produces nothing. Per-task worktrees make +build state private by construction, and as a second effect give every task a +private branch, which removes the commit contamination that forced path-scoped +review packages. + +## Wave eligibility + +Tasks may share a wave only when all three hold: + +1. No `Depends on:` edge between them (directly or transitively). +2. Disjoint `File scope:`. Disjointness makes independence *checkable*, not + guaranteed — never describe it as proven. +3. No intersecting `Exclusive resources:`. Worktrees isolate build + directories, but not shared services: the Docker daemon, a shared local + chain or database, an external sandbox. Two tasks declaring the same + resource never share a wave. + +## Dispatch + +1. **Snapshot the parent.** If the ticket worktree is dirty, the controller + MUST create a snapshot commit on the ticket branch — subject prefixed + `wip:`, capturing staged, unstaged, and untracked state via `git add -A`. + Before staging, the controller MUST read the untracked list + (`git status --porcelain`) and account for every entry: `.gitignore` keeps + ignored state out, but it says nothing about files that were never given + an ignore pattern — a stray credential file, key, or unexplained binary is + exactly what this inspection exists to catch, and finding one aborts + dispatch for explicit disposition instead of committing it. The snapshot + is how parent WIP reaches sub-worktrees: byte-identical, but pinned to a + SHA so every later `BASE..HEAD` computation is well-defined and nothing + uncommitted can ship unreviewed. While any `wip:` commit exists on the + ticket branch, the branch MUST NOT be pushed — no early draft PR, no + backup push — because the subject-line ship gate cannot un-publish content + that already reached a remote. A clean tree skips the snapshot. If the + ticket worktree is mid-merge, mid-rebase, or mid-cherry-pick, dispatch + MUST abort — snapshotting a half-resolved state pins garbage. +2. **Pin the wave base and record the wave manifest.** The wave base is the + ticket branch tip after the snapshot. Every task in the wave branches from + this SHA, and every task's review range starts at it. The controller MUST + record a wave manifest in the ledger before dispatching: wave number, + member task IDs, the wave-base SHA, and each task's worktree path and + branch name. This manifest is what a crashed run resumes from — without + it, a resuming controller cannot tell an already-integrated task from one + that was never dispatched. +3. **Create one worktree per task.** + `git worktree add -b --task- `, + under the runtime's native worktree area — never an ad-hoc path — with the + ticket identity embedded in `` as well as the branch: a path keyed + by task number alone collides with a concurrent ticket's task worktrees + under cluster mode. Quote paths and branch names when running these + commands through a shell. If a task branch or worktree from a previous + run already exists, the controller MUST NOT silently reuse or delete it: + inspect it, then either resume it as that task's fix-round state or record + an explicit disposition. Git surfaces the common leftovers itself — an + existing branch, a non-empty path, a branch checked out elsewhere all make + `git worktree add` refuse — but an empty leftover directory does not, so + the inspection is the guard; the git errors are only its backstop. A + leftover found mid-rebase is an unfinished git operation, not fix-round + state: `git rebase --abort` it, then redo that task's integration from its + recorded branch. +4. **Initialize the environment.** Each sub-worktree runs the repo's + worktree initialization and coherence checks, where the repo defines + them, before any local dev. Env files are regenerated per worktree, never + copied or sourced from a sibling. +5. **Verify build-dir isolation — never assume it.** A globally exported + shared build directory (`CARGO_TARGET_DIR` or any equivalent) silently + defeats per-worktree isolation and reintroduces the lock thrash. Dispatch + MUST unset or override such variables in each sub-worktree's environment + and MUST fail loudly if a shared build dir is still detected. +6. **Seed build caches.** Where the toolchain tolerates relocation, copy the + parent's derived build state (for Cargo, `target/`) into the sub-worktree + so it starts warm: prefer a copy-on-write clone (`cp -c -R` on macOS/APFS, + `cp --reflink=auto -R` on Linux — `auto` degrades to a plain copy on + filesystems without reflink), fall back to a plain copy, and accept a cold + build only when copying is unattractive. Seed only into a destination that + does not exist yet: `cp -R` into an existing directory nests + (`target/target/…`) instead of merging, silently leaving stale artifacts + in charge — so a resumed worktree keeps the build state it already has and + is never re-seeded. Seeding MUST happen while no build runs in the parent + — never copy a build dir a live compiler holds locked. Warm start is an + optimization, not a guarantee: a seed that postdates a toolchain change + just rebuilds (compiler fingerprints invalidate it), which costs time, not + correctness. Before a plain (non-CoW) copy, the controller MUST check free + disk against the seed's size; wave width is chosen against host capacity — + cores, disk, and any per-worktree port space — not just task independence. + Run the ecosystem's dependency install per sub-worktree where required. +7. **Dispatch the worker** with its working directory set to the sub-worktree. + The brief, gate commands, scope, and reporting contract are unchanged. + +## Join and cleanup + +Integrate finished tasks one at a time, in controller-chosen order (default: +task number): + +1. **Verify on the task branch.** The per-task gate command passes there. The + review package is the range `wave-base..task-head` — the branch contains + only this task's commits, so the scope filter no longer has to *select* + this task's work out of a shared branch; its remaining job is the overflow + check. Build the package with the repo's review-package script where one + exists (per `phase-3-execution.md`), giving each task an explicit per-task + output path and the task's declared scope and commits, so edits outside + the declared scope are appended to the package for review and surfaced as + a distinct non-zero exit, which the controller MUST handle as a scope + violation — never as a generic failure to retry blindly. +2. **Integrate — two moves, each from the worktree that owns the branch.** + First, *inside the task worktree*, rebase the task branch onto the current + ticket branch tip. Then, *from the ticket worktree*, advance the ticket + branch with `git merge --ff-only `. The split is not style: + the ticket branch is checked out in the ticket worktree, so `git branch + -f` or a push onto it is refused by git — the ff-only merge is the only + move that advances the checked-out ref, and it can never manufacture a + merge commit. Linear history throughout. A rebase conflict means the + disjoint-scope assumption failed: the controller MUST record the + conflicting paths in the ledger, `git rebase --abort` so the task branch + survives intact, and escalate to a fix round — never auto-resolve, never + force past it. One known-benign shape: two tasks regenerating a shared + derived file (a lockfile, generated bindings) conflict textually but not + semantically — the resolution is to re-run the generator on the rebased + state and commit its output, never to hand-merge generated content. +3. **Run the combined gate.** After each integration, run the affected gate + commands in the ticket worktree. The wave is complete only when the fully + integrated ticket branch passes its combined gates. Record the join in + the ledger — task ID and the ticket-branch SHA it landed as — so a + resumed controller can tell integrated tasks from pending ones. +4. **Clean up.** Only after the ff-only merge has landed the task's commits + on the ticket branch: `git worktree remove `, then delete the task + branch (its commits are reachable from the ticket branch, so the delete + loses nothing — never delete the branch before the merge). If removal + refuses because the worktree is dirty, that is unreported, uncommitted + work — escalate to the worker's fix round instead of forcing; `--force` + is reserved for explicit abandonment. A failed or escalated task MUST + retain its worktree and branch for the fix round. `git worktree prune` + runs at phase close. + +The next wave's base is the integrated ticket branch tip; the snapshot step +repeats if the controller has new WIP. + +## Reconciliation between tasks + +- **Default: reconcile at the join.** Wave tasks are independent by + construction; their work meets on the ticket branch, and the next wave sees + the integrated state. Dependent tasks (`Depends on:`) simply run in a later + wave, branching from a tip that already contains their prerequisites. +- **Mid-wave peer pull: controller-authorized only.** All worktrees share one + git object database, so task A can cherry-pick task B's committed work at + any moment mechanically. That move is permitted only as an explicit + controller decision, and the ledger MUST record that A's effective base now + includes B's commits so A's review range and reviewer context are set + accordingly. A peer pull also constrains the join: integrate B before A, + and verify during A's rebase that the cherry-picked commits drop as + patch-identical duplicates — if they survive (the patch drifted after the + pick), treat it as a conflict and escalate rather than landing B's work + twice. Unmediated peer merging is prohibited — it recreates the + cross-contamination this protocol removes. + +## Shared state has one writer + +The ledger and the ticket branch are controller-owned. Workers MUST commit +only to their own task branch and MUST NOT write the ledger, the plan, or any +other shared file — they report SHAs and findings for the controller to +record. This removes the write races the protocol can remove; it is a rule +workers follow, not a mechanical impossibility, and the worktrees still share +one git object database (git's own locking makes concurrent commits safe, but +refs outside a task's own branch are off-limits to workers for the same +one-writer reason). Reading the ledger under waves: lines are keyed +`Task :`, so filter by task ID before taking "the last line". + +## Thrash detection + +The controller MUST treat these worker signals as a **scheduling fault**, not +a task fault: build output containing lock-wait markers (e.g. Cargo's +`Blocking waiting for file lock`), or repeated build/gate timeouts with no new +ledger progress across consecutive turns. Progress is the discriminator — a +cold build also runs long, but its output advances (new `Compiling ` +lines, new test names) from turn to turn; thrash shows lock-wait markers or +the *same* stalled output repeating. Slow-but-advancing is not a fault. +Response to a fault: stop the affected tasks, re-serialize them or isolate +the contended resource, and record the event in the ledger. This bounds any +eligibility miss to minutes instead of hours. + +## Snapshots never ship + +Phase 5 MUST verify that no `wip:`-prefixed commit remains in the PR range +(`git log --oneline ..HEAD` is clean of them); wave snapshots are +absorbed or squashed before a PR exists. Verified, not assumed. Absorption is +the **controller's** job, done on the ticket branch before anything is +pushed: finish the snapshot's content into the real commit that owns it and +rewrite the `wip:` commit away (fixup-style rebase of the ticket branch, or +reset-and-recommit when the snapshot content became one coherent change). +The no-push-while-wip rule in Dispatch step 1 is what makes this history +rewrite safe — nothing upstream has the old SHAs. With multiple snapshots +(one per wave), absorb each the same way; every one MUST be gone from the +range before the ship gate runs. + +## Runtime bindings + +The controller-managed `git worktree add` flow above is the reference +implementation. A runtime's native worktree convenience may substitute only +when it satisfies every observable requirement of this contract: branch from +the pinned wave-base SHA, honor the task branch name, retain the worktree on +failure, and permit cache seeding. A mechanism that picks its own base or +auto-removes worktrees does not satisfy the contract and may only be used +after verifying each point for that dispatch. Bindings record which +protections their runtime enforces versus which remain the controller's +responsibility. A runtime with no concurrent-dispatch mechanism still follows +this protocol — wave members execute one after another, each in its own +worktree from the same pinned wave base, losing wall-clock parallelism but +none of the guarantees. + +Adoption is per-dispatch, not per-repo: a ticket mid-execution when this +protocol lands finishes its current wave under the rules it started with and +picks up this contract at its next dispatch. A runtime whose binding still +describes sequential execution follows its binding until the binding is +updated — the reference never silently overrides a binding already in force. diff --git a/skills/delivery-ship/SKILL.md b/skills/delivery-ship/SKILL.md index 6856939..c9085c6 100644 --- a/skills/delivery-ship/SKILL.md +++ b/skills/delivery-ship/SKILL.md @@ -1,7 +1,7 @@ --- name: cmk:delivery-ship description: This skill should be used when the user asks to "ship this", "open the PR", "push this to review", "update the tracker and open a PR", or "close out this ticket" — when implementation and review are done, and as phase 5 of the cmk:delivery-pipeline skill. -version: 0.1.0 +version: 0.2.0 --- # Delivery Ship @@ -54,7 +54,10 @@ consequential transition. Keep a straight-line history: rebase on the base branch, replaying only this branch's own commits, new commits over amend, no AI attribution. The branch carries the -issue ID. Every merge-eligible PR targets the canonical integration branch; +issue ID. No `wip:`-prefixed commit may remain in the PR range — verify +with `git log --oneline ..HEAD`, never assume; wave snapshots (see +`cmk:delivery-pipeline`'s `references/worktree-wave-execution.md`) are +absorbed before a PR exists. Every merge-eligible PR targets the canonical integration branch; a stacked issue's PR may open early against its parent's branch as a draft, but the final destination is always canonical — never a feature branch. Automated stacked-PR reconciliation (retarget on parent merge, exact-ancestry diff --git a/skills/delivery-spec-plan/SKILL.md b/skills/delivery-spec-plan/SKILL.md index 2873df8..16b1ff0 100644 --- a/skills/delivery-spec-plan/SKILL.md +++ b/skills/delivery-spec-plan/SKILL.md @@ -1,7 +1,7 @@ --- name: cmk:delivery-spec-plan description: This skill should be used when the user asks for a "spec", "design", "implementation plan", or "how should we build this" for a tracker issue, after context intake for any non-trivial change, and as phase 2 of the cmk:delivery-pipeline skill. -version: 0.1.0 +version: 0.2.0 --- # Delivery Spec & Plan @@ -89,13 +89,14 @@ dispositions, the doc-impact list from the spec, tracker reconciliation duty, the production-readiness tasks, and any invariant the change goes near with the suites that prove it — one line each, exact values verbatim. -**Every task then carries three things in its own `## Task N` body:** +**Every task then carries these in its own `## Task N` body:** ```markdown ## Task 3: Persist the session ledger Depends on: Task 1 File scope: libs/session/src/ledger.rs, libs/session/tests/ledger.rs +Exclusive resources: none @@ -104,10 +105,15 @@ File scope: libs/session/src/ledger.rs, libs/session/tests/ledger.rs - **`Depends on:`** — genuine ordering requirements only, by task number. Omit it, or write `none`, when the task has none. This is what execution schedules from. -- **`File scope:`** — every path the task may touch. Two tasks may run - concurrently only when their scopes are disjoint, and execution checks +- **`File scope:`** — every path the task may touch. Disjoint scopes are + necessary for two tasks to share a wave, not sufficient (execution also + isolates worktrees and honors exclusive resources), and execution checks each task's commits against this list afterwards, so an inaccurate scope surfaces as a scope violation rather than silently permitting a race. +- **`Exclusive resources:`** — non-path shared services the task needs + exclusively: a Docker daemon, a shared local chain or database, an + external sandbox. Write `none` when there are none. Tasks with + intersecting declarations never share an execution wave. - **The obligations, restated inside the task body.** This duplication is deliberate and load-bearing. An execution engine builds an implementer's brief by slicing the plan at the task heading, so a header-level Global From 2e055f7c55dbc7d8dbeec4b95356bf7e775f2f6b Mon Sep 17 00:00:00 2001 From: Daniel Lam Date: Mon, 10 Aug 2026 22:30:31 +0700 Subject: [PATCH 2/2] feat: wave binding duties in vendor template The vendor-bindings template tells a binding author what to record per section but said nothing about the wave protocol: which of its protections the runtime enforces versus leaves to the controller, whether a native worktree convenience satisfies the pinned-base/named-branch/ retention/seeding contract, and the sequential fallback for runtimes without concurrent dispatch. Consuming repos' bindings already need exactly this section; the template now asks for it. --- skills/delivery-workflow/SKILL.md | 2 +- .../delivery-workflow/references/vendor-bindings.md | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/skills/delivery-workflow/SKILL.md b/skills/delivery-workflow/SKILL.md index 2b7e462..c80d3ca 100644 --- a/skills/delivery-workflow/SKILL.md +++ b/skills/delivery-workflow/SKILL.md @@ -1,7 +1,7 @@ --- name: cmk:delivery-workflow description: This skill should be used when the user asks to "start tracked work", "reconcile the tracker", "check if this is ready to ship", "keep the issue useful", or "check acceptance criteria" — or needs the tracking contract every other delivery skill operates inside. -version: 0.1.0 +version: 0.2.0 --- # Delivery Workflow diff --git a/skills/delivery-workflow/references/vendor-bindings.md b/skills/delivery-workflow/references/vendor-bindings.md index 863761b..53197d8 100644 --- a/skills/delivery-workflow/references/vendor-bindings.md +++ b/skills/delivery-workflow/references/vendor-bindings.md @@ -36,6 +36,17 @@ How to enter an isolated worktree for delegated or stacked work, and the repository fallback — the repo's local-stack init and coherence scripts (see `cmk:local-stack`) — when native isolation is unavailable. +For phase-3 wave tasks, record which of the wave protocol's protections +(`cmk:delivery-pipeline`'s `references/worktree-wave-execution.md`) this +runtime enforces versus which remain the controller's responsibility — +snapshot before dispatch, build-dir override, cache seeding, retention on +failure, thrash detection — and whether any native worktree convenience +satisfies the contract (pinned wave base, named task branch, retention on +failure, cache seeding). A mechanism that picks its own base or +auto-removes worktrees does not; the controller-managed `git worktree add` +flow is the reference implementation. A runtime with no concurrent +dispatch states its sequential fallback here. + ## Tool mappings How repository reads, edits, and pattern search map onto this runtime's