r-build · git:20260924.dad7868 · 2026-09-24 · sha256 c74cacab207a0fe3

r-build git:20260924.dad7868A

Immutable. This exact content never changes and is served at /api/v1/blob/c74cacab207a0fe3.

---
name: r-build
description: >
  Use when a plan exists and you want it built: dispatches the plan-execution orchestrator (engineer/QA/review gates) per phase at the right tier.
---

You are the build command. You prepare context and dispatch the
dispatcher subagent to execute an implementation plan.

## Invocation

`/rdf:r-build [N | N-M | --parallel] [--worktree] [--max N] [--consistency-warn-only "<reason>"]`

Arguments:
  N            — single phase (existing behavior)
  N-M          — range of phases (e.g., 1-4) — dispatch in parallel
  --parallel   — auto-batch all pending phases by dependency graph
  --worktree   — force git worktree isolation (overrides auto-derivation)
  --max N      — maximum concurrent dispatchers (default: 4)
  --consistency-warn-only "<reason>" — downgrade a consistency-gate structural
               block to a warning; requires a stated reason (see Section 1)
  (no args)    — next pending phase, serial (existing behavior)

## Protocol

### 1. Locate and Validate the Active Plan

- Source `~/.rdf/state/rdf-bus.sh` and call `rdf_session_init`. If the helper
  is absent (helpers not yet bootstrapped — fresh plugin install before its
  first session restart), stop and tell the user: `/rdf:r-build` needs the
  `~/.rdf/state` helpers — restart your session so the RDF plugin can
  bootstrap them, or run `rdf deploy claude-code` from a checkout.
- `plan_path="$(rdf_active_plan_path)"` — resolves via three-tier
  fallback (session pointer → un-suffixed pointer → root PLAN.md).
- If `$plan_path` is empty, report error and stop:
  "No active plan found. Create one with /rdf:r-plan or write it manually,
   then run /rdf:r-plan --resume <path> to set the pointer."
- `tier="$(rdf_active_tier)"` — resolve the plan's task-class tier
  (`full` when no `**Tier:**` marker); carried into the Section 5
  dispatch payload so the dispatcher can cap gates.
- Read `$plan_path` as the plan input from here forward. Validate
  the plan against
  [reference/plan-schema.md](../reference/plan-schema.md). Apply
  Plan-Version Awareness first, then Rules 1-9 in order. On the first
  violation, print the rule number and the exact failure message from
  the schema doc, then stop without dispatching.

  Rule 9 (test-count self-consistency) is conditional — it fires only
  when a phase contains an explicit test-count assertion. Apply the same
  trigger check as `/rdf:r-plan` Step 2.7: scan each phase's `**Test**`
  field and step prose for an integer adjacent to a test noun; if found
  and not marked `TODO`, verify the declared count matches the `@test`
  references in the phase body. On mismatch, stop with the Rule 9
  failure message before dispatching.

  /rdf:r-plan Step 2.7 should have caught any schema violations before the
  plan was committed. If validation fails here, the plan was authored
  manually, edited after planning, or the pre-reviewer pass was skipped
  — either fix the plan and re-run /rdf:r-build, or re-run /rdf:r-plan to
  regenerate.

- **Consistency micro-gate (spec↔plan↔tasks).** After schema validation,
  run the deterministic cross-check:
  ```bash
  bash ~/.rdf/state/rdf-consistency.sh check "$plan_path"
  ```
  (If a source spec is known, pass it as the second argument for goal /
  edge-case coverage.) Exit 2 = structural break (File-Map/phase mismatch
  or phase-count mismatch) → print the findings and STOP without
  dispatching (fix via `/rdf:r-plan`). Exit 1 = advisory drift (uncovered
  goal/edge case, missing `**Goals:**` field, tier-size) → surface the
  findings and proceed. Exit 0 = clean. Spec Kit `/analyze` precedent;
  mechanical checks only.

  **Escape hatch.** For a rare legitimate structural false-positive (an
  intentional File-Map entry a reviewer approved), re-run with
  `~/.rdf/state/rdf-consistency.sh check --warn-only "$plan_path"` to downgrade
  the exit-2 block to an exit-1 warning. Using `--warn-only` REQUIRES the
  operator to state the reason in the `/rdf:r-build` invocation (e.g.
  `/rdf:r-build --consistency-warn-only "reason: File-Map intentionally lists
  the generated foo.sh"`) — exit-2-with-no-override is too brittle for
  real plans.

### 2. Identify Target Phase

- If `$ARGUMENTS` contains a number N: target Phase N
  - If Phase N does not exist in the active plan, report error and stop
  - If Phase N has `Status: complete`, warn and ask for confirmation
- If no argument: scan phases in order, target first with
  `Status: pending`
  - If all phases are complete, report "All phases complete. Use
    /rdf:r-ship for release workflow." and stop
  - If a phase has `Status: in-progress`, warn that a phase is
    already in progress and ask for confirmation before restarting it

### 2b. Identify Parallel Batch

If arguments contain a range (N-M) or --parallel:

1. Read Phase Dependencies from the active plan preamble
   - Parse structured list: `- Phase N: none` or `- Phase N: [deps]`
   - If no structured list found, fall back to serial with warning:
     "Phase Dependencies section not in structured format. Running
     serially. Use the format: `- Phase N: none` or `- Phase N: [1, 2]`"

2. Determine target phases:
   - Range (N-M): phases N through M inclusive
   - --parallel: all phases with Status: pending
   - If any phase has Status: in-progress, warn and ask:
     "Phase {N} is in-progress (may be from a prior session).
     Include in parallel batch? [Y/skip/abort]"

3. Compute parallel batches from dependency graph:
   - A phase is eligible for a batch when all its dependencies are
     complete (already done or in a prior batch)
   - Phases with `none` dependencies are eligible for the first batch
   - Group eligible phases into batches, respecting --max ceiling
   - Result: ordered list of batches, each batch is a set of
     independent phases

4. Validate file ownership within each batch:
   - For each batch: collect all files from all phases in the batch
   - Parse the **Files:** field from each phase: extract paths from
     lines matching `Create: \`path\``, `Modify: \`path\``, or
     `Delete: \`path\``. This is a best-effort heuristic — if paths
     cannot be extracted (free-form text), skip validation with
     warning: "Cannot parse file list for Phase {N}. Proceeding
     without file ownership validation."
   - If any file appears in more than one phase: split conflicting
     phases into separate batches, warn:
     "Phases {N} and {M} both modify {file}. Serializing."
   - Re-validate after splitting

5. Derive isolation level per batch:
   - For each phase in the batch, derive scope classification
     (same rules as dispatcher: file list + description + governance)
   - Batch isolation = highest scope in the batch:
     scope:multi-file or below → parallel-agent (file-gated)
     scope:cross-cutting or sensitive → parallel-worktree
   - If --worktree flag is set: force parallel-worktree regardless

6. Present dispatch plan to user:
   "Parallel dispatch plan:
    Batch 1 (parallel, {isolation}): Phases {list}
    Batch 2 (serial): Phase {N} (depends: batch 1)
    Batch 3 (parallel, {isolation}): Phases {list}
    Batch 4 (serial): Phase {N} (depends: all)

    {total phases} phases in {total batches} batches. Proceed? [Y/n]"

   Wait for user confirmation.

### 3. Create Task List

Read all phases from the active plan (`$plan_path`) and create a task for each one:

```
For each phase in the active plan, in phase order, one TaskCreate per message:
  TaskCreate:
    subject: "Phase {N}: {description}"
    activeForm: "Building Phase {N}: {short desc}"
Mark already-complete phases as completed immediately.
Mark target phase as in_progress before dispatching.
Mark target phase as completed when dispatcher returns PASS.
```

Issue each `TaskCreate` in its own message — see
[reference/progress-tracking.md](../reference/progress-tracking.md).
Do NOT batch phase TaskCreates in a single message: parallel
execution produces non-deterministic display order (e.g. Phase 1,
7, 6, 5, 3, 4, 2 instead of 1-7).

### 4. Load Governance Context

- Read `.rdf/governance/index.md`
  - If governance index does not exist, warn: "No governance found.
    Run /rdf:r-init to generate governance, or proceed without it."
- Load all governance files unconditionally:
  - conventions.md, constraints.md, verification.md,
    anti-patterns.md, architecture.md
- Read the current operational mode (if `.rdf/governance/index.md`
  has a Mode field other than "development")

### 5. Assemble Dispatch Payload

Build the dispatch prompt for the dispatcher subagent:

```
PHASE: <N>
DESCRIPTION: <phase description from the active plan>
MODE: <execution mode tag: serial-context | serial-agent | parallel-agent>
TIER: <rdf_active_tier — full|quick-plan|bugfix, read at Section 1>
FILES: <file list from the active plan>
ACCEPT: <acceptance criteria from the active plan>
PLAN_PHASE_COUNT: <total phases in the active plan>
PARALLEL_BATCH: <true if dispatched as part of parallel batch, false otherwise>

GOVERNANCE:
  index: .rdf/governance/index.md
  conventions: .rdf/governance/conventions.md
  constraints: .rdf/governance/constraints.md
  verification: .rdf/governance/verification.md
  anti-patterns: .rdf/governance/anti-patterns.md
  architecture: .rdf/governance/architecture.md

OPERATIONAL_MODE: <mode or "development">
PROJECT_ROOT: <absolute path to project root>
```

### 6. Dispatch Dispatcher Subagent

Dispatch the `rdf-dispatcher` subagent with the assembled payload.
The dispatcher handles all execution from here: TDD cycles, engineer
dispatches, quality gates, commit strategy.

### 6b. Dispatch Parallel Batch

Before any worktree creation, source `~/.rdf/state/rdf-bus.sh` and call
`rdf_session_init` to ensure `RDF_SESSION_ID` is set. Each Bash call is a
fresh shell, so every block below that uses `${RDF_SESSION_ID}` starts with
`source ~/.rdf/state/rdf-bus.sh && rdf_session_init` in the same call.
Worktree paths and branch names use the full session id for collision-free
identification across concurrent sessions on the same repository (a resumed
session can reuse its id — see session-safety.md).

For each batch in the dispatch plan (sequential between batches,
parallel within each batch):

**File-gated dispatch (parallel-agent):**
1. Create task per phase in the batch
2. Dispatch N rdf-dispatcher subagents simultaneously
   - Each gets the standard dispatch payload (Section 5) plus:
     PARALLEL_BATCH: true
   - Each operates on the shared working tree
   - File ownership enforced by the plan (validated in 2b.4)
3. Wait for all subagents in the batch to complete
4. Collect results: PASS or FAIL per phase

**Worktree dispatch (parallel-worktree):**
1. Create task per phase in the batch
2. For each phase, create a git worktree. A retry (Option 2) or a resume
   (Option 3) in the same session reuses the session id, so first clear
   any leftover worktree and branch for this phase, logging the branch tip
   so a failed attempt's commits stay recoverable (`git branch <name> <tip>`):
   ```
   source ~/.rdf/state/rdf-bus.sh && rdf_session_init
   [ -n "$RDF_SESSION_ID" ] || { echo "rdf: no session id; refusing worktree setup" >&2; exit 1; }
   root="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)" || exit 1
   wt="${root}/.worktrees/rdf-phase-{N}-${RDF_SESSION_ID}"; br="rdf/phase-{N}-${RDF_SESSION_ID}"
   if tip=$(git rev-parse --verify -q "refs/heads/$br"); then
       echo "removing leftover $br (tip $tip)"
       git worktree remove --force "$wt" 2>/dev/null || true  # worktree may already be gone
       git branch -D "$br"
   fi
   git worktree add "$wt" -b "$br" HEAD
   ```
   (RDF_SESSION_ID is the full session id; prevents cross-session collisions)

   After the batch's `git worktree add` calls, activate the phase scope
   guard from the main worktree (idempotent; once per batch is enough):

   ```
   source ~/.rdf/state/rdf-bus.sh
   rdf_phase_hook_install "$(git rev-parse --show-toplevel)" \
     || echo "warn: phase scope guard (layer 1) not installed; post-merge scope check still applies" >&2
   ```

   The helper copies `~/.rdf/state/git-hooks/pre-commit` (RDF
   self-hosting: `state/git-hooks/pre-commit`) into the repo's
   `rdf-hooks/` and adds an `includeIf "onbranch:rdf/phase-**"` include,
   so the hook runs on phase branches only and chains the project's own
   hooks; rc 2 means git < 2.23. The hook enforces phase scope
   (Files ∪ Tests-may-touch) at `git commit` time. See `plan-schema.md`
   Rule 8 and dispatcher.md "Worktree Pre-Commit Hook Installation".

3. Before each `Task` dispatch, the controller MUST change directory
   into the target worktree:
   ```
   cd .worktrees/rdf-phase-{N}-${RDF_SESSION_ID}
   ```
   The `Task` tool inherits the controller's CWD; the SDK picks an
   adjacent repo non-deterministically when CWD has no `.git/`
   (see workspace CLAUDE.md "Worktree CWD"). This `cd` is the
   actual mechanism that closes the non-deterministic-CWD class.
   For parallel dispatches in a batch, the controller serializes
   the `cd → Task` pair per-phase (parallelism comes from the
   `Task` calls returning before the subagent finishes, not from
   simultaneous `cd`s).

   Then dispatch N rdf-dispatcher subagents simultaneously:
   - Each gets the standard dispatch payload plus:
     PARALLEL_BATCH: true
     PROJECT_ROOT: {worktree path}
     PROJECT_ROOT_MAIN: {main worktree toplevel}
   - Each dispatched with isolation: "worktree"
4. Wait for all subagents in the batch to complete
5. Merge completed worktrees in plan order:
   For each completed phase (in plan order, N ascending):
     git rebase {base-branch} rdf/phase-{N}-${RDF_SESSION_ID}
   Where {base-branch} is the branch HEAD was on when worktrees were
   created (captured at step 2 of worktree dispatch).
     git merge --ff-only rdf/phase-{N}-${RDF_SESSION_ID}
   This produces a clean linear history — phase commits appear in
   plan order with no merge commit artifacts.
   If rebase conflict: stop, report conflicting phases, enter
   failure handling (Section 8)
6. Clean up worktrees:
   git worktree remove .worktrees/rdf-phase-{N}-${RDF_SESSION_ID}
   git branch -d rdf/phase-{N}-${RDF_SESSION_ID}
7. Collect results: PASS or FAIL per phase

**Constraint:** Worktree dispatch MUST be invoked from a top-level
session, not from a subagent. Subagents inherit `RDF_SESSION_ID`
from their parent and would create colliding worktree paths.
The `PARALLEL_BATCH` downgrade in `dispatcher.md` (lines 45-49)
already prevents nested parallel dispatch; this is its
worktree-specific explicit form.

**Post-batch quality gate (worktree dispatch only):**
After merging all worktrees in a batch, run a batch-level QA check:
- Dispatch rdf-qa subagent across the combined diff of all phases
  in the batch
- This catches semantic conflicts that file ownership validation
  cannot detect (e.g., two phases both adding the same function name
  to different files)
- If QA finds issues: enter failure handling (Section 8)

**Progress tracking:**
Write batch progress to `.rdf/work-output/build-progress-${RDF_SESSION_ID}.md`
(derived via `rdf_scoped_filename` from `~/.rdf/state/rdf-bus.sh`):
  DISPATCH_MODE: parallel
  TOTAL_PHASES: {N}
  TOTAL_BATCHES: {N}
  CURRENT_BATCH: {N}
  BATCH_PHASES: [list]
  COMPLETED_PHASES: [list]
  FAILED_PHASES: [list]

After each batch completes, update and proceed to the next batch.
After all batches complete, proceed to end-of-plan sentinel
(unchanged — runs on cumulative diff from phase 1 to HEAD).

### 7. Report Result

After the dispatcher returns:
- Read the dispatcher's status output from .rdf/work-output/
- Report phase result to the user: PASS (phase complete) or FAIL
  (with failure context and which gate failed)
- If PASS and more phases remain:
  > **Phase {N} complete** — {description}
  > Next: Phase {N+1} — {description}. Run `/rdf:r-build` to continue.
- If PASS and all phases are complete:
  - If PLAN_PHASE_COUNT >= 3: the dispatcher runs end-of-plan sentinel
    automatically (this is dispatcher-internal — the build command
    does not dispatch it separately)
    > **All {N} phases complete.** End-of-plan review: {verdict}.
    > Run `/rdf:r-ship` to begin the release workflow.
  - If PLAN_PHASE_COUNT < 3:
    > **All {N} phases complete.**
    > Run `/rdf:r-ship` to begin the release workflow.

### 8. Parallel Failure Handling

When one or more phases in a parallel batch fail:

1. Wait for all phases in the batch to complete (do not interrupt
   running phases on peer failure)

2. Classify each failure:
   - Gate 1 (engineer self-report) failure → recommendation: retry
   - Gate 2 (QA) failure → recommendation: retry
   - Gate 3 (sentinel) MUST-FIX → recommendation: retry
   - Gate 3 (sentinel) architectural concern → recommendation: pause
   - Merge conflict → recommendation: serialize conflicting phases
   - Post-batch QA failure → recommendation: pause

3. Present to user with Recommendation:
   "Batch {N} results:
    [PASS] Phase 1: Replace dispatcher gate selection
    [FAIL] Phase 2: Update agent finding vocabularies (Gate 2: lint)
    [PASS] Phase 3: Simplify r-plan metadata
    [PASS] Phase 4: Simplify r-build dispatch payload

    Phase 2 failed at Gate 2 (QA lint error).
    **Recommendation: retry** — lint errors are typically fixable.

    Options:
    [1] Merge phases 1, 3, 4 now — retry phase 2 after merge
    [2] Retry phase 2 in isolation (attempt 2/3)
    [3] Pause — review failure before proceeding"

4. Execute user's choice:
   - Option 1: Merge successful phases in plan order, then dispatch
     phase 2 serially against new HEAD
   - Option 2: Re-dispatch phase 2's dispatcher subagent (same
     isolation level, max 3 total attempts); worktree dispatch clears the
     failed attempt's worktree and branch first (step 2)
   - Option 3: Write progress to
     `build-progress-${RDF_SESSION_ID}.md`, stop. User can resume
     with `/rdf:r-build --parallel` (which calls `rdf_session_init`
     and reads the scoped progress file); in the same session (or after
     `claude --resume <id>`) the id matches, and step 2 clears the paused
     phase's leftover worktree before re-dispatching it.

## Constraints

- Never execute plan phases directly — always dispatch to dispatcher
- Never modify the active plan — the dispatcher updates phase status
- If governance is missing, dispatch anyway (dispatcher degrades
  gracefully) but warn the user
- Respect the plan's execution mode tags — pass them through unchanged
- Parallel dispatch is additive — /rdf:r-build N (single phase) works unchanged
- Nested parallel downgrade: dispatchers in parallel batches receive PARALLEL_BATCH: true